From de1346ebad0f3c2e221dc288fa533af06c461c96 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Fri, 3 Feb 2017 02:42:47 +0100 Subject: Use libvlr in libmsc (large refactoring) Original libvlr code is by Harald Welte , polished and tweaked by Neels Hofmeyr . 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 --- openbsc/configure.ac | 1 - openbsc/include/openbsc/abis_rsl.h | 1 - openbsc/include/openbsc/auth.h | 4 - openbsc/include/openbsc/bsc_api.h | 3 + openbsc/include/openbsc/chan_alloc.h | 2 +- openbsc/include/openbsc/db.h | 36 +- openbsc/include/openbsc/debug.h | 6 +- openbsc/include/openbsc/gsm_04_08.h | 1 - openbsc/include/openbsc/gsm_04_11.h | 8 +- openbsc/include/openbsc/gsm_data.h | 78 +- openbsc/include/openbsc/gsm_data_shared.h | 1 - openbsc/include/openbsc/gsm_subscriber.h | 92 +-- openbsc/include/openbsc/osmo_msc.h | 68 +- openbsc/include/openbsc/signal.h | 4 +- openbsc/include/openbsc/silent_call.h | 4 +- openbsc/include/openbsc/transaction.h | 7 +- openbsc/include/openbsc/vlr.h | 6 +- openbsc/include/openbsc/vty.h | 1 + openbsc/src/libbsc/abis_rsl.c | 2 +- openbsc/src/libbsc/bsc_api.c | 10 +- openbsc/src/libbsc/bsc_init.c | 7 + openbsc/src/libbsc/bsc_vty.c | 37 +- openbsc/src/libbsc/handover_logic.c | 3 +- openbsc/src/libbsc/paging.c | 1 + openbsc/src/libcommon-cs/common_cs.c | 7 - openbsc/src/libcommon-cs/common_cs_vty.c | 22 +- openbsc/src/libcommon/debug.c | 28 +- openbsc/src/libcommon/gsm_data.c | 10 + openbsc/src/libcommon/gsm_subscriber_base.c | 141 +--- openbsc/src/libcommon/gsup_client.c | 8 +- openbsc/src/libmsc/Makefile.am | 1 + openbsc/src/libmsc/auth.c | 115 --- openbsc/src/libmsc/ctrl_commands.c | 174 +--- openbsc/src/libmsc/db.c | 970 +--------------------- openbsc/src/libmsc/gsm_04_08.c | 1167 ++++++++++++--------------- openbsc/src/libmsc/gsm_04_11.c | 51 +- openbsc/src/libmsc/gsm_subscriber.c | 265 +----- openbsc/src/libmsc/meas_feed.c | 11 +- openbsc/src/libmsc/osmo_msc.c | 247 ++++-- openbsc/src/libmsc/rrlp.c | 6 +- openbsc/src/libmsc/silent_call.c | 8 +- openbsc/src/libmsc/smpp_openbsc.c | 53 +- openbsc/src/libmsc/sms_queue.c | 64 +- openbsc/src/libmsc/subscr_conn.c | 145 +++- openbsc/src/libmsc/token_auth.c | 15 +- openbsc/src/libmsc/transaction.c | 66 +- openbsc/src/libmsc/ussd.c | 7 +- openbsc/src/libmsc/vty_interface_layer3.c | 540 +++++-------- openbsc/src/libvlr/vlr_access_req_fsm.c | 1 + openbsc/src/osmo-nitb/bsc_hack.c | 18 +- openbsc/tests/Makefile.am | 3 +- openbsc/tests/channel/Makefile.am | 1 + openbsc/tests/channel/channel_test.c | 27 +- openbsc/tests/db/db_test.c | 7 + openbsc/tests/mm_auth/mm_auth_test.c | 266 +----- openbsc/tests/mm_auth/mm_auth_test.ok | 41 +- openbsc/tests/subscr/Makefile.am | 18 - openbsc/tests/subscr/subscr_test.c | 117 --- openbsc/tests/subscr/subscr_test.ok | 3 - openbsc/tests/testsuite.at | 14 - openbsc/tests/vty_test_runner.py | 150 +--- 61 files changed, 1627 insertions(+), 3543 deletions(-) delete mode 100644 openbsc/tests/subscr/subscr_test.c delete mode 100644 openbsc/tests/subscr/subscr_test.ok diff --git a/openbsc/configure.ac b/openbsc/configure.ac index 5cf77d3a0..3490f6855 100644 --- a/openbsc/configure.ac +++ b/openbsc/configure.ac @@ -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 diff --git a/openbsc/include/openbsc/abis_rsl.h b/openbsc/include/openbsc/abis_rsl.h index 758c5557a..46e824320 100644 --- a/openbsc/include/openbsc/abis_rsl.h +++ b/openbsc/include/openbsc/abis_rsl.h @@ -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) diff --git a/openbsc/include/openbsc/auth.h b/openbsc/include/openbsc/auth.h index 61811316b..b314bbf19 100644 --- a/openbsc/include/openbsc/auth.h +++ b/openbsc/include/openbsc/auth.h @@ -4,7 +4,6 @@ #include 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 */ diff --git a/openbsc/include/openbsc/bsc_api.h b/openbsc/include/openbsc/bsc_api.h index 3a9311991..40068d6ef 100644 --- a/openbsc/include/openbsc/bsc_api.h +++ b/openbsc/include/openbsc/bsc_api.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); diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h index 78242e5b7..7388e14c5 100644 --- a/openbsc/include/openbsc/chan_alloc.h +++ b/openbsc/include/openbsc/chan_alloc.h @@ -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); diff --git a/openbsc/include/openbsc/db.h b/openbsc/include/openbsc/db.h index bb90705ab..660451a50 100644 --- a/openbsc/include/openbsc/db.h +++ b/openbsc/include/openbsc/db.h @@ -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; diff --git a/openbsc/include/openbsc/debug.h b/openbsc/include/openbsc/debug.h index 74db72397..d8b6f4021 100644 --- a/openbsc/include/openbsc/debug.h +++ b/openbsc/include/openbsc/debug.h @@ -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; diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index bdf4ed2a6..727e8d368 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -9,7 +9,6 @@ struct msgb; struct gsm_bts; -struct gsm_subscriber; struct gsm_network; struct gsm_trans; struct gsm_subscriber_connection; diff --git a/openbsc/include/openbsc/gsm_04_11.h b/openbsc/include/openbsc/gsm_04_11.h index 149de9083..c67ed146b 100644 --- a/openbsc/include/openbsc/gsm_04_11.h +++ b/openbsc/include/openbsc/gsm_04_11.h @@ -3,6 +3,8 @@ #include +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); diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index bb667556e..5693d72e7 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -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; - - /* libbsc subscriber information */ + /* 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; + + /* 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 */ diff --git a/openbsc/include/openbsc/gsm_data_shared.h b/openbsc/include/openbsc/gsm_data_shared.h index 7c469eeef..e931824ca 100644 --- a/openbsc/include/openbsc/gsm_data_shared.h +++ b/openbsc/include/openbsc/gsm_data_shared.h @@ -83,7 +83,6 @@ enum bts_gprs_mode { }; struct gsm_lchan; -struct gsm_subscriber; struct gsm_mncc; struct osmo_rtp_socket; struct rtp_socket; diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index 7e656145a..c65b8a315 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -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 */ diff --git a/openbsc/include/openbsc/osmo_msc.h b/openbsc/include/openbsc/osmo_msc.h index 8f57ce25f..c1791777d 100644 --- a/openbsc/include/openbsc/osmo_msc.h +++ b/openbsc/include/openbsc/osmo_msc.h @@ -3,10 +3,74 @@ #ifndef OSMO_MSC_H #define OSMO_MSC_H +#include + +#include + #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 diff --git a/openbsc/include/openbsc/signal.h b/openbsc/include/openbsc/signal.h index d4ccf80da..49f86d612 100644 --- a/openbsc/include/openbsc/signal.h +++ b/openbsc/include/openbsc/signal.h @@ -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; diff --git a/openbsc/include/openbsc/silent_call.h b/openbsc/include/openbsc/silent_call.h index 619a54327..5fec77b73 100644 --- a/openbsc/include/openbsc/silent_call.h +++ b/openbsc/include/openbsc/silent_call.h @@ -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); diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h index 9a87d04e4..07ab7a7da 100644 --- a/openbsc/include/openbsc/transaction.h +++ b/openbsc/include/openbsc/transaction.h @@ -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 diff --git a/openbsc/include/openbsc/vlr.h b/openbsc/include/openbsc/vlr.h index 878bd25e4..9c469cec9 100644 --- a/openbsc/include/openbsc/vlr.h +++ b/openbsc/include/openbsc/vlr.h @@ -10,6 +10,8 @@ // for GSM_NAME_LENGTH #include +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); diff --git a/openbsc/include/openbsc/vty.h b/openbsc/include/openbsc/vty.h index f79eab582..1d5481599 100644 --- a/openbsc/include/openbsc/vty.h +++ b/openbsc/include/openbsc/vty.h @@ -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); diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 5939e75bf..f2977e83c 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -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; } diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c index 54978e50c..08a5bdf4c 100644 --- a/openbsc/src/libbsc/bsc_api.c +++ b/openbsc/src/libbsc/bsc_api.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -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; diff --git a/openbsc/src/libbsc/bsc_init.c b/openbsc/src/libbsc/bsc_init.c index b17ff79c5..bd47addb6 100644 --- a/openbsc/src/libbsc/bsc_init.c +++ b/openbsc/src/libbsc/bsc_init.c @@ -37,6 +37,7 @@ #include #include #include +#include /* 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; } diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index b1747aa33..d8a234a03 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -53,8 +53,8 @@ #include #include #include - #include +#include #include @@ -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); + 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); - 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 (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)) { diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index ffcca6647..8caa3c989 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -40,6 +40,7 @@ #include #include #include +#include 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); diff --git a/openbsc/src/libbsc/paging.c b/openbsc/src/libbsc/paging.c index bd23d89de..6766ad659 100644 --- a/openbsc/src/libbsc/paging.c +++ b/openbsc/src/libbsc/paging.c @@ -50,6 +50,7 @@ #include #include #include +#include void *tall_paging_ctx; diff --git a/openbsc/src/libcommon-cs/common_cs.c b/openbsc/src/libcommon-cs/common_cs.c index 7905802bf..20fbab8c4 100644 --- a/openbsc/src/libcommon-cs/common_cs.c +++ b/openbsc/src/libcommon-cs/common_cs.c @@ -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; diff --git a/openbsc/src/libcommon-cs/common_cs_vty.c b/openbsc/src/libcommon-cs/common_cs_vty.c index 08a758151..80af33de1 100644 --- a/openbsc/src/libcommon-cs/common_cs_vty.c +++ b/openbsc/src/libcommon-cs/common_cs_vty.c @@ -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); diff --git a/openbsc/src/libcommon/debug.c b/openbsc/src/libcommon/debug.c index 0f8221198..c6db00638 100644 --- a/openbsc/src/libcommon/debug.c +++ b/openbsc/src/libcommon/debug.c @@ -32,7 +32,6 @@ #include #include #include -#include #include /* 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); -} diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index 3e12430e4..f431e3843 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -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; +} diff --git a/openbsc/src/libcommon/gsm_subscriber_base.c b/openbsc/src/libcommon/gsm_subscriber_base.c index 1ecdee5a5..018ed210c 100644 --- a/openbsc/src/libcommon/gsm_subscriber_base.c +++ b/openbsc/src/libcommon/gsm_subscriber_base.c @@ -31,133 +31,34 @@ #include #include #include +#include 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; -} - -struct gsm_subscriber *subscr_alloc(void) -{ - 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; + 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; } -int subscr_purge_inactive(struct gsm_subscriber_group *sgrp) +const char *vlr_subscr_msisdn_or_name(struct vlr_subscr *vsub) { - 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; } diff --git a/openbsc/src/libcommon/gsup_client.c b/openbsc/src/libcommon/gsup_client.c index 2e920a6b6..4ed5c27ed 100644 --- a/openbsc/src/libcommon/gsup_client.c +++ b/openbsc/src/libcommon/gsup_client.c @@ -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; } diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index 9d966dbc1..3f4174ca5 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -42,6 +42,7 @@ libmsc_a_SOURCES = \ osmo_msc.c \ ctrl_commands.c \ meas_feed.c \ + subscr_conn.c \ $(NULL) if BUILD_SMPP diff --git a/openbsc/src/libmsc/auth.c b/openbsc/src/libmsc/auth.c index 19def1ec1..9064ce6c4 100644 --- a/openbsc/src/libmsc/auth.c +++ b/openbsc/src/libmsc/auth.c @@ -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; -} - diff --git a/openbsc/src/libmsc/ctrl_commands.c b/openbsc/src/libmsc/ctrl_commands.c index a56d122d2..671d29135 100644 --- a/openbsc/src/libmsc/ctrl_commands.c +++ b/openbsc/src/libmsc/ctrl_commands.c @@ -25,129 +25,20 @@ #include #include #include +#include #include -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); diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c index 9fa64152f..035d5488f 100644 --- a/openbsc/src/libmsc/db.c +++ b/openbsc/src/libmsc/db.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -43,9 +44,6 @@ #include -/* Semi-Private-Interface (SPI) for the subscriber code */ -void subscr_direct_free(struct gsm_subscriber *subscr); - static char *db_basename = NULL; static char *db_dirname = NULL; static dbi_conn conn; @@ -227,23 +225,33 @@ static struct gsm_sms *sms_from_result_v3(dbi_result result) { struct gsm_sms *sms = sms_alloc(); long long unsigned int sender_id; - struct gsm_subscriber *sender; const char *text, *daddr; const unsigned char *user_data; char buf[32]; + char *quoted; + dbi_result result2; + const char *extension; if (!sms) return NULL; sms->id = dbi_result_get_ulonglong(result, "id"); + /* find extension by id, assuming that the subscriber still exists in + * the db */ sender_id = dbi_result_get_ulonglong(result, "sender_id"); snprintf(buf, sizeof(buf), "%llu", sender_id); - sender = db_get_subscriber(GSM_SUBSCRIBER_ID, buf); - OSMO_ASSERT(sender); - osmo_strlcpy(sms->src.addr, sender->extension, sizeof(sms->src.addr)); - subscr_direct_free(sender); - sender = NULL; + + dbi_conn_quote_string_copy(conn, buf, "ed); + result2 = dbi_conn_queryf(conn, + "SELECT extension FROM Subscriber " + "WHERE id = %s ", quoted); + free(quoted); + extension = dbi_result_get_string(result2, "extension"); + if (extension) + osmo_strlcpy(sms->src.addr, extension, sizeof(sms->src.addr)); + dbi_result_free(result2); + /* got the extension */ sms->reply_path_req = dbi_result_get_ulonglong(result, "reply_path_req"); sms->status_rep_req = dbi_result_get_ulonglong(result, "status_rep_req"); @@ -518,913 +526,6 @@ int db_fini(void) return 0; } -struct gsm_subscriber *db_create_subscriber(const char *imsi, uint64_t smin, - uint64_t smax, bool alloc_exten) -{ - dbi_result result; - struct gsm_subscriber *subscr; - - /* Is this subscriber known in the db? */ - subscr = db_get_subscriber(GSM_SUBSCRIBER_IMSI, imsi); - if (subscr) { - subscr_put(subscr); - return NULL; - } - - subscr = subscr_alloc(); - if (!subscr) - return NULL; - subscr->flags |= GSM_SUBSCRIBER_FIRST_CONTACT; - result = dbi_conn_queryf(conn, - "INSERT INTO Subscriber " - "(imsi, created, updated) " - "VALUES " - "(%s, datetime('now'), datetime('now')) ", - imsi - ); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to create Subscriber by IMSI.\n"); - subscr_put(subscr); - return NULL; - } - subscr->id = dbi_conn_sequence_last(conn, NULL); - osmo_strlcpy(subscr->imsi, imsi, sizeof(subscr->imsi)); - dbi_result_free(result); - LOGP(DDB, LOGL_INFO, "New Subscriber: ID %llu, IMSI %s\n", subscr->id, subscr->imsi); - if (alloc_exten) - db_subscriber_alloc_exten(subscr, smin, smax); - return subscr; -} - -osmo_static_assert(sizeof(unsigned char) == sizeof(struct gsm48_classmark1), classmark1_size); - -static int get_equipment_by_subscr(struct gsm_subscriber *subscr) -{ - dbi_result result; - const char *string; - unsigned char cm1; - const unsigned char *cm2, *cm3; - struct gsm_equipment *equip = &subscr->equipment; - - result = dbi_conn_queryf(conn, - "SELECT Equipment.* " - "FROM Equipment JOIN EquipmentWatch ON " - "EquipmentWatch.equipment_id=Equipment.id " - "WHERE EquipmentWatch.subscriber_id = %llu " - "ORDER BY EquipmentWatch.updated DESC", subscr->id); - if (!result) - return -EIO; - - if (!dbi_result_next_row(result)) { - dbi_result_free(result); - return -ENOENT; - } - - equip->id = dbi_result_get_ulonglong(result, "id"); - - string = dbi_result_get_string(result, "imei"); - if (string) - osmo_strlcpy(equip->imei, string, sizeof(equip->imei)); - - string = dbi_result_get_string(result, "classmark1"); - if (string) { - cm1 = atoi(string) & 0xff; - memcpy(&equip->classmark1, &cm1, sizeof(equip->classmark1)); - } - - equip->classmark2_len = dbi_result_get_field_length(result, "classmark2"); - cm2 = dbi_result_get_binary(result, "classmark2"); - if (equip->classmark2_len > sizeof(equip->classmark2)) - equip->classmark2_len = sizeof(equip->classmark2); - if (cm2) - memcpy(equip->classmark2, cm2, equip->classmark2_len); - - equip->classmark3_len = dbi_result_get_field_length(result, "classmark3"); - cm3 = dbi_result_get_binary(result, "classmark3"); - if (equip->classmark3_len > sizeof(equip->classmark3)) - equip->classmark3_len = sizeof(equip->classmark3); - if (cm3) - memcpy(equip->classmark3, cm3, equip->classmark3_len); - - dbi_result_free(result); - - return 0; -} - -int db_get_authinfo_for_subscr(struct gsm_auth_info *ainfo, - struct gsm_subscriber *subscr) -{ - dbi_result result; - const unsigned char *a3a8_ki; - - result = dbi_conn_queryf(conn, - "SELECT * FROM AuthKeys WHERE subscriber_id=%llu", - subscr->id); - if (!result) - return -EIO; - - if (!dbi_result_next_row(result)) { - dbi_result_free(result); - return -ENOENT; - } - - ainfo->auth_algo = dbi_result_get_ulonglong(result, "algorithm_id"); - ainfo->a3a8_ki_len = dbi_result_get_field_length(result, "a3a8_ki"); - a3a8_ki = dbi_result_get_binary(result, "a3a8_ki"); - if (ainfo->a3a8_ki_len > sizeof(ainfo->a3a8_ki)) - ainfo->a3a8_ki_len = sizeof(ainfo->a3a8_ki); - memcpy(ainfo->a3a8_ki, a3a8_ki, ainfo->a3a8_ki_len); - - dbi_result_free(result); - - return 0; -} - -int db_sync_authinfo_for_subscr(struct gsm_auth_info *ainfo, - struct gsm_subscriber *subscr) -{ - dbi_result result; - struct gsm_auth_info ainfo_old; - int rc, upd; - unsigned char *ki_str; - - /* Deletion ? */ - if (ainfo == NULL) { - result = dbi_conn_queryf(conn, - "DELETE FROM AuthKeys WHERE subscriber_id=%llu", - subscr->id); - - if (!result) - return -EIO; - - dbi_result_free(result); - - return 0; - } - - /* Check if already existing */ - rc = db_get_authinfo_for_subscr(&ainfo_old, subscr); - if (rc && rc != -ENOENT) - return rc; - upd = rc ? 0 : 1; - - /* Update / Insert */ - dbi_conn_quote_binary_copy(conn, - ainfo->a3a8_ki, ainfo->a3a8_ki_len, &ki_str); - - if (!upd) { - result = dbi_conn_queryf(conn, - "INSERT INTO AuthKeys " - "(subscriber_id, algorithm_id, a3a8_ki) " - "VALUES (%llu, %u, %s)", - subscr->id, ainfo->auth_algo, ki_str); - } else { - result = dbi_conn_queryf(conn, - "UPDATE AuthKeys " - "SET algorithm_id=%u, a3a8_ki=%s " - "WHERE subscriber_id=%llu", - ainfo->auth_algo, ki_str, subscr->id); - } - - free(ki_str); - - if (!result) - return -EIO; - - dbi_result_free(result); - - return 0; -} - -int db_get_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple, - struct gsm_subscriber *subscr) -{ - dbi_result result; - int len; - const unsigned char *blob; - - result = dbi_conn_queryf(conn, - "SELECT * FROM AuthLastTuples WHERE subscriber_id=%llu", - subscr->id); - if (!result) - return -EIO; - - if (!dbi_result_next_row(result)) { - dbi_result_free(result); - return -ENOENT; - } - - memset(atuple, 0, sizeof(*atuple)); - - atuple->use_count = dbi_result_get_ulonglong(result, "use_count"); - atuple->key_seq = dbi_result_get_ulonglong(result, "key_seq"); - - len = dbi_result_get_field_length(result, "rand"); - if (len != sizeof(atuple->vec.rand)) - goto err_size; - - blob = dbi_result_get_binary(result, "rand"); - memcpy(atuple->vec.rand, blob, len); - - len = dbi_result_get_field_length(result, "sres"); - if (len != sizeof(atuple->vec.sres)) - goto err_size; - - blob = dbi_result_get_binary(result, "sres"); - memcpy(atuple->vec.sres, blob, len); - - len = dbi_result_get_field_length(result, "kc"); - if (len != sizeof(atuple->vec.kc)) - goto err_size; - - blob = dbi_result_get_binary(result, "kc"); - memcpy(atuple->vec.kc, blob, len); - - dbi_result_free(result); - - return 0; - -err_size: - dbi_result_free(result); - return -EIO; -} - -int db_sync_lastauthtuple_for_subscr(struct gsm_auth_tuple *atuple, - struct gsm_subscriber *subscr) -{ - dbi_result result; - int rc, upd; - struct gsm_auth_tuple atuple_old; - unsigned char *rand_str, *sres_str, *kc_str; - - /* Deletion ? */ - if (atuple == NULL) { - result = dbi_conn_queryf(conn, - "DELETE FROM AuthLastTuples WHERE subscriber_id=%llu", - subscr->id); - - if (!result) - return -EIO; - - dbi_result_free(result); - - return 0; - } - - /* Check if already existing */ - rc = db_get_lastauthtuple_for_subscr(&atuple_old, subscr); - if (rc && rc != -ENOENT) - return rc; - upd = rc ? 0 : 1; - - /* Update / Insert */ - dbi_conn_quote_binary_copy(conn, - atuple->vec.rand, sizeof(atuple->vec.rand), &rand_str); - dbi_conn_quote_binary_copy(conn, - atuple->vec.sres, sizeof(atuple->vec.sres), &sres_str); - dbi_conn_quote_binary_copy(conn, - atuple->vec.kc, sizeof(atuple->vec.kc), &kc_str); - - if (!upd) { - result = dbi_conn_queryf(conn, - "INSERT INTO AuthLastTuples " - "(subscriber_id, issued, use_count, " - "key_seq, rand, sres, kc) " - "VALUES (%llu, datetime('now'), %u, " - "%u, %s, %s, %s ) ", - subscr->id, atuple->use_count, atuple->key_seq, - rand_str, sres_str, kc_str); - } else { - char *issued = atuple->key_seq == atuple_old.key_seq ? - "issued" : "datetime('now')"; - result = dbi_conn_queryf(conn, - "UPDATE AuthLastTuples " - "SET issued=%s, use_count=%u, " - "key_seq=%u, rand=%s, sres=%s, kc=%s " - "WHERE subscriber_id = %llu", - issued, atuple->use_count, atuple->key_seq, - rand_str, sres_str, kc_str, subscr->id); - } - - free(rand_str); - free(sres_str); - free(kc_str); - - if (!result) - return -EIO; - - dbi_result_free(result); - - return 0; -} - -static void db_set_from_query(struct gsm_subscriber *subscr, dbi_conn result) -{ - const char *string; - string = dbi_result_get_string(result, "imsi"); - if (string) - osmo_strlcpy(subscr->imsi, string, sizeof(subscr->imsi)); - - string = dbi_result_get_string(result, "tmsi"); - if (string) - subscr->tmsi = tmsi_from_string(string); - - string = dbi_result_get_string(result, "name"); - if (string) - osmo_strlcpy(subscr->name, string, sizeof(subscr->name)); - - string = dbi_result_get_string(result, "extension"); - if (string) - osmo_strlcpy(subscr->extension, string, sizeof(subscr->extension)); - - subscr->lac = dbi_result_get_ulonglong(result, "lac"); - - if (!dbi_result_field_is_null(result, "expire_lu")) - subscr->expire_lu = dbi_result_get_datetime(result, "expire_lu"); - else - subscr->expire_lu = GSM_SUBSCRIBER_NO_EXPIRATION; - - subscr->authorized = dbi_result_get_ulonglong(result, "authorized"); - -} - -#define BASE_QUERY "SELECT * FROM Subscriber " -struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field, - const char *id) -{ - dbi_result result; - char *quoted; - struct gsm_subscriber *subscr; - - switch (field) { - case GSM_SUBSCRIBER_IMSI: - dbi_conn_quote_string_copy(conn, id, "ed); - result = dbi_conn_queryf(conn, - BASE_QUERY - "WHERE imsi = %s ", - quoted - ); - free(quoted); - break; - case GSM_SUBSCRIBER_TMSI: - dbi_conn_quote_string_copy(conn, id, "ed); - result = dbi_conn_queryf(conn, - BASE_QUERY - "WHERE tmsi = %s ", - quoted - ); - free(quoted); - break; - case GSM_SUBSCRIBER_EXTENSION: - dbi_conn_quote_string_copy(conn, id, "ed); - result = dbi_conn_queryf(conn, - BASE_QUERY - "WHERE extension = %s ", - quoted - ); - free(quoted); - break; - case GSM_SUBSCRIBER_ID: - dbi_conn_quote_string_copy(conn, id, "ed); - result = dbi_conn_queryf(conn, - BASE_QUERY - "WHERE id = %s ", quoted); - free(quoted); - break; - default: - LOGP(DDB, LOGL_NOTICE, "Unknown query selector for Subscriber.\n"); - return NULL; - } - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber.\n"); - return NULL; - } - if (!dbi_result_next_row(result)) { - DEBUGP(DDB, "Failed to find the Subscriber. '%u' '%s'\n", - field, id); - dbi_result_free(result); - return NULL; - } - - subscr = subscr_alloc(); - subscr->id = dbi_result_get_ulonglong(result, "id"); - - db_set_from_query(subscr, result); - DEBUGP(DDB, "Found Subscriber: ID %llu, IMSI %s, NAME '%s', TMSI %x, EXTEN '%s', LAC %hu, AUTH %u\n", - subscr->id, subscr->imsi, subscr->name, subscr->tmsi, subscr->extension, - subscr->lac, subscr->authorized); - dbi_result_free(result); - - get_equipment_by_subscr(subscr); - - return subscr; -} - -int db_subscriber_update(struct gsm_subscriber *subscr) -{ - char buf[32]; - dbi_result result; - - /* Copy the id to a string as queryf with %llu is failing */ - sprintf(buf, "%llu", subscr->id); - result = dbi_conn_queryf(conn, - BASE_QUERY - "WHERE id = %s", buf); - - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber: %llu\n", subscr->id); - return -EIO; - } - if (!dbi_result_next_row(result)) { - DEBUGP(DDB, "Failed to find the Subscriber. %llu\n", - subscr->id); - dbi_result_free(result); - return -EIO; - } - - db_set_from_query(subscr, result); - dbi_result_free(result); - get_equipment_by_subscr(subscr); - - return 0; -} - -int db_sync_subscriber(struct gsm_subscriber *subscriber) -{ - dbi_result result; - char tmsi[14]; - char *q_tmsi, *q_name, *q_extension; - - dbi_conn_quote_string_copy(conn, - subscriber->name, &q_name); - if (subscriber->extension[0] != '\0') - dbi_conn_quote_string_copy(conn, - subscriber->extension, &q_extension); - else - q_extension = strdup("NULL"); - - if (subscriber->tmsi != GSM_RESERVED_TMSI) { - sprintf(tmsi, "%u", subscriber->tmsi); - dbi_conn_quote_string_copy(conn, - tmsi, - &q_tmsi); - } else - q_tmsi = strdup("NULL"); - - if (subscriber->expire_lu == GSM_SUBSCRIBER_NO_EXPIRATION) { - result = dbi_conn_queryf(conn, - "UPDATE Subscriber " - "SET updated = datetime('now'), " - "name = %s, " - "extension = %s, " - "authorized = %i, " - "tmsi = %s, " - "lac = %i, " - "expire_lu = NULL " - "WHERE imsi = %s ", - q_name, - q_extension, - subscriber->authorized, - q_tmsi, - subscriber->lac, - subscriber->imsi); - } else { - result = dbi_conn_queryf(conn, - "UPDATE Subscriber " - "SET updated = datetime('now'), " - "name = %s, " - "extension = %s, " - "authorized = %i, " - "tmsi = %s, " - "lac = %i, " - "expire_lu = datetime(%i, 'unixepoch') " - "WHERE imsi = %s ", - q_name, - q_extension, - subscriber->authorized, - q_tmsi, - subscriber->lac, - (int) subscriber->expire_lu, - subscriber->imsi); - } - - free(q_tmsi); - free(q_name); - free(q_extension); - - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to update Subscriber (by IMSI).\n"); - return 1; - } - - dbi_result_free(result); - - return 0; -} - -int db_subscriber_delete(struct gsm_subscriber *subscr) -{ - dbi_result result; - - result = dbi_conn_queryf(conn, - "DELETE FROM AuthKeys WHERE subscriber_id=%llu", - subscr->id); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete Authkeys for %llu\n", subscr->id); - return -1; - } - dbi_result_free(result); - - result = dbi_conn_queryf(conn, - "DELETE FROM AuthLastTuples WHERE subscriber_id=%llu", - subscr->id); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete AuthLastTuples for %llu\n", subscr->id); - return -1; - } - dbi_result_free(result); - - result = dbi_conn_queryf(conn, - "DELETE FROM AuthToken WHERE subscriber_id=%llu", - subscr->id); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete AuthToken for %llu\n", subscr->id); - return -1; - } - dbi_result_free(result); - - result = dbi_conn_queryf(conn, - "DELETE FROM EquipmentWatch WHERE subscriber_id=%llu", - subscr->id); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete EquipmentWatch for %llu\n", subscr->id); - return -1; - } - dbi_result_free(result); - - if (subscr->extension[0] != '\0') { - result = dbi_conn_queryf(conn, - "DELETE FROM SMS WHERE src_addr=%s OR dest_addr=%s", - subscr->extension, subscr->extension); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete SMS for %llu\n", subscr->id); - return -1; - } - dbi_result_free(result); - } - - result = dbi_conn_queryf(conn, - "DELETE FROM VLR WHERE subscriber_id=%llu", - subscr->id); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete VLR for %llu\n", subscr->id); - return -1; - } - dbi_result_free(result); - - result = dbi_conn_queryf(conn, - "DELETE FROM ApduBlobs WHERE subscriber_id=%llu", - subscr->id); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete ApduBlobs for %llu\n", subscr->id); - return -1; - } - dbi_result_free(result); - - result = dbi_conn_queryf(conn, - "DELETE FROM Subscriber WHERE id=%llu", - subscr->id); - if (!result) { - LOGP(DDB, LOGL_ERROR, - "Failed to delete Subscriber for %llu\n", subscr->id); - return -1; - } - dbi_result_free(result); - - return 0; -} - -/** - * List all the authorized and non-expired subscribers. The callback will - * be called one by one. The subscr argument is not fully initialize and - * subscr_get/subscr_put must not be called. The passed in pointer will be - * deleted after the callback by the database call. - */ -int db_subscriber_list_active(void (*cb)(struct gsm_subscriber*,void*), void *closure) -{ - dbi_result result; - - result = dbi_conn_query(conn, - "SELECT * from Subscriber WHERE LAC != 0 AND authorized = 1"); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to list active subscribers\n"); - return -1; - } - - while (dbi_result_next_row(result)) { - struct gsm_subscriber *subscr; - - subscr = subscr_alloc(); - subscr->id = dbi_result_get_ulonglong(result, "id"); - db_set_from_query(subscr, result); - cb(subscr, closure); - OSMO_ASSERT(subscr->use_count == 1); - llist_del(&subscr->entry); - talloc_free(subscr); - } - - dbi_result_free(result); - return 0; -} - -int db_sync_equipment(struct gsm_equipment *equip) -{ - dbi_result result; - unsigned char *cm2, *cm3; - char *q_imei; - uint8_t classmark1; - - memcpy(&classmark1, &equip->classmark1, sizeof(classmark1)); - DEBUGP(DDB, "Sync Equipment IMEI=%s, classmark1=%02x", - equip->imei, classmark1); - if (equip->classmark2_len) - DEBUGPC(DDB, ", classmark2=%s", - osmo_hexdump(equip->classmark2, equip->classmark2_len)); - if (equip->classmark3_len) - DEBUGPC(DDB, ", classmark3=%s", - osmo_hexdump(equip->classmark3, equip->classmark3_len)); - DEBUGPC(DDB, "\n"); - - dbi_conn_quote_binary_copy(conn, equip->classmark2, - equip->classmark2_len, &cm2); - dbi_conn_quote_binary_copy(conn, equip->classmark3, - equip->classmark3_len, &cm3); - dbi_conn_quote_string_copy(conn, equip->imei, &q_imei); - - result = dbi_conn_queryf(conn, - "UPDATE Equipment SET " - "updated = datetime('now'), " - "classmark1 = %u, " - "classmark2 = %s, " - "classmark3 = %s " - "WHERE imei = %s ", - classmark1, cm2, cm3, q_imei); - - free(cm2); - free(cm3); - free(q_imei); - - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to update Equipment\n"); - return -EIO; - } - - dbi_result_free(result); - return 0; -} - -int db_subscriber_expire(void *priv, void (*callback)(void *priv, long long unsigned int id)) -{ - dbi_result result; - - result = dbi_conn_query(conn, - "SELECT id " - "FROM Subscriber " - "WHERE lac != 0 AND " - "( expire_lu is NOT NULL " - "AND expire_lu < datetime('now') ) " - "LIMIT 1"); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to get expired subscribers\n"); - return -EIO; - } - - while (dbi_result_next_row(result)) - callback(priv, dbi_result_get_ulonglong(result, "id")); - - dbi_result_free(result); - return 0; -} - -int db_subscriber_alloc_tmsi(struct gsm_subscriber *subscriber) -{ - dbi_result result = NULL; - char tmsi[14]; - char *tmsi_quoted; - - for (;;) { - if (RAND_bytes((uint8_t *) &subscriber->tmsi, sizeof(subscriber->tmsi)) != 1) { - LOGP(DDB, LOGL_ERROR, "RAND_bytes failed\n"); - return 1; - } - if (subscriber->tmsi == GSM_RESERVED_TMSI) - continue; - - sprintf(tmsi, "%u", subscriber->tmsi); - dbi_conn_quote_string_copy(conn, tmsi, &tmsi_quoted); - result = dbi_conn_queryf(conn, - "SELECT * FROM Subscriber " - "WHERE tmsi = %s ", - tmsi_quoted); - - free(tmsi_quoted); - - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber " - "while allocating new TMSI.\n"); - return 1; - } - if (dbi_result_get_numrows(result)) { - dbi_result_free(result); - continue; - } - if (!dbi_result_next_row(result)) { - dbi_result_free(result); - DEBUGP(DDB, "Allocated TMSI %u for IMSI %s.\n", - subscriber->tmsi, subscriber->imsi); - return db_sync_subscriber(subscriber); - } - dbi_result_free(result); - } - return 0; -} - -int db_subscriber_alloc_exten(struct gsm_subscriber *subscriber, uint64_t smin, - uint64_t smax) -{ - dbi_result result = NULL; - uint32_t try; - - for (;;) { - try = (rand() % (smax - smin + 1) + smin); - result = dbi_conn_queryf(conn, - "SELECT * FROM Subscriber " - "WHERE extension = %i", - try - ); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to query Subscriber " - "while allocating new extension.\n"); - return 1; - } - if (dbi_result_get_numrows(result)){ - dbi_result_free(result); - continue; - } - if (!dbi_result_next_row(result)) { - dbi_result_free(result); - break; - } - dbi_result_free(result); - } - sprintf(subscriber->extension, "%i", try); - DEBUGP(DDB, "Allocated extension %i for IMSI %s.\n", try, subscriber->imsi); - return db_sync_subscriber(subscriber); -} -/* - * try to allocate a new unique token for this subscriber and return it - * via a parameter. if the subscriber already has a token, return - * an error. - */ - -int db_subscriber_alloc_token(struct gsm_subscriber *subscriber, uint32_t *token) -{ - dbi_result result; - uint32_t try; - - for (;;) { - if (RAND_bytes((uint8_t *) &try, sizeof(try)) != 1) { - LOGP(DDB, LOGL_ERROR, "RAND_bytes failed\n"); - return 1; - } - if (!try) /* 0 is an invalid token */ - continue; - result = dbi_conn_queryf(conn, - "SELECT * FROM AuthToken " - "WHERE subscriber_id = %llu OR token = \"%08X\" ", - subscriber->id, try); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to query AuthToken " - "while allocating new token.\n"); - return 1; - } - if (dbi_result_get_numrows(result)) { - dbi_result_free(result); - continue; - } - if (!dbi_result_next_row(result)) { - dbi_result_free(result); - break; - } - dbi_result_free(result); - } - result = dbi_conn_queryf(conn, - "INSERT INTO AuthToken " - "(subscriber_id, created, token) " - "VALUES " - "(%llu, datetime('now'), \"%08X\") ", - subscriber->id, try); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to create token %08X for " - "IMSI %s.\n", try, subscriber->imsi); - return 1; - } - dbi_result_free(result); - *token = try; - DEBUGP(DDB, "Allocated token %08X for IMSI %s.\n", try, subscriber->imsi); - - return 0; -} - -int db_subscriber_assoc_imei(struct gsm_subscriber *subscriber, char imei[GSM23003_IMEISV_NUM_DIGITS]) -{ - unsigned long long equipment_id, watch_id; - dbi_result result; - - osmo_strlcpy(subscriber->equipment.imei, imei, sizeof(subscriber->equipment.imei)); - - result = dbi_conn_queryf(conn, - "INSERT OR IGNORE INTO Equipment " - "(imei, created, updated) " - "VALUES " - "(%s, datetime('now'), datetime('now')) ", - imei); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to create Equipment by IMEI.\n"); - return 1; - } - - equipment_id = 0; - if (dbi_result_get_numrows_affected(result)) { - equipment_id = dbi_conn_sequence_last(conn, NULL); - } - dbi_result_free(result); - - if (equipment_id) - DEBUGP(DDB, "New Equipment: ID %llu, IMEI %s\n", equipment_id, imei); - else { - result = dbi_conn_queryf(conn, - "SELECT id FROM Equipment " - "WHERE imei = %s ", - imei - ); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to query Equipment by IMEI.\n"); - return 1; - } - if (!dbi_result_next_row(result)) { - LOGP(DDB, LOGL_ERROR, "Failed to find the Equipment.\n"); - dbi_result_free(result); - return 1; - } - equipment_id = dbi_result_get_ulonglong(result, "id"); - dbi_result_free(result); - } - - result = dbi_conn_queryf(conn, - "INSERT OR IGNORE INTO EquipmentWatch " - "(subscriber_id, equipment_id, created, updated) " - "VALUES " - "(%llu, %llu, datetime('now'), datetime('now')) ", - subscriber->id, equipment_id); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to create EquipmentWatch.\n"); - return 1; - } - - watch_id = 0; - if (dbi_result_get_numrows_affected(result)) - watch_id = dbi_conn_sequence_last(conn, NULL); - - dbi_result_free(result); - if (watch_id) - DEBUGP(DDB, "New EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", - equipment_id, subscriber->imsi, imei); - else { - result = dbi_conn_queryf(conn, - "UPDATE EquipmentWatch " - "SET updated = datetime('now') " - "WHERE subscriber_id = %llu AND equipment_id = %llu ", - subscriber->id, equipment_id); - if (!result) { - LOGP(DDB, LOGL_ERROR, "Failed to update EquipmentWatch.\n"); - return 1; - } - dbi_result_free(result); - DEBUGP(DDB, "Updated EquipmentWatch: ID %llu, IMSI %s, IMEI %s\n", - equipment_id, subscriber->imsi, imei); - } - - return 0; -} - /* store an [unsent] SMS to the database */ int db_sms_store(struct gsm_sms *sms) { @@ -1500,7 +601,7 @@ static struct gsm_sms *sms_from_result(struct gsm_network *net, dbi_result resul daddr = dbi_result_get_string(result, "dest_addr"); if (daddr) osmo_strlcpy(sms->dst.addr, daddr, sizeof(sms->dst.addr)); - sms->receiver = subscr_get_by_extension(net->subscr_group, sms->dst.addr); + sms->receiver = vlr_subscr_find_by_msisdn(net->vlr, sms->dst.addr); sms->src.npi = dbi_result_get_ulonglong(result, "src_npi"); sms->src.ton = dbi_result_get_ulonglong(result, "src_ton"); @@ -1602,8 +703,9 @@ struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net, } /* retrieve the next unsent SMS for a given subscriber */ -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) { + struct gsm_network *net = vsub->vlr->user_ctx; dbi_result result; struct gsm_sms *sms; @@ -1614,7 +716,7 @@ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr) "WHERE Subscriber.id = %llu AND SMS.sent IS NULL " "AND Subscriber.lac > 0 " "ORDER BY SMS.id LIMIT 1", - subscr->id); + vsub->id); if (!result) return NULL; @@ -1623,7 +725,7 @@ struct gsm_sms *db_sms_get_unsent_for_subscr(struct gsm_subscriber *subscr) return NULL; } - sms = sms_from_result(subscr->group->net, result); + sms = sms_from_result(net, result); dbi_result_free(result); @@ -1667,26 +769,20 @@ int db_sms_inc_deliver_attempts(struct gsm_sms *sms) return 0; } -int db_apdu_blob_store(struct gsm_subscriber *subscr, - uint8_t apdu_id_flags, uint8_t len, - uint8_t *apdu) +/* Drop all pending SMS to or from the given extension */ +int db_sms_delete_by_msisdn(const char *msisdn) { dbi_result result; - unsigned char *q_apdu; - - dbi_conn_quote_binary_copy(conn, apdu, len, &q_apdu); - + if (!msisdn || !*msisdn) + return 0; result = dbi_conn_queryf(conn, - "INSERT INTO ApduBlobs " - "(created,subscriber_id,apdu_id_flags,apdu) VALUES " - "(datetime('now'),%llu,%u,%s)", - subscr->id, apdu_id_flags, q_apdu); - - free(q_apdu); - - if (!result) - return -EIO; - + "DELETE FROM SMS WHERE src_addr=%s OR dest_addr=%s", + msisdn, msisdn); + if (!result) { + LOGP(DDB, LOGL_ERROR, + "Failed to delete SMS for %s\n", msisdn); + return -1; + } dbi_result_free(result); return 0; } diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 9e74b1e77..8c2e835ce 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -1,7 +1,7 @@ /* GSM Mobile Radio Interface Layer 3 messages on the A-bis interface * 3GPP TS 04.08 version 7.21.0 Release 1998 / ETSI TS 100 940 V7.21.0 */ -/* (C) 2008-2009 by Harald Welte +/* (C) 2008-2016 by Harald Welte * (C) 2008-2012 by Holger Hans Peter Freyther * * All Rights Reserved @@ -58,6 +58,7 @@ #include #include #include +#include #include #include @@ -75,11 +76,10 @@ void *tall_authciphop_ctx; static int tch_rtp_signal(struct gsm_lchan *lchan, int signal); -static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn); +static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, + uint32_t send_tmsi); static int gsm48_tx_simple(struct gsm_subscriber_connection *conn, uint8_t pdisc, uint8_t msg_type); -static void schedule_reject(struct gsm_subscriber_connection *conn); -static void release_anchor(struct gsm_subscriber_connection *conn); struct gsm_lai { uint16_t mcc; @@ -190,215 +190,10 @@ void allocate_security_operation(struct gsm_subscriber_connection *conn) int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, gsm_cbfn *cb, void *cb_data) { - struct gsm_network *net = conn->network; - struct gsm_subscriber *subscr = conn->subscr; - struct gsm_security_operation *op; - struct gsm_auth_tuple atuple; - int status = -1, rc; - - /* Check if we _can_ enable encryption. Cases where we can't: - * - Encryption disabled in config - * - Channel already secured (nothing to do) - * - Subscriber equipment doesn't support configured encryption - */ - if (!net->a5_encryption) { - status = GSM_SECURITY_NOAVAIL; - } else if (conn->lchan->encr.alg_id > RSL_ENC_ALG_A5(0)) { - DEBUGP(DMM, "Requesting to secure an already secure channel"); - status = GSM_SECURITY_ALREADY; - } else if (!ms_cm2_a5n_support(subscr->equipment.classmark2, - net->a5_encryption)) { - DEBUGP(DMM, "Subscriber equipment doesn't support requested encryption"); - status = GSM_SECURITY_NOAVAIL; - } - - /* If not done yet, try to get info for this user */ - if (status < 0) { - rc = auth_get_tuple_for_subscr(&atuple, subscr, key_seq); - if (rc <= 0) - status = GSM_SECURITY_NOAVAIL; - } - - /* Are we done yet ? */ - if (status >= 0) - return cb ? - cb(GSM_HOOK_RR_SECURITY, status, NULL, conn, cb_data) : - 0; - - /* Start an operation (can't have more than one pending !!!) */ - if (conn->sec_operation) - return -EBUSY; - - allocate_security_operation(conn); - op = conn->sec_operation; - op->cb = cb; - op->cb_data = cb_data; - memcpy(&op->atuple, &atuple, sizeof(struct gsm_auth_tuple)); - - /* FIXME: Should start a timer for completion ... */ - - /* Then do whatever is needed ... */ - if (rc == AUTH_DO_AUTH_THEN_CIPH) { - /* Start authentication */ - return gsm48_tx_mm_auth_req(conn, op->atuple.vec.rand, NULL, - op->atuple.key_seq); - } else if (rc == AUTH_DO_CIPH) { - /* Start ciphering directly */ - return gsm0808_cipher_mode(conn, net->a5_encryption, - op->atuple.vec.kc, 8, 0); - } - - return -EINVAL; /* not reached */ -} - -static bool subscr_regexp_check(const struct gsm_network *net, const char *imsi) -{ - if (!net->authorized_reg_str) - return false; - - if (regexec(&net->authorized_regexp, imsi, 0, NULL, 0) != REG_NOMATCH) - return true; - - return false; -} - -static int authorize_subscriber(struct gsm_loc_updating_operation *loc, - struct gsm_subscriber *subscriber) -{ - if (!subscriber) - return 0; - - /* - * Do not send accept yet as more information should arrive. Some - * phones will not send us the information and we will have to check - * what we want to do with that. - */ - if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei)) - return 0; - - switch (subscriber->group->net->auth_policy) { - case GSM_AUTH_POLICY_CLOSED: - return subscriber->authorized; - case GSM_AUTH_POLICY_REGEXP: - if (subscriber->authorized) - return 1; - if (subscr_regexp_check(subscriber->group->net, - subscriber->imsi)) - subscriber->authorized = 1; - return subscriber->authorized; - case GSM_AUTH_POLICY_TOKEN: - if (subscriber->authorized) - return subscriber->authorized; - return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT); - case GSM_AUTH_POLICY_ACCEPT_ALL: - return 1; - default: - return 0; - } -} - -static void release_loc_updating_req(struct gsm_subscriber_connection *conn, int release) -{ - if (!conn->loc_operation) - return; - - /* No need to keep the connection up */ - release_anchor(conn); - - osmo_timer_del(&conn->loc_operation->updating_timer); - talloc_free(conn->loc_operation); - conn->loc_operation = NULL; - subscr_con_put(conn); -} - -static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn) -{ - if (conn->loc_operation) - LOGP(DMM, LOGL_ERROR, "Connection already had operation.\n"); - release_loc_updating_req(conn, 0); - - conn->loc_operation = talloc_zero(tall_locop_ctx, - struct gsm_loc_updating_operation); - if (conn->loc_operation) - subscr_con_get(conn); -} - -static int finish_lu(struct gsm_subscriber_connection *conn) -{ - int rc = 0; - int avoid_tmsi = conn->network->avoid_tmsi; - - /* We're all good */ - if (avoid_tmsi) { - conn->subscr->tmsi = GSM_RESERVED_TMSI; - db_sync_subscriber(conn->subscr); - } else { - db_subscriber_alloc_tmsi(conn->subscr); - } - - rc = gsm0408_loc_upd_acc(conn); - if (conn->network->send_mm_info) { - /* send MM INFO with network name */ - rc = gsm48_tx_mm_info(conn); - } - - /* call subscr_update after putting the loc_upd_acc - * in the transmit queue, since S_SUBSCR_ATTACHED might - * trigger further action like SMS delivery */ - subscr_update(conn->subscr, conn->bts, - GSM_SUBSCRIBER_UPDATE_ATTACHED); - - /* - * The gsm0408_loc_upd_acc sends a MI with the TMSI. The - * MS needs to respond with a TMSI REALLOCATION COMPLETE - * (even if the TMSI is the same). - */ - if (avoid_tmsi) - release_loc_updating_req(conn, 1); - - return rc; -} - -static int _gsm0408_authorize_sec_cb(unsigned int hooknum, unsigned int event, - struct msgb *msg, void *data, void *param) -{ - struct gsm_subscriber_connection *conn = data; - int rc = 0; - - switch (event) { - case GSM_SECURITY_AUTH_FAILED: - release_loc_updating_req(conn, 1); - break; - - case GSM_SECURITY_ALREADY: - LOGP(DMM, LOGL_ERROR, "We don't expect LOCATION " - "UPDATING after CM SERVICE REQUEST\n"); - /* fall through */ - - case GSM_SECURITY_NOAVAIL: - case GSM_SECURITY_SUCCEEDED: - rc = finish_lu(conn); - break; - - default: - rc = -EINVAL; - }; - - return rc; -} - -static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb *msg) -{ - if (!conn->loc_operation) - return 0; - - if (authorize_subscriber(conn->loc_operation, conn->subscr)) - return gsm48_secure_channel(conn, - conn->loc_operation->key_seq, - _gsm0408_authorize_sec_cb, NULL); - return 0; + OSMO_ASSERT(false); } +/* Clear Request was received from MSC, release all transactions */ void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause) { struct gsm_trans *trans, *temp; @@ -410,7 +205,7 @@ void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t caus * Cancel any outstanding location updating request * operation taking place on the subscriber connection. */ - release_loc_updating_req(conn, 0); + //release_loc_updating_req(conn, 1); /* We might need to cancel the paging response or such. */ if (conn->sec_operation && conn->sec_operation->cb) { @@ -419,7 +214,7 @@ void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t caus } release_security_operation(conn); - release_anchor(conn); + msc_release_anchor(conn); /* * Free all transactions that are associated with the released @@ -442,6 +237,7 @@ restart: } } +/* clear all transactions globally; used in case of MNCC socket disconnect */ void gsm0408_clear_all_trans(struct gsm_network *net, int protocol) { struct gsm_trans *trans, *temp; @@ -473,14 +269,15 @@ int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause) msg->lchan = conn->lchan; LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT " - "LAC=%u BTS=%u\n", subscr_name(conn->subscr), + "LAC=%u BTS=%u\n", vlr_subscr_name(conn->vsub), bts->location_area_code, bts->nr); return gsm48_conn_sendmsg(msg, conn, NULL); } /* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */ -static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn) +static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, + uint32_t send_tmsi) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 LOC UPD ACC"); struct gsm48_hdr *gh; @@ -498,16 +295,27 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn) conn->network->network_code, conn->bts->location_area_code); - if (conn->subscr->tmsi == GSM_RESERVED_TMSI) { + if (send_tmsi == GSM_RESERVED_TMSI) { + /* we did not allocate a TMSI to the MS, so we need to + * include the IMSI in order for the MS to delete any + * old TMSI that might still be allocated */ uint8_t mi[10]; int len; - len = gsm48_generate_mid_from_imsi(mi, conn->subscr->imsi); + len = gsm48_generate_mid_from_imsi(mi, conn->vsub->imsi); mid = msgb_put(msg, len); memcpy(mid, mi, len); } else { + /* Include the TMSI, which means that the MS will send a + * TMSI REALLOCATION COMPLETE, and we should wait for + * that until T3250 expiration */ mid = msgb_put(msg, GSM48_MID_TMSI_LEN); - gsm48_generate_mid_from_tmsi(mid, conn->subscr->tmsi); + gsm48_generate_mid_from_tmsi(mid, send_tmsi); } + /* TODO: Follow-on proceed */ + /* TODO: CTS permission */ + /* TODO: Equivalent PLMNs */ + /* TODO: Emergency Number List */ + /* TODO: Per-MS T3312 */ DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); @@ -532,82 +340,29 @@ static int mm_tx_identity_req(struct gsm_subscriber_connection *conn, uint8_t id return gsm48_conn_sendmsg(msg, conn, NULL); } -static struct gsm_subscriber *subscr_create(const struct gsm_network *net, - const char *imsi) -{ - if (!net->auto_create_subscr) - return NULL; - - if (!subscr_regexp_check(net, imsi)) - return NULL; - - return subscr_create_subscriber(net->subscr_group, imsi); -} - /* Parse Chapter 9.2.11 Identity Response */ static int mm_rx_id_resp(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); - struct gsm_network *net = conn->network; uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; char mi_string[GSM48_MI_SIZE]; + if (!conn->vsub) { + LOGP(DMM, LOGL_ERROR, + "Rx MM Identity Response: invalid: no subscriber\n"); + return -EINVAL; + } + gsm48_mi_to_string(mi_string, sizeof(mi_string), &gh->data[1], gh->data[0]); DEBUGP(DMM, "IDENTITY RESPONSE: MI(%s)=%s\n", gsm48_mi_type_name(mi_type), mi_string); osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, gh->data); - switch (mi_type) { - case GSM_MI_TYPE_IMSI: - /* look up subscriber based on IMSI, create if not found */ - if (!conn->subscr) { - conn->subscr = subscr_get_by_imsi(net->subscr_group, - mi_string); - if (!conn->subscr) - conn->subscr = subscr_create(net, mi_string); - } - if (!conn->subscr && conn->loc_operation) { - gsm0408_loc_upd_rej(conn, net->reject_cause); - release_loc_updating_req(conn, 1); - return 0; - } - if (conn->loc_operation) - conn->loc_operation->waiting_for_imsi = 0; - break; - case GSM_MI_TYPE_IMEI: - case GSM_MI_TYPE_IMEISV: - /* update subscribe <-> IMEI mapping */ - if (conn->subscr) { - db_subscriber_assoc_imei(conn->subscr, mi_string); - db_sync_equipment(&conn->subscr->equipment); - } - if (conn->loc_operation) - conn->loc_operation->waiting_for_imei = 0; - break; - } - - /* Check if we can let the mobile station enter */ - return gsm0408_authorize(conn, msg); -} - - -static void loc_upd_rej_cb(void *data) -{ - struct gsm_subscriber_connection *conn = data; - - LOGP(DMM, LOGL_DEBUG, "Location Updating Request procedure timedout.\n"); - gsm0408_loc_upd_rej(conn, conn->network->reject_cause); - release_loc_updating_req(conn, 1); -} - -static void schedule_reject(struct gsm_subscriber_connection *conn) -{ - conn->loc_operation->updating_timer.cb = loc_upd_rej_cb; - conn->loc_operation->updating_timer.data = conn; - osmo_timer_schedule(&conn->loc_operation->updating_timer, 5, 0); + return vlr_subscr_rx_id_resp(conn->vsub, gh->data+1, gh->data[0]); } +/* FIXME: to libosmogsm */ static const struct value_string lupd_names[] = { { GSM48_LUPD_NORMAL, "NORMAL" }, { GSM48_LUPD_PERIODIC, "PERIODIC" }, @@ -615,14 +370,23 @@ static const struct value_string lupd_names[] = { { 0, NULL } }; -/* Chapter 9.2.15: Receive Location Updating Request */ -static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb *msg) +/* Chapter 9.2.15: Receive Location Updating Request. + * Keep this function non-static for direct invocation by unit tests. */ +int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb *msg) { + static const enum subscr_conn_from conn_from_lu = SUBSCR_CONN_FROM_LU; + struct gsm_network *net = conn->network; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_loc_upd_req *lu; - struct gsm_subscriber *subscr = NULL; uint8_t mi_type; char mi_string[GSM48_MI_SIZE]; + enum vlr_lu_type vlr_lu_type = VLR_LU_TYPE_REGULAR; + + uint32_t tmsi; + char *imsi; + struct osmo_location_area_id old_lai, new_lai; + struct osmo_fsm_inst *lu_fsm; + int rc; lu = (struct gsm48_loc_upd_req *) gh->data; @@ -630,97 +394,94 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb gsm48_mi_to_string(mi_string, sizeof(mi_string), lu->mi, lu->mi_len); - DEBUGPC(DMM, "MI(%s)=%s type=%s ", gsm48_mi_type_name(mi_type), - mi_string, get_value_string(lupd_names, lu->type)); + rc = msc_create_conn_fsm(conn, mi_string); + if (rc) + /* logging already happened in msc_create_conn_fsm() */ + return rc; + + conn->classmark.classmark1 = lu->classmark1; + conn->classmark.classmark1_set = true; + + DEBUGP(DMM, "LOCATION UPDATING REQUEST: MI(%s)=%s type=%s\n", + gsm48_mi_type_name(mi_type), mi_string, + get_value_string(lupd_names, lu->type)); osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, &lu->mi_len); switch (lu->type) { case GSM48_LUPD_NORMAL: rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL]); + vlr_lu_type = VLR_LU_TYPE_REGULAR; break; case GSM48_LUPD_IMSI_ATT: rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH]); + vlr_lu_type = VLR_LU_TYPE_IMSI_ATTACH; break; case GSM48_LUPD_PERIODIC: rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_PERIODIC]); + vlr_lu_type = VLR_LU_TYPE_PERIODIC; break; } - /* - * Pseudo Spoof detection: Just drop a second/concurrent - * location updating request. - */ - if (conn->loc_operation) { - DEBUGPC(DMM, "ignoring request due an existing one: %p.\n", - conn->loc_operation); - gsm0408_loc_upd_rej(conn, GSM48_REJECT_PROTOCOL_ERROR); - return 0; - } - - allocate_loc_updating_req(conn); - - conn->loc_operation->key_seq = lu->key_seq; + /* TODO: 10.5.1.6 MS Classmark for UMTS / Classmark 2 */ + /* TODO: 10.5.3.14 Aditional update parameters (CS fallback calls) */ + /* TODO: 10.5.7.8 Device properties */ + /* TODO: 10.5.1.15 MS network feature support */ switch (mi_type) { case GSM_MI_TYPE_IMSI: - DEBUGPC(DMM, "\n"); - /* we always want the IMEI, too */ - mm_tx_identity_req(conn, GSM_MI_TYPE_IMEI); - conn->loc_operation->waiting_for_imei = 1; - - /* look up subscriber based on IMSI, create if not found */ - subscr = subscr_get_by_imsi(conn->network->subscr_group, mi_string); - if (!subscr) - subscr = subscr_create(conn->network, mi_string); - if (!subscr) { - gsm0408_loc_upd_rej(conn, conn->network->reject_cause); - release_loc_updating_req(conn, 0); - return 0; - } + tmsi = GSM_RESERVED_TMSI; + imsi = mi_string; break; case GSM_MI_TYPE_TMSI: - DEBUGPC(DMM, "\n"); - /* look up the subscriber based on TMSI, request IMSI if it fails */ - subscr = subscr_get_by_tmsi(conn->network->subscr_group, - tmsi_from_string(mi_string)); - if (!subscr) { - /* send IDENTITY REQUEST message to get IMSI */ - mm_tx_identity_req(conn, GSM_MI_TYPE_IMSI); - conn->loc_operation->waiting_for_imsi = 1; - } - /* we always want the IMEI, too */ - mm_tx_identity_req(conn, GSM_MI_TYPE_IMEI); - conn->loc_operation->waiting_for_imei = 1; - break; - case GSM_MI_TYPE_IMEI: - case GSM_MI_TYPE_IMEISV: - /* no sim card... FIXME: what to do ? */ - DEBUGPC(DMM, "unimplemented mobile identity type\n"); + tmsi = tmsi_from_string(mi_string); + imsi = NULL; break; default: DEBUGPC(DMM, "unknown mobile identity type\n"); + tmsi = GSM_RESERVED_TMSI; + imsi = NULL; break; } - /* schedule the reject timer */ - schedule_reject(conn); - - if (!subscr) { - DEBUGPC(DRR, "<- Can't find any subscriber for this ID\n"); - /* FIXME: request id? close channel? */ - return -EINVAL; + gsm48_decode_lai(&lu->lai, &old_lai.plmn.mcc, + &old_lai.plmn.mnc, &old_lai.lac); + new_lai.plmn.mcc = conn->network->country_code; + new_lai.plmn.mnc = conn->network->network_code; + new_lai.lac = conn->bts->location_area_code; + DEBUGP(DMM, "LU/new-LAC: %u/%u\n", old_lai.lac, new_lai.lac); + + lu_fsm = vlr_loc_update(conn->conn_fsm, + SUBSCR_CONN_E_ACCEPTED, + SUBSCR_CONN_E_CN_CLOSE, + (void*)&conn_from_lu, + net->vlr, conn, vlr_lu_type, tmsi, imsi, + &old_lai, &new_lai, + conn->network->authentication_required, + conn->network->a5_encryption, + classmark_is_r99(&conn->classmark), + conn->via_ran == RAN_UTRAN_IU); + if (!lu_fsm) { + DEBUGP(DRR, "%s: Can't start LU FSM\n", mi_string); + return 0; } - conn->subscr = subscr; - conn->subscr->equipment.classmark1 = lu->classmark1; + /* From vlr_loc_update() we expect an implicit dispatch of + * VLR_ULA_E_UPDATE_LA, and thus we expect msc_vlr_subscr_assoc() to + * already have been called and completed. Has an error occured? */ - /* check if we can let the subscriber into our network immediately - * or if we need to wait for identity responses. */ - return gsm0408_authorize(conn, msg); + if (!conn->vsub || conn->vsub->lu_fsm != lu_fsm) { + LOGP(DRR, LOGL_ERROR, + "%s: internal error during Location Updating attempt\n", + mi_string); + return -EIO; + } + + return 0; } /* Turn int into semi-octet representation: 98 => 0x89 */ +/* FIXME: libosmocore/libosmogsm */ static uint8_t bcdify(uint8_t value) { uint8_t ret; @@ -924,55 +685,6 @@ int gsm48_tx_mm_auth_rej(struct gsm_subscriber_connection *conn) return gsm48_tx_simple(conn, GSM48_PDISC_MM, GSM48_MT_MM_AUTH_REJ); } -/* - * At the 30C3 phones miss their periodic update - * interval a lot and then remain unreachable. In case - * we still know the TMSI we can just attach it again. - */ -static void implit_attach(struct gsm_subscriber_connection *conn) -{ - if (conn->subscr->lac != GSM_LAC_RESERVED_DETACHED) - return; - - subscr_update(conn->subscr, conn->bts, - GSM_SUBSCRIBER_UPDATE_ATTACHED); -} - - -static int _gsm48_rx_mm_serv_req_sec_cb( - unsigned int hooknum, unsigned int event, - struct msgb *msg, void *data, void *param) -{ - struct gsm_subscriber_connection *conn = data; - int rc = 0; - - /* auth failed or succeeded, the timer was stopped */ - conn->expire_timer_stopped = 1; - - switch (event) { - case GSM_SECURITY_AUTH_FAILED: - /* Nothing to do */ - break; - - case GSM_SECURITY_NOAVAIL: - case GSM_SECURITY_ALREADY: - rc = gsm48_tx_mm_serv_ack(conn); - implit_attach(conn); - break; - - case GSM_SECURITY_SUCCEEDED: - /* nothing to do. CIPHER MODE COMMAND is - * implicit CM SERV ACK */ - implit_attach(conn); - break; - - default: - rc = -EINVAL; - }; - - return rc; -} - /* * Handle CM Service Requests * a) Verify that the packet is long enough to contain the information @@ -981,14 +693,17 @@ static int _gsm48_rx_mm_serv_req_sec_cb( * c) Check that we know the subscriber with the TMSI otherwise reject * with a HLR cause * d) Set the subscriber on the gsm_lchan and accept + * + * Keep this function non-static for direct invocation by unit tests. */ -static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *msg) +int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *msg) { + static const enum subscr_conn_from conn_from_cm_service_req = + SUBSCR_CONN_FROM_CM_SERVICE_REQ; + struct gsm_network *net = conn->network; uint8_t mi_type; char mi_string[GSM48_MI_SIZE]; - struct gsm_network *network = conn->network; - struct gsm_subscriber *subscr; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_service_request *req = (struct gsm48_service_request *)gh->data; @@ -997,6 +712,12 @@ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct m uint8_t *classmark2 = gh->data+2; uint8_t mi_len = *(classmark2 + classmark2_len); uint8_t *mi = (classmark2 + classmark2_len + 1); + struct osmo_location_area_id lai; + int rc; + + lai.plmn.mcc = conn->network->country_code; + lai.plmn.mnc = conn->network->network_code; + lai.lac = conn->bts->location_area_code; DEBUGP(DMM, "<- CM SERVICE REQUEST "); if (msg->data_len < sizeof(struct gsm48_service_request*)) { @@ -1018,14 +739,10 @@ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct m DEBUGPC(DMM, "serv_type=0x%02x MI(%s)=%s\n", req->cm_service_type, gsm48_mi_type_name(mi_type), mi_string); - subscr = subscr_get_by_imsi(network->subscr_group, - mi_string); } else if (mi_type == GSM_MI_TYPE_TMSI) { DEBUGPC(DMM, "serv_type=0x%02x MI(%s)=%s\n", req->cm_service_type, gsm48_mi_type_name(mi_type), mi_string); - subscr = subscr_get_by_tmsi(network->subscr_group, - tmsi_from_string(mi_string)); } else { DEBUGPC(DMM, "mi_type is not expected: %d\n", mi_type); return gsm48_tx_mm_serv_rej(conn, @@ -1034,33 +751,29 @@ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct m osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, (classmark2 + classmark2_len)); - if (is_siemens_bts(conn->bts)) - send_siemens_mrpci(msg->lchan, classmark2-1); - + rc = msc_create_conn_fsm(conn, mi_string); + if (rc) + /* logging already happened in msc_create_conn_fsm() */ + return rc; - /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */ - if (!subscr) - return gsm48_tx_mm_serv_rej(conn, - GSM48_REJECT_IMSI_UNKNOWN_IN_VLR); + memcpy(conn->classmark.classmark2, classmark2, classmark2_len); + conn->classmark.classmark2_len = classmark2_len; - if (!conn->subscr) - conn->subscr = subscr; - else if (conn->subscr == subscr) - subscr_put(subscr); /* lchan already has a ref, don't need another one */ - else { - DEBUGP(DMM, "<- CM Channel already owned by someone else?\n"); - subscr_put(subscr); - } - - subscr->equipment.classmark2_len = classmark2_len; - memcpy(subscr->equipment.classmark2, classmark2, classmark2_len); - db_sync_equipment(&subscr->equipment); + if (is_siemens_bts(conn->bts)) + send_siemens_mrpci(msg->lchan, classmark2-1); - /* we will send a MM message soon */ - conn->expire_timer_stopped = 1; + vlr_proc_acc_req(conn->conn_fsm, + SUBSCR_CONN_E_ACCEPTED, + SUBSCR_CONN_E_CN_CLOSE, + (void*)&conn_from_cm_service_req, + net->vlr, conn, + VLR_PR_ARQ_T_CM_SERV_REQ, mi-1, &lai, + conn->network->authentication_required, + conn->network->a5_encryption, + classmark_is_r99(&conn->classmark), + conn->via_ran == RAN_UTRAN_IU); - return gsm48_secure_channel(conn, req->cipher_key_seq, - _gsm48_rx_mm_serv_req_sec_cb, NULL); + return 0; } static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, struct msgb *msg) @@ -1071,7 +784,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, s (struct gsm48_imsi_detach_ind *) gh->data; uint8_t mi_type = idi->mi[0] & GSM_MI_TYPE_MASK; char mi_string[GSM48_MI_SIZE]; - struct gsm_subscriber *subscr = NULL; + struct vlr_subscr *vsub = NULL; gsm48_mi_to_string(mi_string, sizeof(mi_string), idi->mi, idi->mi_len); DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", @@ -1082,13 +795,12 @@ static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, s switch (mi_type) { case GSM_MI_TYPE_TMSI: DEBUGPC(DMM, "\n"); - subscr = subscr_get_by_tmsi(network->subscr_group, - tmsi_from_string(mi_string)); + vsub = vlr_subscr_find_by_tmsi(network->vlr, + tmsi_from_string(mi_string)); break; case GSM_MI_TYPE_IMSI: DEBUGPC(DMM, "\n"); - subscr = subscr_get_by_imsi(network->subscr_group, - mi_string); + vsub = vlr_subscr_find_by_imsi(network->vlr, mi_string); break; case GSM_MI_TYPE_IMEI: case GSM_MI_TYPE_IMEISV: @@ -1100,22 +812,24 @@ static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, s break; } - if (subscr) { - subscr_update(subscr, conn->bts, - GSM_SUBSCRIBER_UPDATE_DETACHED); - DEBUGP(DMM, "Subscriber: %s\n", subscr_name(subscr)); - subscr->equipment.classmark1 = idi->classmark1; - db_sync_equipment(&subscr->equipment); + /* TODO? We used to remember the subscriber's classmark1 here and + * stored it in the old sqlite db, but now we store it in a conn that + * will be discarded anyway: */ + conn->classmark.classmark1 = idi->classmark1; - subscr_put(subscr); - } else + if (!vsub) { DEBUGP(DMM, "Unknown Subscriber ?!?\n"); + return 0; + } - /* FIXME: iterate over all transactions and release them, - * imagine an IMSI DETACH happening during an active call! */ + LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", + vlr_subscr_name(vsub)); + vlr_subscr_rx_imsi_detach(vsub); + osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_DETACHED, vsub); + vlr_subscr_put(vsub); - release_anchor(conn); + msc_close_connection(conn); return 0; } @@ -1139,7 +853,7 @@ static int parse_gsm_auth_resp(uint8_t *res, uint8_t *res_len, LOGP(DMM, LOGL_ERROR, "%s: MM AUTHENTICATION RESPONSE:" " l3 length invalid: %u\n", - subscr_name(conn->subscr), msgb_l3len(msg)); + vlr_subscr_name(conn->vsub), msgb_l3len(msg)); return -EINVAL; } @@ -1172,7 +886,7 @@ static int parse_umts_auth_resp(uint8_t *res, uint8_t *res_len, LOGP(DMM, LOGL_ERROR, "%s: MM AUTHENTICATION RESPONSE:" " l3 length invalid: %u\n", - subscr_name(conn->subscr), msgb_l3len(msg)); + vlr_subscr_name(conn->vsub), msgb_l3len(msg)); return -EINVAL; } @@ -1182,7 +896,7 @@ static int parse_umts_auth_resp(uint8_t *res, uint8_t *res_len, LOGP(DMM, LOGL_ERROR, "%s: MM R99 AUTHENTICATION RESPONSE:" " expected IEI 0x%02x, got 0x%02x\n", - subscr_name(conn->subscr), + vlr_subscr_name(conn->vsub), GSM48_IE_AUTH_RES_EXT, iei); return -EINVAL; } @@ -1191,7 +905,7 @@ static int parse_umts_auth_resp(uint8_t *res, uint8_t *res_len, LOGP(DMM, LOGL_ERROR, "%s: MM R99 AUTHENTICATION RESPONSE:" " extended Auth Resp IE 0x%02x is too large: %u bytes\n", - subscr_name(conn->subscr), GSM48_IE_AUTH_RES_EXT, ie_len); + vlr_subscr_name(conn->vsub), GSM48_IE_AUTH_RES_EXT, ie_len); return -EINVAL; } @@ -1203,17 +917,15 @@ static int parse_umts_auth_resp(uint8_t *res, uint8_t *res_len, /* Chapter 9.2.3: Authentication Response */ static int gsm48_rx_mm_auth_resp(struct gsm_subscriber_connection *conn, struct msgb *msg) { - struct gsm_network *net = conn->network; uint8_t res[16]; uint8_t res_len; int rc; bool is_r99; - if (!conn->subscr) { + if (!conn->vsub) { LOGP(DMM, LOGL_ERROR, "MM AUTHENTICATION RESPONSE: invalid: no subscriber\n"); - gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); + msc_close_connection(conn); return -EINVAL; } @@ -1227,56 +939,18 @@ static int gsm48_rx_mm_auth_resp(struct gsm_subscriber_connection *conn, struct } if (rc) { - gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); + msc_close_connection(conn); return -EINVAL; } DEBUGP(DMM, "%s: MM %s AUTHENTICATION RESPONSE (%s = %s)\n", - subscr_name(conn->subscr), + vlr_subscr_name(conn->vsub), is_r99 ? "R99" : "GSM", is_r99 ? "res" : "sres", osmo_hexdump_nospc(res, res_len)); - /* Future: vlr_sub_rx_auth_resp(conn->vsub, is_r99, - * conn->via_ran == RAN_UTRAN_IU, - * res, res_len); - */ - - if (res_len != 4) { - LOGP(DMM, LOGL_ERROR, - "%s: MM AUTHENTICATION RESPONSE:" - " UMTS authentication not supported\n", - subscr_name(conn->subscr)); - } - - /* Safety check */ - if (!conn->sec_operation) { - DEBUGP(DMM, "No authentication/cipher operation in progress !!!\n"); - return -EIO; - } - - /* Validate SRES */ - if (memcmp(conn->sec_operation->atuple.vec.sres, res, 4)) { - int rc; - gsm_cbfn *cb = conn->sec_operation->cb; - - DEBUGPC(DMM, "Invalid (expected %s)\n", - osmo_hexdump(conn->sec_operation->atuple.vec.sres, 4)); - - if (cb) - cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED, - NULL, conn, conn->sec_operation->cb_data); - - rc = gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); - return rc; - } - - DEBUGPC(DMM, "OK\n"); - - /* Start ciphering */ - return gsm0808_cipher_mode(conn, net->a5_encryption, - conn->sec_operation->atuple.vec.kc, 8, 0); + return vlr_subscr_rx_auth_resp(conn->vsub, is_r99, + conn->via_ran == RAN_UTRAN_IU, + res, res_len); } static int gsm48_rx_mm_auth_fail(struct gsm_subscriber_connection *conn, struct msgb *msg) @@ -1286,20 +960,11 @@ static int gsm48_rx_mm_auth_fail(struct gsm_subscriber_connection *conn, struct uint8_t auts_tag; uint8_t auts_len; uint8_t *auts; - int rc; - if (!conn->sec_operation) { - DEBUGP(DMM, "%s: MM R99 AUTHENTICATION FAILURE:" - " No authentication/cipher operation in progress\n", - subscr_name(conn->subscr)); - return -EINVAL; - } - - if (!conn->subscr) { + if (!conn->vsub) { LOGP(DMM, LOGL_ERROR, "MM R99 AUTHENTICATION FAILURE: invalid: no subscriber\n"); - gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); + msc_close_connection(conn); return -EINVAL; } @@ -1307,9 +972,8 @@ static int gsm48_rx_mm_auth_fail(struct gsm_subscriber_connection *conn, struct LOGP(DMM, LOGL_ERROR, "%s: MM R99 AUTHENTICATION FAILURE:" " l3 length invalid: %u\n", - subscr_name(conn->subscr), msgb_l3len(msg)); - gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); + vlr_subscr_name(conn->vsub), msgb_l3len(msg)); + msc_close_connection(conn); return -EINVAL; } @@ -1318,10 +982,9 @@ static int gsm48_rx_mm_auth_fail(struct gsm_subscriber_connection *conn, struct if (cause != GSM48_REJECT_SYNCH_FAILURE) { LOGP(DMM, LOGL_INFO, "%s: MM R99 AUTHENTICATION FAILURE: cause 0x%0x\n", - subscr_name(conn->subscr), cause); - rc = gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); - return rc; + vlr_subscr_name(conn->vsub), cause); + vlr_subscr_rx_auth_fail(conn->vsub, NULL); + return 0; } /* This is a Synch Failure procedure, which should pass an AUTS to @@ -1332,9 +995,8 @@ static int gsm48_rx_mm_auth_fail(struct gsm_subscriber_connection *conn, struct LOGP(DMM, LOGL_INFO, "%s: MM R99 AUTHENTICATION FAILURE:" " invalid Synch Failure: missing AUTS IE\n", - subscr_name(conn->subscr)); - gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); + vlr_subscr_name(conn->vsub)); + msc_close_connection(conn); return -EINVAL; } @@ -1349,10 +1011,9 @@ static int gsm48_rx_mm_auth_fail(struct gsm_subscriber_connection *conn, struct " invalid Synch Failure:" " expected AUTS IE 0x%02x of 14 bytes," " got IE 0x%02x of %u bytes\n", - subscr_name(conn->subscr), + vlr_subscr_name(conn->vsub), GSM48_IE_AUTS, auts_tag, auts_len); - gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); + msc_close_connection(conn); return -EINVAL; } @@ -1360,9 +1021,8 @@ static int gsm48_rx_mm_auth_fail(struct gsm_subscriber_connection *conn, struct LOGP(DMM, LOGL_INFO, "%s: MM R99 AUTHENTICATION FAILURE:" " invalid Synch Failure msg: message truncated (%u)\n", - subscr_name(conn->subscr), msgb_l3len(msg)); - gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); + vlr_subscr_name(conn->vsub), msgb_l3len(msg)); + msc_close_connection(conn); return -EINVAL; } @@ -1370,15 +1030,21 @@ static int gsm48_rx_mm_auth_fail(struct gsm_subscriber_connection *conn, struct * large enough. */ DEBUGP(DMM, "%s: MM R99 AUTHENTICATION SYNCH (AUTS = %s)\n", - subscr_name(conn->subscr), osmo_hexdump_nospc(auts, 14)); + vlr_subscr_name(conn->vsub), osmo_hexdump_nospc(auts, 14)); - /* Future: vlr_sub_rx_auth_fail(conn->vsub, auts); */ + return vlr_subscr_rx_auth_fail(conn->vsub, auts); +} - LOGP(DMM, LOGL_ERROR, "%s: MM R99 AUTHENTICATION not supported\n", - subscr_name(conn->subscr)); - rc = gsm48_tx_mm_auth_rej(conn); - release_security_operation(conn); - return rc; +static int gsm48_rx_mm_tmsi_reall_compl(struct gsm_subscriber_connection *conn) +{ + DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n", + vlr_subscr_name(conn->vsub)); + if (!conn->vsub) { + LOGP(DMM, LOGL_ERROR, + "Rx MM TMSI Reallocation Complete: invalid: no subscriber\n"); + return -EINVAL; + } + return vlr_subscr_rx_tmsi_reall_compl(conn->vsub); } /* Receive a GSM 04.08 Mobility Management (MM) message */ @@ -1389,7 +1055,6 @@ static int gsm0408_rcv_mm(struct gsm_subscriber_connection *conn, struct msgb *m switch (gsm48_hdr_msg_type(gh)) { case GSM48_MT_MM_LOC_UPD_REQUEST: - DEBUGP(DMM, "LOCATION UPDATING REQUEST: "); rc = mm_rx_loc_upd_req(conn, msg); break; case GSM48_MT_MM_ID_RESP: @@ -1402,9 +1067,7 @@ static int gsm0408_rcv_mm(struct gsm_subscriber_connection *conn, struct msgb *m rc = gsm48_rx_mm_status(msg); break; case GSM48_MT_MM_TMSI_REALL_COMPL: - DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n", - subscr_name(conn->subscr)); - release_loc_updating_req(conn, 1); + rc = gsm48_rx_mm_tmsi_reall_compl(conn); break; case GSM48_MT_MM_IMSI_DETACH_IND: rc = gsm48_rx_mm_imsi_detach_ind(conn, msg); @@ -1427,18 +1090,37 @@ static int gsm0408_rcv_mm(struct gsm_subscriber_connection *conn, struct msgb *m return rc; } +static uint8_t *gsm48_cm2_get_mi(uint8_t *classmark2_lv, unsigned int tot_len) +{ + /* Check the size for the classmark */ + if (tot_len < 1 + *classmark2_lv) + return NULL; + + uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1; + if (tot_len < 2 + *classmark2_lv + mi_lv[0]) + return NULL; + + return mi_lv; +} + /* Receive a PAGING RESPONSE message from the MS */ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct msgb *msg) { + static const enum subscr_conn_from conn_from_paging_resp = + SUBSCR_CONN_FROM_PAGING_RESP; + struct gsm_network *net = conn->network; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_pag_resp *resp; uint8_t *classmark2_lv = gh->data + 1; + uint8_t *mi_lv; uint8_t mi_type; char mi_string[GSM48_MI_SIZE]; - struct gsm_subscriber *subscr = NULL; - struct bsc_subscr *bsub; - uint32_t tmsi; int rc = 0; + struct osmo_location_area_id lai; + + lai.plmn.mcc = conn->network->country_code; + lai.plmn.mnc = conn->network->network_code; + lai.lac = 23; /* FIXME bts->location_area_code; */ resp = (struct gsm48_pag_resp *) &gh->data[0]; gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh), @@ -1446,55 +1128,31 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m DEBUGP(DRR, "PAGING RESPONSE: MI(%s)=%s\n", gsm48_mi_type_name(mi_type), mi_string); - switch (mi_type) { - case GSM_MI_TYPE_TMSI: - tmsi = tmsi_from_string(mi_string); - subscr = subscr_get_by_tmsi(conn->network->subscr_group, tmsi); - break; - case GSM_MI_TYPE_IMSI: - subscr = subscr_get_by_imsi(conn->network->subscr_group, - mi_string); - break; - } - - if (!subscr) { - DEBUGP(DRR, "<- Can't find any subscriber for this ID\n"); - /* FIXME: request id? close channel? */ - return -EINVAL; - } - - if (!conn->subscr) { - conn->subscr = subscr; - } else if (conn->subscr != subscr) { - LOGP(DRR, LOGL_ERROR, "<- Channel already owned by someone else?\n"); - subscr_put(subscr); - return -EINVAL; - } else { - DEBUGP(DRR, "<- Channel already owned by us\n"); - subscr_put(subscr); - subscr = conn->subscr; + mi_lv = gsm48_cm2_get_mi(classmark2_lv, msgb_l3len(msg) - sizeof(*gh)); + if (!mi_lv) { + /* FIXME */ + return -1; } - log_set_context(LOG_CTX_VLR_SUBSCR, subscr); - DEBUGP(DRR, "<- Channel was requested by %s\n", - subscr->name && strlen(subscr->name) ? subscr->name : subscr->imsi); - - subscr->equipment.classmark2_len = *classmark2_lv; - memcpy(subscr->equipment.classmark2, classmark2_lv+1, *classmark2_lv); - db_sync_equipment(&subscr->equipment); + rc = msc_create_conn_fsm(conn, mi_string); + if (rc) + /* logging already happened in msc_create_conn_fsm() */ + return rc; - /* 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(conn->network->bsc_subscribers, - subscr->imsi); - bsub->tmsi = subscr->tmsi; - bsub->lac = subscr->lac; + memcpy(conn->classmark.classmark2, classmark2_lv+1, *classmark2_lv); + conn->classmark.classmark2_len = *classmark2_lv; - /* We received a paging */ - conn->expire_timer_stopped = 1; + vlr_proc_acc_req(conn->conn_fsm, + SUBSCR_CONN_E_ACCEPTED, + SUBSCR_CONN_E_CN_CLOSE, + (void*)&conn_from_paging_resp, + net->vlr, conn, + VLR_PR_ARQ_T_PAGING_RESP, mi_lv, &lai, + conn->network->authentication_required, + conn->network->a5_encryption, + classmark_is_r99(&conn->classmark), + conn->via_ran == RAN_UTRAN_IU); - rc = gsm48_handle_paging_resp(conn, msg, bsub); return rc; } @@ -1512,7 +1170,12 @@ static int gsm48_rx_rr_app_info(struct gsm_subscriber_connection *conn, struct m DEBUGP(DRR, "RX APPLICATION INFO id/flags=0x%02x apdu_len=%u apdu=%s\n", apdu_id_flags, apdu_len, osmo_hexdump(apdu_data, apdu_len)); + /* we're not using the app info blob anywhere, so ignore. */ +#if 0 return db_apdu_blob_store(conn->subscr, apdu_id_flags, apdu_len, apdu_data); +#else + return 0; +#endif } /* Receive a GSM 04.08 Radio Resource (RR) message */ @@ -1666,12 +1329,12 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans, trans->conn->lchan->ts->trx->bts->nr, trans->conn->lchan->ts->trx->nr, trans->conn->lchan->ts->nr, trans->transaction_id, - (trans->subscr)?(trans->subscr->extension):"-", + vlr_subscr_msisdn_or_name(trans->vsub), get_mncc_name(msg_type)); else DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " "Sending '%s' to MNCC.\n", - (trans->subscr)?(trans->subscr->extension):"-", + vlr_subscr_msisdn_or_name(trans->vsub), get_mncc_name(msg_type)); else DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) " @@ -1737,7 +1400,8 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, /* check all tranactions (without lchan) for subscriber */ switch (event) { case GSM_PAGING_SUCCEEDED: - DEBUGP(DCC, "Paging subscr %s succeeded!\n", transt->subscr->extension); + DEBUGP(DCC, "Paging subscr %s succeeded!\n", + vlr_subscr_msisdn_or_name(transt->vsub)); OSMO_ASSERT(conn); /* Assign lchan */ transt->conn = conn; @@ -1747,7 +1411,7 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, case GSM_PAGING_EXPIRED: case GSM_PAGING_BUSY: DEBUGP(DCC, "Paging subscr %s expired!\n", - transt->subscr->extension); + vlr_subscr_msisdn_or_name(transt->vsub)); /* Temporarily out of order */ mncc_release_ind(transt->net, transt, transt->callref, @@ -2008,7 +1672,7 @@ static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge) return -EIO; /* Which subscriber do we want to track trans1 or trans2? */ - log_set_context(LOG_CTX_VLR_SUBSCR, trans1->subscr); + log_set_context(LOG_CTX_VLR_SUBSCR, trans1->vsub); /* through-connect channel */ return tch_map(trans1->conn->lchan, trans2->conn->lchan); @@ -2029,7 +1693,7 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) if (!trans->conn) return 0; - log_set_context(LOG_CTX_VLR_SUBSCR, trans->subscr); + log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub); lchan = trans->conn->lchan; bts = lchan->ts->trx->bts; @@ -2233,9 +1897,8 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) /* use subscriber as calling party number */ setup.fields |= MNCC_F_CALLING; - osmo_strlcpy(setup.calling.number, trans->subscr->extension, - sizeof(setup.calling.number)); - osmo_strlcpy(setup.imsi, trans->subscr->imsi, sizeof(setup.imsi)); + osmo_strlcpy(setup.calling.number, trans->vsub->msisdn, sizeof(setup.calling.number)); + osmo_strlcpy(setup.imsi, trans->vsub->imsi, sizeof(setup.imsi)); /* bearer capability */ if (TLVP_PRESENT(&tp, GSM48_IE_BEARER_CAP)) { @@ -2284,7 +1947,7 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) new_cc_state(trans, GSM_CSTATE_INITIATED); LOGP(DCC, LOGL_INFO, "Subscriber %s (%s) sends SETUP to %s\n", - subscr_name(trans->subscr), trans->subscr->extension, + vlr_subscr_name(trans->vsub), trans->vsub->msisdn, setup.called.number); rate_ctr_inc(&trans->net->msc_ctrs->ctr[MSC_CTR_CALL_MO_SETUP]); @@ -2321,7 +1984,7 @@ static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg) } /* Get free transaction_id */ - trans_id = trans_assign_trans_id(trans->net, trans->subscr, + trans_id = trans_assign_trans_id(trans->net, trans->vsub, GSM48_PDISC_CC, 0); if (trans_id < 0) { /* no free transaction ID */ @@ -2412,8 +2075,7 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) } /* IMSI of called subscriber */ - osmo_strlcpy(call_conf.imsi, trans->subscr->imsi, - sizeof(call_conf.imsi)); + osmo_strlcpy(call_conf.imsi, trans->vsub->imsi, sizeof(call_conf.imsi)); new_cc_state(trans, GSM_CSTATE_MO_TERM_CALL_CONF); @@ -2566,9 +2228,8 @@ static int gsm48_cc_rx_connect(struct gsm_trans *trans, struct msgb *msg) tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); /* use subscriber as connected party number */ connect.fields |= MNCC_F_CONNECTED; - osmo_strlcpy(connect.connected.number, trans->subscr->extension, - sizeof(connect.connected.number)); - osmo_strlcpy(connect.imsi, trans->subscr->imsi, sizeof(connect.imsi)); + osmo_strlcpy(connect.connected.number, trans->vsub->msisdn, sizeof(connect.connected.number)); + osmo_strlcpy(connect.imsi, trans->vsub->imsi, sizeof(connect.imsi)); /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { @@ -3365,7 +3026,7 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref) mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE); return -EIO; } - log_set_context(LOG_CTX_VLR_SUBSCR, trans->subscr); + log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub); if (!trans->conn) { LOGP(DMNCC, LOGL_NOTICE, "RTP create for trans without conn\n"); mncc_recv_rtp_err(net, callref, MNCC_RTP_CREATE); @@ -3421,7 +3082,7 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg) mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT); return -EIO; } - log_set_context(LOG_CTX_VLR_SUBSCR, trans->subscr); + log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub); if (!trans->conn) { LOGP(DMNCC, LOGL_ERROR, "RTP connect for trans without conn\n"); mncc_recv_rtp_err(net, rtp->callref, MNCC_RTP_CONNECT); @@ -3598,7 +3259,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) LOGP(DMNCC, LOGL_ERROR, "TCH frame for non-existing trans\n"); return -EIO; } - log_set_context(LOG_CTX_VLR_SUBSCR, trans->subscr); + log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub); if (!trans->conn) { LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n"); return 0; @@ -3642,7 +3303,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) /* Callref unknown */ if (!trans) { - struct gsm_subscriber *subscr; + struct vlr_subscr *vsub; if (msg_type != MNCC_SETUP_REQ) { DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " @@ -3665,17 +3326,16 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) } /* New transaction due to setup, find subscriber */ if (data->called.number[0]) - subscr = subscr_get_by_extension(net->subscr_group, - data->called.number); + vsub = vlr_subscr_find_by_msisdn(net->vlr, + data->called.number); else - subscr = subscr_get_by_imsi(net->subscr_group, - data->imsi); + vsub = vlr_subscr_find_by_imsi(net->vlr, data->imsi); /* update the subscriber we deal with */ - log_set_context(LOG_CTX_VLR_SUBSCR, subscr); + log_set_context(LOG_CTX_VLR_SUBSCR, vsub); /* If subscriber is not found */ - if (!subscr) { + if (!vsub) { DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " "Received '%s' from MNCC with " "unknown subscriber %s\n", data->called.number, @@ -3686,22 +3346,22 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) GSM48_CC_CAUSE_UNASSIGNED_NR); } /* If subscriber is not "attached" */ - if (!subscr->lac) { + if (!vsub->lac) { DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " "Received '%s' from MNCC with " "detached subscriber %s\n", data->called.number, get_mncc_name(msg_type), data->called.number); - subscr_put(subscr); + vlr_subscr_put(vsub); /* Temporarily out of order */ return mncc_release_ind(net, NULL, data->callref, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_DEST_OOO); } /* Create transaction */ - trans = trans_alloc(net, subscr, GSM48_PDISC_CC, 0xff, data->callref); + trans = trans_alloc(net, vsub, GSM48_PDISC_CC, 0xff, data->callref); if (!trans) { DEBUGP(DCC, "No memory for trans.\n"); - subscr_put(subscr); + vlr_subscr_put(vsub); /* Ressource unavailable */ mncc_release_ind(net, NULL, data->callref, GSM48_CAUSE_LOC_PRN_S_LU, @@ -3709,7 +3369,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) return -ENOMEM; } /* Find lchan */ - conn = connection_for_subscr(subscr); + conn = connection_for_subscr(vsub); /* If subscriber has no lchan */ if (!conn) { @@ -3717,15 +3377,15 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) llist_for_each_entry(transt, &net->trans_list, entry) { /* Transaction of our lchan? */ if (transt == trans || - transt->subscr != subscr) + transt->vsub != vsub) continue; DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " "Received '%s' from MNCC with " "unallocated channel, paging already " "started for lac %d.\n", data->called.number, - get_mncc_name(msg_type), subscr->lac); - subscr_put(subscr); + get_mncc_name(msg_type), vsub->lac); + vlr_subscr_put(vsub); trans_free(trans); return 0; } @@ -3733,24 +3393,26 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) memcpy(&trans->cc.msg, data, sizeof(struct gsm_mncc)); /* Request a channel */ - trans->paging_request = subscr_request_channel(subscr, - RSL_CHANNEED_TCH_F, setup_trig_pag_evt, + trans->paging_request = subscr_request_channel( + vsub, + RSL_CHANNEED_TCH_F, + setup_trig_pag_evt, trans); if (!trans->paging_request) { LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n"); - subscr_put(subscr); + vlr_subscr_put(vsub); trans_free(trans); return 0; } - subscr_put(subscr); + vlr_subscr_put(vsub); return 0; } /* Assign lchan */ trans->conn = subscr_con_get(conn); - subscr_put(subscr); + vlr_subscr_put(vsub); } else { /* update the subscriber we deal with */ - log_set_context(LOG_CTX_VLR_SUBSCR, trans->subscr); + log_set_context(LOG_CTX_VLR_SUBSCR, trans->vsub); } if (trans->conn) @@ -3760,7 +3422,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) if (!conn) { DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " "Received '%s' from MNCC in paging state\n", - (trans->subscr)?(trans->subscr->extension):"-", + vlr_subscr_msisdn_or_name(trans->vsub), get_mncc_name(msg_type)); mncc_set_cause(&rel, GSM48_CAUSE_LOC_PRN_S_LU, GSM48_CC_CAUSE_NORM_CALL_CLEAR); @@ -3777,7 +3439,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) "Received '%s' from MNCC in state %d (%s)\n", conn->bts->nr, conn->lchan->ts->trx->nr, conn->lchan->ts->nr, trans->transaction_id, - (trans->conn->subscr)?(trans->conn->subscr->extension):"-", + vlr_subscr_msisdn_or_name(trans->conn->vsub), get_mncc_name(msg_type), trans->cc.state, gsm48_cc_state_name(trans->cc.state)); @@ -3864,8 +3526,8 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m return -EINVAL; } - if (!conn->subscr) { - LOGP(DCC, LOGL_ERROR, "Invalid conn, no subscriber\n"); + if (!conn->vsub) { + LOGP(DCC, LOGL_ERROR, "Invalid conn: no subscriber\n"); return -EINVAL; } @@ -3875,7 +3537,7 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) " "Received '%s' from MS in state %d (%s)\n", conn->bts->nr, conn->lchan->ts->trx->nr, conn->lchan->ts->nr, - transaction_id, (conn->subscr)?(conn->subscr->extension):"-", + transaction_id, vlr_subscr_msisdn_or_name(trans->conn->vsub), gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0, gsm48_cc_state_name(trans?(trans->cc.state):0)); @@ -3884,7 +3546,7 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m DEBUGP(DCC, "Unknown transaction ID %x, " "creating new trans.\n", transaction_id); /* Create transaction */ - trans = trans_alloc(conn->network, conn->subscr, + trans = trans_alloc(conn->network, conn->vsub, GSM48_PDISC_CC, transaction_id, new_callref++); if (!trans) { @@ -3908,15 +3570,16 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m return 0; } - assert(trans->subscr); + assert(trans->vsub); rc = datastatelist[i].rout(trans, msg); + msc_subscr_conn_communicating(conn); return rc; } /* Create a dummy to wait five seconds */ -static void release_anchor(struct gsm_subscriber_connection *conn) +void msc_release_anchor(struct gsm_subscriber_connection *conn) { if (!conn->anch_operation) return; @@ -3927,53 +3590,71 @@ static void release_anchor(struct gsm_subscriber_connection *conn) subscr_con_put(conn); } -static void anchor_timeout(void *_data) -{ - struct gsm_subscriber_connection *con = _data; - - release_anchor(con); -} - int gsm0408_new_conn(struct gsm_subscriber_connection *conn) { - conn->anch_operation = talloc_zero(conn, struct gsm_anchor_operation); - if (!conn->anch_operation) - return -1; - - subscr_con_get(conn); - conn->anch_operation->timeout.data = conn; - conn->anch_operation->timeout.cb = anchor_timeout; - osmo_timer_schedule(&conn->anch_operation->timeout, 5, 0); return 0; } -struct gsm_subscriber_connection *msc_subscr_con_allocate(struct gsm_network *network) +static bool msg_is_initially_permitted(const struct gsm48_hdr *hdr) { - struct gsm_subscriber_connection *conn; + uint8_t pdisc = gsm48_hdr_pdisc(hdr); + uint8_t msg_type = gsm48_hdr_msg_type(hdr); - conn = talloc_zero(network, struct gsm_subscriber_connection); - if (!conn) - return NULL; + switch (pdisc) { + case GSM48_PDISC_MM: + switch (msg_type) { + case GSM48_MT_MM_LOC_UPD_REQUEST: + case GSM48_MT_MM_CM_SERV_REQ: + case GSM48_MT_MM_AUTH_RESP: + case GSM48_MT_MM_AUTH_FAIL: + case GSM48_MT_MM_ID_RESP: + case GSM48_MT_MM_TMSI_REALL_COMPL: + case GSM48_MT_MM_IMSI_DETACH_IND: + return true; + default: + break; + } + break; + case GSM48_PDISC_RR: + switch (msg_type) { + case GSM48_MT_RR_CIPH_M_COMPL: + case GSM48_MT_RR_PAG_RESP: + return true; + default: + break; + } + break; + default: + break; + } - conn->network = network; - llist_add_tail(&conn->entry, &network->subscr_conns); - return conn; + return false; } -void msc_subscr_con_free(struct gsm_subscriber_connection *conn) +static void +cm_service_request_concludes(struct gsm_subscriber_connection *conn, + struct msgb *msg) { - if (!conn) + + /* If a CM Service Request was received before, this is the request the + * conn was opened for. No need to wait for further messages. */ + if (!conn->received_cm_service_request) return; - if (conn->subscr) { - subscr_put(conn->subscr); - conn->subscr = NULL; - } + if (log_check_level(DMM, LOGL_DEBUG)) { + struct gsm48_hdr *gh = msgb_l3(msg); + uint8_t pdisc = gsm48_hdr_pdisc(gh); + uint8_t msg_type = gsm48_hdr_msg_type(gh); - llist_del(&conn->entry); - talloc_free(conn); + DEBUGP(DMM, "%s pdisc=%d msg_type=0x%02x:" + " received_cm_service_request changes to false\n", + vlr_subscr_name(conn->vsub), + pdisc, msg_type); + } + conn->received_cm_service_request = false; } + /* Main entry point for GSM 04.08/44.008 Layer 3 data (e.g. from the BSC). */ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) { @@ -3985,14 +3666,33 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) OSMO_ASSERT(msg); LOGP(DRLL, LOGL_DEBUG, "Dispatching 04.08 message, pdisc=%d\n", pdisc); + + if (!msc_subscr_conn_is_accepted(conn) + && !msg_is_initially_permitted(gh)) { + LOGP(DRLL, LOGL_ERROR, + "subscr %s: Message not permitted for initial conn:" + " pdisc=0x%02x msg_type=0x%02x\n", + vlr_subscr_name(conn->vsub), gh->proto_discr, gh->msg_type); + return -EACCES; + } + #if 0 if (silent_call_reroute(conn, msg)) return silent_call_rx(conn, msg); #endif + /* Should we receive RR messages like an odd UTRAN Classmark Change, + * don't close the CM Service Request initiated conn yet. All others + * constitue a service and the conn can be closed, or something unknown + * is happening and we'd rather close the conn instead of idling around + * (we may add more specific exceptions as they become apparent). */ + if (pdisc != GSM48_PDISC_RR) { + cm_service_request_concludes(conn, msg); + } + switch (pdisc) { case GSM48_PDISC_CC: - release_anchor(conn); + msc_release_anchor(conn); rc = gsm0408_rcv_cc(conn, msg); break; case GSM48_PDISC_MM: @@ -4002,7 +3702,7 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) rc = gsm0408_rcv_rr(conn, msg); break; case GSM48_PDISC_SMS: - release_anchor(conn); + msc_release_anchor(conn); rc = gsm0411_rcv_sms(conn, msg); break; case GSM48_PDISC_MM_GPRS: @@ -4012,7 +3712,7 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) rc = -ENOTSUP; break; case GSM48_PDISC_NC_SS: - release_anchor(conn); + msc_release_anchor(conn); rc = handle_rcv_ussd(conn, msg); break; default: @@ -4025,6 +3725,165 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) return rc; } +/*********************************************************************** + * VLR integration + ***********************************************************************/ + +/* VLR asks us to send an authentication request */ +static int msc_vlr_tx_auth_req(void *msc_conn_ref, struct gsm_auth_tuple *at, + bool send_autn) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + return gsm48_tx_mm_auth_req(conn, at->vec.rand, + send_autn? at->vec.autn : NULL, + at->key_seq); +} + +/* VLR asks us to send an authentication reject */ +static int msc_vlr_tx_auth_rej(void *msc_conn_ref) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + return gsm48_tx_mm_auth_rej(conn); +} + +/* VLR asks us to transmit an Identity Request of given type */ +static int msc_vlr_tx_id_req(void *msc_conn_ref, uint8_t mi_type) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + return mm_tx_identity_req(conn, mi_type); +} + +/* VLR asks us to transmit a Location Update Accept */ +static int msc_vlr_tx_lu_acc(void *msc_conn_ref, uint32_t send_tmsi) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + return gsm0408_loc_upd_acc(conn, send_tmsi); +} + +/* VLR asks us to transmit a Location Update Reject */ +static int msc_vlr_tx_lu_rej(void *msc_conn_ref, uint8_t cause) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + return gsm0408_loc_upd_rej(conn, cause); +} + +/* VLR asks us to transmit a CM Service Accept */ +static int msc_vlr_tx_cm_serv_acc(void *msc_conn_ref) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + return gsm48_tx_mm_serv_ack(conn); +} + +/* VLR asks us to transmit a CM Service Reject */ +static int msc_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum vlr_proc_arq_result result) +{ + uint8_t cause; + struct gsm_subscriber_connection *conn = msc_conn_ref; + + switch (result) { + default: + case VLR_PR_ARQ_RES_NONE: + case VLR_PR_ARQ_RES_SYSTEM_FAILURE: + case VLR_PR_ARQ_RES_UNKNOWN_ERROR: + cause = GSM48_REJECT_NETWORK_FAILURE; + break; + case VLR_PR_ARQ_RES_ILLEGAL_SUBSCR: + cause = GSM48_REJECT_LOC_NOT_ALLOWED; + break; + case VLR_PR_ARQ_RES_UNIDENT_SUBSCR: + cause = GSM48_REJECT_INVALID_MANDANTORY_INF; + break; + case VLR_PR_ARQ_RES_ROAMING_NOTALLOWED: + cause = GSM48_REJECT_ROAMING_NOT_ALLOWED; + break; + case VLR_PR_ARQ_RES_ILLEGAL_EQUIP: + cause = GSM48_REJECT_ILLEGAL_MS; + break; + case VLR_PR_ARQ_RES_TIMEOUT: + cause = GSM48_REJECT_CONGESTION; + break; + }; + + return gsm48_tx_mm_serv_rej(conn, cause); +} + +/* VLR asks us to start using ciphering */ +static int msc_vlr_set_ciph_mode(void *msc_conn_ref, + enum vlr_ciph ciph, + bool retrieve_imeisv) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + struct vlr_subscr *vsub; + struct gsm_auth_tuple *tuple; + + if (!conn || !conn->vsub) { + LOGP(DMM, LOGL_ERROR, "Cannot send Ciphering Mode Command to" + " NULL conn/subscriber"); + return -EINVAL; + } + + vsub = conn->vsub; + tuple = vsub->last_tuple; + + if (!tuple) { + LOGP(DMM, LOGL_ERROR, "subscr %s: Cannot send Ciphering Mode" + " Command: no auth tuple available\n", + vlr_subscr_name(vsub)); + return -EINVAL; + } + + /* TODO: MSCSPLIT: don't directly push BSC buttons */ + return gsm0808_cipher_mode(conn, ciph, tuple->vec.kc, 8, + retrieve_imeisv); +} + +/* VLR informs us that the subscriber data has somehow been modified */ +static void msc_vlr_subscr_update(struct vlr_subscr *subscr) +{ + /* FIXME */ +} + +/* VLR informs us that the subscriber has been associated with a conn */ +static void msc_vlr_subscr_assoc(void *msc_conn_ref, + struct vlr_subscr *vsub) +{ + struct gsm_subscriber_connection *conn = msc_conn_ref; + OSMO_ASSERT(!conn->vsub); + conn->vsub = vlr_subscr_get(vsub); +} + +/* operations that we need to implement for libvlr */ +static const struct vlr_ops msc_vlr_ops = { + .tx_auth_req = msc_vlr_tx_auth_req, + .tx_auth_rej = msc_vlr_tx_auth_rej, + .tx_id_req = msc_vlr_tx_id_req, + .tx_lu_acc = msc_vlr_tx_lu_acc, + .tx_lu_rej = msc_vlr_tx_lu_rej, + .tx_cm_serv_acc = msc_vlr_tx_cm_serv_acc, + .tx_cm_serv_rej = msc_vlr_tx_cm_serv_rej, + .set_ciph_mode = msc_vlr_set_ciph_mode, + .subscr_update = msc_vlr_subscr_update, + .subscr_assoc = msc_vlr_subscr_assoc, +}; + +/* Allocate net->vlr so that the VTY may configure the VLR's data structures */ +int msc_vlr_alloc(struct gsm_network *net) +{ + net->vlr = vlr_alloc(net, &msc_vlr_ops); + if (!net->vlr) + return -ENOMEM; + net->vlr->user_ctx = net; + return 0; +} + +/* Launch the VLR, i.e. its GSUP connection */ +int msc_vlr_start(struct gsm_network *net) +{ + OSMO_ASSERT(net->vlr); + return vlr_start(net->vlr, net->gsup_server_addr_str, + net->gsup_server_port); +} + /* * This will be run by the linker when loading the DSO. We use it to * do system initialization, e.g. registration of signal handlers. diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index e395cd428..27dee1047 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -57,6 +57,7 @@ #include #include #include +#include #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; diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index 1a03cf76e..20c02c6b3 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -39,11 +39,10 @@ #include #include #include +#include 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 *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) +struct gsm_subscriber_connection *connection_for_subscr(struct vlr_subscr *vsub) { - /* 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; } diff --git a/openbsc/src/libmsc/meas_feed.c b/openbsc/src/libmsc/meas_feed.c index 3ddcdc39c..1e7b4cd51 100644 --- a/openbsc/src/libmsc/meas_feed.c +++ b/openbsc/src/libmsc/meas_feed.c @@ -18,6 +18,7 @@ #include #include #include +#include #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 */ diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c index 92bc84650..597577ea8 100644 --- a/openbsc/src/libmsc/osmo_msc.c +++ b/openbsc/src/libmsc/osmo_msc.c @@ -25,9 +25,12 @@ #include #include #include +#include +#include #include +/* 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; - - DEBUGP(DRR, "CIPHERING MODE COMPLETE\n"); + 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 }; + + if (!gh) { + LOGP(DRR, LOGL_ERROR, "invalid: msgb without l3 header\n"); + return; + } - /* Safety check */ - if (!conn->sec_operation) { - DEBUGP(DRR, "No authentication/cipher operation in progress !!!\n"); + 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; } - /* FIXME: check for MI (if any) */ + DEBUGP(DRR, "%s: CIPHERING MODE COMPLETE\n", + vlr_subscr_name(conn->vsub)); - /* 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); + 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; + } } - /* Complete the operation */ - release_security_operation(conn); + 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); - - if (conn->use_count == 0) { - msc_release_connection(conn); - } + 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 0 + if (conn->use_count == 0 && conn->conn_fsm) + osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_MO_CLOSE, NULL); +#endif } diff --git a/openbsc/src/libmsc/rrlp.c b/openbsc/src/libmsc/rrlp.c index e695daac7..cd3da066b 100644 --- a/openbsc/src/libmsc/rrlp.c +++ b/openbsc/src/libmsc/rrlp.c @@ -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); diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c index 2e9fd5123..133d42075 100644 --- a/openbsc/src/libmsc/silent_call.c +++ b/openbsc/src/libmsc/silent_call.c @@ -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; diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c index 2703a24b0..77bf379df 100644 --- a/openbsc/src/libmsc/smpp_openbsc.c +++ b/openbsc/src/libmsc/smpp_openbsc.c @@ -44,31 +44,32 @@ #include #include #include +#include #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; diff --git a/openbsc/src/libmsc/sms_queue.c b/openbsc/src/libmsc/sms_queue.c index ebc53c239..e3b554d88 100644 --- a/openbsc/src/libmsc/sms_queue.c +++ b/openbsc/src/libmsc/sms_queue.c @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -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); } diff --git a/openbsc/src/libmsc/subscr_conn.c b/openbsc/src/libmsc/subscr_conn.c index 91ffe4069..fbbecd6bb 100644 --- a/openbsc/src/libmsc/subscr_conn.c +++ b/openbsc/src/libmsc/subscr_conn.c @@ -23,19 +23,24 @@ #include #include +#include #include #include #include #include +#include + +#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); diff --git a/openbsc/src/libmsc/token_auth.c b/openbsc/src/libmsc/token_auth.c index 5af1e980b..9d9ed1e84 100644 --- a/openbsc/src/libmsc/token_auth.c +++ b/openbsc/src/libmsc/token_auth.c @@ -19,6 +19,9 @@ * */ +#if 0 +VLR: what do do with this? + #include #include #include @@ -28,6 +31,7 @@ #include #include #include +#include #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 diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c index 4d0cdb1c3..071acbc36 100644 --- a/openbsc/src/libmsc/transaction.c +++ b/openbsc/src/libmsc/transaction.c @@ -23,25 +23,31 @@ #include #include #include -#include #include #include #include #include +#include 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); + } +} diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c index a27b16376..8c7700b11 100644 --- a/openbsc/src/libmsc/ussd.c +++ b/openbsc/src/libmsc/ussd.c @@ -33,6 +33,7 @@ #include #include #include +#include /* 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); diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index 1bc9372a6..5ed0b0fe1 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -51,74 +51,78 @@ #include #include #include +#include #include +#include + #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); diff --git a/openbsc/src/libvlr/vlr_access_req_fsm.c b/openbsc/src/libvlr/vlr_access_req_fsm.c index f1d96a81e..1ccc37792 100644 --- a/openbsc/src/libvlr/vlr_access_req_fsm.c +++ b/openbsc/src/libvlr/vlr_access_req_fsm.c @@ -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" diff --git a/openbsc/src/osmo-nitb/bsc_hack.c b/openbsc/src/osmo-nitb/bsc_hack.c index dd90b8b4f..10f152bae 100644 --- a/openbsc/src/osmo-nitb/bsc_hack.c +++ b/openbsc/src/osmo-nitb/bsc_hack.c @@ -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; diff --git a/openbsc/tests/Makefile.am b/openbsc/tests/Makefile.am index 9cbc1c172..a40ee4fa3 100644 --- a/openbsc/tests/Makefile.am +++ b/openbsc/tests/Makefile.am @@ -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 diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am index ca470ace4..c7164b475 100644 --- a/openbsc/tests/channel/Makefile.am +++ b/openbsc/tests/channel/Makefile.am @@ -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) \ diff --git a/openbsc/tests/channel/channel_test.c b/openbsc/tests/channel/channel_test.c index 88293d0a8..2c3b44e47 100644 --- a/openbsc/tests/channel/channel_test.c +++ b/openbsc/tests/channel/channel_test.c @@ -29,6 +29,7 @@ #include #include #include +#include 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; diff --git a/openbsc/tests/db/db_test.c b/openbsc/tests/db/db_test.c index 755a6e9eb..a54f11b26 100644 --- a/openbsc/tests/db/db_test.c +++ b/openbsc/tests/db/db_test.c @@ -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() {} diff --git a/openbsc/tests/mm_auth/mm_auth_test.c b/openbsc/tests/mm_auth/mm_auth_test.c index b8777a8c5..f620385f9 100644 --- a/openbsc/tests/mm_auth/mm_auth_test.c +++ b/openbsc/tests/mm_auth/mm_auth_test.c @@ -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; } diff --git a/openbsc/tests/mm_auth/mm_auth_test.ok b/openbsc/tests/mm_auth/mm_auth_test.ok index 6c49f97b7..37b1289be 100644 --- a/openbsc/tests/mm_auth/mm_auth_test.ok +++ b/openbsc/tests/mm_auth/mm_auth_test.ok @@ -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! diff --git a/openbsc/tests/subscr/Makefile.am b/openbsc/tests/subscr/Makefile.am index 6342444ff..5b770bcb2 100644 --- a/openbsc/tests/subscr/Makefile.am +++ b/openbsc/tests/subscr/Makefile.am @@ -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) diff --git a/openbsc/tests/subscr/subscr_test.c b/openbsc/tests/subscr/subscr_test.c deleted file mode 100644 index 2a5d0e1c2..000000000 --- a/openbsc/tests/subscr/subscr_test.c +++ /dev/null @@ -1,117 +0,0 @@ -/* (C) 2008 by Jan Luebbe - * (C) 2009 by Holger Hans Peter Freyther - * (C) 2014 by Alexander Chemeris - * 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 . - * - */ - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include - -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; -} diff --git a/openbsc/tests/subscr/subscr_test.ok b/openbsc/tests/subscr/subscr_test.ok deleted file mode 100644 index 72a376944..000000000 --- a/openbsc/tests/subscr/subscr_test.ok +++ /dev/null @@ -1,3 +0,0 @@ -Testing subscriber core code. -Test subscriber allocation and deletion -Done diff --git a/openbsc/tests/testsuite.at b/openbsc/tests/testsuite.at index 280aeb2ed..cc627dc18 100644 --- a/openbsc/tests/testsuite.at +++ b/openbsc/tests/testsuite.at @@ -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 diff --git a/openbsc/tests/vty_test_runner.py b/openbsc/tests/vty_test_runner.py index 3f4909cb5..f45f5703c 100644 --- a/openbsc/tests/vty_test_runner.py +++ b/openbsc/tests/vty_test_runner.py @@ -248,8 +248,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): @@ -365,42 +367,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() @@ -410,118 +376,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]) - - # 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) + self.assertTrue(self.vty.verify('show subscriber imsi '+imsi, ['% No subscriber found for imsi '+imsi])) - # 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") -- cgit v1.2.3