mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-10-23 08:12:01 +00:00
Use libvlr in libmsc (large refactoring)
Original libvlr code is by Harald Welte <laforge@gnumonks.org>, polished and tweaked by Neels Hofmeyr <nhofmeyr@sysmocom.de>. This is a long series of development collapsed in one patch. The original history may still be available as branch neels/vlr_orig. TODO: This commit may be split in several smaller changes before merging to master. Related: OS#1592 Change-Id: I702ba504ce2de93507312c28eca8d11f09f4ee8b
This commit is contained in:
@@ -238,7 +238,6 @@ AC_OUTPUT(
|
||||
tests/Makefile
|
||||
tests/atlocal
|
||||
tests/gsm0408/Makefile
|
||||
tests/db/Makefile
|
||||
tests/channel/Makefile
|
||||
tests/bsc/Makefile
|
||||
tests/bsc-nat/Makefile
|
||||
|
@@ -29,7 +29,6 @@
|
||||
|
||||
struct gsm_bts;
|
||||
struct gsm_lchan;
|
||||
struct gsm_subscriber;
|
||||
struct gsm_bts_trx_ts;
|
||||
|
||||
#define GSM48_LEN2PLEN(a) (((a) << 2) | 1)
|
||||
|
@@ -4,7 +4,6 @@
|
||||
#include <osmocom/core/utils.h>
|
||||
|
||||
struct gsm_auth_tuple;
|
||||
struct gsm_subscriber;
|
||||
|
||||
enum auth_action {
|
||||
AUTH_ERROR = -1, /* Internal error */
|
||||
@@ -20,7 +19,4 @@ static inline const char *auth_action_str(enum auth_action a)
|
||||
return get_value_string(auth_action_names, a);
|
||||
}
|
||||
|
||||
int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr, int key_seq);
|
||||
|
||||
#endif /* _AUTH_H */
|
||||
|
@@ -41,6 +41,9 @@ struct bsc_api {
|
||||
*/
|
||||
void (*mr_config)(struct gsm_subscriber_connection *conn,
|
||||
struct gsm_lchan *lchan, int full_rate);
|
||||
|
||||
/** Callback for additional actions during conn cleanup */
|
||||
void (*conn_cleanup)(struct gsm_subscriber_connection *conn);
|
||||
};
|
||||
|
||||
int bsc_api_init(struct gsm_network *network, struct bsc_api *api);
|
||||
|
@@ -25,7 +25,7 @@
|
||||
struct gsm_subscriber_connection;
|
||||
|
||||
/* Find an allocated channel for a specified subscriber */
|
||||
struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr);
|
||||
struct gsm_subscriber_connection *connection_for_subscr(struct vlr_subscr *vsub);
|
||||
|
||||
/* Allocate a logical channel (SDCCH, TCH, ...) */
|
||||
struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type, int allow_bigger);
|
||||
|
@@ -29,53 +29,21 @@ struct gsm_network;
|
||||
struct gsm_auth_info;
|
||||
struct gsm_auth_tuple;
|
||||
struct gsm_sms;
|
||||
struct gsm_subscriber;
|
||||
|
||||
/* one time initialisation */
|
||||
int db_init(const char *name);
|
||||
int db_prepare(void);
|
||||
int db_fini(void);
|
||||
|
||||
/* subscriber management */
|
||||
struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t smin,
|
||||
uint64_t smax, bool alloc_exten);
|
||||
struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field,
|
||||
const char *subscr);
|
||||
int db_sync_subscriber(struct gsm_subscriber *subscriber);
|
||||
int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id));
|
||||
int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber);
|
||||
int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t smin,
|
||||
uint64_t smax);
|
||||
int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t* token);
|
||||
int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char *imei);
|
||||
int db_subscriber_delete(struct gsm_subscriber *subscriber);
|
||||
int db_sync_equipment(struct gsm_equipment *equip);
|
||||
int db_subscriber_update(struct gsm_subscriber *subscriber);
|
||||
int db_subscriber_list_active(void (*list_cb)(struct gsm_subscriber*,void*), void*);
|
||||
|
||||
/* auth info */
|
||||
int db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
|
||||
struct gsm_subscriber *subscr);
|
||||
int db_sync_authinfo_for_subscr(struct gsm_auth_info *ainfo,
|
||||
struct gsm_subscriber *subscr);
|
||||
int db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr);
|
||||
int db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr);
|
||||
|
||||
/* SMS store-and-forward */
|
||||
int db_sms_store(struct gsm_sms *sms);
|
||||
struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id);
|
||||
struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id);
|
||||
struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, unsigned long long min_subscr_id, unsigned int failed);
|
||||
struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr);
|
||||
struct gsm_sms *db_sms_get_unsent_for_subscr(struct vlr_subscr *vsub);
|
||||
int db_sms_mark_delivered(struct gsm_sms *sms);
|
||||
int db_sms_inc_deliver_attempts(struct gsm_sms *sms);
|
||||
|
||||
/* APDU blob storage */
|
||||
int db_apdu_blob_store(struct gsm_subscriber *subscr,
|
||||
uint8_t apdu_id_flags, uint8_t len,
|
||||
uint8_t *apdu);
|
||||
int db_sms_delete_by_msisdn(const char *msisdn);
|
||||
|
||||
/* Statistics counter storage */
|
||||
struct osmo_counter;
|
||||
|
@@ -37,12 +37,8 @@ enum {
|
||||
DRANAP,
|
||||
DSUA,
|
||||
DV42BIS,
|
||||
DVLR,
|
||||
Debug_LastEntry,
|
||||
};
|
||||
|
||||
struct gsm_subscriber;
|
||||
|
||||
void log_set_filter_vlr_subscr(struct log_target *target,
|
||||
struct gsm_subscriber *vlr_subscr);
|
||||
|
||||
extern const struct log_info log_info;
|
||||
|
@@ -9,7 +9,6 @@
|
||||
|
||||
struct msgb;
|
||||
struct gsm_bts;
|
||||
struct gsm_subscriber;
|
||||
struct gsm_network;
|
||||
struct gsm_trans;
|
||||
struct gsm_subscriber_connection;
|
||||
|
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_04_11.h>
|
||||
|
||||
struct vlr_subscr;
|
||||
|
||||
#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
|
||||
|
||||
/* SMS deliver PDU */
|
||||
@@ -29,10 +31,12 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn, struct msgb *msg);
|
||||
|
||||
struct gsm_sms *sms_alloc(void);
|
||||
void sms_free(struct gsm_sms *sms);
|
||||
struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, struct gsm_subscriber *sender, int dcs, const char *text);
|
||||
struct gsm_sms *sms_from_text(struct vlr_subscr *receiver,
|
||||
struct vlr_subscr *sender,
|
||||
int dcs, const char *text);
|
||||
|
||||
void _gsm411_sms_trans_free(struct gsm_trans *trans);
|
||||
int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
|
||||
int gsm411_send_sms_subscr(struct vlr_subscr *vsub,
|
||||
struct gsm_sms *sms);
|
||||
int gsm411_send_sms(struct gsm_subscriber_connection *conn,
|
||||
struct gsm_sms *sms);
|
||||
|
@@ -24,6 +24,8 @@
|
||||
struct mncc_sock_state;
|
||||
struct gsm_subscriber_group;
|
||||
struct bsc_subscr;
|
||||
struct vlr_instance;
|
||||
struct vlr_subscr;
|
||||
|
||||
#define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3]
|
||||
|
||||
@@ -62,20 +64,6 @@ struct gsm_auth_tuple {
|
||||
};
|
||||
#define GSM_KEY_SEQ_INVAL 7 /* GSM 04.08 - 10.5.1.2 */
|
||||
|
||||
/*
|
||||
* LOCATION UPDATING REQUEST state
|
||||
*
|
||||
* Our current operation is:
|
||||
* - Get imei/tmsi
|
||||
* - Accept/Reject according to global policy
|
||||
*/
|
||||
struct gsm_loc_updating_operation {
|
||||
struct osmo_timer_list updating_timer;
|
||||
unsigned int waiting_for_imsi : 1;
|
||||
unsigned int waiting_for_imei : 1;
|
||||
unsigned int key_seq : 4;
|
||||
};
|
||||
|
||||
/*
|
||||
* AUTHENTICATION/CIPHERING state
|
||||
*/
|
||||
@@ -113,6 +101,15 @@ enum ran_type {
|
||||
RAN_UTRAN_IU, /* 3G / Iu-interface (IuCS or IuPS) */
|
||||
};
|
||||
|
||||
struct gsm_classmark {
|
||||
bool classmark1_set;
|
||||
struct gsm48_classmark1 classmark1;
|
||||
uint8_t classmark2_len;
|
||||
uint8_t classmark2[3];
|
||||
uint8_t classmark3_len;
|
||||
uint8_t classmark3[14];
|
||||
};
|
||||
|
||||
/* active radio connection of a mobile subscriber */
|
||||
struct gsm_subscriber_connection {
|
||||
/* global linked list of subscriber_connections */
|
||||
@@ -122,12 +119,33 @@ struct gsm_subscriber_connection {
|
||||
* towards A/Iu */
|
||||
uint32_t use_count;
|
||||
|
||||
/* To whom we are allocated at the moment */
|
||||
struct gsm_subscriber *subscr;
|
||||
/* temporary hack: while the same gsm_subscriber_connection is in use
|
||||
* between libbsc and libmsc, we need to prevent a second free from
|
||||
* within libbsc after bsc_api->compl_l3() returns. In
|
||||
* gsm0408_rcvmsg(), compl_l3() is called, and if it returns
|
||||
* BSC_API_CONN_POL_REJECT, the conn is discarded right away. This is
|
||||
* the only instance where libbsc discards a gsm_subscriber_connection.
|
||||
* If compl_l3() returns BSC_API_CONN_POL_ACCEPT and in all other API
|
||||
* calls, ownership of the conn is in libmsc (in the osmo-nitb case) or
|
||||
* in the osmo-bsc code (in the OsmoBSC standalone case). Our VLR
|
||||
* however assumes full ownership of the conn and will discard it when
|
||||
* nothing is pending. So in case we're still in compl_l3() and going
|
||||
* to reject the conn, we must tell libmsc to not free it yet, since
|
||||
* bsc_api.c will do so again/anyway. When the
|
||||
* gsm_subscriber_connection structs are properly separated, this will
|
||||
* go away magically. */
|
||||
bool owned_by_msc;
|
||||
|
||||
/* libbsc subscriber information */
|
||||
/* The MS has opened the conn with a CM Service Request, and we shall
|
||||
* keep it open for an actual request (or until timeout). */
|
||||
bool received_cm_service_request;
|
||||
|
||||
/* libbsc subscriber information (if available) */
|
||||
struct bsc_subscr *bsub;
|
||||
|
||||
/* libmsc/libvlr subscriber information (if available) */
|
||||
struct vlr_subscr *vsub;
|
||||
|
||||
/* LU expiration handling */
|
||||
uint8_t expire_timer_stopped;
|
||||
/* SMS helpers for libmsc */
|
||||
@@ -136,10 +154,11 @@ struct gsm_subscriber_connection {
|
||||
/*
|
||||
* Operations that have a state and might be pending
|
||||
*/
|
||||
struct gsm_loc_updating_operation *loc_operation;
|
||||
struct gsm_security_operation *sec_operation;
|
||||
struct gsm_anchor_operation *anch_operation;
|
||||
|
||||
struct osmo_fsm_inst *conn_fsm;
|
||||
|
||||
/* Are we part of a special "silent" call */
|
||||
int silent_call;
|
||||
|
||||
@@ -154,7 +173,7 @@ struct gsm_subscriber_connection {
|
||||
/* back pointers */
|
||||
struct gsm_network *network;
|
||||
|
||||
int in_release;
|
||||
bool in_release;
|
||||
struct gsm_lchan *lchan; /* BSC */
|
||||
struct gsm_lchan *ho_lchan; /* BSC */
|
||||
struct gsm_bts *bts; /* BSC */
|
||||
@@ -165,6 +184,8 @@ struct gsm_subscriber_connection {
|
||||
|
||||
/* connected via 2G or 3G? */
|
||||
enum ran_type via_ran;
|
||||
|
||||
struct gsm_classmark classmark;
|
||||
};
|
||||
|
||||
|
||||
@@ -310,6 +331,7 @@ struct gsm_network {
|
||||
char *authorized_reg_str;
|
||||
enum gsm48_reject_value reject_cause;
|
||||
int a5_encryption;
|
||||
bool authentication_required;
|
||||
int neci;
|
||||
int send_mm_info;
|
||||
struct {
|
||||
@@ -378,12 +400,8 @@ struct gsm_network {
|
||||
bool auto_assign_exten;
|
||||
uint64_t ext_min;
|
||||
uint64_t ext_max;
|
||||
struct gsm_subscriber_group *subscr_group;
|
||||
struct gsm_sms_queue *sms_queue;
|
||||
|
||||
/* nitb related control */
|
||||
int avoid_tmsi;
|
||||
|
||||
/* control interface */
|
||||
struct ctrl_handle *ctrl;
|
||||
|
||||
@@ -408,6 +426,12 @@ struct gsm_network {
|
||||
* not require gsm_data.h). In an MSC-without-BSC environment, this
|
||||
* pointer is NULL to indicate absence of a bsc_subscribers list. */
|
||||
struct llist_head *bsc_subscribers;
|
||||
|
||||
/* MSC: GSUP server address of the HLR */
|
||||
const char *gsup_server_addr_str;
|
||||
uint16_t gsup_server_port;
|
||||
|
||||
struct vlr_instance *vlr;
|
||||
};
|
||||
|
||||
struct osmo_esme;
|
||||
@@ -430,7 +454,7 @@ struct gsm_sms_addr {
|
||||
|
||||
struct gsm_sms {
|
||||
unsigned long long id;
|
||||
struct gsm_subscriber *receiver;
|
||||
struct vlr_subscr *receiver;
|
||||
struct gsm_sms_addr src, dst;
|
||||
enum gsm_sms_source_id source;
|
||||
|
||||
@@ -576,7 +600,7 @@ extern const struct value_string bts_type_descs[_NUM_GSM_BTS_TYPE+1];
|
||||
|
||||
/* control interface handling */
|
||||
int bsc_base_ctrl_cmds_install(void);
|
||||
int msc_ctrl_cmds_install(void);
|
||||
int msc_ctrl_cmds_install(struct gsm_network *net);
|
||||
|
||||
/* dependency handling */
|
||||
void bts_depend_mark(struct gsm_bts *bts, int dep);
|
||||
@@ -584,4 +608,6 @@ void bts_depend_clear(struct gsm_bts *bts, int dep);
|
||||
int bts_depend_check(struct gsm_bts *bts);
|
||||
int bts_depend_is_depedency(struct gsm_bts *base, struct gsm_bts *other);
|
||||
|
||||
bool classmark_is_r99(struct gsm_classmark *cm);
|
||||
|
||||
#endif /* _GSM_DATA_H */
|
||||
|
@@ -84,7 +84,6 @@ enum bts_gprs_mode {
|
||||
};
|
||||
|
||||
struct gsm_lchan;
|
||||
struct gsm_subscriber;
|
||||
struct gsm_mncc;
|
||||
struct osmo_rtp_socket;
|
||||
struct rtp_socket;
|
||||
|
@@ -19,63 +19,8 @@
|
||||
|
||||
#define GSM_SUBSCRIBER_NO_EXPIRATION 0x0
|
||||
|
||||
struct vty;
|
||||
struct sgsn_mm_ctx;
|
||||
struct sgsn_subscriber_data;
|
||||
|
||||
struct subscr_request;
|
||||
|
||||
struct gsm_subscriber_group {
|
||||
struct gsm_network *net;
|
||||
|
||||
int keep_subscr;
|
||||
};
|
||||
|
||||
struct gsm_equipment {
|
||||
long long unsigned int id;
|
||||
char imei[GSM23003_IMEISV_NUM_DIGITS+1];
|
||||
char name[GSM_NAME_LENGTH];
|
||||
|
||||
struct gsm48_classmark1 classmark1;
|
||||
uint8_t classmark2_len;
|
||||
uint8_t classmark2[3];
|
||||
uint8_t classmark3_len;
|
||||
uint8_t classmark3[14];
|
||||
};
|
||||
|
||||
struct gsm_subscriber {
|
||||
struct gsm_subscriber_group *group;
|
||||
long long unsigned int id;
|
||||
char imsi[GSM23003_IMSI_MAX_DIGITS+1];
|
||||
uint32_t tmsi;
|
||||
uint16_t lac;
|
||||
char name[GSM_NAME_LENGTH];
|
||||
char extension[GSM_EXTENSION_LENGTH];
|
||||
int authorized;
|
||||
time_t expire_lu;
|
||||
|
||||
/* Don't delete subscribers even if group->keep_subscr is not set */
|
||||
int keep_in_ram;
|
||||
|
||||
/* Temporary field which is not stored in the DB/HLR */
|
||||
uint32_t flags;
|
||||
|
||||
/* Every user can only have one equipment in use at any given
|
||||
* point in time */
|
||||
struct gsm_equipment equipment;
|
||||
|
||||
/* for internal management */
|
||||
int use_count;
|
||||
struct llist_head entry;
|
||||
|
||||
/* pending requests */
|
||||
int is_paging;
|
||||
struct llist_head requests;
|
||||
|
||||
/* GPRS/SGSN related fields */
|
||||
struct sgsn_subscriber_data *sgsn_data;
|
||||
};
|
||||
|
||||
enum gsm_subscriber_field {
|
||||
GSM_SUBSCRIBER_IMSI,
|
||||
GSM_SUBSCRIBER_TMSI,
|
||||
@@ -89,42 +34,17 @@ enum gsm_subscriber_update_reason {
|
||||
GSM_SUBSCRIBER_UPDATE_EQUIPMENT,
|
||||
};
|
||||
|
||||
struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr);
|
||||
struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr);
|
||||
struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi);
|
||||
struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_subscriber_group *sgrp,
|
||||
uint32_t tmsi);
|
||||
struct gsm_subscriber *subscr_get_by_imsi(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi);
|
||||
struct gsm_subscriber *subscr_get_by_extension(struct gsm_subscriber_group *sgrp,
|
||||
const char *ext);
|
||||
struct gsm_subscriber *subscr_get_by_id(struct gsm_subscriber_group *sgrp,
|
||||
unsigned long long id);
|
||||
struct gsm_subscriber *subscr_get_or_create(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi);
|
||||
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason);
|
||||
struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_subscriber_group *sgrp,
|
||||
uint32_t tmsi);
|
||||
struct gsm_subscriber *subscr_active_by_imsi(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi);
|
||||
|
||||
char *subscr_name(struct gsm_subscriber *subscr);
|
||||
|
||||
int subscr_purge_inactive(struct gsm_subscriber_group *sgrp);
|
||||
void subscr_update_from_db(struct gsm_subscriber *subscr);
|
||||
void subscr_expire(struct gsm_subscriber_group *sgrp);
|
||||
int subscr_update_expire_lu(struct gsm_subscriber *subscr, struct gsm_bts *bts);
|
||||
int subscr_update(struct vlr_subscr *vsub, struct gsm_bts *bts, int reason);
|
||||
|
||||
/*
|
||||
* Paging handling with authentication
|
||||
*/
|
||||
struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
|
||||
int type, gsm_cbfn *cbfn, void *param);
|
||||
struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub,
|
||||
int channel_type,
|
||||
gsm_cbfn *cbfn, void *param);
|
||||
void subscr_remove_request(struct subscr_request *req);
|
||||
|
||||
/* internal */
|
||||
struct gsm_subscriber *subscr_alloc(void);
|
||||
extern struct llist_head active_subscribers;
|
||||
int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
|
||||
struct msgb *msg, void *data, void *param);
|
||||
|
||||
#endif /* _GSM_SUBSCR_H */
|
||||
|
@@ -3,10 +3,74 @@
|
||||
#ifndef OSMO_MSC_H
|
||||
#define OSMO_MSC_H
|
||||
|
||||
#include <osmocom/core/fsm.h>
|
||||
|
||||
#include <openbsc/gsm_data.h>
|
||||
|
||||
#include "bsc_api.h"
|
||||
|
||||
#define MSC_HLR_REMOTE_IP_DEFAULT "127.0.0.1"
|
||||
#define MSC_HLR_REMOTE_PORT_DEFAULT 2222
|
||||
|
||||
enum subscr_conn_fsm_event {
|
||||
/* Mark 0 as invalid to catch uninitialized vars */
|
||||
SUBSCR_CONN_E_INVALID = 0,
|
||||
/* Timeout on connection establishment starts */
|
||||
SUBSCR_CONN_E_START,
|
||||
/* LU or Process Access FSM has determined that this conn is good */
|
||||
SUBSCR_CONN_E_ACCEPTED,
|
||||
/* received first reply from MS in "real" CC, SMS, USSD communication */
|
||||
SUBSCR_CONN_E_COMMUNICATING,
|
||||
/* Some async action has completed, check again whether all is done */
|
||||
SUBSCR_CONN_E_BUMP,
|
||||
/* MS/BTS/BSC originated close request */
|
||||
SUBSCR_CONN_E_MO_CLOSE,
|
||||
/* MSC originated close request, e.g. failed authentication */
|
||||
SUBSCR_CONN_E_CN_CLOSE,
|
||||
};
|
||||
|
||||
enum subscr_conn_fsm_state {
|
||||
SUBSCR_CONN_S_INIT,
|
||||
SUBSCR_CONN_S_NEW,
|
||||
SUBSCR_CONN_S_ACCEPTED,
|
||||
SUBSCR_CONN_S_COMMUNICATING,
|
||||
SUBSCR_CONN_S_RELEASED,
|
||||
};
|
||||
|
||||
enum subscr_conn_from {
|
||||
SUBSCR_CONN_FROM_INVALID,
|
||||
SUBSCR_CONN_FROM_LU,
|
||||
SUBSCR_CONN_FROM_CM_SERVICE_REQ,
|
||||
SUBSCR_CONN_FROM_PAGING_RESP,
|
||||
};
|
||||
|
||||
extern const struct value_string subscr_conn_from_names[];
|
||||
static inline const char *subscr_conn_from_name(enum subscr_conn_from val)
|
||||
{
|
||||
return get_value_string(subscr_conn_from_names, val);
|
||||
}
|
||||
|
||||
void msc_subscr_conn_init(void);
|
||||
|
||||
struct bsc_api *msc_bsc_api();
|
||||
struct gsm_subscriber_connection *subscr_con_get(struct gsm_subscriber_connection *conn);
|
||||
void subscr_con_put(struct gsm_subscriber_connection *conn);
|
||||
#define subscr_con_get(conn) _subscr_con_get(conn, __BASE_FILE__, __LINE__)
|
||||
struct gsm_subscriber_connection *
|
||||
_subscr_con_get(struct gsm_subscriber_connection *conn,
|
||||
const char *file, int line);
|
||||
#define subscr_con_put(conn) _subscr_con_put(conn, __BASE_FILE__, __LINE__)
|
||||
void _subscr_con_put(struct gsm_subscriber_connection *conn, const char *file,
|
||||
int line);
|
||||
|
||||
int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id);
|
||||
|
||||
int msc_vlr_alloc(struct gsm_network *net);
|
||||
int msc_vlr_start(struct gsm_network *net);
|
||||
|
||||
void msc_close_connection(struct gsm_subscriber_connection *conn);
|
||||
|
||||
bool msc_subscr_conn_is_accepted(struct gsm_subscriber_connection *conn);
|
||||
void msc_subscr_conn_communicating(struct gsm_subscriber_connection *conn);
|
||||
|
||||
void msc_release_anchor(struct gsm_subscriber_connection *conn);
|
||||
|
||||
#endif
|
||||
|
@@ -138,10 +138,8 @@ enum signal_rf {
|
||||
S_RF_GRACE,
|
||||
};
|
||||
|
||||
struct gsm_subscriber;
|
||||
|
||||
struct paging_signal_data {
|
||||
struct gsm_subscriber *subscr;
|
||||
struct vlr_subscr *vsub;
|
||||
struct gsm_bts *bts;
|
||||
|
||||
int paging_result;
|
||||
|
@@ -3,9 +3,9 @@
|
||||
|
||||
struct gsm_subscriber_connection;
|
||||
|
||||
extern int gsm_silent_call_start(struct gsm_subscriber *subscr,
|
||||
extern int gsm_silent_call_start(struct vlr_subscr *vsub,
|
||||
void *data, int type);
|
||||
extern int gsm_silent_call_stop(struct gsm_subscriber *subscr);
|
||||
extern int gsm_silent_call_stop(struct vlr_subscr *vsub);
|
||||
|
||||
#if 0
|
||||
extern int silent_call_rx(struct gsm_subscriber_connection *conn, struct msgb *msg);
|
||||
|
@@ -24,7 +24,7 @@ struct gsm_trans {
|
||||
uint8_t transaction_id;
|
||||
|
||||
/* To whom we belong, unique identifier of remote MM entity */
|
||||
struct gsm_subscriber *subscr;
|
||||
struct vlr_subscr *vsub;
|
||||
|
||||
/* The associated connection we are using to transmit messages */
|
||||
struct gsm_subscriber_connection *conn;
|
||||
@@ -67,13 +67,14 @@ struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
|
||||
uint32_t callref);
|
||||
|
||||
struct gsm_trans *trans_alloc(struct gsm_network *net,
|
||||
struct gsm_subscriber *subscr,
|
||||
struct vlr_subscr *vsub,
|
||||
uint8_t protocol, uint8_t trans_id,
|
||||
uint32_t callref);
|
||||
void trans_free(struct gsm_trans *trans);
|
||||
|
||||
int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr,
|
||||
int trans_assign_trans_id(struct gsm_network *net, struct vlr_subscr *vsub,
|
||||
uint8_t protocol, uint8_t ti_flag);
|
||||
int trans_has_conn(const struct gsm_subscriber_connection *conn);
|
||||
void trans_conn_closed(struct gsm_subscriber_connection *conn);
|
||||
|
||||
#endif
|
||||
|
@@ -10,6 +10,8 @@
|
||||
// for GSM_NAME_LENGTH
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
|
||||
struct log_target;
|
||||
|
||||
/* from 3s to 10s */
|
||||
#define GSM_29002_TIMER_S 10
|
||||
/* from 15s to 30s */
|
||||
@@ -19,7 +21,6 @@
|
||||
/* from 28h to 38h */
|
||||
#define GSM_29002_TIMER_L (32*60*60)
|
||||
|
||||
|
||||
/* VLR subscriber authentication state */
|
||||
enum vlr_subscr_auth_state {
|
||||
/* subscriber needs to be autenticated */
|
||||
@@ -402,3 +403,6 @@ int vlr_set_ciph_mode(struct vlr_instance *vlr,
|
||||
void *msc_conn_ref,
|
||||
enum vlr_ciph ciph_mode,
|
||||
bool retrieve_imeisv);
|
||||
|
||||
void log_set_filter_vlr_subscr(struct log_target *target,
|
||||
struct vlr_subscr *vlr_subscr);
|
||||
|
@@ -38,6 +38,7 @@ enum bsc_vty_node {
|
||||
SMPP_NODE,
|
||||
SMPP_ESME_NODE,
|
||||
GTPHUB_NODE,
|
||||
HLR_NODE,
|
||||
};
|
||||
|
||||
extern int bsc_vty_is_config_node(struct vty *vty, int node);
|
||||
|
@@ -159,7 +159,7 @@ static struct gsm_lchan *lchan_lookup(struct gsm_bts_trx *trx, uint8_t chan_nr,
|
||||
gsm_ts_and_pchan_name(lchan->ts), log_name, chan_nr);
|
||||
|
||||
if (lchan->conn)
|
||||
log_set_context(LOG_CTX_VLR_SUBSCR, lchan->conn->subscr);
|
||||
log_set_context(LOG_CTX_VLR_SUBSCR, lchan->conn->vsub);
|
||||
|
||||
return lchan;
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/trau_mux.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#include <osmocom/gsm/protocol/gsm_08_08.h>
|
||||
#include <osmocom/gsm/gsm48.h>
|
||||
@@ -262,13 +263,14 @@ void bsc_subscr_con_free(struct gsm_subscriber_connection *conn)
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
if (conn->network->bsc_api->conn_cleanup)
|
||||
conn->network->bsc_api->conn_cleanup(conn);
|
||||
|
||||
if (conn->subscr) {
|
||||
subscr_put(conn->subscr);
|
||||
conn->subscr = NULL;
|
||||
if (conn->vsub) {
|
||||
LOGP(DNM, LOGL_ERROR, "conn->vsub should have been cleared.\n");
|
||||
conn->vsub = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (conn->ho_lchan) {
|
||||
LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n");
|
||||
conn->ho_lchan->conn = NULL;
|
||||
|
@@ -37,6 +37,7 @@
|
||||
#include <osmocom/gsm/sysinfo.h>
|
||||
#include <openbsc/e1_config.h>
|
||||
#include <openbsc/common_bsc.h>
|
||||
#include <openbsc/osmo_msc.h>
|
||||
|
||||
/* global pointer to the gsm network data structure */
|
||||
extern struct gsm_network *bsc_gsmnet;
|
||||
@@ -485,6 +486,12 @@ int bsc_network_alloc(mncc_recv_cb_t mncc_recv)
|
||||
bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC");
|
||||
bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC");
|
||||
|
||||
/* TODO: move to libmsc when gsm_network is split between libbsc and
|
||||
* libmsc */
|
||||
bsc_gsmnet->gsup_server_addr_str = talloc_strdup(bsc_gsmnet,
|
||||
MSC_HLR_REMOTE_IP_DEFAULT);
|
||||
bsc_gsmnet->gsup_server_port = MSC_HLR_REMOTE_PORT_DEFAULT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -53,8 +53,8 @@
|
||||
#include <openbsc/abis_rsl.h>
|
||||
#include <openbsc/bsc_msc_data.h>
|
||||
#include <openbsc/osmo_bsc_rf.h>
|
||||
|
||||
#include <openbsc/common_cs.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
@@ -791,6 +791,9 @@ static int config_write_net(struct vty *vty)
|
||||
vty_out(vty, " location updating reject cause %u%s",
|
||||
gsmnet->reject_cause, VTY_NEWLINE);
|
||||
vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
|
||||
vty_out(vty, " authentication %s%s",
|
||||
gsmnet->authentication_required ? "required" : "optional",
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
|
||||
vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
|
||||
vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
|
||||
@@ -821,8 +824,11 @@ static int config_write_net(struct vty *vty)
|
||||
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3122 %u%s", gsmnet->T3122, VTY_NEWLINE);
|
||||
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
|
||||
/*
|
||||
TODO: add in libvlr?
|
||||
vty_out(vty, " subscriber-keep-in-ram %d%s",
|
||||
gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
|
||||
*/
|
||||
if (gsmnet->tz.override != 0) {
|
||||
if (gsmnet->tz.dst)
|
||||
vty_out(vty, " timezone %d %d %d%s",
|
||||
@@ -1006,21 +1012,24 @@ DEFUN(show_ts,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
|
||||
static void subscr_dump_vty(struct vty *vty, struct vlr_subscr *vsub)
|
||||
{
|
||||
vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
|
||||
subscr->authorized, VTY_NEWLINE);
|
||||
if (strlen(subscr->name))
|
||||
vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
|
||||
if (strlen(subscr->extension))
|
||||
vty_out(vty, " Extension: %s%s", subscr->extension,
|
||||
OSMO_ASSERT(vsub);
|
||||
if (strlen(vsub->name))
|
||||
vty_out(vty, " Name: '%s'%s", vsub->name, VTY_NEWLINE);
|
||||
if (strlen(vsub->msisdn))
|
||||
vty_out(vty, " Extension: %s%s", vsub->msisdn,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
|
||||
if (subscr->tmsi != GSM_RESERVED_TMSI)
|
||||
vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
|
||||
if (strlen(vsub->imsi))
|
||||
vty_out(vty, " IMSI: %s%s", vsub->imsi, VTY_NEWLINE);
|
||||
if (vsub->tmsi != GSM_RESERVED_TMSI)
|
||||
vty_out(vty, " TMSI: %08X%s", vsub->tmsi,
|
||||
VTY_NEWLINE);
|
||||
if (vsub->tmsi_new != GSM_RESERVED_TMSI)
|
||||
vty_out(vty, " new TMSI: %08X%s", vsub->tmsi_new,
|
||||
VTY_NEWLINE);
|
||||
|
||||
vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
|
||||
vty_out(vty, " Use count: %u%s", vsub->use_count, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
static void bsc_subscr_dump_vty(struct vty *vty, struct bsc_subscr *bsub)
|
||||
@@ -1149,9 +1158,9 @@ static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
|
||||
vty_out(vty, " Channel Mode / Codec: %s%s",
|
||||
get_value_string(gsm48_cmode_names, lchan->tch_mode),
|
||||
VTY_NEWLINE);
|
||||
if (lchan->conn && lchan->conn->subscr) {
|
||||
if (lchan->conn && lchan->conn->vsub) {
|
||||
vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
|
||||
subscr_dump_vty(vty, lchan->conn->subscr);
|
||||
subscr_dump_vty(vty, lchan->conn->vsub);
|
||||
} else
|
||||
vty_out(vty, " No Subscriber%s", VTY_NEWLINE);
|
||||
if (is_ipaccess_bts(lchan->ts->trx->bts)) {
|
||||
|
@@ -40,6 +40,7 @@
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <openbsc/transaction.h>
|
||||
#include <openbsc/trau_mux.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
struct bsc_handover {
|
||||
struct llist_head list;
|
||||
@@ -261,7 +262,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
|
||||
|
||||
net = new_lchan->ts->trx->bts->network;
|
||||
LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
|
||||
"%u->%u\n", subscr_name(ho->old_lchan->conn->subscr),
|
||||
"%u->%u\n", vlr_subscr_name(ho->old_lchan->conn->vsub),
|
||||
ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr,
|
||||
ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn);
|
||||
|
||||
|
@@ -50,6 +50,7 @@
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <openbsc/bsc_api.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
void *tall_paging_ctx;
|
||||
|
||||
|
@@ -49,17 +49,10 @@ struct gsm_network *gsm_network_init(void *ctx,
|
||||
if (!net)
|
||||
return NULL;
|
||||
|
||||
net->subscr_group = talloc_zero(net, struct gsm_subscriber_group);
|
||||
if (!net->subscr_group) {
|
||||
talloc_free(net);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (gsm_parse_reg(net, &net->authorized_regexp, &net->authorized_reg_str, 1,
|
||||
&default_regexp) != 0)
|
||||
return NULL;
|
||||
|
||||
net->subscr_group->net = net;
|
||||
net->auto_create_subscr = true;
|
||||
net->auto_assign_exten = true;
|
||||
|
||||
|
@@ -168,6 +168,20 @@ DEFUN(cfg_net_encryption,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_authentication,
|
||||
cfg_net_authentication_cmd,
|
||||
"authentication (optional|required)",
|
||||
"Whether to enforce MS authentication in 2G\n"
|
||||
"Allow MS to attach via 2G BSC without authentication\n"
|
||||
"Always do authentication\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
gsmnet->authentication_required = (argv[0][0] == 'r') ? true : false;
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_rrlp_mode, cfg_net_rrlp_mode_cmd,
|
||||
"rrlp mode (none|ms-based|ms-preferred|ass-preferred)",
|
||||
"Radio Resource Location Protocol\n"
|
||||
@@ -203,9 +217,10 @@ DEFUN(cfg_net_subscr_keep,
|
||||
"Keep unused subscribers in RAM.\n"
|
||||
"Delete unused subscribers\n" "Keep unused subscribers\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->subscr_group->keep_subscr = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% subscriber-keep-in-ram is currently not implemented%s",
|
||||
VTY_NEWLINE);
|
||||
/* TODO add a libvlr mechanism to keep vlr_subscrs in RAM? */
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(cfg_net_timezone,
|
||||
@@ -289,6 +304,7 @@ int common_cs_vty_init(struct gsm_network *network,
|
||||
install_element(GSMNET_NODE, &cfg_net_authorize_regexp_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_reject_cause_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_encryption_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_authentication_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_rrlp_mode_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_mm_info_cmd);
|
||||
install_element(GSMNET_NODE, &cfg_net_subscr_keep_cmd);
|
||||
|
@@ -32,7 +32,6 @@
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/gprs/gprs_msgb.h>
|
||||
#include <openbsc/gsm_data.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/debug.h>
|
||||
|
||||
/* default categories */
|
||||
@@ -175,17 +174,22 @@ static const struct log_info_cat default_categories[] = {
|
||||
.description = "SCCP User Adaptation Protocol",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
[DVLR] = {
|
||||
.name = "DVLR",
|
||||
.description = "Visitor Location Register",
|
||||
.enabled = 1, .loglevel = LOGL_DEBUG,
|
||||
},
|
||||
};
|
||||
|
||||
static int filter_fn(const struct log_context *ctx, struct log_target *tar)
|
||||
{
|
||||
const struct gsm_subscriber *subscr = ctx->ctx[LOG_CTX_VLR_SUBSCR];
|
||||
const struct vlr_subscr *vsub = ctx->ctx[LOG_CTX_VLR_SUBSCR];
|
||||
const struct bsc_subscr *bsub = ctx->ctx[LOG_CTX_BSC_SUBSCR];
|
||||
const struct gprs_nsvc *nsvc = ctx->ctx[LOG_CTX_GB_NSVC];
|
||||
const struct gprs_nsvc *bvc = ctx->ctx[LOG_CTX_GB_BVC];
|
||||
|
||||
if ((tar->filter_map & (1 << LOG_FLT_VLR_SUBSCR)) != 0
|
||||
&& subscr && subscr == tar->filter_data[LOG_FLT_VLR_SUBSCR])
|
||||
&& vsub && vsub == tar->filter_data[LOG_FLT_VLR_SUBSCR])
|
||||
return 1;
|
||||
|
||||
if ((tar->filter_map & (1 << LOG_FLT_BSC_SUBSCR)) != 0
|
||||
@@ -210,21 +214,3 @@ const struct log_info log_info = {
|
||||
.cat = default_categories,
|
||||
.num_cat = ARRAY_SIZE(default_categories),
|
||||
};
|
||||
|
||||
void log_set_filter_vlr_subscr(struct log_target *target,
|
||||
struct gsm_subscriber *vlr_subscr)
|
||||
{
|
||||
struct gsm_subscriber **fsub = (void*)&target->filter_data[LOG_FLT_VLR_SUBSCR];
|
||||
|
||||
/* free the old data */
|
||||
if (*fsub) {
|
||||
subscr_put(*fsub);
|
||||
*fsub = NULL;
|
||||
}
|
||||
|
||||
if (vlr_subscr) {
|
||||
target->filter_map |= (1 << LOG_FLT_VLR_SUBSCR);
|
||||
*fsub = subscr_get(vlr_subscr);
|
||||
} else
|
||||
target->filter_map &= ~(1 << LOG_FLT_VLR_SUBSCR);
|
||||
}
|
||||
|
@@ -453,3 +453,13 @@ int bts_depend_check(struct gsm_bts *bts)
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool classmark_is_r99(struct gsm_classmark *cm)
|
||||
{
|
||||
int rev_lev = 0;
|
||||
if (cm->classmark1_set)
|
||||
rev_lev = cm->classmark1.rev_lev;
|
||||
else if (cm->classmark2_len > 0)
|
||||
rev_lev = (cm->classmark2[0] >> 5) & 0x3;
|
||||
return rev_lev >= 2;
|
||||
}
|
||||
|
@@ -31,133 +31,34 @@
|
||||
#include <osmocom/core/utils.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
LLIST_HEAD(active_subscribers);
|
||||
void *tall_subscr_ctx;
|
||||
|
||||
/* for the gsm_subscriber.c */
|
||||
struct llist_head *subscr_bsc_active_subscribers(void)
|
||||
/* return static buffer with printable name of VLR subscriber */
|
||||
const char *vlr_subscr_name(struct vlr_subscr *vsub)
|
||||
{
|
||||
return &active_subscribers;
|
||||
}
|
||||
|
||||
|
||||
char *subscr_name(struct gsm_subscriber *subscr)
|
||||
{
|
||||
if (!subscr)
|
||||
static char buf[32];
|
||||
if (!vsub)
|
||||
return "unknown";
|
||||
|
||||
if (strlen(subscr->name))
|
||||
return subscr->name;
|
||||
|
||||
return subscr->imsi;
|
||||
if (vsub->msisdn[0])
|
||||
snprintf(buf, sizeof(buf), "MSISDN:%s", vsub->msisdn);
|
||||
else if (vsub->imsi[0])
|
||||
snprintf(buf, sizeof(buf), "IMSI:%s", vsub->imsi);
|
||||
else if (vsub->tmsi != GSM_RESERVED_TMSI)
|
||||
snprintf(buf, sizeof(buf), "TMSI:0x%08x", vsub->tmsi);
|
||||
else if (vsub->tmsi_new != GSM_RESERVED_TMSI)
|
||||
snprintf(buf, sizeof(buf), "TMSI(new):0x%08x", vsub->tmsi_new);
|
||||
else
|
||||
return "unknown";
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_alloc(void)
|
||||
const char *vlr_subscr_msisdn_or_name(struct vlr_subscr *vsub)
|
||||
{
|
||||
struct gsm_subscriber *s;
|
||||
|
||||
s = talloc_zero(tall_subscr_ctx, struct gsm_subscriber);
|
||||
if (!s)
|
||||
return NULL;
|
||||
|
||||
llist_add_tail(&s->entry, &active_subscribers);
|
||||
s->use_count = 1;
|
||||
s->tmsi = GSM_RESERVED_TMSI;
|
||||
|
||||
INIT_LLIST_HEAD(&s->requests);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static void subscr_free(struct gsm_subscriber *subscr)
|
||||
{
|
||||
llist_del(&subscr->entry);
|
||||
talloc_free(subscr);
|
||||
}
|
||||
|
||||
void subscr_direct_free(struct gsm_subscriber *subscr)
|
||||
{
|
||||
OSMO_ASSERT(subscr->use_count == 1);
|
||||
subscr_free(subscr);
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_get(struct gsm_subscriber *subscr)
|
||||
{
|
||||
subscr->use_count++;
|
||||
DEBUGP(DREF, "subscr %s usage increases usage to: %d\n",
|
||||
subscr->extension, subscr->use_count);
|
||||
return subscr;
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_put(struct gsm_subscriber *subscr)
|
||||
{
|
||||
subscr->use_count--;
|
||||
DEBUGP(DREF, "subscr %s usage decreased usage to: %d\n",
|
||||
subscr->extension, subscr->use_count);
|
||||
if (subscr->use_count <= 0 &&
|
||||
!((subscr->group && subscr->group->keep_subscr) ||
|
||||
subscr->keep_in_ram))
|
||||
subscr_free(subscr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_get_or_create(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
|
||||
if (strcmp(subscr->imsi, imsi) == 0 && subscr->group == sgrp)
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
|
||||
subscr = subscr_alloc();
|
||||
if (!subscr)
|
||||
return NULL;
|
||||
|
||||
osmo_strlcpy(subscr->imsi, imsi, sizeof(subscr->imsi));
|
||||
subscr->group = sgrp;
|
||||
return subscr;
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_active_by_tmsi(struct gsm_subscriber_group *sgrp,
|
||||
uint32_t tmsi)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
|
||||
if (subscr->tmsi == tmsi && subscr->group == sgrp)
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_active_by_imsi(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
|
||||
if (strcmp(subscr->imsi, imsi) == 0 && subscr->group == sgrp)
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int subscr_purge_inactive(struct gsm_subscriber_group *sgrp)
|
||||
{
|
||||
struct gsm_subscriber *subscr, *tmp;
|
||||
int purged = 0;
|
||||
|
||||
llist_for_each_entry_safe(subscr, tmp, subscr_bsc_active_subscribers(), entry) {
|
||||
if (subscr->group == sgrp && subscr->use_count <= 0) {
|
||||
subscr_free(subscr);
|
||||
purged += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return purged;
|
||||
if (!vsub || !vsub->msisdn[0])
|
||||
return vlr_subscr_name(vsub);
|
||||
return vsub->msisdn;
|
||||
}
|
||||
|
@@ -72,12 +72,12 @@ static int gsup_client_connect(struct gsup_client *gsupc)
|
||||
rc = ipa_client_conn_open(gsupc->link);
|
||||
|
||||
if (rc >= 0) {
|
||||
LOGP(DLGSUP, LOGL_INFO, "GSUP connecting to %s:%d\n",
|
||||
LOGP(DLGSUP, LOGL_NOTICE, "GSUP connecting to %s:%d\n",
|
||||
gsupc->link->addr, gsupc->link->port);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LOGP(DLGSUP, LOGL_INFO, "GSUP failed to connect to %s:%d: %s\n",
|
||||
LOGP(DLGSUP, LOGL_ERROR, "GSUP failed to connect to %s:%d: %s\n",
|
||||
gsupc->link->addr, gsupc->link->port, strerror(-rc));
|
||||
|
||||
if (rc == -EBADF || rc == -ENOTSOCK || rc == -EAFNOSUPPORT ||
|
||||
@@ -323,11 +323,15 @@ void gsup_client_destroy(struct gsup_client *gsupc)
|
||||
int gsup_client_send(struct gsup_client *gsupc, struct msgb *msg)
|
||||
{
|
||||
if (!gsupc) {
|
||||
LOGP(DGPRS, LOGL_NOTICE, "No GSUP client, unable to "
|
||||
"send %s\n", msgb_hexdump(msg));
|
||||
msgb_free(msg);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
if (!gsupc->is_connected) {
|
||||
LOGP(DGPRS, LOGL_NOTICE, "GSUP not connected, unable to "
|
||||
"send %s\n", msgb_hexdump(msg));
|
||||
msgb_free(msg);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ libmsc_a_SOURCES = \
|
||||
osmo_msc.c \
|
||||
ctrl_commands.c \
|
||||
meas_feed.c \
|
||||
subscr_conn.c \
|
||||
$(NULL)
|
||||
|
||||
if BUILD_SMPP
|
||||
|
@@ -40,118 +40,3 @@ const struct value_string auth_action_names[] = {
|
||||
OSMO_VALUE_STRING(AUTH_DO_AUTH),
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
static int
|
||||
_use_xor(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
|
||||
{
|
||||
int i, l = ainfo->a3a8_ki_len;
|
||||
|
||||
if ((l > A38_XOR_MAX_KEY_LEN) || (l < A38_XOR_MIN_KEY_LEN)) {
|
||||
LOGP(DMM, LOGL_ERROR, "Invalid XOR key (len=%d) %s\n",
|
||||
ainfo->a3a8_ki_len,
|
||||
osmo_hexdump(ainfo->a3a8_ki, ainfo->a3a8_ki_len));
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i=0; i<4; i++)
|
||||
atuple->vec.sres[i] = atuple->vec.rand[i] ^ ainfo->a3a8_ki[i];
|
||||
for (i=4; i<12; i++)
|
||||
atuple->vec.kc[i-4] = atuple->vec.rand[i] ^ ainfo->a3a8_ki[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
_use_comp128_v1(struct gsm_auth_info *ainfo, struct gsm_auth_tuple *atuple)
|
||||
{
|
||||
if (ainfo->a3a8_ki_len != A38_COMP128_KEY_LEN) {
|
||||
LOGP(DMM, LOGL_ERROR, "Invalid COMP128v1 key (len=%d) %s\n",
|
||||
ainfo->a3a8_ki_len,
|
||||
osmo_hexdump(ainfo->a3a8_ki, ainfo->a3a8_ki_len));
|
||||
return -1;
|
||||
}
|
||||
|
||||
comp128(ainfo->a3a8_ki, atuple->vec.rand, atuple->vec.sres, atuple->vec.kc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return values
|
||||
* -1 -> Internal error
|
||||
* 0 -> Not available
|
||||
* 1 -> Tuple returned, need to do auth, then enable cipher
|
||||
* 2 -> Tuple returned, need to enable cipher
|
||||
*/
|
||||
int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr, int key_seq)
|
||||
{
|
||||
struct gsm_auth_info ainfo;
|
||||
int rc;
|
||||
|
||||
/* Get subscriber info (if any) */
|
||||
rc = db_get_authinfo_for_subscr(&ainfo, subscr);
|
||||
if (rc < 0) {
|
||||
LOGP(DMM, LOGL_NOTICE,
|
||||
"No retrievable Ki for subscriber %s, skipping auth\n",
|
||||
subscr_name(subscr));
|
||||
return rc == -ENOENT ? AUTH_NOT_AVAIL : AUTH_ERROR;
|
||||
}
|
||||
|
||||
/* If possible, re-use the last tuple and skip auth */
|
||||
rc = db_get_lastauthtuple_for_subscr(atuple, subscr);
|
||||
if ((rc == 0) &&
|
||||
(key_seq != GSM_KEY_SEQ_INVAL) &&
|
||||
(key_seq == atuple->key_seq) &&
|
||||
(atuple->use_count < 3))
|
||||
{
|
||||
atuple->use_count++;
|
||||
db_sync_lastauthtuple_for_subscr(atuple, subscr);
|
||||
DEBUGP(DMM, "Auth tuple use < 3, just doing ciphering\n");
|
||||
return AUTH_DO_CIPH;
|
||||
}
|
||||
|
||||
/* Generate a new one */
|
||||
if (rc != 0) {
|
||||
/* If db_get_lastauthtuple_for_subscr() returned nothing, make
|
||||
* sure the atuple memory is initialized to zero and thus start
|
||||
* off with key_seq = 0. */
|
||||
memset(atuple, 0, sizeof(*atuple));
|
||||
} else {
|
||||
/* If db_get_lastauthtuple_for_subscr() returned a previous
|
||||
* tuple, use the next key_seq. */
|
||||
atuple->key_seq = (atuple->key_seq + 1) % 7;
|
||||
}
|
||||
atuple->use_count = 1;
|
||||
|
||||
if (RAND_bytes(atuple->vec.rand, sizeof(atuple->vec.rand)) != 1) {
|
||||
LOGP(DMM, LOGL_NOTICE, "RAND_bytes failed, can't generate new auth tuple\n");
|
||||
return AUTH_ERROR;
|
||||
}
|
||||
|
||||
switch (ainfo.auth_algo) {
|
||||
case AUTH_ALGO_NONE:
|
||||
DEBUGP(DMM, "No authentication for subscriber\n");
|
||||
return AUTH_NOT_AVAIL;
|
||||
|
||||
case AUTH_ALGO_XOR:
|
||||
if (_use_xor(&ainfo, atuple))
|
||||
return AUTH_NOT_AVAIL;
|
||||
break;
|
||||
|
||||
case AUTH_ALGO_COMP128v1:
|
||||
if (_use_comp128_v1(&ainfo, atuple))
|
||||
return AUTH_NOT_AVAIL;
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUGP(DMM, "Unsupported auth type algo_id=%d\n",
|
||||
ainfo.auth_algo);
|
||||
return AUTH_NOT_AVAIL;
|
||||
}
|
||||
|
||||
db_sync_lastauthtuple_for_subscr(atuple, subscr);
|
||||
|
||||
DEBUGP(DMM, "Need to do authentication and ciphering\n");
|
||||
return AUTH_DO_AUTH_THEN_CIPH;
|
||||
}
|
||||
|
||||
|
@@ -25,129 +25,20 @@
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
static bool alg_supported(const char *alg)
|
||||
{
|
||||
/*
|
||||
* TODO: share this with the vty_interface and extend to all
|
||||
* algorithms supported by libosmocore now. Make it table based
|
||||
* as well.
|
||||
*/
|
||||
if (strcasecmp(alg, "none") == 0)
|
||||
return true;
|
||||
if (strcasecmp(alg, "xor") == 0)
|
||||
return true;
|
||||
if (strcasecmp(alg, "comp128v1") == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
static struct gsm_network *msc_ctrl_net = NULL;
|
||||
|
||||
static int verify_subscriber_modify(struct ctrl_cmd *cmd, const char *value, void *d)
|
||||
{
|
||||
char *tmp, *imsi, *msisdn, *alg, *ki, *saveptr = NULL;
|
||||
int rc = 0;
|
||||
|
||||
tmp = talloc_strdup(cmd, value);
|
||||
if (!tmp)
|
||||
return 1;
|
||||
|
||||
imsi = strtok_r(tmp, ",", &saveptr);
|
||||
msisdn = strtok_r(NULL, ",", &saveptr);
|
||||
alg = strtok_r(NULL, ",", &saveptr);
|
||||
ki = strtok_r(NULL, ",", &saveptr);
|
||||
|
||||
if (!imsi || !msisdn)
|
||||
rc = 1;
|
||||
else if (strlen(imsi) > GSM23003_IMSI_MAX_DIGITS)
|
||||
rc = 1;
|
||||
else if (strlen(msisdn) >= GSM_EXTENSION_LENGTH)
|
||||
rc = 1;
|
||||
else if (alg) {
|
||||
if (!alg_supported(alg))
|
||||
rc = 1;
|
||||
else if (strcasecmp(alg, "none") != 0 && !ki)
|
||||
rc = 1;
|
||||
}
|
||||
|
||||
talloc_free(tmp);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_subscriber_modify(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
struct gsm_network *net = cmd->node;
|
||||
char *tmp, *imsi, *msisdn, *alg, *ki, *saveptr = NULL;
|
||||
struct gsm_subscriber* subscr;
|
||||
int rc;
|
||||
|
||||
tmp = talloc_strdup(cmd, cmd->value);
|
||||
if (!tmp)
|
||||
return 1;
|
||||
|
||||
imsi = strtok_r(tmp, ",", &saveptr);
|
||||
msisdn = strtok_r(NULL, ",", &saveptr);
|
||||
alg = strtok_r(NULL, ",", &saveptr);
|
||||
ki = strtok_r(NULL, ",", &saveptr);
|
||||
|
||||
subscr = subscr_get_by_imsi(net->subscr_group, imsi);
|
||||
if (!subscr)
|
||||
subscr = subscr_create_subscriber(net->subscr_group, imsi);
|
||||
if (!subscr)
|
||||
goto fail;
|
||||
|
||||
subscr->authorized = 1;
|
||||
osmo_strlcpy(subscr->extension, msisdn, sizeof(subscr->extension));
|
||||
|
||||
/* put it back to the db */
|
||||
rc = db_sync_subscriber(subscr);
|
||||
db_subscriber_update(subscr);
|
||||
|
||||
/* handle optional ciphering */
|
||||
if (alg) {
|
||||
if (strcasecmp(alg, "none") == 0)
|
||||
db_sync_authinfo_for_subscr(NULL, subscr);
|
||||
else {
|
||||
struct gsm_auth_info ainfo = { 0, };
|
||||
/* the verify should make sure that this is okay */
|
||||
OSMO_ASSERT(alg);
|
||||
OSMO_ASSERT(ki);
|
||||
|
||||
if (strcasecmp(alg, "xor") == 0)
|
||||
ainfo.auth_algo = AUTH_ALGO_XOR;
|
||||
else if (strcasecmp(alg, "comp128v1") == 0)
|
||||
ainfo.auth_algo = AUTH_ALGO_COMP128v1;
|
||||
|
||||
rc = osmo_hexparse(ki, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
|
||||
if (rc < 0) {
|
||||
subscr_put(subscr);
|
||||
talloc_free(tmp);
|
||||
cmd->reply = "Failed to parse KI";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
ainfo.a3a8_ki_len = rc;
|
||||
db_sync_authinfo_for_subscr(&ainfo, subscr);
|
||||
rc = 0;
|
||||
}
|
||||
db_sync_lastauthtuple_for_subscr(NULL, subscr);
|
||||
}
|
||||
subscr_put(subscr);
|
||||
|
||||
talloc_free(tmp);
|
||||
|
||||
if (rc != 0) {
|
||||
cmd->reply = "Failed to store the record in the DB";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
cmd->reply = "OK";
|
||||
return CTRL_CMD_REPLY;
|
||||
|
||||
fail:
|
||||
talloc_free(tmp);
|
||||
cmd->reply = "Failed to create subscriber";
|
||||
cmd->reply = "Command moved to osmo-hlr, no longer available here";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
@@ -155,32 +46,8 @@ CTRL_CMD_DEFINE_WO(subscriber_modify, "subscriber-modify-v1");
|
||||
|
||||
static int set_subscriber_delete(struct ctrl_cmd *cmd, void *data)
|
||||
{
|
||||
int was_used = 0;
|
||||
int rc;
|
||||
struct gsm_subscriber *subscr;
|
||||
struct gsm_network *net = cmd->node;
|
||||
|
||||
subscr = subscr_get_by_imsi(net->subscr_group, cmd->value);
|
||||
if (!subscr) {
|
||||
cmd->reply = "Failed to find subscriber";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (subscr->use_count != 1) {
|
||||
LOGP(DCTRL, LOGL_NOTICE, "Going to remove active subscriber.\n");
|
||||
was_used = 1;
|
||||
}
|
||||
|
||||
rc = db_subscriber_delete(subscr);
|
||||
subscr_put(subscr);
|
||||
|
||||
if (rc != 0) {
|
||||
cmd->reply = "Failed to remove subscriber";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
cmd->reply = was_used ? "Removed active subscriber" : "Removed";
|
||||
return CTRL_CMD_REPLY;
|
||||
cmd->reply = "Command moved to osmo-hlr, no longer available here";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
CTRL_CMD_DEFINE_WO_NOVRF(subscriber_delete, "subscriber-delete-v1");
|
||||
|
||||
@@ -195,26 +62,35 @@ static int set_subscriber_list(struct ctrl_cmd *cmd, void *d)
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
static void list_cb(struct gsm_subscriber *subscr, void *d)
|
||||
{
|
||||
char **data = (char **) d;
|
||||
*data = talloc_asprintf_append(*data, "%s,%s\n",
|
||||
subscr->imsi, subscr->extension);
|
||||
}
|
||||
|
||||
static int get_subscriber_list(struct ctrl_cmd *cmd, void *d)
|
||||
{
|
||||
struct vlr_subscr *vsub;
|
||||
|
||||
if (!msc_ctrl_net) {
|
||||
cmd->reply = "MSC CTRL commands not initialized";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
if (!msc_ctrl_net->vlr) {
|
||||
cmd->reply = "VLR not initialized";
|
||||
return CTRL_CMD_ERROR;
|
||||
}
|
||||
|
||||
cmd->reply = talloc_strdup(cmd, "");
|
||||
|
||||
db_subscriber_list_active(list_cb, &cmd->reply);
|
||||
printf("%s\n", cmd->reply);
|
||||
llist_for_each_entry(vsub, &msc_ctrl_net->vlr->subscribers, list) {
|
||||
cmd->reply = talloc_asprintf_append(cmd->reply, "%s,%s\n",
|
||||
vsub->imsi, vsub->msisdn);
|
||||
}
|
||||
printf("%s\n", cmd->reply); /* <-- what? */
|
||||
return CTRL_CMD_REPLY;
|
||||
}
|
||||
CTRL_CMD_DEFINE(subscriber_list, "subscriber-list-active-v1");
|
||||
|
||||
int msc_ctrl_cmds_install(void)
|
||||
int msc_ctrl_cmds_install(struct gsm_network *net)
|
||||
{
|
||||
int rc = 0;
|
||||
msc_ctrl_net = net;
|
||||
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_subscriber_modify);
|
||||
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_subscriber_delete);
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -57,6 +57,7 @@
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <openbsc/bsc_api.h>
|
||||
#include <openbsc/osmo_msc.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#ifdef BUILD_SMPP
|
||||
#include "smpp_smsc.h"
|
||||
@@ -75,7 +76,7 @@ void sms_free(struct gsm_sms *sms)
|
||||
{
|
||||
/* drop references to subscriber structure */
|
||||
if (sms->receiver)
|
||||
subscr_put(sms->receiver);
|
||||
vlr_subscr_put(sms->receiver);
|
||||
#ifdef BUILD_SMPP
|
||||
if (sms->smpp.esme)
|
||||
smpp_esme_put(sms->smpp.esme);
|
||||
@@ -84,8 +85,8 @@ void sms_free(struct gsm_sms *sms)
|
||||
talloc_free(sms);
|
||||
}
|
||||
|
||||
struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver,
|
||||
struct gsm_subscriber *sender,
|
||||
struct gsm_sms *sms_from_text(struct vlr_subscr *receiver,
|
||||
struct vlr_subscr *sender,
|
||||
int dcs, const char *text)
|
||||
{
|
||||
struct gsm_sms *sms = sms_alloc();
|
||||
@@ -93,16 +94,16 @@ struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver,
|
||||
if (!sms)
|
||||
return NULL;
|
||||
|
||||
sms->receiver = subscr_get(receiver);
|
||||
sms->receiver = vlr_subscr_get(receiver);
|
||||
osmo_strlcpy(sms->text, text, sizeof(sms->text));
|
||||
|
||||
osmo_strlcpy(sms->src.addr, sender->extension, sizeof(sms->src.addr));
|
||||
osmo_strlcpy(sms->src.addr, sender->msisdn, sizeof(sms->src.addr));
|
||||
sms->reply_path_req = 0;
|
||||
sms->status_rep_req = 0;
|
||||
sms->ud_hdr_ind = 0;
|
||||
sms->protocol_id = 0; /* implicit */
|
||||
sms->data_coding_scheme = dcs;
|
||||
osmo_strlcpy(sms->dst.addr, receiver->extension, sizeof(sms->dst.addr));
|
||||
osmo_strlcpy(sms->dst.addr, receiver->msisdn, sizeof(sms->dst.addr));
|
||||
/* Generate user_data */
|
||||
sms->user_data_len = gsm_7bit_encode_n(sms->user_data, sizeof(sms->user_data),
|
||||
sms->text, NULL);
|
||||
@@ -298,7 +299,7 @@ int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg,
|
||||
goto try_local;
|
||||
if (rc < 0) {
|
||||
LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.",
|
||||
subscr_name(conn->subscr), rc);
|
||||
vlr_subscr_name(conn->vsub), rc);
|
||||
rc = GSM411_RP_CAUSE_MO_TEMP_FAIL;
|
||||
/* rc will be logged by gsm411_send_rp_error() */
|
||||
rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[
|
||||
@@ -311,8 +312,8 @@ try_local:
|
||||
#endif
|
||||
|
||||
/* determine gsms->receiver based on dialled number */
|
||||
gsms->receiver = subscr_get_by_extension(conn->network->subscr_group,
|
||||
gsms->dst.addr);
|
||||
gsms->receiver = vlr_subscr_find_by_msisdn(conn->network->vlr,
|
||||
gsms->dst.addr);
|
||||
if (!gsms->receiver) {
|
||||
#ifdef BUILD_SMPP
|
||||
/* Avoid a second look-up */
|
||||
@@ -327,7 +328,7 @@ try_local:
|
||||
rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]);
|
||||
} else if (rc < 0) {
|
||||
LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.",
|
||||
subscr_name(conn->subscr), rc);
|
||||
vlr_subscr_name(conn->vsub), rc);
|
||||
rc = GSM411_RP_CAUSE_MO_TEMP_FAIL;
|
||||
/* rc will be logged by gsm411_send_rp_error() */
|
||||
rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[
|
||||
@@ -466,13 +467,12 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
|
||||
}
|
||||
}
|
||||
|
||||
osmo_strlcpy(gsms->src.addr, conn->subscr->extension,
|
||||
sizeof(gsms->src.addr));
|
||||
osmo_strlcpy(gsms->src.addr, conn->vsub->msisdn, sizeof(gsms->src.addr));
|
||||
|
||||
LOGP(DLSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
|
||||
"MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
|
||||
"UserDataLength: 0x%02x, UserData: \"%s\"\n",
|
||||
subscr_name(conn->subscr), sms_mti, sms_vpf, gsms->msg_ref,
|
||||
vlr_subscr_name(conn->vsub), sms_mti, sms_vpf, gsms->msg_ref,
|
||||
gsms->protocol_id, gsms->data_coding_scheme, gsms->dst.addr,
|
||||
gsms->user_data_len,
|
||||
sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
|
||||
@@ -629,7 +629,7 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
|
||||
* the cause and take action depending on it */
|
||||
|
||||
LOGP(DLSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
|
||||
subscr_name(trans->conn->subscr), cause_len, cause,
|
||||
vlr_subscr_name(trans->conn->vsub), cause_len, cause,
|
||||
get_value_string(gsm411_rp_cause_strs, cause));
|
||||
|
||||
if (!sms) {
|
||||
@@ -799,7 +799,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
|
||||
int new_trans = 0;
|
||||
int rc = 0;
|
||||
|
||||
if (!conn->subscr)
|
||||
if (!conn->vsub)
|
||||
return -EIO;
|
||||
/* FIXME: send some error message */
|
||||
|
||||
@@ -819,7 +819,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
|
||||
|
||||
if (!trans) {
|
||||
DEBUGP(DLSMS, " -> (new transaction)\n");
|
||||
trans = trans_alloc(conn->network, conn->subscr,
|
||||
trans = trans_alloc(conn->network, conn->vsub,
|
||||
GSM48_PDISC_SMS,
|
||||
transaction_id, new_callref++);
|
||||
if (!trans) {
|
||||
@@ -861,6 +861,8 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
|
||||
}
|
||||
}
|
||||
|
||||
msc_subscr_conn_communicating(conn);
|
||||
|
||||
gsm411_smc_recv(&trans->sms.smc_inst,
|
||||
(new_trans) ? GSM411_MMSMS_EST_IND : GSM411_MMSMS_DATA_IND,
|
||||
msg, msg_type);
|
||||
@@ -881,7 +883,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
|
||||
int rc;
|
||||
|
||||
transaction_id =
|
||||
trans_assign_trans_id(conn->network, conn->subscr,
|
||||
trans_assign_trans_id(conn->network, conn->vsub,
|
||||
GSM48_PDISC_SMS, 0);
|
||||
if (transaction_id == -1) {
|
||||
LOGP(DLSMS, LOGL_ERROR, "No available transaction ids\n");
|
||||
@@ -894,7 +896,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
|
||||
DEBUGP(DLSMS, "%s()\n", __func__);
|
||||
|
||||
/* FIXME: allocate transaction with message reference */
|
||||
trans = trans_alloc(conn->network, conn->subscr,
|
||||
trans = trans_alloc(conn->network, conn->vsub,
|
||||
GSM48_PDISC_SMS,
|
||||
transaction_id, new_callref++);
|
||||
if (!trans) {
|
||||
@@ -989,7 +991,7 @@ static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
|
||||
/* high-level function to send a SMS to a given subscriber. The function
|
||||
* will take care of paging the subscriber, establishing the RLL SAPI3
|
||||
* connection, etc. */
|
||||
int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
|
||||
int gsm411_send_sms_subscr(struct vlr_subscr *vsub,
|
||||
struct gsm_sms *sms)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn;
|
||||
@@ -997,18 +999,18 @@ int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
|
||||
|
||||
/* check if we already have an open lchan to the subscriber.
|
||||
* if yes, send the SMS this way */
|
||||
conn = connection_for_subscr(subscr);
|
||||
conn = connection_for_subscr(vsub);
|
||||
if (conn) {
|
||||
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS via already open connection %p to %s\n",
|
||||
conn, subscr_name(subscr));
|
||||
conn, vlr_subscr_name(vsub));
|
||||
return gsm411_send_sms(conn, sms);
|
||||
}
|
||||
|
||||
/* if not, we have to start paging */
|
||||
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n",
|
||||
subscr_name(subscr));
|
||||
res = subscr_request_channel(subscr, RSL_CHANNEED_SDCCH,
|
||||
paging_cb_send_sms, sms);
|
||||
vlr_subscr_name(vsub));
|
||||
res = subscr_request_channel(vsub, RSL_CHANNEED_SDCCH,
|
||||
paging_cb_send_sms, sms);
|
||||
if (!res) {
|
||||
send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY);
|
||||
sms_free(sms);
|
||||
@@ -1035,6 +1037,7 @@ void _gsm411_sms_trans_free(struct gsm_trans *trans)
|
||||
}
|
||||
}
|
||||
|
||||
/* Process incoming SAPI N-REJECT from BSC */
|
||||
void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm_network *net;
|
||||
|
@@ -39,11 +39,10 @@
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
void *tall_sub_req_ctx;
|
||||
|
||||
extern struct llist_head *subscr_bsc_active_subscribers(void);
|
||||
|
||||
int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
|
||||
gsm_cbfn *cb, void *cb_data);
|
||||
|
||||
@@ -62,31 +61,35 @@ struct subscr_request {
|
||||
void *param;
|
||||
};
|
||||
|
||||
static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
|
||||
int type, const char *ident)
|
||||
static struct bsc_subscr *vlr_subscr_to_bsc_sub(struct llist_head *bsc_subscribers,
|
||||
struct vlr_subscr *vsub)
|
||||
{
|
||||
struct gsm_subscriber *subscr = db_get_subscriber(type, ident);
|
||||
if (subscr)
|
||||
subscr->group = sgrp;
|
||||
return subscr;
|
||||
struct bsc_subscr *sub;
|
||||
/* TODO MSC split -- creating a BSC subscriber directly from MSC data
|
||||
* structures in RAM. At some point the MSC will send a message to the
|
||||
* BSC instead. */
|
||||
sub = bsc_subscr_find_or_create_by_imsi(bsc_subscribers, vsub->imsi);
|
||||
sub->tmsi = vsub->tmsi;
|
||||
sub->lac = vsub->lac;
|
||||
return sub;
|
||||
}
|
||||
|
||||
/*
|
||||
* We got the channel assigned and can now hand this channel
|
||||
* over to one of our callbacks.
|
||||
*/
|
||||
static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
|
||||
struct msgb *msg, void *data, void *param)
|
||||
int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
|
||||
struct msgb *msg, void *data, void *param)
|
||||
{
|
||||
struct subscr_request *request, *tmp;
|
||||
struct gsm_subscriber_connection *conn = data;
|
||||
struct gsm_subscriber *subscr = param;
|
||||
struct vlr_subscr *vsub = param;
|
||||
struct paging_signal_data sig_data;
|
||||
struct bsc_subscr *bsub;
|
||||
struct gsm_network *net;
|
||||
|
||||
OSMO_ASSERT(subscr && subscr->is_paging);
|
||||
net = subscr->group->net;
|
||||
OSMO_ASSERT(vsub && vsub->cs.is_paging);
|
||||
net = vsub->vlr->user_ctx;
|
||||
|
||||
/*
|
||||
* Stop paging on all other BTS. E.g. if this is
|
||||
@@ -95,18 +98,12 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
|
||||
* and forget we wanted to page.
|
||||
*/
|
||||
|
||||
/* TODO MSC split -- creating a BSC subscriber directly from MSC data
|
||||
* structures in RAM. At some point the MSC will send a message to the
|
||||
* BSC instead. */
|
||||
bsub = bsc_subscr_find_or_create_by_imsi(net->bsc_subscribers,
|
||||
subscr->imsi);
|
||||
bsub->tmsi = subscr->tmsi;
|
||||
bsub->lac = subscr->lac;
|
||||
bsub = vlr_subscr_to_bsc_sub(conn->network->bsc_subscribers, vsub);
|
||||
paging_request_stop(&net->bts_list, NULL, bsub, NULL, NULL);
|
||||
bsc_subscr_put(bsub);
|
||||
|
||||
/* Inform parts of the system we don't know */
|
||||
sig_data.subscr = subscr;
|
||||
sig_data.vsub = vsub;
|
||||
sig_data.bts = conn ? conn->bts : NULL;
|
||||
sig_data.conn = conn;
|
||||
sig_data.paging_result = event;
|
||||
@@ -117,15 +114,15 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
|
||||
&sig_data
|
||||
);
|
||||
|
||||
llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) {
|
||||
llist_for_each_entry_safe(request, tmp, &vsub->cs.requests, entry) {
|
||||
llist_del(&request->entry);
|
||||
request->cbfn(hooknum, event, msg, data, request->param);
|
||||
talloc_free(request);
|
||||
}
|
||||
|
||||
/* balanced with the moment we start paging */
|
||||
subscr->is_paging = 0;
|
||||
subscr_put(subscr);
|
||||
vsub->cs.is_paging = false;
|
||||
vlr_subscr_put(vsub);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -176,46 +173,41 @@ static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
|
||||
return gsm48_secure_channel(conn, pr->key_seq, subscr_paging_sec_cb, param);
|
||||
}
|
||||
|
||||
struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
|
||||
int channel_type, gsm_cbfn *cbfn, void *param)
|
||||
struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub,
|
||||
int channel_type,
|
||||
gsm_cbfn *cbfn, void *param)
|
||||
{
|
||||
int rc;
|
||||
struct subscr_request *request;
|
||||
struct bsc_subscr *bsub;
|
||||
struct gsm_network *net = subscr->group->net;
|
||||
struct gsm_network *net = vsub->vlr->user_ctx;
|
||||
|
||||
/* Start paging.. we know it is async so we can do it before */
|
||||
if (!subscr->is_paging) {
|
||||
if (!vsub->cs.is_paging) {
|
||||
LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
|
||||
subscr_name(subscr));
|
||||
/* TODO MSC split -- creating a BSC subscriber directly from
|
||||
* MSC data structures in RAM. At some point the MSC will send
|
||||
* a message to the BSC instead. */
|
||||
bsub = bsc_subscr_find_or_create_by_imsi(net->bsc_subscribers,
|
||||
subscr->imsi);
|
||||
bsub->tmsi = subscr->tmsi;
|
||||
bsub->lac = subscr->lac;
|
||||
vlr_subscr_name(vsub));
|
||||
bsub = vlr_subscr_to_bsc_sub(net->bsc_subscribers, vsub);
|
||||
rc = paging_request(net, bsub, channel_type, subscr_paging_cb,
|
||||
subscr);
|
||||
vsub);
|
||||
bsc_subscr_put(bsub);
|
||||
if (rc <= 0) {
|
||||
LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
|
||||
subscr_name(subscr), rc);
|
||||
vlr_subscr_name(vsub), rc);
|
||||
return NULL;
|
||||
}
|
||||
/* reduced on the first paging callback */
|
||||
subscr_get(subscr);
|
||||
subscr->is_paging = 1;
|
||||
vlr_subscr_get(vsub);
|
||||
vsub->cs.is_paging = true;
|
||||
}
|
||||
|
||||
/* TODO: Stop paging in case of memory allocation failure */
|
||||
request = talloc_zero(subscr, struct subscr_request);
|
||||
request = talloc_zero(vsub, struct subscr_request);
|
||||
if (!request)
|
||||
return NULL;
|
||||
|
||||
request->cbfn = cbfn;
|
||||
request->param = param;
|
||||
llist_add_tail(&request->entry, &subscr->requests);
|
||||
llist_add_tail(&request->entry, &vsub->cs.requests);
|
||||
return request;
|
||||
}
|
||||
|
||||
@@ -225,196 +217,13 @@ void subscr_remove_request(struct subscr_request *request)
|
||||
talloc_free(request);
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi)
|
||||
struct gsm_subscriber_connection *connection_for_subscr(struct vlr_subscr *vsub)
|
||||
{
|
||||
struct gsm_subscriber *subscr = db_create_subscriber(imsi,
|
||||
sgrp->net->ext_min,
|
||||
sgrp->net->ext_max,
|
||||
sgrp->net->auto_assign_exten);
|
||||
if (subscr)
|
||||
subscr->group = sgrp;
|
||||
return subscr;
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_get_by_tmsi(struct gsm_subscriber_group *sgrp,
|
||||
uint32_t tmsi)
|
||||
{
|
||||
char tmsi_string[14];
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
/* we might have a record in memory already */
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
|
||||
if (tmsi == subscr->tmsi)
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
|
||||
sprintf(tmsi_string, "%u", tmsi);
|
||||
return get_subscriber(sgrp, GSM_SUBSCRIBER_TMSI, tmsi_string);
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_get_by_imsi(struct gsm_subscriber_group *sgrp,
|
||||
const char *imsi)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
|
||||
if (strcmp(subscr->imsi, imsi) == 0)
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
|
||||
return get_subscriber(sgrp, GSM_SUBSCRIBER_IMSI, imsi);
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_get_by_extension(struct gsm_subscriber_group *sgrp,
|
||||
const char *ext)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
|
||||
if (strcmp(subscr->extension, ext) == 0)
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
|
||||
return get_subscriber(sgrp, GSM_SUBSCRIBER_EXTENSION, ext);
|
||||
}
|
||||
|
||||
struct gsm_subscriber *subscr_get_by_id(struct gsm_subscriber_group *sgrp,
|
||||
unsigned long long id)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
char buf[32];
|
||||
sprintf(buf, "%llu", id);
|
||||
|
||||
llist_for_each_entry(subscr, subscr_bsc_active_subscribers(), entry) {
|
||||
if (subscr->id == id)
|
||||
return subscr_get(subscr);
|
||||
}
|
||||
|
||||
return get_subscriber(sgrp, GSM_SUBSCRIBER_ID, buf);
|
||||
}
|
||||
|
||||
int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!s) {
|
||||
LOGP(DMM, LOGL_ERROR, "LU Expiration but NULL subscriber\n");
|
||||
return -1;
|
||||
}
|
||||
if (!bts) {
|
||||
LOGP(DMM, LOGL_ERROR, "%s: LU Expiration but NULL bts\n",
|
||||
subscr_name(s));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Table 10.5.33: The T3212 timeout value field is coded as the
|
||||
* binary representation of the timeout value for
|
||||
* periodic updating in decihours. Mark the subscriber as
|
||||
* inactive if it missed two consecutive location updates.
|
||||
* Timeout is twice the t3212 value plus one minute */
|
||||
|
||||
/* Is expiration handling enabled? */
|
||||
if (bts->si_common.chan_desc.t3212 == 0)
|
||||
s->expire_lu = GSM_SUBSCRIBER_NO_EXPIRATION;
|
||||
else
|
||||
s->expire_lu = time(NULL) +
|
||||
(bts->si_common.chan_desc.t3212 * 60 * 6 * 2) + 60;
|
||||
|
||||
rc = db_sync_subscriber(s);
|
||||
db_subscriber_update(s);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* FIXME: Migrate pending requests from one BSC to another */
|
||||
switch (reason) {
|
||||
case GSM_SUBSCRIBER_UPDATE_ATTACHED:
|
||||
s->group = bts->network->subscr_group;
|
||||
/* Indicate "attached to LAC" */
|
||||
s->lac = bts->location_area_code;
|
||||
|
||||
LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n",
|
||||
subscr_name(s), s->lac);
|
||||
|
||||
/*
|
||||
* The below will set a new expire_lu but as a side-effect
|
||||
* the new lac will be saved in the database.
|
||||
*/
|
||||
rc = subscr_update_expire_lu(s, bts);
|
||||
osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_ATTACHED, s);
|
||||
break;
|
||||
case GSM_SUBSCRIBER_UPDATE_DETACHED:
|
||||
/* Only detach if we are currently in this area */
|
||||
if (bts->location_area_code == s->lac)
|
||||
s->lac = GSM_LAC_RESERVED_DETACHED;
|
||||
LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", subscr_name(s));
|
||||
rc = db_sync_subscriber(s);
|
||||
db_subscriber_update(s);
|
||||
osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_DETACHED, s);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "subscr_update with unknown reason: %d\n",
|
||||
reason);
|
||||
rc = db_sync_subscriber(s);
|
||||
db_subscriber_update(s);
|
||||
break;
|
||||
};
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void subscr_update_from_db(struct gsm_subscriber *sub)
|
||||
{
|
||||
db_subscriber_update(sub);
|
||||
}
|
||||
|
||||
static void subscr_expire_callback(void *data, long long unsigned int id)
|
||||
{
|
||||
struct gsm_network *net = data;
|
||||
struct gsm_subscriber *s = subscr_get_by_id(net->subscr_group, id);
|
||||
struct gsm_subscriber_connection *conn = connection_for_subscr(s);
|
||||
|
||||
/*
|
||||
* The subscriber is active and the phone stopped the timer. As
|
||||
* we don't want to periodically update the database for active
|
||||
* subscribers we will just do it when the subscriber was selected
|
||||
* for expiration. This way on the next around another subscriber
|
||||
* will be selected.
|
||||
*/
|
||||
if (conn && conn->expire_timer_stopped) {
|
||||
LOGP(DMM, LOGL_DEBUG, "Not expiring subscriber %s (ID %llu)\n",
|
||||
subscr_name(s), id);
|
||||
subscr_update_expire_lu(s, conn->bts);
|
||||
subscr_put(s);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
LOGP(DMM, LOGL_NOTICE, "Expiring inactive subscriber %s (ID %llu)\n",
|
||||
subscr_name(s), id);
|
||||
s->lac = GSM_LAC_RESERVED_DETACHED;
|
||||
db_sync_subscriber(s);
|
||||
|
||||
subscr_put(s);
|
||||
}
|
||||
|
||||
void subscr_expire(struct gsm_subscriber_group *sgrp)
|
||||
{
|
||||
db_subscriber_expire(sgrp->net, subscr_expire_callback);
|
||||
}
|
||||
|
||||
struct gsm_subscriber_connection *connection_for_subscr(struct gsm_subscriber *subscr)
|
||||
{
|
||||
/* FIXME: replace this with a backpointer in gsm_subscriber? */
|
||||
struct gsm_network *net = subscr->group->net;
|
||||
struct gsm_network *net = vsub->vlr->user_ctx;
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
llist_for_each_entry(conn, &net->subscr_conns, entry) {
|
||||
if (conn->subscr == subscr)
|
||||
if (conn->vsub == vsub)
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/meas_feed.h>
|
||||
#include <openbsc/vty.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#include "meas_feed.h"
|
||||
|
||||
@@ -35,13 +36,13 @@ static int process_meas_rep(struct gsm_meas_rep *mr)
|
||||
{
|
||||
struct msgb *msg;
|
||||
struct meas_feed_meas *mfm;
|
||||
struct gsm_subscriber *subscr;
|
||||
struct vlr_subscr *vsub;
|
||||
|
||||
/* ignore measurements as long as we don't know who it is */
|
||||
if (!mr->lchan || !mr->lchan->conn || !mr->lchan->conn->subscr)
|
||||
if (!mr->lchan || !mr->lchan->conn || !mr->lchan->conn->vsub)
|
||||
return 0;
|
||||
|
||||
subscr = mr->lchan->conn->subscr;
|
||||
vsub = mr->lchan->conn->vsub;
|
||||
|
||||
msg = msgb_alloc(sizeof(struct meas_feed_meas), "Meas. Feed");
|
||||
if (!msg)
|
||||
@@ -53,8 +54,8 @@ static int process_meas_rep(struct gsm_meas_rep *mr)
|
||||
mfm->hdr.version = MEAS_FEED_VERSION;
|
||||
|
||||
/* fill in MEAS_FEED_MEAS specific header */
|
||||
osmo_strlcpy(mfm->imsi, subscr->imsi, sizeof(mfm->imsi));
|
||||
osmo_strlcpy(mfm->name, subscr->name, sizeof(mfm->name));
|
||||
osmo_strlcpy(mfm->imsi, vsub->imsi, sizeof(mfm->imsi));
|
||||
osmo_strlcpy(mfm->name, vsub->name, sizeof(mfm->name));
|
||||
osmo_strlcpy(mfm->scenario, g_mfs.scenario, sizeof(mfm->scenario));
|
||||
|
||||
/* copy the entire measurement report */
|
||||
|
@@ -25,9 +25,12 @@
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/transaction.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/vlr.h>
|
||||
#include <openbsc/osmo_msc.h>
|
||||
|
||||
#include <openbsc/gsm_04_11.h>
|
||||
|
||||
/* Receive a SAPI-N-REJECT from BSC */
|
||||
static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
|
||||
{
|
||||
int sapi = dlci & 0x7;
|
||||
@@ -36,18 +39,52 @@ static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
|
||||
gsm411_sapi_n_reject(conn);
|
||||
}
|
||||
|
||||
/* Receive a CLEAR REQUEST from BSC */
|
||||
static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
|
||||
{
|
||||
gsm0408_clear_request(conn, cause);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool keep_conn(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
/* TODO: what about a silent call? */
|
||||
|
||||
if (!conn->conn_fsm) {
|
||||
DEBUGP(DMM, "No conn_fsm, release conn\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (conn->conn_fsm->state) {
|
||||
case SUBSCR_CONN_S_NEW:
|
||||
case SUBSCR_CONN_S_ACCEPTED:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive a COMPLETE LAYER3 INFO from BSC */
|
||||
static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
|
||||
uint16_t chosen_channel)
|
||||
{
|
||||
gsm0408_new_conn(conn);
|
||||
gsm0408_dispatch(conn, msg);
|
||||
|
||||
/* NOTE: after the MSC split, returning BSC_API_CONN_POL_REJECT shall
|
||||
* be replaced with a call to msc_subscr_con_free() */
|
||||
|
||||
if (!keep_conn(conn)) {
|
||||
DEBUGP(DMM, "compl_l3: Discarding conn\n");
|
||||
return BSC_API_CONN_POL_REJECT;
|
||||
}
|
||||
DEBUGP(DMM, "compl_l3: Keeping conn\n");
|
||||
conn->owned_by_msc = true;
|
||||
DEBUGP(DMM, "%s owned_by_msc = true\n",
|
||||
vlr_subscr_name(conn->vsub));
|
||||
return BSC_API_CONN_POL_ACCEPT;
|
||||
|
||||
#if 0
|
||||
/*
|
||||
* If this is a silent call we want the channel to remain open as long as
|
||||
* possible and this is why we accept this connection regardless of any
|
||||
@@ -55,20 +92,38 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
|
||||
*/
|
||||
if (conn->silent_call)
|
||||
return BSC_API_CONN_POL_ACCEPT;
|
||||
if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
|
||||
if (conn->sec_operation || conn->anch_operation)
|
||||
return BSC_API_CONN_POL_ACCEPT;
|
||||
if (trans_has_conn(conn))
|
||||
return BSC_API_CONN_POL_ACCEPT;
|
||||
|
||||
LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n");
|
||||
return BSC_API_CONN_POL_REJECT;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void subscr_conn_bump(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return;
|
||||
if (!conn->conn_fsm)
|
||||
return;
|
||||
if (!(conn->conn_fsm->state == SUBSCR_CONN_S_ACCEPTED
|
||||
|| conn->conn_fsm->state == SUBSCR_CONN_S_COMMUNICATING))
|
||||
return;
|
||||
osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_BUMP, NULL);
|
||||
}
|
||||
|
||||
/* Receive a DTAP message from BSC */
|
||||
static void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
|
||||
{
|
||||
gsm0408_dispatch(conn, msg);
|
||||
|
||||
/* Bump whether the conn wants to be closed */
|
||||
subscr_conn_bump(conn);
|
||||
}
|
||||
|
||||
/* Receive an ASSIGNMENT COMPLETE from BSC */
|
||||
static void msc_assign_compl(struct gsm_subscriber_connection *conn,
|
||||
uint8_t rr_cause, uint8_t chosen_channel,
|
||||
uint8_t encr_alg_id, uint8_t speec)
|
||||
@@ -76,58 +131,135 @@ static void msc_assign_compl(struct gsm_subscriber_connection *conn,
|
||||
LOGP(DRR, LOGL_DEBUG, "MSC assign complete (do nothing).\n");
|
||||
}
|
||||
|
||||
/* Receive an ASSIGNMENT FAILURE from BSC */
|
||||
static void msc_assign_fail(struct gsm_subscriber_connection *conn,
|
||||
uint8_t cause, uint8_t *rr_cause)
|
||||
{
|
||||
LOGP(DRR, LOGL_DEBUG, "MSC assign failure (do nothing).\n");
|
||||
}
|
||||
|
||||
/* Receive a CLASSMARK CHNAGE from BSC */
|
||||
static void msc_classmark_chg(struct gsm_subscriber_connection *conn,
|
||||
const uint8_t *cm2, uint8_t cm2_len,
|
||||
const uint8_t *cm3, uint8_t cm3_len)
|
||||
{
|
||||
struct gsm_subscriber *subscr = conn->subscr;
|
||||
|
||||
if (subscr) {
|
||||
subscr->equipment.classmark2_len = cm2_len;
|
||||
memcpy(subscr->equipment.classmark2, cm2, cm2_len);
|
||||
if (cm3) {
|
||||
subscr->equipment.classmark3_len = cm3_len;
|
||||
memcpy(subscr->equipment.classmark3, cm3, cm3_len);
|
||||
}
|
||||
db_sync_equipment(&subscr->equipment);
|
||||
conn->classmark.classmark2_len = cm2_len;
|
||||
memcpy(conn->classmark.classmark2, cm2, cm2_len);
|
||||
if (cm3) {
|
||||
conn->classmark.classmark3_len = cm3_len;
|
||||
memcpy(conn->classmark.classmark3, cm3, cm3_len);
|
||||
}
|
||||
}
|
||||
|
||||
/* Receive a CIPHERING MODE COMPLETE from BSC */
|
||||
static void msc_ciph_m_compl(struct gsm_subscriber_connection *conn,
|
||||
struct msgb *msg, uint8_t alg_id)
|
||||
{
|
||||
gsm_cbfn *cb;
|
||||
struct gsm48_hdr *gh = msgb_l3(msg);
|
||||
unsigned int payload_len = msgb_l3len(msg) - sizeof(*gh);
|
||||
struct tlv_parsed tp;
|
||||
uint8_t mi_type;
|
||||
char imeisv[GSM48_MI_SIZE] = "";
|
||||
struct vlr_ciph_result ciph_res = { .cause = VLR_CIPH_REJECT };
|
||||
|
||||
DEBUGP(DRR, "CIPHERING MODE COMPLETE\n");
|
||||
|
||||
/* Safety check */
|
||||
if (!conn->sec_operation) {
|
||||
DEBUGP(DRR, "No authentication/cipher operation in progress !!!\n");
|
||||
if (!gh) {
|
||||
LOGP(DRR, LOGL_ERROR, "invalid: msgb without l3 header\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* FIXME: check for MI (if any) */
|
||||
|
||||
/* Call back whatever was in progress (if anything) ... */
|
||||
cb = conn->sec_operation->cb;
|
||||
if (cb) {
|
||||
cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_SUCCEEDED,
|
||||
NULL, conn, conn->sec_operation->cb_data);
|
||||
|
||||
if (!conn) {
|
||||
LOGP(DRR, LOGL_ERROR,
|
||||
"invalid: rx Ciphering Mode Complete on NULL conn\n");
|
||||
return;
|
||||
}
|
||||
if (!conn->vsub) {
|
||||
LOGP(DRR, LOGL_ERROR,
|
||||
"invalid: rx Ciphering Mode Complete for NULL subscr\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Complete the operation */
|
||||
release_security_operation(conn);
|
||||
DEBUGP(DRR, "%s: CIPHERING MODE COMPLETE\n",
|
||||
vlr_subscr_name(conn->vsub));
|
||||
|
||||
tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0);
|
||||
|
||||
/* bearer capability */
|
||||
if (TLVP_PRESENT(&tp, GSM48_IE_MOBILE_ID)) {
|
||||
mi_type = TLVP_VAL(&tp, GSM48_IE_MOBILE_ID)[0] & GSM_MI_TYPE_MASK;
|
||||
if (mi_type == GSM_MI_TYPE_IMEISV
|
||||
&& TLVP_LEN(&tp, GSM48_IE_MOBILE_ID) > 0) {
|
||||
gsm48_mi_to_string(imeisv, sizeof(imeisv),
|
||||
TLVP_VAL(&tp, GSM48_IE_MOBILE_ID),
|
||||
TLVP_LEN(&tp, GSM48_IE_MOBILE_ID));
|
||||
ciph_res.imeisv = imeisv;
|
||||
}
|
||||
}
|
||||
|
||||
ciph_res.cause = VLR_CIPH_COMPL;
|
||||
vlr_subscr_rx_ciph_res(conn->vsub, &ciph_res);
|
||||
}
|
||||
|
||||
struct gsm_subscriber_connection *msc_subscr_con_allocate(struct gsm_network *network)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
conn = talloc_zero(network, struct gsm_subscriber_connection);
|
||||
if (!conn)
|
||||
return NULL;
|
||||
|
||||
conn->network = network;
|
||||
llist_add_tail(&conn->entry, &network->subscr_conns);
|
||||
return conn;
|
||||
}
|
||||
|
||||
void msc_subscr_cleanup(struct vlr_subscr *vsub)
|
||||
{
|
||||
if (!vsub)
|
||||
return;
|
||||
vsub->lu_fsm = NULL;
|
||||
}
|
||||
|
||||
void msc_subscr_con_cleanup(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
msc_release_anchor(conn);
|
||||
|
||||
if (conn->vsub) {
|
||||
DEBUGP(DRLL, "subscr %s: Freeing subscriber connection\n",
|
||||
vlr_subscr_name(conn->vsub));
|
||||
msc_subscr_cleanup(conn->vsub);
|
||||
vlr_subscr_put(conn->vsub);
|
||||
conn->vsub = NULL;
|
||||
} else
|
||||
DEBUGP(DRLL, "Freeing subscriber connection"
|
||||
" with NULL subscriber\n");
|
||||
|
||||
if (!conn->conn_fsm)
|
||||
return;
|
||||
|
||||
osmo_fsm_inst_term(conn->conn_fsm,
|
||||
(conn->conn_fsm->state == SUBSCR_CONN_S_RELEASED)
|
||||
? OSMO_FSM_TERM_REGULAR
|
||||
: OSMO_FSM_TERM_ERROR,
|
||||
NULL);
|
||||
conn->conn_fsm = NULL;
|
||||
}
|
||||
|
||||
void msc_subscr_con_free(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
msc_subscr_con_cleanup(conn);
|
||||
|
||||
llist_del(&conn->entry);
|
||||
talloc_free(conn);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* MSC-level operations to be called by libbsc in NITB */
|
||||
static struct bsc_api msc_handler = {
|
||||
.sapi_n_reject = msc_sapi_n_reject,
|
||||
.compl_l3 = msc_compl_l3,
|
||||
@@ -137,46 +269,33 @@ static struct bsc_api msc_handler = {
|
||||
.assign_fail = msc_assign_fail,
|
||||
.classmark_chg = msc_classmark_chg,
|
||||
.cipher_mode_compl = msc_ciph_m_compl,
|
||||
.conn_cleanup = msc_subscr_con_cleanup,
|
||||
};
|
||||
|
||||
struct bsc_api *msc_bsc_api() {
|
||||
return &msc_handler;
|
||||
}
|
||||
|
||||
/* lchan release handling */
|
||||
static void msc_release_connection(struct gsm_subscriber_connection *conn)
|
||||
void msc_close_connection(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
/* skip when we are in release, e.g. due an error */
|
||||
if (!conn)
|
||||
return;
|
||||
if (conn->in_release)
|
||||
return;
|
||||
|
||||
if (conn->silent_call)
|
||||
LOGP(DMSC, LOGL_ERROR, "release_connection() but silent_call active?!?\n");
|
||||
|
||||
/* check if there is a pending operation */
|
||||
if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
|
||||
LOGP(DMSC, LOGL_ERROR, "relase_connection() but {loc,sec,anch}_operation alive?!?\n");
|
||||
|
||||
if (trans_has_conn(conn))
|
||||
LOGP(DMSC, LOGL_ERROR, "release_conncetion() but transactions alive?!?\n");
|
||||
|
||||
/* no more connections, asking to release the channel */
|
||||
|
||||
/*
|
||||
* We had stopped the LU expire timer T3212. Now we are about
|
||||
* to send the MS back to the idle state and this should lead
|
||||
* to restarting the timer. Set the new expiration time.
|
||||
*/
|
||||
if (conn->expire_timer_stopped)
|
||||
subscr_update_expire_lu(conn->subscr, conn->bts);
|
||||
|
||||
conn->in_release = 1;
|
||||
gsm0808_clear(conn);
|
||||
msc_subscr_con_free(conn);
|
||||
if (!conn->conn_fsm) {
|
||||
/* No FSM means no valid process is ongoing. Discard right
|
||||
* away. */
|
||||
msc_subscr_con_free(conn);
|
||||
return;
|
||||
}
|
||||
if (conn->conn_fsm->state == SUBSCR_CONN_S_RELEASED)
|
||||
return;
|
||||
osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_CN_CLOSE, NULL);
|
||||
}
|
||||
|
||||
/* increment the ref-count. Needs to be called by every user */
|
||||
struct gsm_subscriber_connection *subscr_con_get(struct gsm_subscriber_connection *conn)
|
||||
struct gsm_subscriber_connection *_subscr_con_get(struct gsm_subscriber_connection *conn,
|
||||
const char *file, int line)
|
||||
{
|
||||
OSMO_ASSERT(conn);
|
||||
|
||||
@@ -184,25 +303,31 @@ struct gsm_subscriber_connection *subscr_con_get(struct gsm_subscriber_connectio
|
||||
return NULL;
|
||||
|
||||
conn->use_count++;
|
||||
DEBUGP(DMSC, "increased subscr_con use_count to %u\n", conn->use_count);
|
||||
LOGPSRC(DMSC, LOGL_DEBUG, file, line,
|
||||
"subscr %s: increased subscr_con use_count to %u\n",
|
||||
vlr_subscr_name(conn->vsub), conn->use_count);
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
/* decrement the ref-count. Once it reaches zero, we release */
|
||||
void subscr_con_put(struct gsm_subscriber_connection *conn)
|
||||
void _subscr_con_put(struct gsm_subscriber_connection *conn,
|
||||
const char *file, int line)
|
||||
{
|
||||
OSMO_ASSERT(conn);
|
||||
|
||||
if (conn->use_count == 0) {
|
||||
LOGP(DMSC, LOGL_ERROR, "tryin to decrement conn use count, but is alrady 0\n");
|
||||
LOGP(DMSC, LOGL_ERROR, "trying to decrement conn use count, but is alrady 0\n");
|
||||
return;
|
||||
}
|
||||
|
||||
conn->use_count--;
|
||||
DEBUGP(DMSC, "decreased subscr_con use_count to %u\n", conn->use_count);
|
||||
LOGPSRC(DMSC, LOGL_DEBUG, file, line,
|
||||
"subscr %s: decreased subscr_conn use_count to %u\n",
|
||||
vlr_subscr_name(conn->vsub), conn->use_count);
|
||||
|
||||
if (conn->use_count == 0) {
|
||||
msc_release_connection(conn);
|
||||
}
|
||||
#if 0
|
||||
if (conn->use_count == 0 && conn->conn_fsm)
|
||||
osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_MO_CLOSE, NULL);
|
||||
#endif
|
||||
}
|
||||
|
@@ -65,14 +65,14 @@ static int send_rrlp_req(struct gsm_subscriber_connection *conn)
|
||||
static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
|
||||
void *handler_data, void *signal_data)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
struct vlr_subscr *vsub;
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
switch (signal) {
|
||||
case S_SUBSCR_ATTACHED:
|
||||
/* A subscriber has attached. */
|
||||
subscr = signal_data;
|
||||
conn = connection_for_subscr(subscr);
|
||||
vsub = signal_data;
|
||||
conn = connection_for_subscr(vsub);
|
||||
if (!conn)
|
||||
break;
|
||||
send_rrlp_req(conn);
|
||||
|
@@ -122,20 +122,20 @@ int silent_call_reroute(struct gsm_subscriber_connection *conn, struct msgb *msg
|
||||
|
||||
|
||||
/* initiate a silent call with a given subscriber */
|
||||
int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type)
|
||||
int gsm_silent_call_start(struct vlr_subscr *vsub, void *data, int type)
|
||||
{
|
||||
struct subscr_request *req;
|
||||
|
||||
req = subscr_request_channel(subscr, type, paging_cb_silent, data);
|
||||
req = subscr_request_channel(vsub, type, paging_cb_silent, data);
|
||||
return req != NULL;
|
||||
}
|
||||
|
||||
/* end a silent call with a given subscriber */
|
||||
int gsm_silent_call_stop(struct gsm_subscriber *subscr)
|
||||
int gsm_silent_call_stop(struct vlr_subscr *vsub)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn;
|
||||
|
||||
conn = connection_for_subscr(subscr);
|
||||
conn = connection_for_subscr(vsub);
|
||||
if (!conn)
|
||||
return -EINVAL;
|
||||
|
||||
|
@@ -44,31 +44,32 @@
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/transaction.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#include "smpp_smsc.h"
|
||||
|
||||
/*! \brief find gsm_subscriber for a given SMPP NPI/TON/Address */
|
||||
static struct gsm_subscriber *subscr_by_dst(struct gsm_network *net,
|
||||
uint8_t npi, uint8_t ton, const char *addr)
|
||||
/*! \brief find vlr_subscr for a given SMPP NPI/TON/Address */
|
||||
static struct vlr_subscr *subscr_by_dst(struct gsm_network *net,
|
||||
uint8_t npi, uint8_t ton,
|
||||
const char *addr)
|
||||
{
|
||||
struct gsm_subscriber *subscr = NULL;
|
||||
struct vlr_subscr *vsub = NULL;
|
||||
|
||||
switch (npi) {
|
||||
case NPI_Land_Mobile_E212:
|
||||
subscr = subscr_get_by_imsi(net->subscr_group, addr);
|
||||
vsub = vlr_subscr_find_by_imsi(net->vlr, addr);
|
||||
break;
|
||||
case NPI_ISDN_E163_E164:
|
||||
case NPI_Private:
|
||||
subscr = subscr_get_by_extension(net->subscr_group, addr);
|
||||
vsub = vlr_subscr_find_by_msisdn(net->vlr, addr);
|
||||
break;
|
||||
default:
|
||||
LOGP(DSMPP, LOGL_NOTICE, "Unsupported NPI: %u\n", npi);
|
||||
break;
|
||||
}
|
||||
|
||||
/* tag the context in case we know it */
|
||||
log_set_context(LOG_CTX_VLR_SUBSCR, subscr);
|
||||
return subscr;
|
||||
log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
|
||||
return vsub;
|
||||
}
|
||||
|
||||
/*! \brief find a TLV with given tag in list of libsmpp34 TLVs */
|
||||
@@ -87,7 +88,7 @@ static struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag)
|
||||
static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
|
||||
const struct submit_sm_t *submit)
|
||||
{
|
||||
struct gsm_subscriber *dest;
|
||||
struct vlr_subscr *dest;
|
||||
struct gsm_sms *sms;
|
||||
struct tlv_t *t;
|
||||
const uint8_t *sms_msg;
|
||||
@@ -110,7 +111,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
|
||||
/* ERROR: we cannot have both! */
|
||||
LOGP(DLSMS, LOGL_ERROR, "SMPP Cannot have payload in "
|
||||
"TLV _and_ in the header\n");
|
||||
subscr_put(dest);
|
||||
vlr_subscr_put(dest);
|
||||
return ESME_ROPTPARNOTALLWD;
|
||||
}
|
||||
sms_msg = t->value.octet;
|
||||
@@ -121,7 +122,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
|
||||
} else {
|
||||
LOGP(DLSMS, LOGL_ERROR,
|
||||
"SMPP neither message payload nor valid sm_length.\n");
|
||||
subscr_put(dest);
|
||||
vlr_subscr_put(dest);
|
||||
return ESME_RINVPARLEN;
|
||||
}
|
||||
|
||||
@@ -133,7 +134,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
|
||||
sms->receiver = dest;
|
||||
sms->dst.ton = submit->dest_addr_ton;
|
||||
sms->dst.npi = submit->dest_addr_npi;
|
||||
osmo_strlcpy(sms->dst.addr, dest->extension, sizeof(sms->dst.addr));
|
||||
osmo_strlcpy(sms->dst.addr, dest->msisdn, sizeof(sms->dst.addr));
|
||||
|
||||
/* fill in the source address */
|
||||
sms->src.ton = submit->source_addr_ton;
|
||||
@@ -251,7 +252,7 @@ int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void alert_all_esme(struct smsc *smsc, struct gsm_subscriber *subscr,
|
||||
static void alert_all_esme(struct smsc *smsc, struct vlr_subscr *vsub,
|
||||
uint8_t smpp_avail_status)
|
||||
{
|
||||
struct osmo_esme *esme;
|
||||
@@ -264,11 +265,11 @@ static void alert_all_esme(struct smsc *smsc, struct gsm_subscriber *subscr,
|
||||
if (esme->acl && esme->acl->deliver_src_imsi) {
|
||||
smpp_tx_alert(esme, TON_Subscriber_Number,
|
||||
NPI_Land_Mobile_E212,
|
||||
subscr->imsi, smpp_avail_status);
|
||||
vsub->imsi, smpp_avail_status);
|
||||
} else {
|
||||
smpp_tx_alert(esme, TON_Network_Specific,
|
||||
NPI_ISDN_E163_E164,
|
||||
subscr->extension, smpp_avail_status);
|
||||
vsub->msisdn, smpp_avail_status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,7 +316,7 @@ static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
|
||||
}
|
||||
break;
|
||||
case S_SMS_SMMA:
|
||||
if (!sig_sms->trans || !sig_sms->trans->subscr) {
|
||||
if (!sig_sms->trans || !sig_sms->trans->vsub) {
|
||||
/* SMMA without a subscriber? strange... */
|
||||
LOGP(DLSMS, LOGL_NOTICE, "SMMA without subscriber?\n");
|
||||
break;
|
||||
@@ -324,7 +325,7 @@ static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
|
||||
/* There's no real 1:1 match for SMMA in SMPP. However,
|
||||
* an ALERT NOTIFICATION seems to be the most logical
|
||||
* choice */
|
||||
alert_all_esme(smsc, sig_sms->trans->subscr, 0);
|
||||
alert_all_esme(smsc, sig_sms->trans->vsub, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -335,7 +336,7 @@ static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
|
||||
static int smpp_subscr_cb(unsigned int subsys, unsigned int signal,
|
||||
void *handler_data, void *signal_data)
|
||||
{
|
||||
struct gsm_subscriber *subscr = signal_data;
|
||||
struct vlr_subscr *vsub = signal_data;
|
||||
struct smsc *smsc = handler_data;
|
||||
uint8_t smpp_avail_status;
|
||||
|
||||
@@ -351,7 +352,7 @@ static int smpp_subscr_cb(unsigned int subsys, unsigned int signal,
|
||||
return 0;
|
||||
}
|
||||
|
||||
alert_all_esme(smsc, subscr, smpp_avail_status);
|
||||
alert_all_esme(smsc, vsub, smpp_avail_status);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -451,12 +452,12 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
|
||||
dl_meas->full.rx_qual);
|
||||
}
|
||||
|
||||
if (lchan->conn && lchan->conn->subscr) {
|
||||
struct gsm_subscriber *subscr = lchan->conn->subscr;
|
||||
size_t imei_len = strlen(subscr->equipment.imei);
|
||||
if (lchan->conn && lchan->conn->vsub) {
|
||||
struct vlr_subscr *vsub = lchan->conn->vsub;
|
||||
size_t imei_len = strlen(vsub->imei);
|
||||
if (imei_len)
|
||||
append_tlv(req_tlv, TLVID_osmo_imei,
|
||||
(uint8_t *)subscr->equipment.imei, imei_len+1);
|
||||
(uint8_t *)vsub->imei, imei_len+1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,13 +479,13 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
|
||||
deliver.source_addr_npi = NPI_Land_Mobile_E212;
|
||||
snprintf((char *)deliver.source_addr,
|
||||
sizeof(deliver.source_addr), "%s",
|
||||
conn->subscr->imsi);
|
||||
conn->vsub->imsi);
|
||||
} else {
|
||||
deliver.source_addr_ton = TON_Network_Specific;
|
||||
deliver.source_addr_npi = NPI_ISDN_E163_E164;
|
||||
snprintf((char *)deliver.source_addr,
|
||||
sizeof(deliver.source_addr), "%s",
|
||||
conn->subscr->extension);
|
||||
conn->vsub->msisdn);
|
||||
}
|
||||
|
||||
deliver.dest_addr_ton = sms->dst.ton;
|
||||
|
@@ -36,6 +36,7 @@
|
||||
#include <openbsc/gsm_04_11.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/signal.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#include <osmocom/core/talloc.h>
|
||||
|
||||
@@ -47,7 +48,7 @@
|
||||
struct gsm_sms_pending {
|
||||
struct llist_head entry;
|
||||
|
||||
struct gsm_subscriber *subscr;
|
||||
struct vlr_subscr *vsub;
|
||||
unsigned long long sms_id;
|
||||
int failed_attempts;
|
||||
int resend;
|
||||
@@ -88,12 +89,12 @@ static int sms_is_in_pending(struct gsm_sms_queue *smsq, struct gsm_sms *sms)
|
||||
|
||||
static struct gsm_sms_pending *sms_subscriber_find_pending(
|
||||
struct gsm_sms_queue *smsq,
|
||||
struct gsm_subscriber *subscr)
|
||||
struct vlr_subscr *vsub)
|
||||
{
|
||||
struct gsm_sms_pending *pending;
|
||||
|
||||
llist_for_each_entry(pending, &smsq->pending_sms, entry) {
|
||||
if (pending->subscr == subscr)
|
||||
if (pending->vsub == vsub)
|
||||
return pending;
|
||||
}
|
||||
|
||||
@@ -101,9 +102,9 @@ static struct gsm_sms_pending *sms_subscriber_find_pending(
|
||||
}
|
||||
|
||||
static int sms_subscriber_is_pending(struct gsm_sms_queue *smsq,
|
||||
struct gsm_subscriber *subscr)
|
||||
struct vlr_subscr *vsub)
|
||||
{
|
||||
return sms_subscriber_find_pending(smsq, subscr) != NULL;
|
||||
return sms_subscriber_find_pending(smsq, vsub) != NULL;
|
||||
}
|
||||
|
||||
static struct gsm_sms_pending *sms_pending_from(struct gsm_sms_queue *smsq,
|
||||
@@ -115,27 +116,28 @@ static struct gsm_sms_pending *sms_pending_from(struct gsm_sms_queue *smsq,
|
||||
if (!pending)
|
||||
return NULL;
|
||||
|
||||
pending->subscr = subscr_get(sms->receiver);
|
||||
pending->vsub = vlr_subscr_get(sms->receiver);
|
||||
pending->sms_id = sms->id;
|
||||
return pending;
|
||||
}
|
||||
|
||||
static void sms_pending_free(struct gsm_sms_pending *pending)
|
||||
{
|
||||
subscr_put(pending->subscr);
|
||||
vlr_subscr_put(pending->vsub);
|
||||
llist_del(&pending->entry);
|
||||
talloc_free(pending);
|
||||
}
|
||||
|
||||
static void sms_pending_resend(struct gsm_sms_pending *pending)
|
||||
{
|
||||
struct gsm_network *net = pending->vsub->vlr->user_ctx;
|
||||
struct gsm_sms_queue *smsq;
|
||||
LOGP(DLSMS, LOGL_DEBUG,
|
||||
"Scheduling resend of SMS %llu.\n", pending->sms_id);
|
||||
|
||||
pending->resend = 1;
|
||||
|
||||
smsq = pending->subscr->group->net->sms_queue;
|
||||
smsq = net->sms_queue;
|
||||
if (osmo_timer_pending(&smsq->resend_pending))
|
||||
return;
|
||||
|
||||
@@ -144,12 +146,13 @@ static void sms_pending_resend(struct gsm_sms_pending *pending)
|
||||
|
||||
static void sms_pending_failed(struct gsm_sms_pending *pending, int paging_error)
|
||||
{
|
||||
struct gsm_network *net = pending->vsub->vlr->user_ctx;
|
||||
struct gsm_sms_queue *smsq;
|
||||
|
||||
LOGP(DLSMS, LOGL_NOTICE, "Sending SMS %llu failed %d times.\n",
|
||||
pending->sms_id, pending->failed_attempts);
|
||||
|
||||
smsq = pending->subscr->group->net->sms_queue;
|
||||
smsq = net->sms_queue;
|
||||
if (++pending->failed_attempts < smsq->max_fail)
|
||||
return sms_pending_resend(pending);
|
||||
|
||||
@@ -191,8 +194,11 @@ static struct gsm_sms *take_next_sms(struct gsm_sms_queue *smsq)
|
||||
struct gsm_sms *sms;
|
||||
|
||||
sms = db_sms_get_unsent_by_subscr(smsq->network, smsq->last_subscr_id, 10);
|
||||
DEBUGP(DLSMS, "db_sms_get_unsent_by_subscr(id = %llu) returned %p\n",
|
||||
smsq->last_subscr_id, sms);
|
||||
if (sms) {
|
||||
smsq->last_subscr_id = sms->receiver->id + 1;
|
||||
DEBUGP(DLSMS, "take_next_sms() returns %p\n", sms);
|
||||
return sms;
|
||||
}
|
||||
|
||||
@@ -200,8 +206,11 @@ static struct gsm_sms *take_next_sms(struct gsm_sms_queue *smsq)
|
||||
smsq->last_subscr_id = 0;
|
||||
sms = db_sms_get_unsent_by_subscr(smsq->network,
|
||||
smsq->last_subscr_id, 10);
|
||||
DEBUGP(DLSMS, "db_sms_get_unsent_by_subscr(id = %llu) returned %p\n",
|
||||
smsq->last_subscr_id, sms);
|
||||
if (sms)
|
||||
smsq->last_subscr_id = sms->receiver->id + 1;
|
||||
DEBUGP(DLSMS, "take_next_sms() returns %p\n", sms);
|
||||
return sms;
|
||||
}
|
||||
|
||||
@@ -289,17 +298,18 @@ static void sms_submit_pending(void *_data)
|
||||
/**
|
||||
* Send the next SMS or trigger the queue
|
||||
*/
|
||||
static void sms_send_next(struct gsm_subscriber *subscr)
|
||||
static void sms_send_next(struct vlr_subscr *vsub)
|
||||
{
|
||||
struct gsm_sms_queue *smsq = subscr->group->net->sms_queue;
|
||||
struct gsm_network *net = vsub->vlr->user_ctx;
|
||||
struct gsm_sms_queue *smsq = net->sms_queue;
|
||||
struct gsm_sms_pending *pending;
|
||||
struct gsm_sms *sms;
|
||||
|
||||
/* the subscriber should not be in the queue */
|
||||
OSMO_ASSERT(!sms_subscriber_is_pending(smsq, subscr));
|
||||
OSMO_ASSERT(!sms_subscriber_is_pending(smsq, vsub));
|
||||
|
||||
/* check for more messages for this subscriber */
|
||||
sms = db_sms_get_unsent_for_subscr(subscr);
|
||||
sms = db_sms_get_unsent_for_subscr(vsub);
|
||||
if (!sms)
|
||||
goto no_pending_sms;
|
||||
|
||||
@@ -322,7 +332,7 @@ static void sms_send_next(struct gsm_subscriber *subscr)
|
||||
|
||||
no_pending_sms:
|
||||
/* Try to send the SMS to avoid the queue being stuck */
|
||||
sms_submit_pending(subscr->group->net->sms_queue);
|
||||
sms_submit_pending(net->sms_queue);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -364,7 +374,7 @@ int sms_queue_start(struct gsm_network *network, int max_pending)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sub_ready_for_sm(struct gsm_network *net, struct gsm_subscriber *subscr)
|
||||
static int sub_ready_for_sm(struct gsm_network *net, struct vlr_subscr *vsub)
|
||||
{
|
||||
struct gsm_sms *sms;
|
||||
struct gsm_sms_pending *pending;
|
||||
@@ -385,20 +395,20 @@ static int sub_ready_for_sm(struct gsm_network *net, struct gsm_subscriber *subs
|
||||
*/
|
||||
|
||||
/* check if we have pending requests */
|
||||
pending = sms_subscriber_find_pending(net->sms_queue, subscr);
|
||||
pending = sms_subscriber_find_pending(net->sms_queue, vsub);
|
||||
if (pending) {
|
||||
LOGP(DMSC, LOGL_NOTICE,
|
||||
"Pending paging while subscriber %llu attached.\n",
|
||||
subscr->id);
|
||||
vsub->id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
conn = connection_for_subscr(subscr);
|
||||
conn = connection_for_subscr(vsub);
|
||||
if (!conn)
|
||||
return -1;
|
||||
|
||||
/* Now try to deliver any pending SMS to this sub */
|
||||
sms = db_sms_get_unsent_for_subscr(subscr);
|
||||
sms = db_sms_get_unsent_for_subscr(vsub);
|
||||
if (!sms)
|
||||
return -1;
|
||||
gsm411_send_sms(conn, sms);
|
||||
@@ -408,13 +418,13 @@ static int sub_ready_for_sm(struct gsm_network *net, struct gsm_subscriber *subs
|
||||
static int sms_subscr_cb(unsigned int subsys, unsigned int signal,
|
||||
void *handler_data, void *signal_data)
|
||||
{
|
||||
struct gsm_subscriber *subscr = signal_data;
|
||||
struct vlr_subscr *vsub = signal_data;
|
||||
|
||||
if (signal != S_SUBSCR_ATTACHED)
|
||||
return 0;
|
||||
|
||||
/* this is readyForSM */
|
||||
return sub_ready_for_sm(handler_data, subscr);
|
||||
return sub_ready_for_sm(handler_data, vsub);
|
||||
}
|
||||
|
||||
static int sms_sms_cb(unsigned int subsys, unsigned int signal,
|
||||
@@ -423,7 +433,7 @@ static int sms_sms_cb(unsigned int subsys, unsigned int signal,
|
||||
struct gsm_network *network = handler_data;
|
||||
struct sms_signal_data *sig_sms = signal_data;
|
||||
struct gsm_sms_pending *pending;
|
||||
struct gsm_subscriber *subscr;
|
||||
struct vlr_subscr *vsub;
|
||||
|
||||
/* We got a new SMS and maybe should launch the queue again. */
|
||||
if (signal == S_SMS_SUBMITTED || signal == S_SMS_SMMA) {
|
||||
@@ -449,11 +459,11 @@ static int sms_sms_cb(unsigned int subsys, unsigned int signal,
|
||||
case S_SMS_DELIVERED:
|
||||
/* Remember the subscriber and clear the pending entry */
|
||||
network->sms_queue->pending -= 1;
|
||||
subscr = subscr_get(pending->subscr);
|
||||
vsub = vlr_subscr_get(pending->vsub);
|
||||
sms_pending_free(pending);
|
||||
/* Attempt to send another SMS to this subscriber */
|
||||
sms_send_next(subscr);
|
||||
subscr_put(subscr);
|
||||
sms_send_next(vsub);
|
||||
vlr_subscr_put(vsub);
|
||||
break;
|
||||
case S_SMS_MEM_EXCEEDED:
|
||||
network->sms_queue->pending -= 1;
|
||||
@@ -510,7 +520,7 @@ int sms_queue_stats(struct gsm_sms_queue *smsq, struct vty *vty)
|
||||
|
||||
llist_for_each_entry(pending, &smsq->pending_sms, entry)
|
||||
vty_out(vty, " SMS Pending for Subscriber: %llu SMS: %llu Failed: %d.%s",
|
||||
pending->subscr->id, pending->sms_id,
|
||||
pending->vsub->id, pending->sms_id,
|
||||
pending->failed_attempts, VTY_NEWLINE);
|
||||
return 0;
|
||||
}
|
||||
@@ -537,7 +547,7 @@ int sms_queue_clear(struct gsm_sms_queue *smsq)
|
||||
|
||||
llist_for_each_entry_safe(pending, tmp, &smsq->pending_sms, entry) {
|
||||
LOGP(DLSMS, LOGL_NOTICE,
|
||||
"SMSqueue clearing for sub %llu\n", pending->subscr->id);
|
||||
"SMSqueue clearing for sub %llu\n", pending->vsub->id);
|
||||
sms_pending_free(pending);
|
||||
}
|
||||
|
||||
|
@@ -23,19 +23,24 @@
|
||||
|
||||
#include <osmocom/core/logging.h>
|
||||
#include <osmocom/core/fsm.h>
|
||||
#include <osmocom/core/signal.h>
|
||||
|
||||
#include <openbsc/osmo_msc.h>
|
||||
#include <openbsc/vlr.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/transaction.h>
|
||||
#include <openbsc/signal.h>
|
||||
|
||||
#define SUBSCR_CONN_TIMEOUT 5 /* seconds */
|
||||
|
||||
static const struct value_string subscr_conn_fsm_event_names[] = {
|
||||
OSMO_VALUE_STRING(SUBSCR_CONN_E_INVALID),
|
||||
OSMO_VALUE_STRING(SUBSCR_CONN_E_START),
|
||||
OSMO_VALUE_STRING(SUBSCR_CONN_E_ACCEPTED),
|
||||
OSMO_VALUE_STRING(SUBSCR_CONN_E_COMMUNICATING),
|
||||
OSMO_VALUE_STRING(SUBSCR_CONN_E_BUMP),
|
||||
OSMO_VALUE_STRING(SUBSCR_CONN_E_MO_CLOSE),
|
||||
OSMO_VALUE_STRING(SUBSCR_CONN_E_CN_CLOSE),
|
||||
OSMO_VALUE_STRING(SUBSCR_CONN_E_CLOSE_CONF),
|
||||
{ 0, NULL }
|
||||
};
|
||||
|
||||
@@ -50,7 +55,14 @@ const struct value_string subscr_conn_from_names[] = {
|
||||
static void paging_resp(struct gsm_subscriber_connection *conn,
|
||||
enum gsm_paging_event pe)
|
||||
{
|
||||
subscr_paging_dispatch(GSM_HOOK_RR_PAGING, pe, NULL, conn, conn->subscr);
|
||||
subscr_paging_dispatch(GSM_HOOK_RR_PAGING, pe, NULL, conn, conn->vsub);
|
||||
}
|
||||
|
||||
void subscr_conn_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
OSMO_ASSERT(event == SUBSCR_CONN_E_START);
|
||||
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_NEW,
|
||||
SUBSCR_CONN_TIMEOUT, 0);
|
||||
}
|
||||
|
||||
void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
@@ -67,12 +79,11 @@ void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
/* If accepted, transition the state, all other cases mean failure. */
|
||||
switch (event) {
|
||||
case SUBSCR_CONN_E_ACCEPTED:
|
||||
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_ACCEPTED, 0, 0);
|
||||
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_ACCEPTED, SUBSCR_CONN_TIMEOUT, 0);
|
||||
break;
|
||||
|
||||
case SUBSCR_CONN_E_MO_CLOSE:
|
||||
case SUBSCR_CONN_E_CN_CLOSE:
|
||||
case SUBSCR_CONN_E_CLOSE_CONF:
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -143,8 +154,7 @@ static void subscr_conn_fsm_bump(struct osmo_fsm_inst *fi, uint32_t event, void
|
||||
if (conn->received_cm_service_request)
|
||||
return;
|
||||
|
||||
/* is this needed? */
|
||||
if (conn->subscr && !llist_empty(&conn->subscr->requests))
|
||||
if (conn->vsub && !llist_empty(&conn->vsub->cs.requests))
|
||||
return;
|
||||
|
||||
if (trans_has_conn(conn))
|
||||
@@ -153,9 +163,19 @@ static void subscr_conn_fsm_bump(struct osmo_fsm_inst *fi, uint32_t event, void
|
||||
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
|
||||
}
|
||||
|
||||
static void subscr_conn_fsm_accepted_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn = fi->priv;
|
||||
osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_ATTACHED, conn->vsub);
|
||||
}
|
||||
|
||||
static void subscr_conn_fsm_accepted(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch (event) {
|
||||
case SUBSCR_CONN_E_COMMUNICATING:
|
||||
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_COMMUNICATING, 0, 0);
|
||||
return;
|
||||
|
||||
case SUBSCR_CONN_E_BUMP:
|
||||
subscr_conn_fsm_bump(fi, event, data);
|
||||
return;
|
||||
@@ -169,34 +189,91 @@ static void subscr_conn_fsm_accepted(struct osmo_fsm_inst *fi, uint32_t event, v
|
||||
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
|
||||
}
|
||||
|
||||
static void subscr_conn_fsm_release(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
static void subscr_conn_fsm_communicating(struct osmo_fsm_inst *fi, uint32_t event, void *data)
|
||||
{
|
||||
switch (event) {
|
||||
case SUBSCR_CONN_E_COMMUNICATING:
|
||||
/* no-op */
|
||||
return;
|
||||
|
||||
case SUBSCR_CONN_E_BUMP:
|
||||
subscr_conn_fsm_bump(fi, event, data);
|
||||
return;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Whatever unexpected happens in the accepted state, it means release.
|
||||
* Even if an unexpected event is passed, the safest thing to do is
|
||||
* discard the conn. We don't expect another SUBSCR_CONN_E_ACCEPTED. */
|
||||
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
|
||||
}
|
||||
|
||||
static void subscr_conn_fsm_cleanup(struct osmo_fsm_inst *fi,
|
||||
enum osmo_fsm_term_cause cause)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn = fi->priv;
|
||||
fi->priv = NULL;
|
||||
|
||||
if (!conn)
|
||||
return;
|
||||
|
||||
if (conn->in_release)
|
||||
return;
|
||||
conn->in_release = true;
|
||||
conn->conn_fsm = NULL;
|
||||
|
||||
/* If we're closing in a middle of a trans, we need to clean up */
|
||||
if (conn->use_count) {
|
||||
DEBUGP(DMM, "%s: still in use (%u), cleaning up transactions\n",
|
||||
vlr_subscr_name(conn->vsub), conn->use_count);
|
||||
trans_conn_closed(conn);
|
||||
}
|
||||
if (conn->use_count)
|
||||
LOGP(DMM, LOGL_ERROR, "%s: closing conn but still in use (%u)\n",
|
||||
vlr_subscr_name(conn->vsub), conn->use_count);
|
||||
|
||||
/* temporary hack, see owned_by_msc */
|
||||
if (!conn->owned_by_msc) {
|
||||
DEBUGP(DMM, "%s leaving bsc_subscr_con_free() to bsc_api.c, owned_by_msc = false\n",
|
||||
subscr_name(conn->subscr));
|
||||
vlr_subscr_name(conn->vsub));
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGP(DMM, "%s calling bsc_subscr_con_free(), owned_by_msc = true\n",
|
||||
subscr_name(conn->subscr));
|
||||
vlr_subscr_name(conn->vsub));
|
||||
gsm0808_clear(conn);
|
||||
bsc_subscr_con_free(conn);
|
||||
}
|
||||
|
||||
int subscr_conn_fsm_timeout(struct osmo_fsm_inst *fi)
|
||||
{
|
||||
struct gsm_subscriber_connection *conn = fi->priv;
|
||||
if (conn)
|
||||
vlr_subscr_conn_timeout(conn->vsub);
|
||||
osmo_fsm_inst_dispatch(fi, SUBSCR_CONN_E_CN_CLOSE, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void subscr_conn_fsm_release(struct osmo_fsm_inst *fi, uint32_t prev_state)
|
||||
{
|
||||
osmo_fsm_inst_term(fi, OSMO_FSM_TERM_REGULAR, NULL);
|
||||
}
|
||||
|
||||
#define S(x) (1 << (x))
|
||||
|
||||
static const struct osmo_fsm_state subscr_conn_fsm_states[] = {
|
||||
[SUBSCR_CONN_S_INIT] = {
|
||||
.name = OSMO_STRINGIFY(SUBSCR_CONN_S_INIT),
|
||||
.in_event_mask = S(SUBSCR_CONN_E_START),
|
||||
.out_state_mask = S(SUBSCR_CONN_S_NEW),
|
||||
.action = subscr_conn_fsm_init,
|
||||
},
|
||||
[SUBSCR_CONN_S_NEW] = {
|
||||
.name = OSMO_STRINGIFY(SUBSCR_CONN_S_NEW),
|
||||
.in_event_mask = S(SUBSCR_CONN_E_ACCEPTED) |
|
||||
S(SUBSCR_CONN_E_MO_CLOSE) |
|
||||
S(SUBSCR_CONN_E_CN_CLOSE) |
|
||||
S(SUBSCR_CONN_E_CLOSE_CONF),
|
||||
S(SUBSCR_CONN_E_CN_CLOSE),
|
||||
.out_state_mask = S(SUBSCR_CONN_S_ACCEPTED) |
|
||||
S(SUBSCR_CONN_S_RELEASED),
|
||||
.action = subscr_conn_fsm_new,
|
||||
@@ -204,14 +281,27 @@ static const struct osmo_fsm_state subscr_conn_fsm_states[] = {
|
||||
[SUBSCR_CONN_S_ACCEPTED] = {
|
||||
.name = OSMO_STRINGIFY(SUBSCR_CONN_S_ACCEPTED),
|
||||
/* allow everything to release for any odd behavior */
|
||||
.in_event_mask = S(SUBSCR_CONN_E_ACCEPTED) |
|
||||
S(SUBSCR_CONN_E_BUMP) |
|
||||
.in_event_mask = S(SUBSCR_CONN_E_COMMUNICATING) |
|
||||
S(SUBSCR_CONN_E_BUMP) |
|
||||
S(SUBSCR_CONN_E_ACCEPTED) |
|
||||
S(SUBSCR_CONN_E_MO_CLOSE) |
|
||||
S(SUBSCR_CONN_E_CN_CLOSE) |
|
||||
S(SUBSCR_CONN_E_CLOSE_CONF),
|
||||
.out_state_mask = S(SUBSCR_CONN_S_RELEASED),
|
||||
S(SUBSCR_CONN_E_CN_CLOSE),
|
||||
.out_state_mask = S(SUBSCR_CONN_S_RELEASED) |
|
||||
S(SUBSCR_CONN_S_COMMUNICATING),
|
||||
.onenter = subscr_conn_fsm_accepted_enter,
|
||||
.action = subscr_conn_fsm_accepted,
|
||||
},
|
||||
[SUBSCR_CONN_S_COMMUNICATING] = {
|
||||
.name = OSMO_STRINGIFY(SUBSCR_CONN_S_COMMUNICATING),
|
||||
/* allow everything to release for any odd behavior */
|
||||
.in_event_mask = S(SUBSCR_CONN_E_BUMP) |
|
||||
S(SUBSCR_CONN_E_ACCEPTED) |
|
||||
S(SUBSCR_CONN_E_COMMUNICATING) |
|
||||
S(SUBSCR_CONN_E_MO_CLOSE) |
|
||||
S(SUBSCR_CONN_E_CN_CLOSE),
|
||||
.out_state_mask = S(SUBSCR_CONN_S_RELEASED),
|
||||
.action = subscr_conn_fsm_communicating,
|
||||
},
|
||||
[SUBSCR_CONN_S_RELEASED] = {
|
||||
.name = OSMO_STRINGIFY(SUBSCR_CONN_S_RELEASED),
|
||||
.onenter = subscr_conn_fsm_release,
|
||||
@@ -226,6 +316,8 @@ static struct osmo_fsm subscr_conn_fsm = {
|
||||
.allstate_action = NULL,
|
||||
.log_subsys = DVLR,
|
||||
.event_names = subscr_conn_fsm_event_names,
|
||||
.cleanup = subscr_conn_fsm_cleanup,
|
||||
.timer_cb = subscr_conn_fsm_timeout,
|
||||
};
|
||||
|
||||
int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id)
|
||||
@@ -239,7 +331,13 @@ int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
fi = osmo_fsm_inst_alloc(&subscr_conn_fsm, conn, conn, LOGL_DEBUG, id);
|
||||
/* Allocate the FSM not with the subscr_conn. Semantically it would
|
||||
* make sense, but in subscr_conn_fsm_cleanup(), we want to discard the
|
||||
* subscriber connection. If the FSM is freed along with the subscriber
|
||||
* connection, then in _osmo_fsm_inst_term() the osmo_fsm_inst_free()
|
||||
* that follows the cleanup() call would run into a double free. */
|
||||
fi = osmo_fsm_inst_alloc(&subscr_conn_fsm, conn->network, conn,
|
||||
LOGL_DEBUG, id);
|
||||
|
||||
if (!fi) {
|
||||
LOGP(DMM, LOGL_ERROR,
|
||||
@@ -247,6 +345,7 @@ int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id)
|
||||
return -ENOMEM;
|
||||
}
|
||||
conn->conn_fsm = fi;
|
||||
osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_START, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -254,15 +353,23 @@ bool msc_subscr_conn_is_accepted(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
if (!conn)
|
||||
return false;
|
||||
if (!conn->subscr)
|
||||
if (!conn->vsub)
|
||||
return false;
|
||||
if (!conn->conn_fsm)
|
||||
return false;
|
||||
if (conn->conn_fsm->state != SUBSCR_CONN_S_ACCEPTED)
|
||||
if (!(conn->conn_fsm->state == SUBSCR_CONN_S_ACCEPTED
|
||||
|| conn->conn_fsm->state == SUBSCR_CONN_S_COMMUNICATING))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void msc_subscr_conn_communicating(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
OSMO_ASSERT(conn);
|
||||
osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_COMMUNICATING,
|
||||
NULL);
|
||||
}
|
||||
|
||||
void msc_subscr_conn_init(void)
|
||||
{
|
||||
osmo_fsm_register(&subscr_conn_fsm);
|
||||
|
@@ -19,6 +19,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#if 0
|
||||
VLR: what do do with this?
|
||||
|
||||
#include <stdio.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <openbsc/signal.h>
|
||||
@@ -28,6 +31,7 @@
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/chan_alloc.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#define TOKEN_SMS_TEXT "HAR 2009 GSM. Register at http://har2009.gnumonks.org/ " \
|
||||
"Your IMSI is %s, auth token is %08X, phone no is %s."
|
||||
@@ -37,13 +41,15 @@ static char *build_sms_string(struct gsm_subscriber *subscr, uint32_t token)
|
||||
char *sms_str;
|
||||
unsigned int len;
|
||||
|
||||
len = strlen(subscr->imsi) + 8 + strlen(TOKEN_SMS_TEXT);
|
||||
OSMO_ASSERT(subscr->vsub);
|
||||
|
||||
len = strlen(subscr->vsub->imsi) + 8 + strlen(TOKEN_SMS_TEXT);
|
||||
sms_str = talloc_size(tall_bsc_ctx, len);
|
||||
if (!sms_str)
|
||||
return NULL;
|
||||
|
||||
snprintf(sms_str, len, TOKEN_SMS_TEXT, subscr->imsi, token,
|
||||
subscr->extension);
|
||||
snprintf(sms_str, len, TOKEN_SMS_TEXT, subscr->vsub->imsi, token,
|
||||
subscr->vsub->msisdn);
|
||||
sms_str[len-1] = '\0';
|
||||
|
||||
return sms_str;
|
||||
@@ -99,7 +105,7 @@ static int token_subscr_cb(unsigned int subsys, unsigned int signal,
|
||||
unauth:
|
||||
|
||||
/* make sure we don't allow him in again unless he clicks the web UI */
|
||||
subscr->authorized = 0;
|
||||
subscr->vsub->authorized = 0;
|
||||
db_sync_subscriber(subscr);
|
||||
if (rc) {
|
||||
struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
|
||||
@@ -158,3 +164,4 @@ void on_dso_load_token(void)
|
||||
osmo_signal_register_handler(SS_SUBSCR, token_subscr_cb, NULL);
|
||||
osmo_signal_register_handler(SS_SMS, token_sms_cb, NULL);
|
||||
}
|
||||
#endif
|
||||
|
@@ -23,25 +23,31 @@
|
||||
#include <openbsc/mncc.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <osmocom/core/talloc.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/gsm_04_08.h>
|
||||
#include <openbsc/mncc.h>
|
||||
#include <openbsc/paging.h>
|
||||
#include <openbsc/osmo_msc.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
void *tall_trans_ctx;
|
||||
|
||||
void _gsm48_cc_trans_free(struct gsm_trans *trans);
|
||||
|
||||
/* Find a transaction in connection for given protocol + transaction ID
|
||||
* \param[in] conn Connection in whihc we want to find transaction
|
||||
* \param[in] proto Protocol of transaction
|
||||
* \param[in] trans_id Transaction ID of transaction
|
||||
* \returns Matching transaction, if any
|
||||
*/
|
||||
struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
|
||||
uint8_t proto, uint8_t trans_id)
|
||||
{
|
||||
struct gsm_trans *trans;
|
||||
struct gsm_network *net = conn->network;
|
||||
struct gsm_subscriber *subscr = conn->subscr;
|
||||
struct vlr_subscr *vsub = conn->vsub;
|
||||
|
||||
llist_for_each_entry(trans, &net->trans_list, entry) {
|
||||
if (trans->subscr == subscr &&
|
||||
if (trans->vsub == vsub &&
|
||||
trans->protocol == proto &&
|
||||
trans->transaction_id == trans_id)
|
||||
return trans;
|
||||
@@ -49,6 +55,11 @@ struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Find a transaction by call reference
|
||||
* \param[in] net Network in which we should search
|
||||
* \param[in] callref Call Reference of transaction
|
||||
* \returns Matching transaction, if any
|
||||
*/
|
||||
struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
|
||||
uint32_t callref)
|
||||
{
|
||||
@@ -61,21 +72,28 @@ struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! Allocate a new transaction and add it to network list
|
||||
* \param[in] net Netwokr in which we allocate transaction
|
||||
* \param[in] subscr Subscriber for which we allocate transaction
|
||||
* \param[in] protocol Protocol (CC/SMS/...)
|
||||
* \param[in] callref Call Reference
|
||||
* \returns Transaction
|
||||
*/
|
||||
struct gsm_trans *trans_alloc(struct gsm_network *net,
|
||||
struct gsm_subscriber *subscr,
|
||||
struct vlr_subscr *vsub,
|
||||
uint8_t protocol, uint8_t trans_id,
|
||||
uint32_t callref)
|
||||
{
|
||||
struct gsm_trans *trans;
|
||||
|
||||
DEBUGP(DCC, "subscr=%p, net=%p\n", subscr, net);
|
||||
DEBUGP(DCC, "subscr=%p, net=%p\n", vsub, net);
|
||||
|
||||
trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
|
||||
if (!trans)
|
||||
return NULL;
|
||||
|
||||
trans->subscr = subscr;
|
||||
subscr_get(trans->subscr);
|
||||
trans->vsub = vsub;
|
||||
vlr_subscr_get(trans->vsub);
|
||||
|
||||
trans->protocol = protocol;
|
||||
trans->transaction_id = trans_id;
|
||||
@@ -87,6 +105,9 @@ struct gsm_trans *trans_alloc(struct gsm_network *net,
|
||||
return trans;
|
||||
}
|
||||
|
||||
/* Release a transaction
|
||||
* \param[in] trans Transaction to be released
|
||||
*/
|
||||
void trans_free(struct gsm_trans *trans)
|
||||
{
|
||||
switch (trans->protocol) {
|
||||
@@ -103,9 +124,9 @@ void trans_free(struct gsm_trans *trans)
|
||||
trans->paging_request = NULL;
|
||||
}
|
||||
|
||||
if (trans->subscr) {
|
||||
subscr_put(trans->subscr);
|
||||
trans->subscr = NULL;
|
||||
if (trans->vsub) {
|
||||
vlr_subscr_put(trans->vsub);
|
||||
trans->vsub = NULL;
|
||||
}
|
||||
|
||||
llist_del(&trans->entry);
|
||||
@@ -118,8 +139,13 @@ void trans_free(struct gsm_trans *trans)
|
||||
}
|
||||
|
||||
/* allocate an unused transaction ID for the given subscriber
|
||||
* in the given protocol using the ti_flag specified */
|
||||
int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr,
|
||||
* in the given protocol using the ti_flag specified
|
||||
* \param[in] net GSM network
|
||||
* \param[in] subscr Subscriber for which to find ID
|
||||
* \param[in] protocol Protocol for whihc to find ID
|
||||
* \param[in] ti_flag FIXME
|
||||
*/
|
||||
int trans_assign_trans_id(struct gsm_network *net, struct vlr_subscr *vsub,
|
||||
uint8_t protocol, uint8_t ti_flag)
|
||||
{
|
||||
struct gsm_trans *trans;
|
||||
@@ -131,7 +157,7 @@ int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr
|
||||
|
||||
/* generate bitmask of already-used TIDs for this (subscr,proto) */
|
||||
llist_for_each_entry(trans, &net->trans_list, entry) {
|
||||
if (trans->subscr != subscr ||
|
||||
if (trans->vsub != vsub ||
|
||||
trans->protocol != protocol ||
|
||||
trans->transaction_id == 0xff)
|
||||
continue;
|
||||
@@ -151,6 +177,10 @@ int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Check if we have any transaction for given connection
|
||||
* \param[in] conn Connection to check
|
||||
* \returns 1 in case there is a transaction, 0 otherwise
|
||||
*/
|
||||
int trans_has_conn(const struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm_trans *trans;
|
||||
@@ -161,3 +191,13 @@ int trans_has_conn(const struct gsm_subscriber_connection *conn)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void trans_conn_closed(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm_trans *trans, *t2;
|
||||
|
||||
llist_for_each_entry_safe(trans, t2, &conn->network->trans_list, entry) {
|
||||
if (trans->conn == conn)
|
||||
trans_free(trans);
|
||||
}
|
||||
}
|
||||
|
@@ -33,6 +33,7 @@
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/osmo_msc.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
/* Declarations of USSD strings to be recognised */
|
||||
const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
|
||||
@@ -73,6 +74,7 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
msc_subscr_conn_communicating(conn);
|
||||
if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.ussd_text)) {
|
||||
DEBUGP(DMM, "USSD: Own number requested\n");
|
||||
rc = send_own_number(conn, msg, &req);
|
||||
@@ -87,9 +89,12 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
|
||||
/* A network-specific handler function */
|
||||
static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req)
|
||||
{
|
||||
char *own_number = conn->subscr->extension;
|
||||
char *own_number = conn->vsub->msisdn;
|
||||
char response_string[GSM_EXTENSION_LENGTH + 20];
|
||||
|
||||
DEBUGP(DMM, "%s: MSISDN = %s\n", vlr_subscr_name(conn->vsub),
|
||||
own_number);
|
||||
|
||||
/* Need trailing CR as EOT character */
|
||||
snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
|
||||
return gsm0480_send_ussd_response(conn, msg, response_string, req);
|
||||
|
@@ -51,74 +51,78 @@
|
||||
#include <openbsc/sms_queue.h>
|
||||
#include <openbsc/mncc_int.h>
|
||||
#include <openbsc/handover.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
#include <osmocom/vty/logging.h>
|
||||
|
||||
#include <openbsc/osmo_msc.h>
|
||||
|
||||
#include "meas_feed.h"
|
||||
|
||||
extern struct gsm_network *gsmnet_from_vty(struct vty *v);
|
||||
|
||||
static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
|
||||
static void subscr_dump_full_vty(struct vty *vty, struct vlr_subscr *vsub)
|
||||
{
|
||||
int rc;
|
||||
int reqs;
|
||||
struct gsm_auth_info ainfo;
|
||||
struct gsm_auth_tuple atuple;
|
||||
struct llist_head *entry;
|
||||
char expire_time[200];
|
||||
|
||||
vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
|
||||
subscr->authorized, VTY_NEWLINE);
|
||||
if (strlen(subscr->name))
|
||||
vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
|
||||
if (strlen(subscr->extension))
|
||||
vty_out(vty, " Extension: %s%s", subscr->extension,
|
||||
if (strlen(vsub->name))
|
||||
vty_out(vty, " Name: '%s'%s", vsub->name, VTY_NEWLINE);
|
||||
if (strlen(vsub->msisdn))
|
||||
vty_out(vty, " Extension: %s%s", vsub->msisdn,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " LAC: %d/0x%x%s",
|
||||
subscr->lac, subscr->lac, VTY_NEWLINE);
|
||||
vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
|
||||
if (subscr->tmsi != GSM_RESERVED_TMSI)
|
||||
vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
|
||||
vsub->lac, vsub->lac, VTY_NEWLINE);
|
||||
vty_out(vty, " IMSI: %s%s", vsub->imsi, VTY_NEWLINE);
|
||||
if (vsub->tmsi != GSM_RESERVED_TMSI)
|
||||
vty_out(vty, " TMSI: %08X%s", vsub->tmsi,
|
||||
VTY_NEWLINE);
|
||||
if (vsub->tmsi_new != GSM_RESERVED_TMSI)
|
||||
vty_out(vty, " new TMSI: %08X%s", vsub->tmsi_new,
|
||||
VTY_NEWLINE);
|
||||
|
||||
rc = db_get_authinfo_for_subscr(&ainfo, subscr);
|
||||
if (!rc) {
|
||||
#if 0
|
||||
/* TODO: add this to vlr_subscr? */
|
||||
if (vsub->auth_info.auth_algo != AUTH_ALGO_NONE) {
|
||||
struct gsm_auth_info *i = &vsub->auth_info;
|
||||
vty_out(vty, " A3A8 algorithm id: %d%s",
|
||||
ainfo.auth_algo, VTY_NEWLINE);
|
||||
i->auth_algo, VTY_NEWLINE);
|
||||
vty_out(vty, " A3A8 Ki: %s%s",
|
||||
osmo_hexdump(ainfo.a3a8_ki, ainfo.a3a8_ki_len),
|
||||
osmo_hexdump(i->a3a8_ki, i->a3a8_ki_len),
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
#endif
|
||||
|
||||
rc = db_get_lastauthtuple_for_subscr(&atuple, subscr);
|
||||
if (!rc) {
|
||||
if (vsub->last_tuple) {
|
||||
struct gsm_auth_tuple *t = vsub->last_tuple;
|
||||
vty_out(vty, " A3A8 last tuple (used %d times):%s",
|
||||
atuple.use_count, VTY_NEWLINE);
|
||||
t->use_count, VTY_NEWLINE);
|
||||
vty_out(vty, " seq # : %d%s",
|
||||
atuple.key_seq, VTY_NEWLINE);
|
||||
t->key_seq, VTY_NEWLINE);
|
||||
vty_out(vty, " RAND : %s%s",
|
||||
osmo_hexdump(atuple.vec.rand, sizeof(atuple.vec.rand)),
|
||||
osmo_hexdump(t->vec.rand, sizeof(t->vec.rand)),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " SRES : %s%s",
|
||||
osmo_hexdump(atuple.vec.sres, sizeof(atuple.vec.sres)),
|
||||
osmo_hexdump(t->vec.sres, sizeof(t->vec.sres)),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " Kc : %s%s",
|
||||
osmo_hexdump(atuple.vec.kc, sizeof(atuple.vec.kc)),
|
||||
osmo_hexdump(t->vec.kc, sizeof(t->vec.kc)),
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
/* print the expiration time of a subscriber */
|
||||
strftime(expire_time, sizeof(expire_time),
|
||||
"%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
|
||||
"%a, %d %b %Y %T %z", localtime(&vsub->expire_lu));
|
||||
expire_time[sizeof(expire_time) - 1] = '\0';
|
||||
vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
|
||||
|
||||
reqs = 0;
|
||||
llist_for_each(entry, &subscr->requests)
|
||||
llist_for_each(entry, &vsub->cs.requests)
|
||||
reqs += 1;
|
||||
vty_out(vty, " Paging: %s paging Requests: %d%s",
|
||||
subscr->is_paging ? "is" : "not", reqs, VTY_NEWLINE);
|
||||
vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
|
||||
vty_out(vty, " Paging: %s paging for %d requests%s",
|
||||
vsub->cs.is_paging ? "is" : "not", reqs, VTY_NEWLINE);
|
||||
vty_out(vty, " Use count: %u%s", vsub->use_count, VTY_NEWLINE);
|
||||
}
|
||||
|
||||
|
||||
@@ -129,11 +133,18 @@ DEFUN(show_subscr_cache,
|
||||
SHOW_STR "Show information about subscribers\n"
|
||||
"Display contents of subscriber cache\n")
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct vlr_subscr *vsub;
|
||||
int count = 0;
|
||||
|
||||
llist_for_each_entry(subscr, &active_subscribers, entry) {
|
||||
llist_for_each_entry(vsub, &gsmnet->vlr->subscribers, list) {
|
||||
if (++count > 100) {
|
||||
vty_out(vty, "%% More than %d subscribers in cache,"
|
||||
" stopping here.%s", count-1, VTY_NEWLINE);
|
||||
break;
|
||||
}
|
||||
vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
|
||||
subscr_dump_full_vty(vty, subscr);
|
||||
subscr_dump_full_vty(vty, vsub);
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
@@ -162,10 +173,11 @@ DEFUN(sms_send_pend,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int _send_sms_str(struct gsm_subscriber *receiver,
|
||||
struct gsm_subscriber *sender,
|
||||
char *str, uint8_t tp_pid)
|
||||
static int _send_sms_str(struct vlr_subscr *receiver,
|
||||
struct vlr_subscr *sender,
|
||||
char *str, uint8_t tp_pid)
|
||||
{
|
||||
struct gsm_network *net = receiver->vlr->user_ctx;
|
||||
struct gsm_sms *sms;
|
||||
|
||||
sms = sms_from_text(receiver, sender, 0, str);
|
||||
@@ -180,22 +192,20 @@ static int _send_sms_str(struct gsm_subscriber *receiver,
|
||||
LOGP(DLSMS, LOGL_DEBUG, "SMS stored in DB\n");
|
||||
|
||||
sms_free(sms);
|
||||
sms_queue_trigger(receiver->group->net->sms_queue);
|
||||
sms_queue_trigger(net->sms_queue);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static struct gsm_subscriber *get_subscr_by_argv(struct gsm_network *gsmnet,
|
||||
const char *type,
|
||||
const char *id)
|
||||
static struct vlr_subscr *get_vsub_by_argv(struct gsm_network *gsmnet,
|
||||
const char *type,
|
||||
const char *id)
|
||||
{
|
||||
if (!strcmp(type, "extension"))
|
||||
return subscr_get_by_extension(gsmnet->subscr_group, id);
|
||||
else if (!strcmp(type, "imsi"))
|
||||
return subscr_get_by_imsi(gsmnet->subscr_group, id);
|
||||
if (!strcmp(type, "extension") || !strcmp(type, "msisdn"))
|
||||
return vlr_subscr_find_by_msisdn(gsmnet->vlr, id);
|
||||
else if (!strcmp(type, "imsi") || !strcmp(type, "id"))
|
||||
return vlr_subscr_find_by_imsi(gsmnet->vlr, id);
|
||||
else if (!strcmp(type, "tmsi"))
|
||||
return subscr_get_by_tmsi(gsmnet->subscr_group, atoi(id));
|
||||
else if (!strcmp(type, "id"))
|
||||
return subscr_get_by_id(gsmnet->subscr_group, atoi(id));
|
||||
return vlr_subscr_find_by_tmsi(gsmnet->vlr, atoi(id));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -213,18 +223,18 @@ DEFUN(show_subscr,
|
||||
SHOW_STR SUBSCR_HELP)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr =
|
||||
get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0],
|
||||
argv[1]);
|
||||
|
||||
if (!subscr) {
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
subscr_dump_full_vty(vty, subscr);
|
||||
subscr_dump_full_vty(vty, vsub);
|
||||
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -237,28 +247,9 @@ DEFUN(subscriber_create,
|
||||
"Identify the subscriber by his IMSI\n" \
|
||||
"Identifier for the subscriber\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
subscr = subscr_get_by_imsi(gsmnet->subscr_group, argv[0]);
|
||||
if (subscr)
|
||||
db_sync_subscriber(subscr);
|
||||
else {
|
||||
subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0]);
|
||||
|
||||
if (!subscr) {
|
||||
vty_out(vty, "%% No subscriber created for IMSI %s%s",
|
||||
argv[0], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
/* Show info about the created subscriber. */
|
||||
subscr_dump_full_vty(vty, subscr);
|
||||
|
||||
subscr_put(subscr);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber create' now needs to be done at osmo-hlr%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_send_pending_sms,
|
||||
@@ -267,21 +258,21 @@ DEFUN(subscriber_send_pending_sms,
|
||||
SUBSCR_HELP "SMS Operations\n" "Send pending SMS\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr;
|
||||
struct vlr_subscr *vsub;
|
||||
struct gsm_sms *sms;
|
||||
|
||||
subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
if (!subscr) {
|
||||
vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
sms = db_sms_get_unsent_by_subscr(gsmnet, subscr->id, UINT_MAX);
|
||||
sms = db_sms_get_unsent_by_subscr(gsmnet, vsub->id, UINT_MAX);
|
||||
if (sms)
|
||||
gsm411_send_sms_subscr(sms->receiver, sms);
|
||||
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -292,12 +283,12 @@ DEFUN(subscriber_send_sms,
|
||||
SUBSCR_HELP "SMS Operations\n" SUBSCR_HELP "Send SMS\n" "Actual SMS Text\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct gsm_subscriber *sender = get_subscr_by_argv(gsmnet, argv[2], argv[3]);
|
||||
struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct vlr_subscr *sender = get_vsub_by_argv(gsmnet, argv[2], argv[3]);
|
||||
char *str;
|
||||
int rc;
|
||||
|
||||
if (!subscr) {
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
rc = CMD_WARNING;
|
||||
@@ -312,15 +303,15 @@ DEFUN(subscriber_send_sms,
|
||||
}
|
||||
|
||||
str = argv_concat(argv, argc, 4);
|
||||
rc = _send_sms_str(subscr, sender, str, 0);
|
||||
rc = _send_sms_str(vsub, sender, str, 0);
|
||||
talloc_free(str);
|
||||
|
||||
err:
|
||||
if (sender)
|
||||
subscr_put(sender);
|
||||
vlr_subscr_put(sender);
|
||||
|
||||
if (subscr)
|
||||
subscr_put(subscr);
|
||||
if (vsub)
|
||||
vlr_subscr_put(vsub);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -332,12 +323,12 @@ DEFUN(subscriber_silent_sms,
|
||||
SUBSCR_HELP "Silent SMS Operations\n" SUBSCR_HELP "Send SMS\n" "Actual SMS Text\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct gsm_subscriber *sender = get_subscr_by_argv(gsmnet, argv[2], argv[3]);
|
||||
struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct vlr_subscr *sender = get_vsub_by_argv(gsmnet, argv[2], argv[3]);
|
||||
char *str;
|
||||
int rc;
|
||||
|
||||
if (!subscr) {
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
rc = CMD_WARNING;
|
||||
@@ -352,15 +343,15 @@ DEFUN(subscriber_silent_sms,
|
||||
}
|
||||
|
||||
str = argv_concat(argv, argc, 4);
|
||||
rc = _send_sms_str(subscr, sender, str, 64);
|
||||
rc = _send_sms_str(vsub, sender, str, 64);
|
||||
talloc_free(str);
|
||||
|
||||
err:
|
||||
if (sender)
|
||||
subscr_put(sender);
|
||||
vlr_subscr_put(sender);
|
||||
|
||||
if (subscr)
|
||||
subscr_put(subscr);
|
||||
if (vsub)
|
||||
vlr_subscr_put(vsub);
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -379,10 +370,10 @@ DEFUN(subscriber_silent_call_start,
|
||||
CHAN_TYPE_HELP)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
|
||||
int rc, type;
|
||||
|
||||
if (!subscr) {
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -397,15 +388,15 @@ DEFUN(subscriber_silent_call_start,
|
||||
else
|
||||
type = RSL_CHANNEED_ANY; /* Defaults to ANY */
|
||||
|
||||
rc = gsm_silent_call_start(subscr, vty, type);
|
||||
rc = gsm_silent_call_start(vsub, vty, type);
|
||||
if (rc <= 0) {
|
||||
vty_out(vty, "%% Subscriber not attached%s",
|
||||
VTY_NEWLINE);
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -417,22 +408,22 @@ DEFUN(subscriber_silent_call_stop,
|
||||
CHAN_TYPE_HELP)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
|
||||
int rc;
|
||||
|
||||
if (!subscr) {
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
rc = gsm_silent_call_stop(subscr);
|
||||
rc = gsm_silent_call_stop(vsub);
|
||||
if (rc < 0) {
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -449,10 +440,10 @@ DEFUN(subscriber_ussd_notify,
|
||||
char *text;
|
||||
struct gsm_subscriber_connection *conn;
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
|
||||
int level;
|
||||
|
||||
if (!subscr) {
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
@@ -461,15 +452,15 @@ DEFUN(subscriber_ussd_notify,
|
||||
level = atoi(argv[2]);
|
||||
text = argv_concat(argv, argc, 3);
|
||||
if (!text) {
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
conn = connection_for_subscr(subscr);
|
||||
conn = connection_for_subscr(vsub);
|
||||
if (!conn) {
|
||||
vty_out(vty, "%% An active connection is required for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
talloc_free(text);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
@@ -477,7 +468,7 @@ DEFUN(subscriber_ussd_notify,
|
||||
msc_send_ussd_notify(conn, level, text);
|
||||
msc_send_ussd_release_complete(conn);
|
||||
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
talloc_free(text);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
@@ -485,32 +476,12 @@ DEFUN(subscriber_ussd_notify,
|
||||
DEFUN(ena_subscr_delete,
|
||||
ena_subscr_delete_cmd,
|
||||
"subscriber " SUBSCR_TYPES " ID delete",
|
||||
SUBSCR_HELP "Delete subscriber in HLR\n")
|
||||
SUBSCR_HELP "Delete subscriber in VLR\n")
|
||||
{
|
||||
int rc;
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr =
|
||||
get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
|
||||
if (!subscr) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (subscr->use_count != 1) {
|
||||
vty_out(vty, "Removing active subscriber%s", VTY_NEWLINE);
|
||||
}
|
||||
|
||||
rc = db_subscriber_delete(subscr);
|
||||
subscr_put(subscr);
|
||||
|
||||
if (rc != 0) {
|
||||
vty_out(vty, "Failed to remove subscriber%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber delete' is no longer supported.%s"
|
||||
"%% This is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(ena_subscr_expire,
|
||||
@@ -519,19 +490,28 @@ DEFUN(ena_subscr_expire,
|
||||
SUBSCR_HELP "Expire the subscriber Now\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr =
|
||||
get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0],
|
||||
argv[1]);
|
||||
|
||||
if (!subscr) {
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
subscr->expire_lu = time(0);
|
||||
db_sync_subscriber(subscr);
|
||||
subscr_put(subscr);
|
||||
if (vsub->lu_complete) {
|
||||
vsub->lu_complete = false;
|
||||
vlr_subscr_put(vsub);
|
||||
vty_out(vty, "%% VLR released subscriber %s%s",
|
||||
vlr_subscr_name(vsub), VTY_NEWLINE);
|
||||
}
|
||||
|
||||
if (vsub->use_count > 1)
|
||||
vty_out(vty, "%% Subscriber %s is still in use,"
|
||||
" should be released soon%s",
|
||||
vlr_subscr_name(vsub), VTY_NEWLINE);
|
||||
|
||||
vlr_subscr_put(vsub);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -542,22 +522,10 @@ DEFUN(ena_subscr_authorized,
|
||||
"Subscriber should NOT be authorized\n"
|
||||
"Subscriber should be authorized\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr =
|
||||
get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
|
||||
if (!subscr) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
subscr->authorized = atoi(argv[2]);
|
||||
db_sync_subscriber(subscr);
|
||||
|
||||
subscr_put(subscr);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber authorized' is no longer supported.%s"
|
||||
"%% Authorization is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(ena_subscr_name,
|
||||
@@ -566,38 +534,10 @@ DEFUN(ena_subscr_name,
|
||||
SUBSCR_HELP "Set the name of the subscriber\n"
|
||||
"Name of the Subscriber\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr =
|
||||
get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
char *name;
|
||||
|
||||
if (!subscr) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
name = argv_concat(argv, argc, 2);
|
||||
if (!name) {
|
||||
subscr_put(subscr);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (strlen(name) > sizeof(subscr->name)-1) {
|
||||
vty_out(vty,
|
||||
"%% NAME is too long, max. %zu characters are allowed%s",
|
||||
sizeof(subscr->name)-1, VTY_NEWLINE);
|
||||
subscr_put(subscr);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
osmo_strlcpy(subscr->name, name, sizeof(subscr->name));
|
||||
talloc_free(name);
|
||||
db_sync_subscriber(subscr);
|
||||
|
||||
subscr_put(subscr);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber name' is no longer supported.%s"
|
||||
"%% This is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(ena_subscr_extension,
|
||||
@@ -606,30 +546,10 @@ DEFUN(ena_subscr_extension,
|
||||
SUBSCR_HELP "Set the extension (phone number) of the subscriber\n"
|
||||
"Extension (phone number)\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr =
|
||||
get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
const char *ext = argv[2];
|
||||
|
||||
if (!subscr) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (strlen(ext) > sizeof(subscr->extension)-1) {
|
||||
vty_out(vty,
|
||||
"%% EXTENSION is too long, max. %zu characters are allowed%s",
|
||||
sizeof(subscr->extension)-1, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
osmo_strlcpy(subscr->extension, ext, sizeof(subscr->extension));
|
||||
db_sync_subscriber(subscr);
|
||||
|
||||
subscr_put(subscr);
|
||||
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber extension' is no longer supported.%s"
|
||||
"%% This is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(ena_subscr_handover,
|
||||
@@ -642,20 +562,20 @@ DEFUN(ena_subscr_handover,
|
||||
struct gsm_subscriber_connection *conn;
|
||||
struct gsm_bts *bts;
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr =
|
||||
get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
struct vlr_subscr *vsub =
|
||||
get_vsub_by_argv(gsmnet, argv[0], argv[1]);
|
||||
|
||||
if (!subscr) {
|
||||
if (!vsub) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s.%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
conn = connection_for_subscr(subscr);
|
||||
conn = connection_for_subscr(vsub);
|
||||
if (!conn) {
|
||||
vty_out(vty, "%% No active connection for subscriber %s %s.%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
@@ -663,7 +583,7 @@ DEFUN(ena_subscr_handover,
|
||||
if (!bts) {
|
||||
vty_out(vty, "%% BTS with number(%d) could not be found.%s",
|
||||
atoi(argv[2]), VTY_NEWLINE);
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
@@ -679,7 +599,7 @@ DEFUN(ena_subscr_handover,
|
||||
VTY_NEWLINE);
|
||||
}
|
||||
|
||||
subscr_put(subscr);
|
||||
vlr_subscr_put(vsub);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -695,69 +615,10 @@ DEFUN(ena_subscr_a3a8,
|
||||
SUBSCR_HELP "Set a3a8 parameters for the subscriber\n"
|
||||
A3A8_ALG_HELP "Encryption Key Ki\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr =
|
||||
get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
const char *alg_str = argv[2];
|
||||
const char *ki_str = argc == 4 ? argv[3] : NULL;
|
||||
struct gsm_auth_info ainfo;
|
||||
int rc, minlen, maxlen;
|
||||
|
||||
if (!subscr) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (!strcasecmp(alg_str, "none")) {
|
||||
ainfo.auth_algo = AUTH_ALGO_NONE;
|
||||
minlen = maxlen = 0;
|
||||
} else if (!strcasecmp(alg_str, "xor")) {
|
||||
ainfo.auth_algo = AUTH_ALGO_XOR;
|
||||
minlen = A38_XOR_MIN_KEY_LEN;
|
||||
maxlen = A38_XOR_MAX_KEY_LEN;
|
||||
} else if (!strcasecmp(alg_str, "comp128v1")) {
|
||||
ainfo.auth_algo = AUTH_ALGO_COMP128v1;
|
||||
minlen = maxlen = A38_COMP128_KEY_LEN;
|
||||
} else {
|
||||
/* Unknown method */
|
||||
subscr_put(subscr);
|
||||
vty_out(vty, "%% Unknown auth method %s%s",
|
||||
alg_str, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (ki_str) {
|
||||
rc = osmo_hexparse(ki_str, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
|
||||
if ((rc > maxlen) || (rc < minlen)) {
|
||||
subscr_put(subscr);
|
||||
vty_out(vty, "%% Wrong Ki `%s'%s",
|
||||
ki_str, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
ainfo.a3a8_ki_len = rc;
|
||||
} else {
|
||||
ainfo.a3a8_ki_len = 0;
|
||||
if (minlen) {
|
||||
subscr_put(subscr);
|
||||
vty_out(vty, "%% Missing Ki argument%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
}
|
||||
|
||||
rc = db_sync_authinfo_for_subscr(
|
||||
ainfo.auth_algo == AUTH_ALGO_NONE ? NULL : &ainfo,
|
||||
subscr);
|
||||
|
||||
/* the last tuple probably invalid with the new auth settings */
|
||||
db_sync_lastauthtuple_for_subscr(NULL, subscr);
|
||||
subscr_put(subscr);
|
||||
|
||||
if (rc) {
|
||||
vty_out(vty, "%% Operation has failed%s", VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber a3a8' is no longer supported.%s"
|
||||
"%% This is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_purge,
|
||||
@@ -765,12 +626,11 @@ DEFUN(subscriber_purge,
|
||||
"subscriber purge-inactive",
|
||||
"Operations on a Subscriber\n" "Purge subscribers with a zero use count.\n")
|
||||
{
|
||||
struct gsm_network *net = gsmnet_from_vty(vty);
|
||||
int purged;
|
||||
|
||||
purged = subscr_purge_inactive(net->subscr_group);
|
||||
vty_out(vty, "%d subscriber(s) were purged.%s", purged, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
/* TODO: does this still have a use with the VLR? */
|
||||
vty_out(vty, "%% 'subscriber purge-inactive' is no longer supported.%s"
|
||||
"%% This is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(subscriber_update,
|
||||
@@ -778,18 +638,9 @@ DEFUN(subscriber_update,
|
||||
"subscriber " SUBSCR_TYPES " ID update",
|
||||
SUBSCR_HELP "Update the subscriber data from the dabase.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
|
||||
|
||||
if (!subscr) {
|
||||
vty_out(vty, "%% No subscriber found for %s %s%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
subscr_update_from_db(subscr);
|
||||
subscr_put(subscr);
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber update' is no longer supported.%s",
|
||||
VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
static int scall_cbfn(unsigned int subsys, unsigned int signal,
|
||||
@@ -1035,7 +886,7 @@ DEFUN(logging_fltr_imsi,
|
||||
LOGGING_STR FILTER_STR
|
||||
"Filter log messages by IMSI\n" "IMSI to be used as filter\n")
|
||||
{
|
||||
struct gsm_subscriber *vlr_subscr;
|
||||
struct vlr_subscr *vlr_subscr;
|
||||
struct bsc_subscr *bsc_subscr;
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
struct log_target *tgt = osmo_log_vty2tgt(vty);
|
||||
@@ -1044,7 +895,7 @@ DEFUN(logging_fltr_imsi,
|
||||
if (!tgt)
|
||||
return CMD_WARNING;
|
||||
|
||||
vlr_subscr = subscr_get_by_imsi(gsmnet->subscr_group, imsi);
|
||||
vlr_subscr = vlr_subscr_find_by_imsi(gsmnet->vlr, imsi);
|
||||
bsc_subscr = bsc_subscr_find_by_imsi(gsmnet->bsc_subscribers, imsi);
|
||||
|
||||
if (!vlr_subscr && !bsc_subscr) {
|
||||
@@ -1058,6 +909,50 @@ DEFUN(logging_fltr_imsi,
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static struct cmd_node hlr_node = {
|
||||
HLR_NODE,
|
||||
"%s(config-hlr)# ",
|
||||
1,
|
||||
};
|
||||
|
||||
DEFUN(cfg_hlr, cfg_hlr_cmd,
|
||||
"hlr", "Configure connection to the HLR")
|
||||
{
|
||||
vty->node = HLR_NODE;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_hlr_remote_ip, cfg_hlr_remote_ip_cmd, "remote-ip A.B.C.D",
|
||||
"Remote GSUP address of the HLR\n"
|
||||
"Remote GSUP address (default: " MSC_HLR_REMOTE_IP_DEFAULT ")")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
talloc_free((void*)gsmnet->gsup_server_addr_str);
|
||||
gsmnet->gsup_server_addr_str = talloc_strdup(gsmnet, argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
DEFUN(cfg_hlr_remote_port, cfg_hlr_remote_port_cmd, "remote-port <1-65535>",
|
||||
"Remote GSUP port of the HLR\n"
|
||||
"Remote GSUP port (default: " OSMO_STRINGIFY(MSC_HLR_REMOTE_PORT_DEFAULT) ")")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->gsup_server_port = atoi(argv[0]);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static int config_write_hlr(struct vty *vty)
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
|
||||
vty_out(vty, "hlr%s", VTY_NEWLINE);
|
||||
vty_out(vty, " remote-ip %s%s",
|
||||
gsmnet->gsup_server_addr_str, VTY_NEWLINE);
|
||||
vty_out(vty, " remote-port %u%s",
|
||||
gsmnet->gsup_server_port, VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
static struct cmd_node nitb_node = {
|
||||
NITB_NODE,
|
||||
"%s(config-nitb)# ",
|
||||
@@ -1078,18 +973,10 @@ DEFUN(cfg_nitb_subscr_random, cfg_nitb_subscr_random_cmd,
|
||||
"Set random parameters for a new record when a subscriber is first seen.\n"
|
||||
"Minimum for subscriber extension\n""Maximum for subscriber extension\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
uint64_t mi = atoi(argv[0]), ma = atoi(argv[1]);
|
||||
gsmnet->auto_create_subscr = true;
|
||||
gsmnet->auto_assign_exten = true;
|
||||
if (mi >= ma) {
|
||||
vty_out(vty, "Incorrect range: %s >= %s, expected MIN < MAX%s",
|
||||
argv[0], argv[1], VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
gsmnet->ext_min = mi;
|
||||
gsmnet->ext_max = ma;
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s"
|
||||
"%% This is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
|
||||
@@ -1097,19 +984,20 @@ DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
|
||||
"Make a new record when a subscriber is first seen.\n"
|
||||
"Do not automatically assign extension to created subscribers\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->auto_create_subscr = true;
|
||||
gsmnet->auto_assign_exten = argc ? false : true;
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s"
|
||||
"%% This is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nitb_no_subscr_create, cfg_nitb_no_subscr_create_cmd,
|
||||
"no subscriber-create-on-demand",
|
||||
NO_STR "Make a new record when a subscriber is first seen.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->auto_create_subscr = false;
|
||||
return CMD_SUCCESS;
|
||||
vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s"
|
||||
"%% This is now up to osmo-hlr.%s",
|
||||
VTY_NEWLINE, VTY_NEWLINE);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
DEFUN(cfg_nitb_assign_tmsi, cfg_nitb_assign_tmsi_cmd,
|
||||
@@ -1117,7 +1005,7 @@ DEFUN(cfg_nitb_assign_tmsi, cfg_nitb_assign_tmsi_cmd,
|
||||
"Assign TMSI during Location Updating.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->avoid_tmsi = 0;
|
||||
gsmnet->vlr->cfg.assign_tmsi = true;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1126,7 +1014,7 @@ DEFUN(cfg_nitb_no_assign_tmsi, cfg_nitb_no_assign_tmsi_cmd,
|
||||
NO_STR "Assign TMSI during Location Updating.\n")
|
||||
{
|
||||
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
|
||||
gsmnet->avoid_tmsi = 1;
|
||||
gsmnet->vlr->cfg.assign_tmsi = false;
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1147,7 +1035,7 @@ static int config_write_nitb(struct vty *vty)
|
||||
PRIu64"%s", gsmnet->ext_min, gsmnet->ext_max,
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " %sassign-tmsi%s",
|
||||
gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
|
||||
gsmnet->vlr->cfg.assign_tmsi? "" : "no ", VTY_NEWLINE);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -1197,6 +1085,10 @@ int bsc_vty_init_extra(void)
|
||||
install_element(CFG_LOG_NODE, &log_level_sms_cmd);
|
||||
install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_hlr_cmd);
|
||||
install_node(&hlr_node, config_write_hlr);
|
||||
install_element(HLR_NODE, &cfg_hlr_remote_ip_cmd);
|
||||
install_element(HLR_NODE, &cfg_hlr_remote_port_cmd);
|
||||
|
||||
install_element(CONFIG_NODE, &cfg_nitb_cmd);
|
||||
install_node(&nitb_node, config_write_nitb);
|
||||
|
@@ -340,6 +340,7 @@ static void proc_arq_vlr_fn_init(struct osmo_fsm_inst *fi,
|
||||
vsub = vlr_subscr_find_by_tmsi(par->vlr, par->tmsi);
|
||||
}
|
||||
if (vsub) {
|
||||
log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
|
||||
if (vsub->proc_arq_fsm && fi != vsub->proc_arq_fsm) {
|
||||
LOGPFSML(fi, LOGL_ERROR,
|
||||
"Another proc_arq_fsm is already"
|
||||
|
@@ -240,7 +240,7 @@ static void db_sync_timer_cb(void *data)
|
||||
|
||||
static void subscr_expire_cb(void *data)
|
||||
{
|
||||
subscr_expire(bsc_gsmnet->subscr_group);
|
||||
/* TODO expire vlr_subscrs? */
|
||||
osmo_timer_schedule(&bsc_gsmnet->subscr_expire_timer, EXPIRE_INTERVAL);
|
||||
}
|
||||
|
||||
@@ -261,7 +261,9 @@ int main(int argc, char **argv)
|
||||
|
||||
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
|
||||
talloc_ctx_init(tall_bsc_ctx);
|
||||
#if 0
|
||||
on_dso_load_token();
|
||||
#endif
|
||||
on_dso_load_rrlp();
|
||||
on_dso_load_ho_dec();
|
||||
|
||||
@@ -285,6 +287,10 @@ int main(int argc, char **argv)
|
||||
/* Initialize VTY */
|
||||
bsc_vty_init(bsc_gsmnet);
|
||||
ctrl_vty_init(tall_bsc_ctx);
|
||||
if (msc_vlr_alloc(bsc_gsmnet)) {
|
||||
fprintf(stderr, "Failed to allocate VLR\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef BUILD_SMPP
|
||||
if (smpp_openbsc_alloc_init(tall_bsc_ctx) < 0)
|
||||
@@ -341,7 +347,7 @@ int main(int argc, char **argv)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msc_ctrl_cmds_install() != 0) {
|
||||
if (msc_ctrl_cmds_install(bsc_gsmnet) != 0) {
|
||||
printf("Failed to initialize the MSC control commands.\n");
|
||||
return -1;
|
||||
}
|
||||
@@ -355,6 +361,14 @@ int main(int argc, char **argv)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
osmo_fsm_log_addr(true);
|
||||
if (msc_vlr_start(bsc_gsmnet)) {
|
||||
fprintf(stderr, "Failed to start VLR\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
msc_subscr_conn_init();
|
||||
|
||||
if (db_init(database_name)) {
|
||||
printf("DB: Failed to init database. Please check the option settings.\n");
|
||||
return -1;
|
||||
|
@@ -1,6 +1,5 @@
|
||||
SUBDIRS = \
|
||||
gsm0408 \
|
||||
db \
|
||||
channel \
|
||||
mgcp \
|
||||
gprs \
|
||||
@@ -10,6 +9,8 @@ SUBDIRS = \
|
||||
subscr \
|
||||
mm_auth \
|
||||
nanobts_omlattr \
|
||||
vlr \
|
||||
subscr_conn \
|
||||
$(NULL)
|
||||
|
||||
if BUILD_NAT
|
||||
|
@@ -26,6 +26,7 @@ channel_test_SOURCES = \
|
||||
channel_test_LDADD = \
|
||||
$(top_builddir)/src/libmsc/libmsc.a \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libvlr/libvlr.a \
|
||||
$(top_builddir)/src/libcommon-cs/libcommon-cs.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
|
@@ -29,6 +29,7 @@
|
||||
#include <openbsc/abis_rsl.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/vlr.h>
|
||||
|
||||
static int s_end = 0;
|
||||
static struct gsm_subscriber_connection s_conn;
|
||||
@@ -70,23 +71,25 @@ void test_request_chan(void)
|
||||
network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
|
||||
if (!network)
|
||||
exit(1);
|
||||
network->vlr = talloc_zero(network, struct vlr_instance);
|
||||
network->vlr->user_ctx = network;
|
||||
INIT_LLIST_HEAD(&network->vlr->subscribers);
|
||||
INIT_LLIST_HEAD(&network->vlr->operations);
|
||||
|
||||
bts = gsm_bts_alloc(network);
|
||||
bts->location_area_code = 23;
|
||||
s_conn.network = network;
|
||||
|
||||
/* Create a dummy subscriber */
|
||||
struct gsm_subscriber *subscr = subscr_alloc();
|
||||
subscr->lac = 23;
|
||||
subscr->group = network->subscr_group;
|
||||
|
||||
OSMO_ASSERT(subscr->group);
|
||||
OSMO_ASSERT(subscr->group->net == network);
|
||||
struct vlr_subscr *vsub = vlr_subscr_alloc(network->vlr);
|
||||
vsub->lac = 23;
|
||||
|
||||
/* Ask for a channel... */
|
||||
struct subscr_request *sr;
|
||||
sr = subscr_request_channel(subscr, RSL_CHANNEED_TCH_F, subscr_cb, (void*)0x2342L);
|
||||
sr = subscr_request_channel(vsub, RSL_CHANNEED_TCH_F, subscr_cb, (void*)0x2342L);
|
||||
OSMO_ASSERT(sr);
|
||||
OSMO_ASSERT(s_cbfn);
|
||||
s_conn.network = network;
|
||||
s_cbfn(101, 200, (void*)0x1323L, &s_conn, s_data);
|
||||
|
||||
OSMO_ASSERT(s_end);
|
||||
@@ -140,5 +143,13 @@ void gsm48_secure_channel() {}
|
||||
void paging_request_stop() {}
|
||||
void vty_out() {}
|
||||
|
||||
struct tlv_definition nm_att_tlvdef;
|
||||
void ipa_client_conn_clear_queue() {}
|
||||
void ipa_client_conn_close() {}
|
||||
void ipa_client_conn_create() {}
|
||||
void ipa_client_conn_destroy() {}
|
||||
void ipa_client_conn_open() {}
|
||||
void ipa_client_conn_send() {}
|
||||
void ipa_msg_push_header() {}
|
||||
void ipaccess_bts_handle_ccm() {}
|
||||
|
||||
struct tlv_definition nm_att_tlvdef;
|
||||
|
@@ -254,3 +254,10 @@ int main()
|
||||
|
||||
/* stubs */
|
||||
void vty_out() {}
|
||||
void vlr_subscr_disconnected() {}
|
||||
void vlr_subscr_rx_tmsi_reall_compl() {}
|
||||
void vlr_subscr_rx_id_resp() {}
|
||||
void vlr_subscr_rx_auth_resp() {}
|
||||
void vlr_loc_update() {}
|
||||
void vlr_proc_acc_req() {}
|
||||
void vlr_init() {}
|
||||
|
@@ -10,6 +10,7 @@
|
||||
|
||||
#define min(A,B) ((A)>(B)? (B) : (A))
|
||||
|
||||
#if 0
|
||||
static char *auth_tuple_str(struct gsm_auth_tuple *atuple)
|
||||
{
|
||||
static char buf[256];
|
||||
@@ -60,10 +61,7 @@ static bool auth_tuple_is(struct gsm_auth_tuple *atuple,
|
||||
}
|
||||
return same;
|
||||
}
|
||||
|
||||
/* override, requires '-Wl,--wrap=db_get_authinfo_for_subscr' */
|
||||
int __real_db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
|
||||
struct gsm_subscriber *subscr);
|
||||
#endif
|
||||
|
||||
int test_get_authinfo_rc = 0;
|
||||
struct gsm_auth_info test_auth_info = {0};
|
||||
@@ -73,268 +71,14 @@ struct gsm_auth_info default_auth_info = {
|
||||
.a3a8_ki = { 0 }
|
||||
};
|
||||
|
||||
int __wrap_db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo,
|
||||
struct gsm_subscriber *subscr)
|
||||
{
|
||||
*ainfo = test_auth_info;
|
||||
printf("wrapped: db_get_authinfo_for_subscr(): rc = %d\n", test_get_authinfo_rc);
|
||||
return test_get_authinfo_rc;
|
||||
}
|
||||
|
||||
/* override, requires '-Wl,--wrap=db_get_lastauthtuple_for_subscr' */
|
||||
int __real_db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr);
|
||||
|
||||
int test_get_lastauthtuple_rc = 0;
|
||||
struct gsm_auth_tuple test_last_auth_tuple = { 0 };
|
||||
struct gsm_auth_tuple default_auth_tuple = { 0 };
|
||||
|
||||
int __wrap_db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr)
|
||||
{
|
||||
*atuple = test_last_auth_tuple;
|
||||
printf("wrapped: db_get_lastauthtuple_for_subscr(): rc = %d\n", test_get_lastauthtuple_rc);
|
||||
return test_get_lastauthtuple_rc;
|
||||
}
|
||||
|
||||
/* override, requires '-Wl,--wrap=db_sync_lastauthtuple_for_subscr' */
|
||||
int __real_db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr);
|
||||
int test_sync_lastauthtuple_rc = 0;
|
||||
int __wrap_db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr)
|
||||
{
|
||||
test_last_auth_tuple = *atuple;
|
||||
printf("wrapped: db_sync_lastauthtuple_for_subscr(): rc = %d\n", test_sync_lastauthtuple_rc);
|
||||
return test_sync_lastauthtuple_rc;
|
||||
}
|
||||
|
||||
int auth_get_tuple_for_subscr_verbose(struct gsm_auth_tuple *atuple,
|
||||
struct gsm_subscriber *subscr,
|
||||
int key_seq)
|
||||
{
|
||||
int auth_action;
|
||||
auth_action = auth_get_tuple_for_subscr(atuple, subscr, key_seq);
|
||||
printf("auth_get_tuple_for_subscr(key_seq=%d) --> auth_action == %s\n",
|
||||
key_seq, auth_action_str(auth_action));
|
||||
return auth_action;
|
||||
}
|
||||
|
||||
/* override libssl RAND_bytes() to get testable crypto results */
|
||||
int RAND_bytes(uint8_t *rand, int len)
|
||||
{
|
||||
memset(rand, 23, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void test_error()
|
||||
{
|
||||
int auth_action;
|
||||
|
||||
struct gsm_auth_tuple atuple = {0};
|
||||
struct gsm_subscriber subscr = {0};
|
||||
int key_seq = 0;
|
||||
|
||||
printf("\n* test_error()\n");
|
||||
|
||||
/* any error (except -ENOENT) */
|
||||
test_get_authinfo_rc = -EIO;
|
||||
auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
|
||||
key_seq);
|
||||
OSMO_ASSERT(auth_action == AUTH_ERROR);
|
||||
}
|
||||
|
||||
static void test_auth_not_avail()
|
||||
{
|
||||
int auth_action;
|
||||
|
||||
struct gsm_auth_tuple atuple = {0};
|
||||
struct gsm_subscriber subscr = {0};
|
||||
int key_seq = 0;
|
||||
|
||||
printf("\n* test_auth_not_avail()\n");
|
||||
|
||||
/* no entry */
|
||||
test_get_authinfo_rc = -ENOENT;
|
||||
auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
|
||||
key_seq);
|
||||
OSMO_ASSERT(auth_action == AUTH_NOT_AVAIL);
|
||||
}
|
||||
|
||||
static void test_auth_then_ciph1()
|
||||
{
|
||||
int auth_action;
|
||||
|
||||
struct gsm_auth_tuple atuple = {0};
|
||||
struct gsm_subscriber subscr = {0};
|
||||
int key_seq;
|
||||
|
||||
printf("\n* test_auth_then_ciph1()\n");
|
||||
|
||||
/* Ki entry, but no auth tuple negotiated yet */
|
||||
test_auth_info = default_auth_info;
|
||||
test_last_auth_tuple = default_auth_tuple;
|
||||
test_get_authinfo_rc = 0;
|
||||
test_get_lastauthtuple_rc = -ENOENT;
|
||||
key_seq = 0;
|
||||
auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
|
||||
key_seq);
|
||||
OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
|
||||
OSMO_ASSERT(auth_tuple_is(&atuple,
|
||||
"gsm_auth_tuple {\n"
|
||||
" .use_count = 1\n"
|
||||
" .key_seq = 0\n"
|
||||
" .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
|
||||
" .sres = a1 ab c6 90 \n"
|
||||
" .kc = 0f 27 ed f3 ac 97 ac 00 \n"
|
||||
"}\n"
|
||||
));
|
||||
|
||||
/* With a different last saved key_seq stored in the out-arg of
|
||||
* db_get_lastauthtuple_for_subscr() by coincidence, expect absolutely
|
||||
* the same as above. */
|
||||
test_auth_info = default_auth_info;
|
||||
test_last_auth_tuple = default_auth_tuple;
|
||||
test_last_auth_tuple.key_seq = 3;
|
||||
test_get_authinfo_rc = 0;
|
||||
test_get_lastauthtuple_rc = -ENOENT;
|
||||
key_seq = 0;
|
||||
auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
|
||||
key_seq);
|
||||
OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
|
||||
OSMO_ASSERT(auth_tuple_is(&atuple,
|
||||
"gsm_auth_tuple {\n"
|
||||
" .use_count = 1\n"
|
||||
" .key_seq = 0\n"
|
||||
" .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
|
||||
" .sres = a1 ab c6 90 \n"
|
||||
" .kc = 0f 27 ed f3 ac 97 ac 00 \n"
|
||||
"}\n"
|
||||
));
|
||||
}
|
||||
|
||||
static void test_auth_then_ciph2()
|
||||
{
|
||||
int auth_action;
|
||||
|
||||
struct gsm_auth_tuple atuple = {0};
|
||||
struct gsm_subscriber subscr = {0};
|
||||
int key_seq;
|
||||
|
||||
printf("\n* test_auth_then_ciph2()\n");
|
||||
|
||||
/* Ki entry, auth tuple negotiated, but invalid incoming key_seq */
|
||||
test_auth_info = default_auth_info;
|
||||
test_last_auth_tuple = default_auth_tuple;
|
||||
test_last_auth_tuple.key_seq = 2;
|
||||
test_get_authinfo_rc = 0;
|
||||
test_get_lastauthtuple_rc = 0;
|
||||
key_seq = GSM_KEY_SEQ_INVAL;
|
||||
auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
|
||||
key_seq);
|
||||
OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
|
||||
OSMO_ASSERT(auth_tuple_is(&atuple,
|
||||
"gsm_auth_tuple {\n"
|
||||
" .use_count = 1\n"
|
||||
" .key_seq = 3\n"
|
||||
" .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
|
||||
" .sres = a1 ab c6 90 \n"
|
||||
" .kc = 0f 27 ed f3 ac 97 ac 00 \n"
|
||||
"}\n"
|
||||
));
|
||||
|
||||
/* Change the last saved key_seq, expect last_auth_tuple.key_seq + 1 */
|
||||
test_auth_info = default_auth_info;
|
||||
test_last_auth_tuple = default_auth_tuple;
|
||||
test_last_auth_tuple.key_seq = 3;
|
||||
test_get_authinfo_rc = 0;
|
||||
test_get_lastauthtuple_rc = 0;
|
||||
key_seq = GSM_KEY_SEQ_INVAL;
|
||||
auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
|
||||
key_seq);
|
||||
OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
|
||||
OSMO_ASSERT(auth_tuple_is(&atuple,
|
||||
"gsm_auth_tuple {\n"
|
||||
" .use_count = 1\n"
|
||||
" .key_seq = 4\n"
|
||||
" .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
|
||||
" .sres = a1 ab c6 90 \n"
|
||||
" .kc = 0f 27 ed f3 ac 97 ac 00 \n"
|
||||
"}\n"
|
||||
));
|
||||
}
|
||||
|
||||
static void test_auth_reuse()
|
||||
{
|
||||
int auth_action;
|
||||
struct gsm_auth_tuple atuple = {0};
|
||||
struct gsm_subscriber subscr = {0};
|
||||
int key_seq;
|
||||
|
||||
printf("\n* test_auth_reuse()\n");
|
||||
|
||||
/* Ki entry, auth tuple negotiated, valid+matching incoming key_seq */
|
||||
test_auth_info = default_auth_info;
|
||||
test_last_auth_tuple = default_auth_tuple;
|
||||
test_last_auth_tuple.key_seq = key_seq = 3;
|
||||
test_last_auth_tuple.use_count = 1;
|
||||
test_get_authinfo_rc = 0;
|
||||
test_get_lastauthtuple_rc = 0;
|
||||
auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
|
||||
key_seq);
|
||||
OSMO_ASSERT(auth_action == AUTH_DO_CIPH);
|
||||
OSMO_ASSERT(auth_tuple_is(&atuple,
|
||||
"gsm_auth_tuple {\n"
|
||||
" .use_count = 2\n"
|
||||
" .key_seq = 3\n"
|
||||
" .rand = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \n"
|
||||
" .sres = 00 00 00 00 \n"
|
||||
" .kc = 00 00 00 00 00 00 00 00 \n"
|
||||
"}\n"
|
||||
));
|
||||
}
|
||||
|
||||
static void test_auth_reuse_key_seq_mismatch()
|
||||
{
|
||||
int auth_action;
|
||||
struct gsm_auth_tuple atuple = {0};
|
||||
struct gsm_subscriber subscr = {0};
|
||||
int key_seq;
|
||||
|
||||
printf("\n* test_auth_reuse_key_seq_mismatch()\n");
|
||||
|
||||
/* Ki entry, auth tuple negotiated, valid+matching incoming key_seq */
|
||||
test_auth_info = default_auth_info;
|
||||
test_last_auth_tuple = default_auth_tuple;
|
||||
test_last_auth_tuple.key_seq = 3;
|
||||
key_seq = 4;
|
||||
test_last_auth_tuple.use_count = 1;
|
||||
test_get_authinfo_rc = 0;
|
||||
test_get_lastauthtuple_rc = 0;
|
||||
auth_action = auth_get_tuple_for_subscr_verbose(&atuple, &subscr,
|
||||
key_seq);
|
||||
OSMO_ASSERT(auth_action == AUTH_DO_AUTH_THEN_CIPH);
|
||||
OSMO_ASSERT(auth_tuple_is(&atuple,
|
||||
"gsm_auth_tuple {\n"
|
||||
" .use_count = 1\n"
|
||||
" .key_seq = 4\n"
|
||||
" .rand = 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 17 \n"
|
||||
" .sres = a1 ab c6 90 \n"
|
||||
" .kc = 0f 27 ed f3 ac 97 ac 00 \n"
|
||||
"}\n"
|
||||
));
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
osmo_init_logging(&log_info);
|
||||
log_set_log_level(osmo_stderr_target, LOGL_INFO);
|
||||
|
||||
test_error();
|
||||
test_auth_not_avail();
|
||||
test_auth_then_ciph1();
|
||||
test_auth_then_ciph2();
|
||||
test_auth_reuse();
|
||||
test_auth_reuse_key_seq_mismatch();
|
||||
printf("Nothing being tested!\n");
|
||||
|
||||
/* TODO auth_get_tuple_for_subscr() no longer exists ... test auth somehow?? */
|
||||
return 0;
|
||||
}
|
||||
|
@@ -1,40 +1 @@
|
||||
|
||||
* test_error()
|
||||
wrapped: db_get_authinfo_for_subscr(): rc = -5
|
||||
auth_get_tuple_for_subscr(key_seq=0) --> auth_action == AUTH_ERROR
|
||||
|
||||
* test_auth_not_avail()
|
||||
wrapped: db_get_authinfo_for_subscr(): rc = -2
|
||||
auth_get_tuple_for_subscr(key_seq=0) --> auth_action == AUTH_NOT_AVAIL
|
||||
|
||||
* test_auth_then_ciph1()
|
||||
wrapped: db_get_authinfo_for_subscr(): rc = 0
|
||||
wrapped: db_get_lastauthtuple_for_subscr(): rc = -2
|
||||
wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0
|
||||
auth_get_tuple_for_subscr(key_seq=0) --> auth_action == AUTH_DO_AUTH_THEN_CIPH
|
||||
wrapped: db_get_authinfo_for_subscr(): rc = 0
|
||||
wrapped: db_get_lastauthtuple_for_subscr(): rc = -2
|
||||
wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0
|
||||
auth_get_tuple_for_subscr(key_seq=0) --> auth_action == AUTH_DO_AUTH_THEN_CIPH
|
||||
|
||||
* test_auth_then_ciph2()
|
||||
wrapped: db_get_authinfo_for_subscr(): rc = 0
|
||||
wrapped: db_get_lastauthtuple_for_subscr(): rc = 0
|
||||
wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0
|
||||
auth_get_tuple_for_subscr(key_seq=7) --> auth_action == AUTH_DO_AUTH_THEN_CIPH
|
||||
wrapped: db_get_authinfo_for_subscr(): rc = 0
|
||||
wrapped: db_get_lastauthtuple_for_subscr(): rc = 0
|
||||
wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0
|
||||
auth_get_tuple_for_subscr(key_seq=7) --> auth_action == AUTH_DO_AUTH_THEN_CIPH
|
||||
|
||||
* test_auth_reuse()
|
||||
wrapped: db_get_authinfo_for_subscr(): rc = 0
|
||||
wrapped: db_get_lastauthtuple_for_subscr(): rc = 0
|
||||
wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0
|
||||
auth_get_tuple_for_subscr(key_seq=3) --> auth_action == AUTH_DO_CIPH
|
||||
|
||||
* test_auth_reuse_key_seq_mismatch()
|
||||
wrapped: db_get_authinfo_for_subscr(): rc = 0
|
||||
wrapped: db_get_lastauthtuple_for_subscr(): rc = 0
|
||||
wrapped: db_sync_lastauthtuple_for_subscr(): rc = 0
|
||||
auth_get_tuple_for_subscr(key_seq=4) --> auth_action == AUTH_DO_AUTH_THEN_CIPH
|
||||
Nothing being tested!
|
||||
|
@@ -18,32 +18,14 @@ AM_LDFLAGS = \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DIST = \
|
||||
subscr_test.ok \
|
||||
bsc_subscr_test.ok \
|
||||
bsc_subscr_test.err \
|
||||
$(NULL)
|
||||
|
||||
noinst_PROGRAMS = \
|
||||
subscr_test \
|
||||
bsc_subscr_test \
|
||||
$(NULL)
|
||||
|
||||
subscr_test_SOURCES = \
|
||||
subscr_test.c \
|
||||
$(NULL)
|
||||
|
||||
subscr_test_LDADD = \
|
||||
$(top_builddir)/src/libbsc/libbsc.a \
|
||||
$(top_builddir)/src/libcommon-cs/libcommon-cs.a \
|
||||
$(top_builddir)/src/libtrau/libtrau.a \
|
||||
$(top_builddir)/src/libcommon/libcommon.a \
|
||||
$(LIBOSMOCORE_LIBS) \
|
||||
$(LIBOSMOABIS_LIBS) \
|
||||
$(LIBOSMOGSM_LIBS) \
|
||||
$(LIBSMPP34_LIBS) \
|
||||
$(LIBOSMOVTY_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
bsc_subscr_test_SOURCES = \
|
||||
bsc_subscr_test.c \
|
||||
$(NULL)
|
||||
|
@@ -1,117 +0,0 @@
|
||||
/* (C) 2008 by Jan Luebbe <jluebbe@debian.org>
|
||||
* (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
|
||||
* (C) 2014 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
|
||||
* All Rights Reserved
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/db.h>
|
||||
#include <openbsc/gsm_subscriber.h>
|
||||
#include <openbsc/gsm_04_11.h>
|
||||
|
||||
#include <osmocom/core/application.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static struct gsm_network dummy_net;
|
||||
static struct gsm_subscriber_group dummy_sgrp;
|
||||
|
||||
static void test_subscr(void)
|
||||
{
|
||||
struct gsm_subscriber *subscr;
|
||||
const char *imsi = "1234567890";
|
||||
|
||||
printf("Test subscriber allocation and deletion\n");
|
||||
|
||||
/* Don't keep subscr */
|
||||
|
||||
dummy_sgrp.keep_subscr = 0;
|
||||
|
||||
OSMO_ASSERT(llist_empty(&active_subscribers));
|
||||
|
||||
subscr = subscr_get_or_create(&dummy_sgrp, imsi);
|
||||
|
||||
OSMO_ASSERT(!llist_empty(&active_subscribers));
|
||||
OSMO_ASSERT(subscr->use_count == 1);
|
||||
|
||||
subscr_put(subscr);
|
||||
|
||||
OSMO_ASSERT(llist_empty(&active_subscribers));
|
||||
|
||||
/* Keep subscr */
|
||||
|
||||
dummy_sgrp.keep_subscr = 1;
|
||||
|
||||
subscr = subscr_get_or_create(&dummy_sgrp, imsi);
|
||||
|
||||
OSMO_ASSERT(!llist_empty(&active_subscribers));
|
||||
OSMO_ASSERT(subscr->use_count == 1);
|
||||
|
||||
subscr_put(subscr);
|
||||
OSMO_ASSERT(!llist_empty(&active_subscribers));
|
||||
OSMO_ASSERT(subscr->use_count == 0);
|
||||
|
||||
subscr_get(subscr);
|
||||
OSMO_ASSERT(subscr->use_count == 1);
|
||||
|
||||
subscr_purge_inactive(&dummy_sgrp);
|
||||
|
||||
OSMO_ASSERT(!llist_empty(&active_subscribers));
|
||||
OSMO_ASSERT(subscr->use_count == 1);
|
||||
|
||||
subscr_put(subscr);
|
||||
OSMO_ASSERT(!llist_empty(&active_subscribers));
|
||||
OSMO_ASSERT(subscr->use_count == 0);
|
||||
|
||||
subscr_purge_inactive(&dummy_sgrp);
|
||||
|
||||
OSMO_ASSERT(llist_empty(&active_subscribers));
|
||||
|
||||
/* Test force_no_keep */
|
||||
|
||||
dummy_sgrp.keep_subscr = 0;
|
||||
|
||||
subscr = subscr_get_or_create(&dummy_sgrp, imsi);
|
||||
OSMO_ASSERT(subscr);
|
||||
subscr->keep_in_ram = 1;
|
||||
|
||||
OSMO_ASSERT(!llist_empty(&active_subscribers));
|
||||
OSMO_ASSERT(subscr->use_count == 1);
|
||||
|
||||
subscr->keep_in_ram = 0;
|
||||
|
||||
subscr_put(subscr);
|
||||
OSMO_ASSERT(llist_empty(&active_subscribers));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
printf("Testing subscriber core code.\n");
|
||||
osmo_init_logging(&log_info);
|
||||
log_set_print_filename(osmo_stderr_target, 0);
|
||||
|
||||
dummy_net.subscr_group = &dummy_sgrp;
|
||||
dummy_sgrp.net = &dummy_net;
|
||||
|
||||
test_subscr();
|
||||
|
||||
printf("Done\n");
|
||||
return 0;
|
||||
}
|
@@ -1,3 +0,0 @@
|
||||
Testing subscriber core code.
|
||||
Test subscriber allocation and deletion
|
||||
Done
|
@@ -7,12 +7,6 @@ cat $abs_srcdir/gsm0408/gsm0408_test.ok > expout
|
||||
AT_CHECK([$abs_top_builddir/tests/gsm0408/gsm0408_test], [], [expout], [ignore])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([subscr])
|
||||
AT_KEYWORDS([subscr])
|
||||
cat $abs_srcdir/subscr/subscr_test.ok > expout
|
||||
AT_CHECK([$abs_top_builddir/tests/subscr/subscr_test], [], [expout], [ignore])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([bsc_subscr])
|
||||
AT_KEYWORDS([bsc_subscr])
|
||||
cat $abs_srcdir/subscr/bsc_subscr_test.ok > expout
|
||||
@@ -20,14 +14,6 @@ cat $abs_srcdir/subscr/bsc_subscr_test.err > experr
|
||||
AT_CHECK([$abs_top_builddir/tests/subscr/bsc_subscr_test], [], [expout], [experr])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([db])
|
||||
AT_KEYWORDS([db])
|
||||
cat $abs_srcdir/db/db_test.ok > expout
|
||||
cat $abs_srcdir/db/db_test.err > experr
|
||||
cat $abs_srcdir/db/hlr.sqlite3 > hlr.sqlite3
|
||||
AT_CHECK([$abs_top_builddir/tests/db/db_test], [], [expout], [experr])
|
||||
AT_CLEANUP
|
||||
|
||||
AT_SETUP([channel])
|
||||
AT_KEYWORDS([channel])
|
||||
cat $abs_srcdir/channel/channel_test.ok > expout
|
||||
|
@@ -247,8 +247,10 @@ class TestVTYNITB(TestVTYGenericBSC):
|
||||
self.vty.command("end")
|
||||
self.vty.command("configure terminal")
|
||||
self.vty.command("nitb")
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand", ['']))
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand no-extension", ['']))
|
||||
self.assertTrue(self.vty.verify('subscriber-create-on-demand',
|
||||
["% 'subscriber-create-on-demand' is no longer supported.", '% This is now up to osmo-hlr.']))
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand no-extension",
|
||||
["% 'subscriber-create-on-demand' is no longer supported.", '% This is now up to osmo-hlr.']))
|
||||
self.vty.command("end")
|
||||
|
||||
def testSi2Q(self):
|
||||
@@ -364,42 +366,6 @@ class TestVTYNITB(TestVTYGenericBSC):
|
||||
if classNum != 10:
|
||||
self.assertEquals(res.find("rach access-control-class " + str(classNum) + " barred"), -1)
|
||||
|
||||
def testSubscriberCreateDeleteTwice(self):
|
||||
"""
|
||||
OS#1657 indicates that there might be an issue creating the
|
||||
same subscriber twice. This test will use the VTY command to
|
||||
create a subscriber and then issue a second create command
|
||||
with the same IMSI. The test passes if the VTY continues to
|
||||
respond to VTY commands.
|
||||
"""
|
||||
self.vty.enable()
|
||||
|
||||
imsi = "204300854013739"
|
||||
|
||||
# Initially we don't have this subscriber
|
||||
self.vty.verify('show subscriber imsi '+imsi, ['% No subscriber found for imsi '+imsi])
|
||||
|
||||
# Lets create one
|
||||
res = self.vty.command('subscriber create imsi '+imsi)
|
||||
self.assert_(res.find(" IMSI: "+imsi) > 0)
|
||||
# And now create one again.
|
||||
res2 = self.vty.command('subscriber create imsi '+imsi)
|
||||
self.assert_(res2.find(" IMSI: "+imsi) > 0)
|
||||
self.assertEqual(res, res2)
|
||||
|
||||
# Verify it has been created
|
||||
res = self.vty.command('show subscriber imsi '+imsi)
|
||||
self.assert_(res.find(" IMSI: "+imsi) > 0)
|
||||
|
||||
# Delete it
|
||||
res = self.vty.command('subscriber imsi ' + imsi + ' delete')
|
||||
self.assert_("" == res)
|
||||
|
||||
# Now it should not be there anymore
|
||||
res = self.vty.command('show subscriber imsi '+imsi)
|
||||
self.assert_(('% No subscriber found for imsi ' + imsi) == res)
|
||||
|
||||
|
||||
def testSubscriberCreateDelete(self):
|
||||
self.vty.enable()
|
||||
|
||||
@@ -409,118 +375,24 @@ class TestVTYNITB(TestVTYGenericBSC):
|
||||
imsi4 = "444583744053764"
|
||||
|
||||
# Initially we don't have this subscriber
|
||||
self.vty.verify('show subscriber imsi '+imsi, ['% No subscriber found for imsi '+imsi])
|
||||
self.assertTrue(self.vty.verify('show subscriber imsi '+imsi, ['% No subscriber found for imsi '+imsi]))
|
||||
|
||||
# Lets create one
|
||||
res = self.vty.command('subscriber create imsi '+imsi)
|
||||
self.assert_(res.find(" IMSI: "+imsi) > 0)
|
||||
self.assert_(res.find("Extension") > 0)
|
||||
|
||||
# Now we have it
|
||||
res = self.vty.command('show subscriber imsi '+imsi)
|
||||
self.assert_(res.find(" IMSI: "+imsi) > 0)
|
||||
|
||||
# With narrow random interval
|
||||
self.vty.command("configure terminal")
|
||||
self.vty.command("nitb")
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand", ['']))
|
||||
# wrong interval
|
||||
res = self.vty.command("subscriber-create-on-demand random 221 122")
|
||||
# error string will contain arguments
|
||||
self.assert_(res.find("122") > 0)
|
||||
self.assert_(res.find("221") > 0)
|
||||
# correct interval - silent ok
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand random 221 222", ['']))
|
||||
self.vty.command("end")
|
||||
|
||||
res = self.vty.command('subscriber create imsi ' + imsi2)
|
||||
self.assert_(res.find(" IMSI: " + imsi2) > 0)
|
||||
self.assert_(res.find("221") > 0 or res.find("222") > 0)
|
||||
self.assert_(res.find(" Extension: ") > 0)
|
||||
|
||||
# Without extension
|
||||
self.vty.command("configure terminal")
|
||||
self.vty.command("nitb")
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand no-extension", ['']))
|
||||
self.vty.command("end")
|
||||
res = self.vty.command('subscriber create imsi ' + imsi3)
|
||||
self.assert_(res.find(" IMSI: " + imsi3) > 0)
|
||||
self.assertEquals(res.find("Extension"), -1)
|
||||
|
||||
# With extension again
|
||||
self.vty.command("configure terminal")
|
||||
self.vty.command("nitb")
|
||||
self.assertTrue(self.vty.verify("no subscriber-create-on-demand", ['']))
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand", ['']))
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand random 221 666", ['']))
|
||||
self.vty.command("end")
|
||||
|
||||
res = self.vty.command('subscriber create imsi ' + imsi4)
|
||||
self.assert_(res.find(" IMSI: " + imsi4) > 0)
|
||||
self.assert_(res.find(" Extension: ") > 0)
|
||||
|
||||
# Delete it
|
||||
res = self.vty.command('subscriber imsi ' + imsi + ' delete')
|
||||
self.assert_("" == res)
|
||||
res = self.vty.command('subscriber imsi ' + imsi2 + ' delete')
|
||||
self.assert_("" == res)
|
||||
res = self.vty.command('subscriber imsi ' + imsi3 + ' delete')
|
||||
self.assert_("" == res)
|
||||
res = self.vty.command('subscriber imsi ' + imsi4 + ' delete')
|
||||
self.assert_("" == res)
|
||||
|
||||
# Now it should not be there anymore
|
||||
res = self.vty.command('show subscriber imsi '+imsi)
|
||||
self.assert_(('% No subscriber found for imsi ' + imsi) == res)
|
||||
# deprecated
|
||||
self.assertTrue(self.vty.verify('subscriber create imsi '+imsi, ["% 'subscriber create' now needs to be done at osmo-hlr"]))
|
||||
|
||||
def testSubscriberSettings(self):
|
||||
self.vty.enable()
|
||||
|
||||
imsi = "204300854013739"
|
||||
imsi2 = "204301824913769"
|
||||
wrong_imsi = "204300999999999"
|
||||
|
||||
# Lets create one
|
||||
res = self.vty.command('subscriber create imsi '+imsi)
|
||||
self.assert_(res.find(" IMSI: "+imsi) > 0)
|
||||
self.assert_(res.find("Extension") > 0)
|
||||
|
||||
self.vty.verify('subscriber imsi '+wrong_imsi+' name wrong', ['% No subscriber found for imsi '+wrong_imsi])
|
||||
res = self.vty.command('subscriber imsi '+imsi+' name '+('X' * 160))
|
||||
self.assert_(res.find("NAME is too long") > 0)
|
||||
|
||||
self.vty.verify('subscriber imsi '+imsi+' name '+('G' * 159), [''])
|
||||
|
||||
self.vty.verify('subscriber imsi '+wrong_imsi+' extension 840', ['% No subscriber found for imsi '+wrong_imsi])
|
||||
res = self.vty.command('subscriber imsi '+imsi+' extension '+('9' * 15))
|
||||
self.assert_(res.find("EXTENSION is too long") > 0)
|
||||
|
||||
self.vty.verify('subscriber imsi '+imsi+' extension '+('1' * 14), [''])
|
||||
self.assertTrue(self.vty.verify('subscriber imsi '+imsi+' name foo', ["% 'subscriber name' is no longer supported.", '% This is now up to osmo-hlr.']))
|
||||
self.assertTrue(self.vty.verify('subscriber imsi '+imsi+' extension 1234', ["% 'subscriber extension' is no longer supported.", '% This is now up to osmo-hlr.']))
|
||||
self.assertTrue(self.vty.verify('subscriber imsi '+imsi+' delete', ["% 'subscriber delete' is no longer supported.", '% This is now up to osmo-hlr.']))
|
||||
|
||||
# With narrow random interval
|
||||
self.vty.command("configure terminal")
|
||||
self.vty.command("nitb")
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand", ['']))
|
||||
# wrong interval
|
||||
res = self.vty.command("subscriber-create-on-demand random 221 122")
|
||||
self.assert_(res.find("122") > 0)
|
||||
self.assert_(res.find("221") > 0)
|
||||
# correct interval
|
||||
self.assertTrue(self.vty.verify("subscriber-create-on-demand random 221 222", ['']))
|
||||
self.vty.command("end")
|
||||
|
||||
# create subscriber with extension in a configured interval
|
||||
res = self.vty.command('subscriber create imsi ' + imsi2)
|
||||
self.assert_(res.find(" IMSI: " + imsi2) > 0)
|
||||
self.assert_(res.find("221") > 0 or res.find("222") > 0)
|
||||
self.assert_(res.find(" Extension: ") > 0)
|
||||
|
||||
# Delete it
|
||||
res = self.vty.command('subscriber imsi ' + imsi + ' delete')
|
||||
self.assert_(res != "")
|
||||
# imsi2 is inactive so deletion should succeed
|
||||
res = self.vty.command('subscriber imsi ' + imsi2 + ' delete')
|
||||
self.assert_("" == res)
|
||||
self.assertTrue(self.vty.verify('subscriber-create-on-demand', ["% 'subscriber-create-on-demand' is no longer supported.", '% This is now up to osmo-hlr.']))
|
||||
|
||||
def testShowPagingGroup(self):
|
||||
res = self.vty.command("show paging-group 255 1234567")
|
||||
|
Reference in New Issue
Block a user