aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/configure.ac1
-rw-r--r--openbsc/include/openbsc/abis_rsl.h1
-rw-r--r--openbsc/include/openbsc/auth.h4
-rw-r--r--openbsc/include/openbsc/bsc_api.h3
-rw-r--r--openbsc/include/openbsc/chan_alloc.h2
-rw-r--r--openbsc/include/openbsc/db.h36
-rw-r--r--openbsc/include/openbsc/debug.h6
-rw-r--r--openbsc/include/openbsc/gsm_04_08.h1
-rw-r--r--openbsc/include/openbsc/gsm_04_11.h8
-rw-r--r--openbsc/include/openbsc/gsm_data.h78
-rw-r--r--openbsc/include/openbsc/gsm_data_shared.h1
-rw-r--r--openbsc/include/openbsc/gsm_subscriber.h92
-rw-r--r--openbsc/include/openbsc/osmo_msc.h68
-rw-r--r--openbsc/include/openbsc/signal.h4
-rw-r--r--openbsc/include/openbsc/silent_call.h4
-rw-r--r--openbsc/include/openbsc/transaction.h7
-rw-r--r--openbsc/include/openbsc/vlr.h6
-rw-r--r--openbsc/include/openbsc/vty.h1
-rw-r--r--openbsc/src/libbsc/abis_rsl.c2
-rw-r--r--openbsc/src/libbsc/bsc_api.c10
-rw-r--r--openbsc/src/libbsc/bsc_init.c7
-rw-r--r--openbsc/src/libbsc/bsc_vty.c37
-rw-r--r--openbsc/src/libbsc/handover_logic.c3
-rw-r--r--openbsc/src/libbsc/paging.c1
-rw-r--r--openbsc/src/libcommon-cs/common_cs.c7
-rw-r--r--openbsc/src/libcommon-cs/common_cs_vty.c22
-rw-r--r--openbsc/src/libcommon/debug.c28
-rw-r--r--openbsc/src/libcommon/gsm_data.c10
-rw-r--r--openbsc/src/libcommon/gsm_subscriber_base.c141
-rw-r--r--openbsc/src/libcommon/gsup_client.c8
-rw-r--r--openbsc/src/libmsc/Makefile.am1
-rw-r--r--openbsc/src/libmsc/auth.c115
-rw-r--r--openbsc/src/libmsc/ctrl_commands.c174
-rw-r--r--openbsc/src/libmsc/db.c970
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c1167
-rw-r--r--openbsc/src/libmsc/gsm_04_11.c51
-rw-r--r--openbsc/src/libmsc/gsm_subscriber.c265
-rw-r--r--openbsc/src/libmsc/meas_feed.c11
-rw-r--r--openbsc/src/libmsc/osmo_msc.c247
-rw-r--r--openbsc/src/libmsc/rrlp.c6
-rw-r--r--openbsc/src/libmsc/silent_call.c8
-rw-r--r--openbsc/src/libmsc/smpp_openbsc.c53
-rw-r--r--openbsc/src/libmsc/sms_queue.c64
-rw-r--r--openbsc/src/libmsc/subscr_conn.c146
-rw-r--r--openbsc/src/libmsc/token_auth.c15
-rw-r--r--openbsc/src/libmsc/transaction.c66
-rw-r--r--openbsc/src/libmsc/ussd.c7
-rw-r--r--openbsc/src/libmsc/vty_interface_layer3.c540
-rw-r--r--openbsc/src/libvlr/vlr_access_req_fsm.c1
-rw-r--r--openbsc/src/osmo-nitb/bsc_hack.c18
-rw-r--r--openbsc/tests/Makefile.am3
-rw-r--r--openbsc/tests/channel/Makefile.am1
-rw-r--r--openbsc/tests/channel/channel_test.c27
-rw-r--r--openbsc/tests/db/db_test.c7
-rw-r--r--openbsc/tests/mm_auth/mm_auth_test.c266
-rw-r--r--openbsc/tests/mm_auth/mm_auth_test.ok41
-rw-r--r--openbsc/tests/subscr/Makefile.am18
-rw-r--r--openbsc/tests/subscr/subscr_test.c117
-rw-r--r--openbsc/tests/subscr/subscr_test.ok3
-rw-r--r--openbsc/tests/testsuite.at14
-rw-r--r--openbsc/tests/vty_test_runner.py150
61 files changed, 1628 insertions, 3543 deletions
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 <osmocom/core/utils.h>
struct gsm_auth_tuple;
-struct gsm_subscriber;
enum auth_action {
AUTH_ERROR = -1, /* Internal error */
@@ -20,7 +19,4 @@ static inline const char *auth_action_str(enum auth_action a)
return get_value_string(auth_action_names, a);
}
-int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple,
- struct gsm_subscriber *subscr, int key_seq);
-
#endif /* _AUTH_H */
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 <osmocom/gsm/protocol/gsm_04_11.h>
+struct vlr_subscr;
+
#define UM_SAPI_SMS 3 /* See GSM 04.05/04.06 */
/* SMS deliver PDU */
@@ -29,10 +31,12 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn, struct msgb *msg);
struct gsm_sms *sms_alloc(void);
void sms_free(struct gsm_sms *sms);
-struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver, struct gsm_subscriber *sender, int dcs, const char *text);
+struct gsm_sms *sms_from_text(struct vlr_subscr *receiver,
+ struct vlr_subscr *sender,
+ int dcs, const char *text);
void _gsm411_sms_trans_free(struct gsm_trans *trans);
-int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
+int gsm411_send_sms_subscr(struct vlr_subscr *vsub,
struct gsm_sms *sms);
int gsm411_send_sms(struct gsm_subscriber_connection *conn,
struct gsm_sms *sms);
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]
@@ -63,20 +65,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
*/
struct gsm_security_operation {
@@ -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 <osmocom/core/fsm.h>
+
+#include <openbsc/gsm_data.h>
+
#include "bsc_api.h"
+#define MSC_HLR_REMOTE_IP_DEFAULT "127.0.0.1"
+#define MSC_HLR_REMOTE_PORT_DEFAULT 2222
+
+enum subscr_conn_fsm_event {
+ /* Mark 0 as invalid to catch uninitialized vars */
+ SUBSCR_CONN_E_INVALID = 0,
+ /* Timeout on connection establishment starts */
+ SUBSCR_CONN_E_START,
+ /* LU or Process Access FSM has determined that this conn is good */
+ SUBSCR_CONN_E_ACCEPTED,
+ /* received first reply from MS in "real" CC, SMS, USSD communication */
+ SUBSCR_CONN_E_COMMUNICATING,
+ /* Some async action has completed, check again whether all is done */
+ SUBSCR_CONN_E_BUMP,
+ /* MS/BTS/BSC originated close request */
+ SUBSCR_CONN_E_MO_CLOSE,
+ /* MSC originated close request, e.g. failed authentication */
+ SUBSCR_CONN_E_CN_CLOSE,
+};
+
+enum subscr_conn_fsm_state {
+ SUBSCR_CONN_S_INIT,
+ SUBSCR_CONN_S_NEW,
+ SUBSCR_CONN_S_ACCEPTED,
+ SUBSCR_CONN_S_COMMUNICATING,
+ SUBSCR_CONN_S_RELEASED,
+};
+
+enum subscr_conn_from {
+ SUBSCR_CONN_FROM_INVALID,
+ SUBSCR_CONN_FROM_LU,
+ SUBSCR_CONN_FROM_CM_SERVICE_REQ,
+ SUBSCR_CONN_FROM_PAGING_RESP,
+};
+
+extern const struct value_string subscr_conn_from_names[];
+static inline const char *subscr_conn_from_name(enum subscr_conn_from val)
+{
+ return get_value_string(subscr_conn_from_names, val);
+}
+
+void msc_subscr_conn_init(void);
+
struct bsc_api *msc_bsc_api();
-struct gsm_subscriber_connection *subscr_con_get(struct gsm_subscriber_connection *conn);
-void subscr_con_put(struct gsm_subscriber_connection *conn);
+#define subscr_con_get(conn) _subscr_con_get(conn, __BASE_FILE__, __LINE__)
+struct gsm_subscriber_connection *
+_subscr_con_get(struct gsm_subscriber_connection *conn,
+ const char *file, int line);
+#define subscr_con_put(conn) _subscr_con_put(conn, __BASE_FILE__, __LINE__)
+void _subscr_con_put(struct gsm_subscriber_connection *conn, const char *file,
+ int line);
+
+int msc_create_conn_fsm(struct gsm_subscriber_connection *conn, const char *id);
+
+int msc_vlr_alloc(struct gsm_network *net);
+int msc_vlr_start(struct gsm_network *net);
+
+void msc_close_connection(struct gsm_subscriber_connection *conn);
+
+bool msc_subscr_conn_is_accepted(struct gsm_subscriber_connection *conn);
+void msc_subscr_conn_communicating(struct gsm_subscriber_connection *conn);
+
+void msc_release_anchor(struct gsm_subscriber_connection *conn);
#endif
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 <openbsc/gsm_subscriber.h>
+struct log_target;
+
/* from 3s to 10s */
#define GSM_29002_TIMER_S 10
/* from 15s to 30s */
@@ -19,7 +21,6 @@
/* from 28h to 38h */
#define GSM_29002_TIMER_L (32*60*60)
-
/* VLR subscriber authentication state */
enum vlr_subscr_auth_state {
/* subscriber needs to be autenticated */
@@ -402,3 +403,6 @@ int vlr_set_ciph_mode(struct vlr_instance *vlr,
void *msc_conn_ref,
enum vlr_ciph ciph_mode,
bool retrieve_imeisv);
+
+void log_set_filter_vlr_subscr(struct log_target *target,
+ struct vlr_subscr *vlr_subscr);
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 <openbsc/debug.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/trau_mux.h>
+#include <openbsc/vlr.h>
#include <osmocom/gsm/protocol/gsm_08_08.h>
#include <osmocom/gsm/gsm48.h>
@@ -262,13 +263,14 @@ void bsc_subscr_con_free(struct gsm_subscriber_connection *conn)
if (!conn)
return;
+ if (conn->network->bsc_api->conn_cleanup)
+ conn->network->bsc_api->conn_cleanup(conn);
- if (conn->subscr) {
- subscr_put(conn->subscr);
- conn->subscr = NULL;
+ if (conn->vsub) {
+ LOGP(DNM, LOGL_ERROR, "conn->vsub should have been cleared.\n");
+ conn->vsub = NULL;
}
-
if (conn->ho_lchan) {
LOGP(DNM, LOGL_ERROR, "The ho_lchan should have been cleared.\n");
conn->ho_lchan->conn = NULL;
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 <osmocom/gsm/sysinfo.h>
#include <openbsc/e1_config.h>
#include <openbsc/common_bsc.h>
+#include <openbsc/osmo_msc.h>
/* global pointer to the gsm network data structure */
extern struct gsm_network *bsc_gsmnet;
@@ -485,6 +486,12 @@ int bsc_network_alloc(mncc_recv_cb_t mncc_recv)
bsc_gsmnet->name_long = talloc_strdup(bsc_gsmnet, "OpenBSC");
bsc_gsmnet->name_short = talloc_strdup(bsc_gsmnet, "OpenBSC");
+ /* TODO: move to libmsc when gsm_network is split between libbsc and
+ * libmsc */
+ bsc_gsmnet->gsup_server_addr_str = talloc_strdup(bsc_gsmnet,
+ MSC_HLR_REMOTE_IP_DEFAULT);
+ bsc_gsmnet->gsup_server_port = MSC_HLR_REMOTE_PORT_DEFAULT;
+
return 0;
}
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 <openbsc/abis_rsl.h>
#include <openbsc/bsc_msc_data.h>
#include <openbsc/osmo_bsc_rf.h>
-
#include <openbsc/common_cs.h>
+#include <openbsc/vlr.h>
#include <inttypes.h>
@@ -791,6 +791,9 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " location updating reject cause %u%s",
gsmnet->reject_cause, VTY_NEWLINE);
vty_out(vty, " encryption a5 %u%s", gsmnet->a5_encryption, VTY_NEWLINE);
+ vty_out(vty, " authentication %s%s",
+ gsmnet->authentication_required ? "required" : "optional",
+ VTY_NEWLINE);
vty_out(vty, " neci %u%s", gsmnet->neci, VTY_NEWLINE);
vty_out(vty, " paging any use tch %d%s", gsmnet->pag_any_tch, VTY_NEWLINE);
vty_out(vty, " rrlp mode %s%s", rrlp_mode_name(gsmnet->rrlp.mode),
@@ -821,8 +824,11 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " timer t3119 %u%s", gsmnet->T3119, VTY_NEWLINE);
vty_out(vty, " timer t3122 %u%s", gsmnet->T3122, VTY_NEWLINE);
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
+ /*
+ TODO: add in libvlr?
vty_out(vty, " subscriber-keep-in-ram %d%s",
gsmnet->subscr_group->keep_subscr, VTY_NEWLINE);
+ */
if (gsmnet->tz.override != 0) {
if (gsmnet->tz.dst)
vty_out(vty, " timezone %d %d %d%s",
@@ -1006,21 +1012,24 @@ DEFUN(show_ts,
return CMD_SUCCESS;
}
-static void subscr_dump_vty(struct vty *vty, struct gsm_subscriber *subscr)
+static void subscr_dump_vty(struct vty *vty, struct vlr_subscr *vsub)
{
- vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
- subscr->authorized, VTY_NEWLINE);
- if (strlen(subscr->name))
- vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
- if (strlen(subscr->extension))
- vty_out(vty, " Extension: %s%s", subscr->extension,
+ OSMO_ASSERT(vsub);
+ if (strlen(vsub->name))
+ vty_out(vty, " Name: '%s'%s", vsub->name, VTY_NEWLINE);
+ if (strlen(vsub->msisdn))
+ vty_out(vty, " Extension: %s%s", vsub->msisdn,
+ VTY_NEWLINE);
+ 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 <osmocom/core/talloc.h>
#include <openbsc/transaction.h>
#include <openbsc/trau_mux.h>
+#include <openbsc/vlr.h>
struct bsc_handover {
struct llist_head list;
@@ -261,7 +262,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
net = new_lchan->ts->trx->bts->network;
LOGP(DHO, LOGL_INFO, "Subscriber %s HO from BTS %u->%u on ARFCN "
- "%u->%u\n", subscr_name(ho->old_lchan->conn->subscr),
+ "%u->%u\n", vlr_subscr_name(ho->old_lchan->conn->vsub),
ho->old_lchan->ts->trx->bts->nr, new_lchan->ts->trx->bts->nr,
ho->old_lchan->ts->trx->arfcn, new_lchan->ts->trx->arfcn);
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 <openbsc/gsm_data.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_api.h>
+#include <openbsc/vlr.h>
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 <osmocom/core/logging.h>
#include <osmocom/gprs/gprs_msgb.h>
#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_subscriber.h>
#include <openbsc/debug.h>
/* default categories */
@@ -175,17 +174,22 @@ static const struct log_info_cat default_categories[] = {
.description = "SCCP User Adaptation Protocol",
.enabled = 1, .loglevel = LOGL_DEBUG,
},
+ [DVLR] = {
+ .name = "DVLR",
+ .description = "Visitor Location Register",
+ .enabled = 1, .loglevel = LOGL_DEBUG,
+ },
};
static int filter_fn(const struct log_context *ctx, struct log_target *tar)
{
- const struct gsm_subscriber *subscr = ctx->ctx[LOG_CTX_VLR_SUBSCR];
+ const struct vlr_subscr *vsub = ctx->ctx[LOG_CTX_VLR_SUBSCR];
const struct bsc_subscr *bsub = ctx->ctx[LOG_CTX_BSC_SUBSCR];
const struct gprs_nsvc *nsvc = ctx->ctx[LOG_CTX_GB_NSVC];
const struct gprs_nsvc *bvc = ctx->ctx[LOG_CTX_GB_BVC];
if ((tar->filter_map & (1 << LOG_FLT_VLR_SUBSCR)) != 0
- && subscr && subscr == tar->filter_data[LOG_FLT_VLR_SUBSCR])
+ && vsub && vsub == tar->filter_data[LOG_FLT_VLR_SUBSCR])
return 1;
if ((tar->filter_map & (1 << LOG_FLT_BSC_SUBSCR)) != 0
@@ -210,21 +214,3 @@ const struct log_info log_info = {
.cat = default_categories,
.num_cat = ARRAY_SIZE(default_categories),
};
-
-void log_set_filter_vlr_subscr(struct log_target *target,
- struct gsm_subscriber *vlr_subscr)
-{
- struct gsm_subscriber **fsub = (void*)&target->filter_data[LOG_FLT_VLR_SUBSCR];
-
- /* free the old data */
- if (*fsub) {
- subscr_put(*fsub);
- *fsub = NULL;
- }
-
- if (vlr_subscr) {
- target->filter_map |= (1 << LOG_FLT_VLR_SUBSCR);
- *fsub = subscr_get(vlr_subscr);
- } else
- target->filter_map &= ~(1 << LOG_FLT_VLR_SUBSCR);
-}
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 <osmocom/core/utils.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/debug.h>
+#include <openbsc/vlr.h>
LLIST_HEAD(active_subscribers);
void *tall_subscr_ctx;
-/* for the gsm_subscriber.c */
-struct llist_head *subscr_bsc_active_subscribers(void)
+/* return static buffer with printable name of VLR subscriber */
+const char *vlr_subscr_name(struct vlr_subscr *vsub)
{
- return &active_subscribers;
-}
-
-
-char *subscr_name(struct gsm_subscriber *subscr)
-{
- if (!subscr)
+ static char buf[32];
+ if (!vsub)
return "unknown";
-
- if (strlen(subscr->name))
- return subscr->name;
-
- return subscr->imsi;
-}
-
-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 <openbsc/gsm_subscriber.h>
#include <openbsc/db.h>
#include <openbsc/debug.h>
+#include <openbsc/vlr.h>
#include <stdbool.h>
-static bool alg_supported(const char *alg)
-{
- /*
- * TODO: share this with the vty_interface and extend to all
- * algorithms supported by libosmocore now. Make it table based
- * as well.
- */
- if (strcasecmp(alg, "none") == 0)
- return true;
- if (strcasecmp(alg, "xor") == 0)
- return true;
- if (strcasecmp(alg, "comp128v1") == 0)
- return true;
- return false;
-}
+static struct gsm_network *msc_ctrl_net = NULL;
static int verify_subscriber_modify(struct ctrl_cmd *cmd, const char *value, void *d)
{
- char *tmp, *imsi, *msisdn, *alg, *ki, *saveptr = NULL;
- int rc = 0;
-
- tmp = talloc_strdup(cmd, value);
- if (!tmp)
- return 1;
-
- imsi = strtok_r(tmp, ",", &saveptr);
- msisdn = strtok_r(NULL, ",", &saveptr);
- alg = strtok_r(NULL, ",", &saveptr);
- ki = strtok_r(NULL, ",", &saveptr);
-
- if (!imsi || !msisdn)
- rc = 1;
- else if (strlen(imsi) > GSM23003_IMSI_MAX_DIGITS)
- rc = 1;
- else if (strlen(msisdn) >= GSM_EXTENSION_LENGTH)
- rc = 1;
- else if (alg) {
- if (!alg_supported(alg))
- rc = 1;
- else if (strcasecmp(alg, "none") != 0 && !ki)
- rc = 1;
- }
-
- talloc_free(tmp);
- return rc;
+ return 0;
}
static int set_subscriber_modify(struct ctrl_cmd *cmd, void *data)
{
- struct gsm_network *net = cmd->node;
- char *tmp, *imsi, *msisdn, *alg, *ki, *saveptr = NULL;
- struct gsm_subscriber* subscr;
- int rc;
-
- tmp = talloc_strdup(cmd, cmd->value);
- if (!tmp)
- return 1;
-
- imsi = strtok_r(tmp, ",", &saveptr);
- msisdn = strtok_r(NULL, ",", &saveptr);
- alg = strtok_r(NULL, ",", &saveptr);
- ki = strtok_r(NULL, ",", &saveptr);
-
- subscr = subscr_get_by_imsi(net->subscr_group, imsi);
- if (!subscr)
- subscr = subscr_create_subscriber(net->subscr_group, imsi);
- if (!subscr)
- goto fail;
-
- subscr->authorized = 1;
- osmo_strlcpy(subscr->extension, msisdn, sizeof(subscr->extension));
-
- /* put it back to the db */
- rc = db_sync_subscriber(subscr);
- db_subscriber_update(subscr);
-
- /* handle optional ciphering */
- if (alg) {
- if (strcasecmp(alg, "none") == 0)
- db_sync_authinfo_for_subscr(NULL, subscr);
- else {
- struct gsm_auth_info ainfo = { 0, };
- /* the verify should make sure that this is okay */
- OSMO_ASSERT(alg);
- OSMO_ASSERT(ki);
-
- if (strcasecmp(alg, "xor") == 0)
- ainfo.auth_algo = AUTH_ALGO_XOR;
- else if (strcasecmp(alg, "comp128v1") == 0)
- ainfo.auth_algo = AUTH_ALGO_COMP128v1;
-
- rc = osmo_hexparse(ki, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
- if (rc < 0) {
- subscr_put(subscr);
- talloc_free(tmp);
- cmd->reply = "Failed to parse KI";
- return CTRL_CMD_ERROR;
- }
-
- ainfo.a3a8_ki_len = rc;
- db_sync_authinfo_for_subscr(&ainfo, subscr);
- rc = 0;
- }
- db_sync_lastauthtuple_for_subscr(NULL, subscr);
- }
- subscr_put(subscr);
-
- talloc_free(tmp);
-
- if (rc != 0) {
- cmd->reply = "Failed to store the record in the DB";
- return CTRL_CMD_ERROR;
- }
-
- cmd->reply = "OK";
- return CTRL_CMD_REPLY;
-
-fail:
- talloc_free(tmp);
- cmd->reply = "Failed to create subscriber";
+ cmd->reply = "Command moved to osmo-hlr, no longer available here";
return CTRL_CMD_ERROR;
}
@@ -155,32 +46,8 @@ CTRL_CMD_DEFINE_WO(subscriber_modify, "subscriber-modify-v1");
static int set_subscriber_delete(struct ctrl_cmd *cmd, void *data)
{
- int was_used = 0;
- int rc;
- struct gsm_subscriber *subscr;
- struct gsm_network *net = cmd->node;
-
- subscr = subscr_get_by_imsi(net->subscr_group, cmd->value);
- if (!subscr) {
- cmd->reply = "Failed to find subscriber";
- return CTRL_CMD_ERROR;
- }
-
- if (subscr->use_count != 1) {
- LOGP(DCTRL, LOGL_NOTICE, "Going to remove active subscriber.\n");
- was_used = 1;
- }
-
- rc = db_subscriber_delete(subscr);
- subscr_put(subscr);
-
- if (rc != 0) {
- cmd->reply = "Failed to remove subscriber";
- return CTRL_CMD_ERROR;
- }
-
- cmd->reply = was_used ? "Removed active subscriber" : "Removed";
- return CTRL_CMD_REPLY;
+ cmd->reply = "Command moved to osmo-hlr, no longer available here";
+ return CTRL_CMD_ERROR;
}
CTRL_CMD_DEFINE_WO_NOVRF(subscriber_delete, "subscriber-delete-v1");
@@ -195,26 +62,35 @@ static int set_subscriber_list(struct ctrl_cmd *cmd, void *d)
return CTRL_CMD_ERROR;
}
-static void list_cb(struct gsm_subscriber *subscr, void *d)
-{
- char **data = (char **) d;
- *data = talloc_asprintf_append(*data, "%s,%s\n",
- subscr->imsi, subscr->extension);
-}
-
static int get_subscriber_list(struct ctrl_cmd *cmd, void *d)
{
+ struct vlr_subscr *vsub;
+
+ if (!msc_ctrl_net) {
+ cmd->reply = "MSC CTRL commands not initialized";
+ return CTRL_CMD_ERROR;
+ }
+
+ if (!msc_ctrl_net->vlr) {
+ cmd->reply = "VLR not initialized";
+ return CTRL_CMD_ERROR;
+ }
+
cmd->reply = talloc_strdup(cmd, "");
- db_subscriber_list_active(list_cb, &cmd->reply);
- printf("%s\n", cmd->reply);
+ llist_for_each_entry(vsub, &msc_ctrl_net->vlr->subscribers, list) {
+ cmd->reply = talloc_asprintf_append(cmd->reply, "%s,%s\n",
+ vsub->imsi, vsub->msisdn);
+ }
+ printf("%s\n", cmd->reply); /* <-- what? */
return CTRL_CMD_REPLY;
}
CTRL_CMD_DEFINE(subscriber_list, "subscriber-list-active-v1");
-int msc_ctrl_cmds_install(void)
+int msc_ctrl_cmds_install(struct gsm_network *net)
{
int rc = 0;
+ msc_ctrl_net = net;
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_subscriber_modify);
rc |= ctrl_cmd_install(CTRL_NODE_ROOT, &cmd_subscriber_delete);
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 <openbsc/gsm_04_11.h>
#include <openbsc/db.h>
#include <openbsc/debug.h>
+#include <openbsc/vlr.h>
#include <osmocom/gsm/protocol/gsm_23_003.h>
#include <osmocom/core/talloc.h>
@@ -43,9 +44,6 @@
#include <openssl/rand.h>
-/* 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, &quoted);
+ 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, &quoted);
- 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, &quoted);
- 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, &quoted);
- 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, &quoted);
- 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 <laforge@gnumonks.org>
+/* (C) 2008-2016 by Harald Welte <laforge@gnumonks.org>
* (C) 2008-2012 by Holger Hans Peter Freyther <zecke@selfish.org>
*
* All Rights Reserved
@@ -58,6 +58,7 @@
#include <openbsc/mncc_int.h>
#include <osmocom/abis/e1_input.h>
#include <osmocom/core/bitvec.h>
+#include <openbsc/vlr.h>
#include <osmocom/gsm/gsm48.h>
#include <osmocom/gsm/gsm0480.h>
@@ -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;
@@ -925,55 +686,6 @@ int gsm48_tx_mm_auth_rej(struct gsm_subscriber_connection *conn)
}
/*
- * 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
* we require otherwsie reject with INCORRECT_MESSAGE
@@ -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 <openbsc/chan_alloc.h>
#include <openbsc/bsc_api.h>
#include <openbsc/osmo_msc.h>
+#include <openbsc/vlr.h>
#ifdef BUILD_SMPP
#include "smpp_smsc.h"
@@ -75,7 +76,7 @@ void sms_free(struct gsm_sms *sms)
{
/* drop references to subscriber structure */
if (sms->receiver)
- subscr_put(sms->receiver);
+ vlr_subscr_put(sms->receiver);
#ifdef BUILD_SMPP
if (sms->smpp.esme)
smpp_esme_put(sms->smpp.esme);
@@ -84,8 +85,8 @@ void sms_free(struct gsm_sms *sms)
talloc_free(sms);
}
-struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver,
- struct gsm_subscriber *sender,
+struct gsm_sms *sms_from_text(struct vlr_subscr *receiver,
+ struct vlr_subscr *sender,
int dcs, const char *text)
{
struct gsm_sms *sms = sms_alloc();
@@ -93,16 +94,16 @@ struct gsm_sms *sms_from_text(struct gsm_subscriber *receiver,
if (!sms)
return NULL;
- sms->receiver = subscr_get(receiver);
+ sms->receiver = vlr_subscr_get(receiver);
osmo_strlcpy(sms->text, text, sizeof(sms->text));
- osmo_strlcpy(sms->src.addr, sender->extension, sizeof(sms->src.addr));
+ osmo_strlcpy(sms->src.addr, sender->msisdn, sizeof(sms->src.addr));
sms->reply_path_req = 0;
sms->status_rep_req = 0;
sms->ud_hdr_ind = 0;
sms->protocol_id = 0; /* implicit */
sms->data_coding_scheme = dcs;
- osmo_strlcpy(sms->dst.addr, receiver->extension, sizeof(sms->dst.addr));
+ osmo_strlcpy(sms->dst.addr, receiver->msisdn, sizeof(sms->dst.addr));
/* Generate user_data */
sms->user_data_len = gsm_7bit_encode_n(sms->user_data, sizeof(sms->user_data),
sms->text, NULL);
@@ -298,7 +299,7 @@ int sms_route_mt_sms(struct gsm_subscriber_connection *conn, struct msgb *msg,
goto try_local;
if (rc < 0) {
LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.",
- subscr_name(conn->subscr), rc);
+ vlr_subscr_name(conn->vsub), rc);
rc = GSM411_RP_CAUSE_MO_TEMP_FAIL;
/* rc will be logged by gsm411_send_rp_error() */
rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[
@@ -311,8 +312,8 @@ try_local:
#endif
/* determine gsms->receiver based on dialled number */
- gsms->receiver = subscr_get_by_extension(conn->network->subscr_group,
- gsms->dst.addr);
+ gsms->receiver = vlr_subscr_find_by_msisdn(conn->network->vlr,
+ gsms->dst.addr);
if (!gsms->receiver) {
#ifdef BUILD_SMPP
/* Avoid a second look-up */
@@ -327,7 +328,7 @@ try_local:
rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_SMS_NO_RECEIVER]);
} else if (rc < 0) {
LOGP(DLSMS, LOGL_ERROR, "%s: SMS delivery error: %d.",
- subscr_name(conn->subscr), rc);
+ vlr_subscr_name(conn->vsub), rc);
rc = GSM411_RP_CAUSE_MO_TEMP_FAIL;
/* rc will be logged by gsm411_send_rp_error() */
rate_ctr_inc(&conn->bts->network->msc_ctrs->ctr[
@@ -466,13 +467,12 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m
}
}
- osmo_strlcpy(gsms->src.addr, conn->subscr->extension,
- sizeof(gsms->src.addr));
+ osmo_strlcpy(gsms->src.addr, conn->vsub->msisdn, sizeof(gsms->src.addr));
LOGP(DLSMS, LOGL_INFO, "RX SMS: Sender: %s, MTI: 0x%02x, VPF: 0x%02x, "
"MR: 0x%02x PID: 0x%02x, DCS: 0x%02x, DA: %s, "
"UserDataLength: 0x%02x, UserData: \"%s\"\n",
- subscr_name(conn->subscr), sms_mti, sms_vpf, gsms->msg_ref,
+ vlr_subscr_name(conn->vsub), sms_mti, sms_vpf, gsms->msg_ref,
gsms->protocol_id, gsms->data_coding_scheme, gsms->dst.addr,
gsms->user_data_len,
sms_alphabet == DCS_7BIT_DEFAULT ? gsms->text :
@@ -629,7 +629,7 @@ static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans,
* the cause and take action depending on it */
LOGP(DLSMS, LOGL_NOTICE, "%s: RX SMS RP-ERROR, cause %d:%d (%s)\n",
- subscr_name(trans->conn->subscr), cause_len, cause,
+ vlr_subscr_name(trans->conn->vsub), cause_len, cause,
get_value_string(gsm411_rp_cause_strs, cause));
if (!sms) {
@@ -799,7 +799,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
int new_trans = 0;
int rc = 0;
- if (!conn->subscr)
+ if (!conn->vsub)
return -EIO;
/* FIXME: send some error message */
@@ -819,7 +819,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
if (!trans) {
DEBUGP(DLSMS, " -> (new transaction)\n");
- trans = trans_alloc(conn->network, conn->subscr,
+ trans = trans_alloc(conn->network, conn->vsub,
GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
@@ -861,6 +861,8 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
}
}
+ msc_subscr_conn_communicating(conn);
+
gsm411_smc_recv(&trans->sms.smc_inst,
(new_trans) ? GSM411_MMSMS_EST_IND : GSM411_MMSMS_DATA_IND,
msg, msg_type);
@@ -881,7 +883,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
int rc;
transaction_id =
- trans_assign_trans_id(conn->network, conn->subscr,
+ trans_assign_trans_id(conn->network, conn->vsub,
GSM48_PDISC_SMS, 0);
if (transaction_id == -1) {
LOGP(DLSMS, LOGL_ERROR, "No available transaction ids\n");
@@ -894,7 +896,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
DEBUGP(DLSMS, "%s()\n", __func__);
/* FIXME: allocate transaction with message reference */
- trans = trans_alloc(conn->network, conn->subscr,
+ trans = trans_alloc(conn->network, conn->vsub,
GSM48_PDISC_SMS,
transaction_id, new_callref++);
if (!trans) {
@@ -989,7 +991,7 @@ static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
/* high-level function to send a SMS to a given subscriber. The function
* will take care of paging the subscriber, establishing the RLL SAPI3
* connection, etc. */
-int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
+int gsm411_send_sms_subscr(struct vlr_subscr *vsub,
struct gsm_sms *sms)
{
struct gsm_subscriber_connection *conn;
@@ -997,18 +999,18 @@ int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
/* check if we already have an open lchan to the subscriber.
* if yes, send the SMS this way */
- conn = connection_for_subscr(subscr);
+ conn = connection_for_subscr(vsub);
if (conn) {
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS via already open connection %p to %s\n",
- conn, subscr_name(subscr));
+ conn, vlr_subscr_name(vsub));
return gsm411_send_sms(conn, sms);
}
/* if not, we have to start paging */
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n",
- subscr_name(subscr));
- res = subscr_request_channel(subscr, RSL_CHANNEED_SDCCH,
- paging_cb_send_sms, sms);
+ vlr_subscr_name(vsub));
+ res = subscr_request_channel(vsub, RSL_CHANNEED_SDCCH,
+ paging_cb_send_sms, sms);
if (!res) {
send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY);
sms_free(sms);
@@ -1035,6 +1037,7 @@ void _gsm411_sms_trans_free(struct gsm_trans *trans)
}
}
+/* Process incoming SAPI N-REJECT from BSC */
void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn)
{
struct gsm_network *net;
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 <openbsc/signal.h>
#include <openbsc/db.h>
#include <openbsc/chan_alloc.h>
+#include <openbsc/vlr.h>
void *tall_sub_req_ctx;
-extern struct llist_head *subscr_bsc_active_subscribers(void);
-
int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
gsm_cbfn *cb, void *cb_data);
@@ -62,31 +61,35 @@ struct subscr_request {
void *param;
};
-static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp,
- int type, const char *ident)
+static struct bsc_subscr *vlr_subscr_to_bsc_sub(struct llist_head *bsc_subscribers,
+ struct vlr_subscr *vsub)
{
- struct gsm_subscriber *subscr = db_get_subscriber(type, ident);
- if (subscr)
- subscr->group = sgrp;
- return subscr;
+ struct bsc_subscr *sub;
+ /* TODO MSC split -- creating a BSC subscriber directly from MSC data
+ * structures in RAM. At some point the MSC will send a message to the
+ * BSC instead. */
+ sub = bsc_subscr_find_or_create_by_imsi(bsc_subscribers, vsub->imsi);
+ sub->tmsi = vsub->tmsi;
+ sub->lac = vsub->lac;
+ return sub;
}
/*
* We got the channel assigned and can now hand this channel
* over to one of our callbacks.
*/
-static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
- struct msgb *msg, void *data, void *param)
+int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
+ struct msgb *msg, void *data, void *param)
{
struct subscr_request *request, *tmp;
struct gsm_subscriber_connection *conn = data;
- struct gsm_subscriber *subscr = param;
+ struct vlr_subscr *vsub = param;
struct paging_signal_data sig_data;
struct bsc_subscr *bsub;
struct gsm_network *net;
- OSMO_ASSERT(subscr && subscr->is_paging);
- net = subscr->group->net;
+ OSMO_ASSERT(vsub && vsub->cs.is_paging);
+ net = vsub->vlr->user_ctx;
/*
* Stop paging on all other BTS. E.g. if this is
@@ -95,18 +98,12 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
* and forget we wanted to page.
*/
- /* TODO MSC split -- creating a BSC subscriber directly from MSC data
- * structures in RAM. At some point the MSC will send a message to the
- * BSC instead. */
- bsub = bsc_subscr_find_or_create_by_imsi(net->bsc_subscribers,
- subscr->imsi);
- bsub->tmsi = subscr->tmsi;
- bsub->lac = subscr->lac;
+ bsub = vlr_subscr_to_bsc_sub(conn->network->bsc_subscribers, vsub);
paging_request_stop(&net->bts_list, NULL, bsub, NULL, NULL);
bsc_subscr_put(bsub);
/* Inform parts of the system we don't know */
- sig_data.subscr = subscr;
+ sig_data.vsub = vsub;
sig_data.bts = conn ? conn->bts : NULL;
sig_data.conn = conn;
sig_data.paging_result = event;
@@ -117,15 +114,15 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event,
&sig_data
);
- llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) {
+ llist_for_each_entry_safe(request, tmp, &vsub->cs.requests, entry) {
llist_del(&request->entry);
request->cbfn(hooknum, event, msg, data, request->param);
talloc_free(request);
}
/* balanced with the moment we start paging */
- subscr->is_paging = 0;
- subscr_put(subscr);
+ vsub->cs.is_paging = false;
+ vlr_subscr_put(vsub);
return 0;
}
@@ -176,46 +173,41 @@ static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
return gsm48_secure_channel(conn, pr->key_seq, subscr_paging_sec_cb, param);
}
-struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr,
- int channel_type, gsm_cbfn *cbfn, void *param)
+struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub,
+ int channel_type,
+ gsm_cbfn *cbfn, void *param)
{
int rc;
struct subscr_request *request;
struct bsc_subscr *bsub;
- struct gsm_network *net = subscr->group->net;
+ struct gsm_network *net = vsub->vlr->user_ctx;
/* Start paging.. we know it is async so we can do it before */
- if (!subscr->is_paging) {
+ if (!vsub->cs.is_paging) {
LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n",
- subscr_name(subscr));
- /* TODO MSC split -- creating a BSC subscriber directly from
- * MSC data structures in RAM. At some point the MSC will send
- * a message to the BSC instead. */
- bsub = bsc_subscr_find_or_create_by_imsi(net->bsc_subscribers,
- subscr->imsi);
- bsub->tmsi = subscr->tmsi;
- bsub->lac = subscr->lac;
+ vlr_subscr_name(vsub));
+ bsub = vlr_subscr_to_bsc_sub(net->bsc_subscribers, vsub);
rc = paging_request(net, bsub, channel_type, subscr_paging_cb,
- subscr);
+ vsub);
bsc_subscr_put(bsub);
if (rc <= 0) {
LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n",
- subscr_name(subscr), rc);
+ vlr_subscr_name(vsub), rc);
return NULL;
}
/* reduced on the first paging callback */
- subscr_get(subscr);
- subscr->is_paging = 1;
+ vlr_subscr_get(vsub);
+ vsub->cs.is_paging = true;
}
/* TODO: Stop paging in case of memory allocation failure */
- request = talloc_zero(subscr, struct subscr_request);
+ request = talloc_zero(vsub, struct subscr_request);
if (!request)
return NULL;
request->cbfn = cbfn;
request->param = param;
- llist_add_tail(&request->entry, &subscr->requests);
+ llist_add_tail(&request->entry, &vsub->cs.requests);
return request;
}
@@ -225,196 +217,13 @@ void subscr_remove_request(struct subscr_request *request)
talloc_free(request);
}
-struct gsm_subscriber *subscr_create_subscriber(struct gsm_subscriber_group *sgrp,
- const char *imsi)
-{
- struct gsm_subscriber *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 <openbsc/gsm_subscriber.h>
#include <openbsc/meas_feed.h>
#include <openbsc/vty.h>
+#include <openbsc/vlr.h>
#include "meas_feed.h"
@@ -35,13 +36,13 @@ static int process_meas_rep(struct gsm_meas_rep *mr)
{
struct msgb *msg;
struct meas_feed_meas *mfm;
- struct gsm_subscriber *subscr;
+ struct vlr_subscr *vsub;
/* ignore measurements as long as we don't know who it is */
- if (!mr->lchan || !mr->lchan->conn || !mr->lchan->conn->subscr)
+ if (!mr->lchan || !mr->lchan->conn || !mr->lchan->conn->vsub)
return 0;
- subscr = mr->lchan->conn->subscr;
+ vsub = mr->lchan->conn->vsub;
msg = msgb_alloc(sizeof(struct meas_feed_meas), "Meas. Feed");
if (!msg)
@@ -53,8 +54,8 @@ static int process_meas_rep(struct gsm_meas_rep *mr)
mfm->hdr.version = MEAS_FEED_VERSION;
/* fill in MEAS_FEED_MEAS specific header */
- osmo_strlcpy(mfm->imsi, subscr->imsi, sizeof(mfm->imsi));
- osmo_strlcpy(mfm->name, subscr->name, sizeof(mfm->name));
+ osmo_strlcpy(mfm->imsi, vsub->imsi, sizeof(mfm->imsi));
+ osmo_strlcpy(mfm->name, vsub->name, sizeof(mfm->name));
osmo_strlcpy(mfm->scenario, g_mfs.scenario, sizeof(mfm->scenario));
/* copy the entire measurement report */
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 <openbsc/debug.h>
#include <openbsc/transaction.h>
#include <openbsc/db.h>
+#include <openbsc/vlr.h>
+#include <openbsc/osmo_msc.h>
#include <openbsc/gsm_04_11.h>
+/* Receive a SAPI-N-REJECT from BSC */
static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
{
int sapi = dlci & 0x7;
@@ -36,18 +39,52 @@ static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
gsm411_sapi_n_reject(conn);
}
+/* Receive a CLEAR REQUEST from BSC */
static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
{
gsm0408_clear_request(conn, cause);
return 1;
}
+static bool keep_conn(struct gsm_subscriber_connection *conn)
+{
+ /* TODO: what about a silent call? */
+
+ if (!conn->conn_fsm) {
+ DEBUGP(DMM, "No conn_fsm, release conn\n");
+ return false;
+ }
+
+ switch (conn->conn_fsm->state) {
+ case SUBSCR_CONN_S_NEW:
+ case SUBSCR_CONN_S_ACCEPTED:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Receive a COMPLETE LAYER3 INFO from BSC */
static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg,
uint16_t chosen_channel)
{
gsm0408_new_conn(conn);
gsm0408_dispatch(conn, msg);
+ /* NOTE: after the MSC split, returning BSC_API_CONN_POL_REJECT shall
+ * be replaced with a call to msc_subscr_con_free() */
+
+ if (!keep_conn(conn)) {
+ DEBUGP(DMM, "compl_l3: Discarding conn\n");
+ return BSC_API_CONN_POL_REJECT;
+ }
+ DEBUGP(DMM, "compl_l3: Keeping conn\n");
+ conn->owned_by_msc = true;
+ DEBUGP(DMM, "%s owned_by_msc = true\n",
+ vlr_subscr_name(conn->vsub));
+ return BSC_API_CONN_POL_ACCEPT;
+
+#if 0
/*
* If this is a silent call we want the channel to remain open as long as
* possible and this is why we accept this connection regardless of any
@@ -55,20 +92,38 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg
*/
if (conn->silent_call)
return BSC_API_CONN_POL_ACCEPT;
- if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
+ if (conn->sec_operation || conn->anch_operation)
return BSC_API_CONN_POL_ACCEPT;
if (trans_has_conn(conn))
return BSC_API_CONN_POL_ACCEPT;
LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n");
return BSC_API_CONN_POL_REJECT;
+#endif
+}
+
+static void subscr_conn_bump(struct gsm_subscriber_connection *conn)
+{
+ if (!conn)
+ return;
+ if (!conn->conn_fsm)
+ return;
+ if (!(conn->conn_fsm->state == SUBSCR_CONN_S_ACCEPTED
+ || conn->conn_fsm->state == SUBSCR_CONN_S_COMMUNICATING))
+ return;
+ osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_BUMP, NULL);
}
+/* Receive a DTAP message from BSC */
static void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
{
gsm0408_dispatch(conn, msg);
+
+ /* Bump whether the conn wants to be closed */
+ subscr_conn_bump(conn);
}
+/* Receive an ASSIGNMENT COMPLETE from BSC */
static void msc_assign_compl(struct gsm_subscriber_connection *conn,
uint8_t rr_cause, uint8_t chosen_channel,
uint8_t encr_alg_id, uint8_t speec)
@@ -76,58 +131,135 @@ static void msc_assign_compl(struct gsm_subscriber_connection *conn,
LOGP(DRR, LOGL_DEBUG, "MSC assign complete (do nothing).\n");
}
+/* Receive an ASSIGNMENT FAILURE from BSC */
static void msc_assign_fail(struct gsm_subscriber_connection *conn,
uint8_t cause, uint8_t *rr_cause)
{
LOGP(DRR, LOGL_DEBUG, "MSC assign failure (do nothing).\n");
}
+/* Receive a CLASSMARK CHNAGE from BSC */
static void msc_classmark_chg(struct gsm_subscriber_connection *conn,
const uint8_t *cm2, uint8_t cm2_len,
const uint8_t *cm3, uint8_t cm3_len)
{
- struct gsm_subscriber *subscr = conn->subscr;
-
- if (subscr) {
- subscr->equipment.classmark2_len = cm2_len;
- memcpy(subscr->equipment.classmark2, cm2, cm2_len);
- if (cm3) {
- subscr->equipment.classmark3_len = cm3_len;
- memcpy(subscr->equipment.classmark3, cm3, cm3_len);
- }
- db_sync_equipment(&subscr->equipment);
+ conn->classmark.classmark2_len = cm2_len;
+ memcpy(conn->classmark.classmark2, cm2, cm2_len);
+ if (cm3) {
+ conn->classmark.classmark3_len = cm3_len;
+ memcpy(conn->classmark.classmark3, cm3, cm3_len);
}
}
+/* Receive a CIPHERING MODE COMPLETE from BSC */
static void msc_ciph_m_compl(struct gsm_subscriber_connection *conn,
struct msgb *msg, uint8_t alg_id)
{
- gsm_cbfn *cb;
-
- 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 <openbsc/signal.h>
#include <openbsc/transaction.h>
#include <openbsc/gsm_subscriber.h>
+#include <openbsc/vlr.h>
#include "smpp_smsc.h"
-/*! \brief find gsm_subscriber for a given SMPP NPI/TON/Address */
-static struct gsm_subscriber *subscr_by_dst(struct gsm_network *net,
- uint8_t npi, uint8_t ton, const char *addr)
+/*! \brief find vlr_subscr for a given SMPP NPI/TON/Address */
+static struct vlr_subscr *subscr_by_dst(struct gsm_network *net,
+ uint8_t npi, uint8_t ton,
+ const char *addr)
{
- struct gsm_subscriber *subscr = NULL;
+ struct vlr_subscr *vsub = NULL;
switch (npi) {
case NPI_Land_Mobile_E212:
- subscr = subscr_get_by_imsi(net->subscr_group, addr);
+ vsub = vlr_subscr_find_by_imsi(net->vlr, addr);
break;
case NPI_ISDN_E163_E164:
case NPI_Private:
- subscr = subscr_get_by_extension(net->subscr_group, addr);
+ vsub = vlr_subscr_find_by_msisdn(net->vlr, addr);
break;
default:
LOGP(DSMPP, LOGL_NOTICE, "Unsupported NPI: %u\n", npi);
break;
}
- /* tag the context in case we know it */
- log_set_context(LOG_CTX_VLR_SUBSCR, subscr);
- return subscr;
+ log_set_context(LOG_CTX_VLR_SUBSCR, vsub);
+ return vsub;
}
/*! \brief find a TLV with given tag in list of libsmpp34 TLVs */
@@ -87,7 +88,7 @@ static struct tlv_t *find_tlv(struct tlv_t *head, uint16_t tag)
static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
const struct submit_sm_t *submit)
{
- struct gsm_subscriber *dest;
+ struct vlr_subscr *dest;
struct gsm_sms *sms;
struct tlv_t *t;
const uint8_t *sms_msg;
@@ -110,7 +111,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
/* ERROR: we cannot have both! */
LOGP(DLSMS, LOGL_ERROR, "SMPP Cannot have payload in "
"TLV _and_ in the header\n");
- subscr_put(dest);
+ vlr_subscr_put(dest);
return ESME_ROPTPARNOTALLWD;
}
sms_msg = t->value.octet;
@@ -121,7 +122,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
} else {
LOGP(DLSMS, LOGL_ERROR,
"SMPP neither message payload nor valid sm_length.\n");
- subscr_put(dest);
+ vlr_subscr_put(dest);
return ESME_RINVPARLEN;
}
@@ -133,7 +134,7 @@ static int submit_to_sms(struct gsm_sms **psms, struct gsm_network *net,
sms->receiver = dest;
sms->dst.ton = submit->dest_addr_ton;
sms->dst.npi = submit->dest_addr_npi;
- osmo_strlcpy(sms->dst.addr, dest->extension, sizeof(sms->dst.addr));
+ osmo_strlcpy(sms->dst.addr, dest->msisdn, sizeof(sms->dst.addr));
/* fill in the source address */
sms->src.ton = submit->source_addr_ton;
@@ -251,7 +252,7 @@ int handle_smpp_submit(struct osmo_esme *esme, struct submit_sm_t *submit,
return rc;
}
-static void alert_all_esme(struct smsc *smsc, struct gsm_subscriber *subscr,
+static void alert_all_esme(struct smsc *smsc, struct vlr_subscr *vsub,
uint8_t smpp_avail_status)
{
struct osmo_esme *esme;
@@ -264,11 +265,11 @@ static void alert_all_esme(struct smsc *smsc, struct gsm_subscriber *subscr,
if (esme->acl && esme->acl->deliver_src_imsi) {
smpp_tx_alert(esme, TON_Subscriber_Number,
NPI_Land_Mobile_E212,
- subscr->imsi, smpp_avail_status);
+ vsub->imsi, smpp_avail_status);
} else {
smpp_tx_alert(esme, TON_Network_Specific,
NPI_ISDN_E163_E164,
- subscr->extension, smpp_avail_status);
+ vsub->msisdn, smpp_avail_status);
}
}
}
@@ -315,7 +316,7 @@ static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
}
break;
case S_SMS_SMMA:
- if (!sig_sms->trans || !sig_sms->trans->subscr) {
+ if (!sig_sms->trans || !sig_sms->trans->vsub) {
/* SMMA without a subscriber? strange... */
LOGP(DLSMS, LOGL_NOTICE, "SMMA without subscriber?\n");
break;
@@ -324,7 +325,7 @@ static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
/* There's no real 1:1 match for SMMA in SMPP. However,
* an ALERT NOTIFICATION seems to be the most logical
* choice */
- alert_all_esme(smsc, sig_sms->trans->subscr, 0);
+ alert_all_esme(smsc, sig_sms->trans->vsub, 0);
break;
}
@@ -335,7 +336,7 @@ static int smpp_sms_cb(unsigned int subsys, unsigned int signal,
static int smpp_subscr_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
- struct gsm_subscriber *subscr = signal_data;
+ struct vlr_subscr *vsub = signal_data;
struct smsc *smsc = handler_data;
uint8_t smpp_avail_status;
@@ -351,7 +352,7 @@ static int smpp_subscr_cb(unsigned int subsys, unsigned int signal,
return 0;
}
- alert_all_esme(smsc, subscr, smpp_avail_status);
+ alert_all_esme(smsc, vsub, smpp_avail_status);
return 0;
}
@@ -451,12 +452,12 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan)
dl_meas->full.rx_qual);
}
- if (lchan->conn && lchan->conn->subscr) {
- struct gsm_subscriber *subscr = lchan->conn->subscr;
- size_t imei_len = strlen(subscr->equipment.imei);
+ if (lchan->conn && lchan->conn->vsub) {
+ struct vlr_subscr *vsub = lchan->conn->vsub;
+ size_t imei_len = strlen(vsub->imei);
if (imei_len)
append_tlv(req_tlv, TLVID_osmo_imei,
- (uint8_t *)subscr->equipment.imei, imei_len+1);
+ (uint8_t *)vsub->imei, imei_len+1);
}
}
@@ -478,13 +479,13 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
deliver.source_addr_npi = NPI_Land_Mobile_E212;
snprintf((char *)deliver.source_addr,
sizeof(deliver.source_addr), "%s",
- conn->subscr->imsi);
+ conn->vsub->imsi);
} else {
deliver.source_addr_ton = TON_Network_Specific;
deliver.source_addr_npi = NPI_ISDN_E163_E164;
snprintf((char *)deliver.source_addr,
sizeof(deliver.source_addr), "%s",
- conn->subscr->extension);
+ conn->vsub->msisdn);
}
deliver.dest_addr_ton = sms->dst.ton;
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 <openbsc/gsm_04_11.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/signal.h>
+#include <openbsc/vlr.h>
#include <osmocom/core/talloc.h>
@@ -47,7 +48,7 @@
struct gsm_sms_pending {
struct llist_head entry;
- struct gsm_subscriber *subscr;
+ struct vlr_subscr *vsub;
unsigned long long sms_id;
int failed_attempts;
int resend;
@@ -88,12 +89,12 @@ static int sms_is_in_pending(struct gsm_sms_queue *smsq, struct gsm_sms *sms)
static struct gsm_sms_pending *sms_subscriber_find_pending(
struct gsm_sms_queue *smsq,
- struct gsm_subscriber *subscr)
+ struct vlr_subscr *vsub)
{
struct gsm_sms_pending *pending;
llist_for_each_entry(pending, &smsq->pending_sms, entry) {
- if (pending->subscr == subscr)
+ if (pending->vsub == vsub)
return pending;
}
@@ -101,9 +102,9 @@ static struct gsm_sms_pending *sms_subscriber_find_pending(
}
static int sms_subscriber_is_pending(struct gsm_sms_queue *smsq,
- struct gsm_subscriber *subscr)
+ struct vlr_subscr *vsub)
{
- return sms_subscriber_find_pending(smsq, subscr) != NULL;
+ return sms_subscriber_find_pending(smsq, vsub) != NULL;
}
static struct gsm_sms_pending *sms_pending_from(struct gsm_sms_queue *smsq,
@@ -115,27 +116,28 @@ static struct gsm_sms_pending *sms_pending_from(struct gsm_sms_queue *smsq,
if (!pending)
return NULL;
- pending->subscr = subscr_get(sms->receiver);
+ pending->vsub = vlr_subscr_get(sms->receiver);
pending->sms_id = sms->id;
return pending;
}
static void sms_pending_free(struct gsm_sms_pending *pending)
{
- subscr_put(pending->subscr);
+ vlr_subscr_put(pending->vsub);
llist_del(&pending->entry);
talloc_free(pending);
}
static void sms_pending_resend(struct gsm_sms_pending *pending)
{
+ struct gsm_network *net = pending->vsub->vlr->user_ctx;
struct gsm_sms_queue *smsq;
LOGP(DLSMS, LOGL_DEBUG,
"Scheduling resend of SMS %llu.\n", pending->sms_id);
pending->resend = 1;
- smsq = pending->subscr->group->net->sms_queue;
+ smsq = net->sms_queue;
if (osmo_timer_pending(&smsq->resend_pending))
return;
@@ -144,12 +146,13 @@ static void sms_pending_resend(struct gsm_sms_pending *pending)
static void sms_pending_failed(struct gsm_sms_pending *pending, int paging_error)
{
+ struct gsm_network *net = pending->vsub->vlr->user_ctx;
struct gsm_sms_queue *smsq;
LOGP(DLSMS, LOGL_NOTICE, "Sending SMS %llu failed %d times.\n",
pending->sms_id, pending->failed_attempts);
- smsq = pending->subscr->group->net->sms_queue;
+ smsq = net->sms_queue;
if (++pending->failed_attempts < smsq->max_fail)
return sms_pending_resend(pending);
@@ -191,8 +194,11 @@ static struct gsm_sms *take_next_sms(struct gsm_sms_queue *smsq)
struct gsm_sms *sms;
sms = db_sms_get_unsent_by_subscr(smsq->network, smsq->last_subscr_id, 10);
+ DEBUGP(DLSMS, "db_sms_get_unsent_by_subscr(id = %llu) returned %p\n",
+ smsq->last_subscr_id, sms);
if (sms) {
smsq->last_subscr_id = sms->receiver->id + 1;
+ DEBUGP(DLSMS, "take_next_sms() returns %p\n", sms);
return sms;
}
@@ -200,8 +206,11 @@ static struct gsm_sms *take_next_sms(struct gsm_sms_queue *smsq)
smsq->last_subscr_id = 0;
sms = db_sms_get_unsent_by_subscr(smsq->network,
smsq->last_subscr_id, 10);
+ DEBUGP(DLSMS, "db_sms_get_unsent_by_subscr(id = %llu) returned %p\n",
+ smsq->last_subscr_id, sms);
if (sms)
smsq->last_subscr_id = sms->receiver->id + 1;
+ DEBUGP(DLSMS, "take_next_sms() returns %p\n", sms);
return sms;
}
@@ -289,17 +298,18 @@ static void sms_submit_pending(void *_data)
/**
* Send the next SMS or trigger the queue
*/
-static void sms_send_next(struct gsm_subscriber *subscr)
+static void sms_send_next(struct vlr_subscr *vsub)
{
- struct gsm_sms_queue *smsq = subscr->group->net->sms_queue;
+ struct gsm_network *net = vsub->vlr->user_ctx;
+ struct gsm_sms_queue *smsq = net->sms_queue;
struct gsm_sms_pending *pending;
struct gsm_sms *sms;
/* the subscriber should not be in the queue */
- OSMO_ASSERT(!sms_subscriber_is_pending(smsq, subscr));
+ OSMO_ASSERT(!sms_subscriber_is_pending(smsq, vsub));
/* check for more messages for this subscriber */
- sms = db_sms_get_unsent_for_subscr(subscr);
+ sms = db_sms_get_unsent_for_subscr(vsub);
if (!sms)
goto no_pending_sms;
@@ -322,7 +332,7 @@ static void sms_send_next(struct gsm_subscriber *subscr)
no_pending_sms:
/* Try to send the SMS to avoid the queue being stuck */
- sms_submit_pending(subscr->group->net->sms_queue);
+ sms_submit_pending(net->sms_queue);
}
/*
@@ -364,7 +374,7 @@ int sms_queue_start(struct gsm_network *network, int max_pending)
return 0;
}
-static int sub_ready_for_sm(struct gsm_network *net, struct gsm_subscriber *subscr)
+static int sub_ready_for_sm(struct gsm_network *net, struct vlr_subscr *vsub)
{
struct gsm_sms *sms;
struct gsm_sms_pending *pending;
@@ -385,20 +395,20 @@ static int sub_ready_for_sm(struct gsm_network *net, struct gsm_subscriber *subs
*/
/* check if we have pending requests */
- pending = sms_subscriber_find_pending(net->sms_queue, subscr);
+ pending = sms_subscriber_find_pending(net->sms_queue, vsub);
if (pending) {
LOGP(DMSC, LOGL_NOTICE,
"Pending paging while subscriber %llu attached.\n",
- subscr->id);
+ vsub->id);
return 0;
}
- conn = connection_for_subscr(subscr);
+ conn = connection_for_subscr(vsub);
if (!conn)
return -1;
/* Now try to deliver any pending SMS to this sub */
- sms = db_sms_get_unsent_for_subscr(subscr);
+ sms = db_sms_get_unsent_for_subscr(vsub);
if (!sms)
return -1;
gsm411_send_sms(conn, sms);
@@ -408,13 +418,13 @@ static int sub_ready_for_sm(struct gsm_network *net, struct gsm_subscriber *subs
static int sms_subscr_cb(unsigned int subsys, unsigned int signal,
void *handler_data, void *signal_data)
{
- struct gsm_subscriber *subscr = signal_data;
+ struct vlr_subscr *vsub = signal_data;
if (signal != S_SUBSCR_ATTACHED)
return 0;
/* this is readyForSM */
- return sub_ready_for_sm(handler_data, subscr);
+ return sub_ready_for_sm(handler_data, vsub);
}
static int sms_sms_cb(unsigned int subsys, unsigned int signal,
@@ -423,7 +433,7 @@ static int sms_sms_cb(unsigned int subsys, unsigned int signal,
struct gsm_network *network = handler_data;
struct sms_signal_data *sig_sms = signal_data;
struct gsm_sms_pending *pending;
- struct gsm_subscriber *subscr;
+ struct vlr_subscr *vsub;
/* We got a new SMS and maybe should launch the queue again. */
if (signal == S_SMS_SUBMITTED || signal == S_SMS_SMMA) {
@@ -449,11 +459,11 @@ static int sms_sms_cb(unsigned int subsys, unsigned int signal,
case S_SMS_DELIVERED:
/* Remember the subscriber and clear the pending entry */
network->sms_queue->pending -= 1;
- subscr = subscr_get(pending->subscr);
+ vsub = vlr_subscr_get(pending->vsub);
sms_pending_free(pending);
/* Attempt to send another SMS to this subscriber */
- sms_send_next(subscr);
- subscr_put(subscr);
+ sms_send_next(vsub);
+ vlr_subscr_put(vsub);
break;
case S_SMS_MEM_EXCEEDED:
network->sms_queue->pending -= 1;
@@ -510,7 +520,7 @@ int sms_queue_stats(struct gsm_sms_queue *smsq, struct vty *vty)
llist_for_each_entry(pending, &smsq->pending_sms, entry)
vty_out(vty, " SMS Pending for Subscriber: %llu SMS: %llu Failed: %d.%s",
- pending->subscr->id, pending->sms_id,
+ pending->vsub->id, pending->sms_id,
pending->failed_attempts, VTY_NEWLINE);
return 0;
}
@@ -537,7 +547,7 @@ int sms_queue_clear(struct gsm_sms_queue *smsq)
llist_for_each_entry_safe(pending, tmp, &smsq->pending_sms, entry) {
LOGP(DLSMS, LOGL_NOTICE,
- "SMSqueue clearing for sub %llu\n", pending->subscr->id);
+ "SMSqueue clearing for sub %llu\n", pending->vsub->id);
sms_pending_free(pending);
}
diff --git a/openbsc/src/libmsc/subscr_conn.c b/openbsc/src/libmsc/subscr_conn.c
index 91ffe4069..8fe8758c9 100644
--- a/openbsc/src/libmsc/subscr_conn.c
+++ b/openbsc/src/libmsc/subscr_conn.c
@@ -23,19 +23,24 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/fsm.h>
+#include <osmocom/core/signal.h>
#include <openbsc/osmo_msc.h>
#include <openbsc/vlr.h>
#include <openbsc/debug.h>
#include <openbsc/transaction.h>
+#include <openbsc/signal.h>
+
+#define SUBSCR_CONN_TIMEOUT 5 /* seconds */
static const struct value_string subscr_conn_fsm_event_names[] = {
OSMO_VALUE_STRING(SUBSCR_CONN_E_INVALID),
+ OSMO_VALUE_STRING(SUBSCR_CONN_E_START),
OSMO_VALUE_STRING(SUBSCR_CONN_E_ACCEPTED),
+ OSMO_VALUE_STRING(SUBSCR_CONN_E_COMMUNICATING),
OSMO_VALUE_STRING(SUBSCR_CONN_E_BUMP),
OSMO_VALUE_STRING(SUBSCR_CONN_E_MO_CLOSE),
OSMO_VALUE_STRING(SUBSCR_CONN_E_CN_CLOSE),
- OSMO_VALUE_STRING(SUBSCR_CONN_E_CLOSE_CONF),
{ 0, NULL }
};
@@ -50,7 +55,14 @@ const struct value_string subscr_conn_from_names[] = {
static void paging_resp(struct gsm_subscriber_connection *conn,
enum gsm_paging_event pe)
{
- subscr_paging_dispatch(GSM_HOOK_RR_PAGING, pe, NULL, conn, conn->subscr);
+ subscr_paging_dispatch(GSM_HOOK_RR_PAGING, pe, NULL, conn, conn->vsub);
+}
+
+void subscr_conn_fsm_init(struct osmo_fsm_inst *fi, uint32_t event, void *data)
+{
+ OSMO_ASSERT(event == SUBSCR_CONN_E_START);
+ osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_NEW,
+ SUBSCR_CONN_TIMEOUT, 0);
}
void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data)
@@ -67,12 +79,11 @@ void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data)
/* If accepted, transition the state, all other cases mean failure. */
switch (event) {
case SUBSCR_CONN_E_ACCEPTED:
- osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_ACCEPTED, 0, 0);
+ osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_ACCEPTED, SUBSCR_CONN_TIMEOUT, 0);
break;
case SUBSCR_CONN_E_MO_CLOSE:
case SUBSCR_CONN_E_CN_CLOSE:
- case SUBSCR_CONN_E_CLOSE_CONF:
break;
default:
@@ -143,8 +154,7 @@ static void subscr_conn_fsm_bump(struct osmo_fsm_inst *fi, uint32_t event, void
if (conn->received_cm_service_request)
return;
- /* is this needed? */
- if (conn->subscr && !llist_empty(&conn->subscr->requests))
+ if (conn->vsub && !llist_empty(&conn->vsub->cs.requests))
return;
if (trans_has_conn(conn))
@@ -153,9 +163,20 @@ 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,
+ SUBSCR_CONN_TIMEOUT, 0);
+ return;
+
case SUBSCR_CONN_E_BUMP:
subscr_conn_fsm_bump(fi, event, data);
return;
@@ -169,34 +190,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 +282,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 +317,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 +332,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 +346,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 +354,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 <stdio.h>
#include <osmocom/core/talloc.h>
#include <openbsc/signal.h>
@@ -28,6 +31,7 @@
#include <openbsc/gsm_subscriber.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/db.h>
+#include <openbsc/vlr.h>
#define TOKEN_SMS_TEXT "HAR 2009 GSM. Register at http://har2009.gnumonks.org/ " \
"Your IMSI is %s, auth token is %08X, phone no is %s."
@@ -37,13 +41,15 @@ static char *build_sms_string(struct gsm_subscriber *subscr, uint32_t token)
char *sms_str;
unsigned int len;
- len = strlen(subscr->imsi) + 8 + strlen(TOKEN_SMS_TEXT);
+ OSMO_ASSERT(subscr->vsub);
+
+ len = strlen(subscr->vsub->imsi) + 8 + strlen(TOKEN_SMS_TEXT);
sms_str = talloc_size(tall_bsc_ctx, len);
if (!sms_str)
return NULL;
- snprintf(sms_str, len, TOKEN_SMS_TEXT, subscr->imsi, token,
- subscr->extension);
+ snprintf(sms_str, len, TOKEN_SMS_TEXT, subscr->vsub->imsi, token,
+ subscr->vsub->msisdn);
sms_str[len-1] = '\0';
return sms_str;
@@ -99,7 +105,7 @@ static int token_subscr_cb(unsigned int subsys, unsigned int signal,
unauth:
/* make sure we don't allow him in again unless he clicks the web UI */
- subscr->authorized = 0;
+ subscr->vsub->authorized = 0;
db_sync_subscriber(subscr);
if (rc) {
struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
@@ -158,3 +164,4 @@ void on_dso_load_token(void)
osmo_signal_register_handler(SS_SUBSCR, token_subscr_cb, NULL);
osmo_signal_register_handler(SS_SMS, token_sms_cb, NULL);
}
+#endif
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 <openbsc/mncc.h>
#include <openbsc/debug.h>
#include <osmocom/core/talloc.h>
-#include <openbsc/gsm_subscriber.h>
#include <openbsc/gsm_04_08.h>
#include <openbsc/mncc.h>
#include <openbsc/paging.h>
#include <openbsc/osmo_msc.h>
+#include <openbsc/vlr.h>
void *tall_trans_ctx;
void _gsm48_cc_trans_free(struct gsm_trans *trans);
+/* Find a transaction in connection for given protocol + transaction ID
+ * \param[in] conn Connection in whihc we want to find transaction
+ * \param[in] proto Protocol of transaction
+ * \param[in] trans_id Transaction ID of transaction
+ * \returns Matching transaction, if any
+ */
struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
uint8_t proto, uint8_t trans_id)
{
struct gsm_trans *trans;
struct gsm_network *net = conn->network;
- struct gsm_subscriber *subscr = conn->subscr;
+ struct vlr_subscr *vsub = conn->vsub;
llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->subscr == subscr &&
+ if (trans->vsub == vsub &&
trans->protocol == proto &&
trans->transaction_id == trans_id)
return trans;
@@ -49,6 +55,11 @@ struct gsm_trans *trans_find_by_id(struct gsm_subscriber_connection *conn,
return NULL;
}
+/* Find a transaction by call reference
+ * \param[in] net Network in which we should search
+ * \param[in] callref Call Reference of transaction
+ * \returns Matching transaction, if any
+ */
struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
uint32_t callref)
{
@@ -61,21 +72,28 @@ struct gsm_trans *trans_find_by_callref(struct gsm_network *net,
return NULL;
}
+/*! Allocate a new transaction and add it to network list
+ * \param[in] net Netwokr in which we allocate transaction
+ * \param[in] subscr Subscriber for which we allocate transaction
+ * \param[in] protocol Protocol (CC/SMS/...)
+ * \param[in] callref Call Reference
+ * \returns Transaction
+ */
struct gsm_trans *trans_alloc(struct gsm_network *net,
- struct gsm_subscriber *subscr,
+ struct vlr_subscr *vsub,
uint8_t protocol, uint8_t trans_id,
uint32_t callref)
{
struct gsm_trans *trans;
- DEBUGP(DCC, "subscr=%p, net=%p\n", subscr, net);
+ DEBUGP(DCC, "subscr=%p, net=%p\n", vsub, net);
trans = talloc_zero(tall_trans_ctx, struct gsm_trans);
if (!trans)
return NULL;
- trans->subscr = subscr;
- subscr_get(trans->subscr);
+ trans->vsub = vsub;
+ vlr_subscr_get(trans->vsub);
trans->protocol = protocol;
trans->transaction_id = trans_id;
@@ -87,6 +105,9 @@ struct gsm_trans *trans_alloc(struct gsm_network *net,
return trans;
}
+/* Release a transaction
+ * \param[in] trans Transaction to be released
+ */
void trans_free(struct gsm_trans *trans)
{
switch (trans->protocol) {
@@ -103,9 +124,9 @@ void trans_free(struct gsm_trans *trans)
trans->paging_request = NULL;
}
- if (trans->subscr) {
- subscr_put(trans->subscr);
- trans->subscr = NULL;
+ if (trans->vsub) {
+ vlr_subscr_put(trans->vsub);
+ trans->vsub = NULL;
}
llist_del(&trans->entry);
@@ -118,8 +139,13 @@ void trans_free(struct gsm_trans *trans)
}
/* allocate an unused transaction ID for the given subscriber
- * in the given protocol using the ti_flag specified */
-int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr,
+ * in the given protocol using the ti_flag specified
+ * \param[in] net GSM network
+ * \param[in] subscr Subscriber for which to find ID
+ * \param[in] protocol Protocol for whihc to find ID
+ * \param[in] ti_flag FIXME
+ */
+int trans_assign_trans_id(struct gsm_network *net, struct vlr_subscr *vsub,
uint8_t protocol, uint8_t ti_flag)
{
struct gsm_trans *trans;
@@ -131,7 +157,7 @@ int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr
/* generate bitmask of already-used TIDs for this (subscr,proto) */
llist_for_each_entry(trans, &net->trans_list, entry) {
- if (trans->subscr != subscr ||
+ if (trans->vsub != vsub ||
trans->protocol != protocol ||
trans->transaction_id == 0xff)
continue;
@@ -151,6 +177,10 @@ int trans_assign_trans_id(struct gsm_network *net, struct gsm_subscriber *subscr
return -1;
}
+/* Check if we have any transaction for given connection
+ * \param[in] conn Connection to check
+ * \returns 1 in case there is a transaction, 0 otherwise
+ */
int trans_has_conn(const struct gsm_subscriber_connection *conn)
{
struct gsm_trans *trans;
@@ -161,3 +191,13 @@ int trans_has_conn(const struct gsm_subscriber_connection *conn)
return 0;
}
+
+void trans_conn_closed(struct gsm_subscriber_connection *conn)
+{
+ struct gsm_trans *trans, *t2;
+
+ llist_for_each_entry_safe(trans, t2, &conn->network->trans_list, entry) {
+ if (trans->conn == conn)
+ trans_free(trans);
+ }
+}
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 <openbsc/gsm_subscriber.h>
#include <openbsc/debug.h>
#include <openbsc/osmo_msc.h>
+#include <openbsc/vlr.h>
/* Declarations of USSD strings to be recognised */
const char USSD_TEXT_OWN_NUMBER[] = "*#100#";
@@ -73,6 +74,7 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
return 0;
}
+ msc_subscr_conn_communicating(conn);
if (!strcmp(USSD_TEXT_OWN_NUMBER, (const char *)req.ussd_text)) {
DEBUGP(DMM, "USSD: Own number requested\n");
rc = send_own_number(conn, msg, &req);
@@ -87,9 +89,12 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
/* A network-specific handler function */
static int send_own_number(struct gsm_subscriber_connection *conn, const struct msgb *msg, const struct ss_request *req)
{
- char *own_number = conn->subscr->extension;
+ char *own_number = conn->vsub->msisdn;
char response_string[GSM_EXTENSION_LENGTH + 20];
+ DEBUGP(DMM, "%s: MSISDN = %s\n", vlr_subscr_name(conn->vsub),
+ own_number);
+
/* Need trailing CR as EOT character */
snprintf(response_string, sizeof(response_string), "Your extension is %s\r", own_number);
return gsm0480_send_ussd_response(conn, msg, response_string, req);
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 <openbsc/sms_queue.h>
#include <openbsc/mncc_int.h>
#include <openbsc/handover.h>
+#include <openbsc/vlr.h>
#include <osmocom/vty/logging.h>
+#include <openbsc/osmo_msc.h>
+
#include "meas_feed.h"
extern struct gsm_network *gsmnet_from_vty(struct vty *v);
-static void subscr_dump_full_vty(struct vty *vty, struct gsm_subscriber *subscr)
+static void subscr_dump_full_vty(struct vty *vty, struct vlr_subscr *vsub)
{
- int rc;
int reqs;
- struct gsm_auth_info ainfo;
- struct gsm_auth_tuple atuple;
struct llist_head *entry;
char expire_time[200];
- vty_out(vty, " ID: %llu, Authorized: %d%s", subscr->id,
- subscr->authorized, VTY_NEWLINE);
- if (strlen(subscr->name))
- vty_out(vty, " Name: '%s'%s", subscr->name, VTY_NEWLINE);
- if (strlen(subscr->extension))
- vty_out(vty, " Extension: %s%s", subscr->extension,
+ if (strlen(vsub->name))
+ vty_out(vty, " Name: '%s'%s", vsub->name, VTY_NEWLINE);
+ if (strlen(vsub->msisdn))
+ vty_out(vty, " Extension: %s%s", vsub->msisdn,
VTY_NEWLINE);
vty_out(vty, " LAC: %d/0x%x%s",
- subscr->lac, subscr->lac, VTY_NEWLINE);
- vty_out(vty, " IMSI: %s%s", subscr->imsi, VTY_NEWLINE);
- if (subscr->tmsi != GSM_RESERVED_TMSI)
- vty_out(vty, " TMSI: %08X%s", subscr->tmsi,
+ vsub->lac, vsub->lac, VTY_NEWLINE);
+ vty_out(vty, " IMSI: %s%s", vsub->imsi, VTY_NEWLINE);
+ if (vsub->tmsi != GSM_RESERVED_TMSI)
+ vty_out(vty, " TMSI: %08X%s", vsub->tmsi,
+ VTY_NEWLINE);
+ if (vsub->tmsi_new != GSM_RESERVED_TMSI)
+ vty_out(vty, " new TMSI: %08X%s", vsub->tmsi_new,
VTY_NEWLINE);
- rc = db_get_authinfo_for_subscr(&ainfo, subscr);
- if (!rc) {
+#if 0
+ /* TODO: add this to vlr_subscr? */
+ if (vsub->auth_info.auth_algo != AUTH_ALGO_NONE) {
+ struct gsm_auth_info *i = &vsub->auth_info;
vty_out(vty, " A3A8 algorithm id: %d%s",
- ainfo.auth_algo, VTY_NEWLINE);
+ i->auth_algo, VTY_NEWLINE);
vty_out(vty, " A3A8 Ki: %s%s",
- osmo_hexdump(ainfo.a3a8_ki, ainfo.a3a8_ki_len),
+ osmo_hexdump(i->a3a8_ki, i->a3a8_ki_len),
VTY_NEWLINE);
}
+#endif
- rc = db_get_lastauthtuple_for_subscr(&atuple, subscr);
- if (!rc) {
+ if (vsub->last_tuple) {
+ struct gsm_auth_tuple *t = vsub->last_tuple;
vty_out(vty, " A3A8 last tuple (used %d times):%s",
- atuple.use_count, VTY_NEWLINE);
+ t->use_count, VTY_NEWLINE);
vty_out(vty, " seq # : %d%s",
- atuple.key_seq, VTY_NEWLINE);
+ t->key_seq, VTY_NEWLINE);
vty_out(vty, " RAND : %s%s",
- osmo_hexdump(atuple.vec.rand, sizeof(atuple.vec.rand)),
+ osmo_hexdump(t->vec.rand, sizeof(t->vec.rand)),
VTY_NEWLINE);
vty_out(vty, " SRES : %s%s",
- osmo_hexdump(atuple.vec.sres, sizeof(atuple.vec.sres)),
+ osmo_hexdump(t->vec.sres, sizeof(t->vec.sres)),
VTY_NEWLINE);
vty_out(vty, " Kc : %s%s",
- osmo_hexdump(atuple.vec.kc, sizeof(atuple.vec.kc)),
+ osmo_hexdump(t->vec.kc, sizeof(t->vec.kc)),
VTY_NEWLINE);
}
/* print the expiration time of a subscriber */
strftime(expire_time, sizeof(expire_time),
- "%a, %d %b %Y %T %z", localtime(&subscr->expire_lu));
+ "%a, %d %b %Y %T %z", localtime(&vsub->expire_lu));
expire_time[sizeof(expire_time) - 1] = '\0';
vty_out(vty, " Expiration Time: %s%s", expire_time, VTY_NEWLINE);
reqs = 0;
- llist_for_each(entry, &subscr->requests)
+ llist_for_each(entry, &vsub->cs.requests)
reqs += 1;
- vty_out(vty, " Paging: %s paging Requests: %d%s",
- subscr->is_paging ? "is" : "not", reqs, VTY_NEWLINE);
- vty_out(vty, " Use count: %u%s", subscr->use_count, VTY_NEWLINE);
+ vty_out(vty, " Paging: %s paging for %d requests%s",
+ vsub->cs.is_paging ? "is" : "not", reqs, VTY_NEWLINE);
+ vty_out(vty, " Use count: %u%s", vsub->use_count, VTY_NEWLINE);
}
@@ -129,11 +133,18 @@ DEFUN(show_subscr_cache,
SHOW_STR "Show information about subscribers\n"
"Display contents of subscriber cache\n")
{
- struct gsm_subscriber *subscr;
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ struct vlr_subscr *vsub;
+ int count = 0;
- llist_for_each_entry(subscr, &active_subscribers, entry) {
+ llist_for_each_entry(vsub, &gsmnet->vlr->subscribers, list) {
+ if (++count > 100) {
+ vty_out(vty, "%% More than %d subscribers in cache,"
+ " stopping here.%s", count-1, VTY_NEWLINE);
+ break;
+ }
vty_out(vty, " Subscriber:%s", VTY_NEWLINE);
- subscr_dump_full_vty(vty, subscr);
+ subscr_dump_full_vty(vty, vsub);
}
return CMD_SUCCESS;
@@ -162,10 +173,11 @@ DEFUN(sms_send_pend,
return CMD_SUCCESS;
}
-static int _send_sms_str(struct gsm_subscriber *receiver,
- struct gsm_subscriber *sender,
- char *str, uint8_t tp_pid)
+static int _send_sms_str(struct vlr_subscr *receiver,
+ struct vlr_subscr *sender,
+ char *str, uint8_t tp_pid)
{
+ struct gsm_network *net = receiver->vlr->user_ctx;
struct gsm_sms *sms;
sms = sms_from_text(receiver, sender, 0, str);
@@ -180,22 +192,20 @@ static int _send_sms_str(struct gsm_subscriber *receiver,
LOGP(DLSMS, LOGL_DEBUG, "SMS stored in DB\n");
sms_free(sms);
- sms_queue_trigger(receiver->group->net->sms_queue);
+ sms_queue_trigger(net->sms_queue);
return CMD_SUCCESS;
}
-static struct gsm_subscriber *get_subscr_by_argv(struct gsm_network *gsmnet,
- const char *type,
- const char *id)
+static struct vlr_subscr *get_vsub_by_argv(struct gsm_network *gsmnet,
+ const char *type,
+ const char *id)
{
- if (!strcmp(type, "extension"))
- return subscr_get_by_extension(gsmnet->subscr_group, id);
- else if (!strcmp(type, "imsi"))
- return subscr_get_by_imsi(gsmnet->subscr_group, id);
+ if (!strcmp(type, "extension") || !strcmp(type, "msisdn"))
+ return vlr_subscr_find_by_msisdn(gsmnet->vlr, id);
+ else if (!strcmp(type, "imsi") || !strcmp(type, "id"))
+ return vlr_subscr_find_by_imsi(gsmnet->vlr, id);
else if (!strcmp(type, "tmsi"))
- return subscr_get_by_tmsi(gsmnet->subscr_group, atoi(id));
- else if (!strcmp(type, "id"))
- return subscr_get_by_id(gsmnet->subscr_group, atoi(id));
+ return vlr_subscr_find_by_tmsi(gsmnet->vlr, atoi(id));
return NULL;
}
@@ -213,18 +223,18 @@ DEFUN(show_subscr,
SHOW_STR SUBSCR_HELP)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr =
- get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+ struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0],
+ argv[1]);
- if (!subscr) {
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
- subscr_dump_full_vty(vty, subscr);
+ subscr_dump_full_vty(vty, vsub);
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_SUCCESS;
}
@@ -237,28 +247,9 @@ DEFUN(subscriber_create,
"Identify the subscriber by his IMSI\n" \
"Identifier for the subscriber\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr;
-
- subscr = subscr_get_by_imsi(gsmnet->subscr_group, argv[0]);
- if (subscr)
- db_sync_subscriber(subscr);
- else {
- subscr = subscr_create_subscriber(gsmnet->subscr_group, argv[0]);
-
- if (!subscr) {
- vty_out(vty, "%% No subscriber created for IMSI %s%s",
- argv[0], VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- /* Show info about the created subscriber. */
- subscr_dump_full_vty(vty, subscr);
-
- subscr_put(subscr);
-
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber create' now needs to be done at osmo-hlr%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(subscriber_send_pending_sms,
@@ -267,21 +258,21 @@ DEFUN(subscriber_send_pending_sms,
SUBSCR_HELP "SMS Operations\n" "Send pending SMS\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr;
+ struct vlr_subscr *vsub;
struct gsm_sms *sms;
- subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
- if (!subscr) {
+ vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
- sms = db_sms_get_unsent_by_subscr(gsmnet, subscr->id, UINT_MAX);
+ sms = db_sms_get_unsent_by_subscr(gsmnet, vsub->id, UINT_MAX);
if (sms)
gsm411_send_sms_subscr(sms->receiver, sms);
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_SUCCESS;
}
@@ -292,12 +283,12 @@ DEFUN(subscriber_send_sms,
SUBSCR_HELP "SMS Operations\n" SUBSCR_HELP "Send SMS\n" "Actual SMS Text\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
- struct gsm_subscriber *sender = get_subscr_by_argv(gsmnet, argv[2], argv[3]);
+ struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
+ struct vlr_subscr *sender = get_vsub_by_argv(gsmnet, argv[2], argv[3]);
char *str;
int rc;
- if (!subscr) {
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
rc = CMD_WARNING;
@@ -312,15 +303,15 @@ DEFUN(subscriber_send_sms,
}
str = argv_concat(argv, argc, 4);
- rc = _send_sms_str(subscr, sender, str, 0);
+ rc = _send_sms_str(vsub, sender, str, 0);
talloc_free(str);
err:
if (sender)
- subscr_put(sender);
+ vlr_subscr_put(sender);
- if (subscr)
- subscr_put(subscr);
+ if (vsub)
+ vlr_subscr_put(vsub);
return rc;
}
@@ -332,12 +323,12 @@ DEFUN(subscriber_silent_sms,
SUBSCR_HELP "Silent SMS Operations\n" SUBSCR_HELP "Send SMS\n" "Actual SMS Text\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
- struct gsm_subscriber *sender = get_subscr_by_argv(gsmnet, argv[2], argv[3]);
+ struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
+ struct vlr_subscr *sender = get_vsub_by_argv(gsmnet, argv[2], argv[3]);
char *str;
int rc;
- if (!subscr) {
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
rc = CMD_WARNING;
@@ -352,15 +343,15 @@ DEFUN(subscriber_silent_sms,
}
str = argv_concat(argv, argc, 4);
- rc = _send_sms_str(subscr, sender, str, 64);
+ rc = _send_sms_str(vsub, sender, str, 64);
talloc_free(str);
err:
if (sender)
- subscr_put(sender);
+ vlr_subscr_put(sender);
- if (subscr)
- subscr_put(subscr);
+ if (vsub)
+ vlr_subscr_put(vsub);
return rc;
}
@@ -379,10 +370,10 @@ DEFUN(subscriber_silent_call_start,
CHAN_TYPE_HELP)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+ struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
int rc, type;
- if (!subscr) {
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
return CMD_WARNING;
@@ -397,15 +388,15 @@ DEFUN(subscriber_silent_call_start,
else
type = RSL_CHANNEED_ANY; /* Defaults to ANY */
- rc = gsm_silent_call_start(subscr, vty, type);
+ rc = gsm_silent_call_start(vsub, vty, type);
if (rc <= 0) {
vty_out(vty, "%% Subscriber not attached%s",
VTY_NEWLINE);
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_WARNING;
}
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_SUCCESS;
}
@@ -417,22 +408,22 @@ DEFUN(subscriber_silent_call_stop,
CHAN_TYPE_HELP)
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+ struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
int rc;
- if (!subscr) {
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
- rc = gsm_silent_call_stop(subscr);
+ rc = gsm_silent_call_stop(vsub);
if (rc < 0) {
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_WARNING;
}
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_SUCCESS;
}
@@ -449,10 +440,10 @@ DEFUN(subscriber_ussd_notify,
char *text;
struct gsm_subscriber_connection *conn;
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+ struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0], argv[1]);
int level;
- if (!subscr) {
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
return CMD_WARNING;
@@ -461,15 +452,15 @@ DEFUN(subscriber_ussd_notify,
level = atoi(argv[2]);
text = argv_concat(argv, argc, 3);
if (!text) {
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_WARNING;
}
- conn = connection_for_subscr(subscr);
+ conn = connection_for_subscr(vsub);
if (!conn) {
vty_out(vty, "%% An active connection is required for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
talloc_free(text);
return CMD_WARNING;
}
@@ -477,7 +468,7 @@ DEFUN(subscriber_ussd_notify,
msc_send_ussd_notify(conn, level, text);
msc_send_ussd_release_complete(conn);
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
talloc_free(text);
return CMD_SUCCESS;
}
@@ -485,32 +476,12 @@ DEFUN(subscriber_ussd_notify,
DEFUN(ena_subscr_delete,
ena_subscr_delete_cmd,
"subscriber " SUBSCR_TYPES " ID delete",
- SUBSCR_HELP "Delete subscriber in HLR\n")
+ SUBSCR_HELP "Delete subscriber in VLR\n")
{
- int rc;
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr =
- get_subscr_by_argv(gsmnet, argv[0], argv[1]);
-
- if (!subscr) {
- vty_out(vty, "%% No subscriber found for %s %s%s",
- argv[0], argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (subscr->use_count != 1) {
- vty_out(vty, "Removing active subscriber%s", VTY_NEWLINE);
- }
-
- rc = db_subscriber_delete(subscr);
- subscr_put(subscr);
-
- if (rc != 0) {
- vty_out(vty, "Failed to remove subscriber%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber delete' is no longer supported.%s"
+ "%% This is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(ena_subscr_expire,
@@ -519,19 +490,28 @@ DEFUN(ena_subscr_expire,
SUBSCR_HELP "Expire the subscriber Now\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr =
- get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+ struct vlr_subscr *vsub = get_vsub_by_argv(gsmnet, argv[0],
+ argv[1]);
- if (!subscr) {
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s%s",
argv[0], argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
- subscr->expire_lu = time(0);
- db_sync_subscriber(subscr);
- subscr_put(subscr);
+ if (vsub->lu_complete) {
+ vsub->lu_complete = false;
+ vlr_subscr_put(vsub);
+ vty_out(vty, "%% VLR released subscriber %s%s",
+ vlr_subscr_name(vsub), VTY_NEWLINE);
+ }
+
+ if (vsub->use_count > 1)
+ vty_out(vty, "%% Subscriber %s is still in use,"
+ " should be released soon%s",
+ vlr_subscr_name(vsub), VTY_NEWLINE);
+ vlr_subscr_put(vsub);
return CMD_SUCCESS;
}
@@ -542,22 +522,10 @@ DEFUN(ena_subscr_authorized,
"Subscriber should NOT be authorized\n"
"Subscriber should be authorized\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr =
- get_subscr_by_argv(gsmnet, argv[0], argv[1]);
-
- if (!subscr) {
- vty_out(vty, "%% No subscriber found for %s %s%s",
- argv[0], argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- subscr->authorized = atoi(argv[2]);
- db_sync_subscriber(subscr);
-
- subscr_put(subscr);
-
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber authorized' is no longer supported.%s"
+ "%% Authorization is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(ena_subscr_name,
@@ -566,38 +534,10 @@ DEFUN(ena_subscr_name,
SUBSCR_HELP "Set the name of the subscriber\n"
"Name of the Subscriber\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr =
- get_subscr_by_argv(gsmnet, argv[0], argv[1]);
- char *name;
-
- if (!subscr) {
- vty_out(vty, "%% No subscriber found for %s %s%s",
- argv[0], argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- name = argv_concat(argv, argc, 2);
- if (!name) {
- subscr_put(subscr);
- return CMD_WARNING;
- }
-
- if (strlen(name) > sizeof(subscr->name)-1) {
- vty_out(vty,
- "%% NAME is too long, max. %zu characters are allowed%s",
- sizeof(subscr->name)-1, VTY_NEWLINE);
- subscr_put(subscr);
- return CMD_WARNING;
- }
-
- osmo_strlcpy(subscr->name, name, sizeof(subscr->name));
- talloc_free(name);
- db_sync_subscriber(subscr);
-
- subscr_put(subscr);
-
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber name' is no longer supported.%s"
+ "%% This is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(ena_subscr_extension,
@@ -606,30 +546,10 @@ DEFUN(ena_subscr_extension,
SUBSCR_HELP "Set the extension (phone number) of the subscriber\n"
"Extension (phone number)\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr =
- get_subscr_by_argv(gsmnet, argv[0], argv[1]);
- const char *ext = argv[2];
-
- if (!subscr) {
- vty_out(vty, "%% No subscriber found for %s %s%s",
- argv[0], argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (strlen(ext) > sizeof(subscr->extension)-1) {
- vty_out(vty,
- "%% EXTENSION is too long, max. %zu characters are allowed%s",
- sizeof(subscr->extension)-1, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- osmo_strlcpy(subscr->extension, ext, sizeof(subscr->extension));
- db_sync_subscriber(subscr);
-
- subscr_put(subscr);
-
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber extension' is no longer supported.%s"
+ "%% This is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(ena_subscr_handover,
@@ -642,20 +562,20 @@ DEFUN(ena_subscr_handover,
struct gsm_subscriber_connection *conn;
struct gsm_bts *bts;
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr =
- get_subscr_by_argv(gsmnet, argv[0], argv[1]);
+ struct vlr_subscr *vsub =
+ get_vsub_by_argv(gsmnet, argv[0], argv[1]);
- if (!subscr) {
+ if (!vsub) {
vty_out(vty, "%% No subscriber found for %s %s.%s",
argv[0], argv[1], VTY_NEWLINE);
return CMD_WARNING;
}
- conn = connection_for_subscr(subscr);
+ conn = connection_for_subscr(vsub);
if (!conn) {
vty_out(vty, "%% No active connection for subscriber %s %s.%s",
argv[0], argv[1], VTY_NEWLINE);
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_WARNING;
}
@@ -663,7 +583,7 @@ DEFUN(ena_subscr_handover,
if (!bts) {
vty_out(vty, "%% BTS with number(%d) could not be found.%s",
atoi(argv[2]), VTY_NEWLINE);
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_WARNING;
}
@@ -679,7 +599,7 @@ DEFUN(ena_subscr_handover,
VTY_NEWLINE);
}
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_SUCCESS;
}
@@ -695,69 +615,10 @@ DEFUN(ena_subscr_a3a8,
SUBSCR_HELP "Set a3a8 parameters for the subscriber\n"
A3A8_ALG_HELP "Encryption Key Ki\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr =
- get_subscr_by_argv(gsmnet, argv[0], argv[1]);
- const char *alg_str = argv[2];
- const char *ki_str = argc == 4 ? argv[3] : NULL;
- struct gsm_auth_info ainfo;
- int rc, minlen, maxlen;
-
- if (!subscr) {
- vty_out(vty, "%% No subscriber found for %s %s%s",
- argv[0], argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (!strcasecmp(alg_str, "none")) {
- ainfo.auth_algo = AUTH_ALGO_NONE;
- minlen = maxlen = 0;
- } else if (!strcasecmp(alg_str, "xor")) {
- ainfo.auth_algo = AUTH_ALGO_XOR;
- minlen = A38_XOR_MIN_KEY_LEN;
- maxlen = A38_XOR_MAX_KEY_LEN;
- } else if (!strcasecmp(alg_str, "comp128v1")) {
- ainfo.auth_algo = AUTH_ALGO_COMP128v1;
- minlen = maxlen = A38_COMP128_KEY_LEN;
- } else {
- /* Unknown method */
- subscr_put(subscr);
- vty_out(vty, "%% Unknown auth method %s%s",
- alg_str, VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- if (ki_str) {
- rc = osmo_hexparse(ki_str, ainfo.a3a8_ki, sizeof(ainfo.a3a8_ki));
- if ((rc > maxlen) || (rc < minlen)) {
- subscr_put(subscr);
- vty_out(vty, "%% Wrong Ki `%s'%s",
- ki_str, VTY_NEWLINE);
- return CMD_WARNING;
- }
- ainfo.a3a8_ki_len = rc;
- } else {
- ainfo.a3a8_ki_len = 0;
- if (minlen) {
- subscr_put(subscr);
- vty_out(vty, "%% Missing Ki argument%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- }
-
- rc = db_sync_authinfo_for_subscr(
- ainfo.auth_algo == AUTH_ALGO_NONE ? NULL : &ainfo,
- subscr);
-
- /* the last tuple probably invalid with the new auth settings */
- db_sync_lastauthtuple_for_subscr(NULL, subscr);
- subscr_put(subscr);
-
- if (rc) {
- vty_out(vty, "%% Operation has failed%s", VTY_NEWLINE);
- return CMD_WARNING;
- }
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber a3a8' is no longer supported.%s"
+ "%% This is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(subscriber_purge,
@@ -765,12 +626,11 @@ DEFUN(subscriber_purge,
"subscriber purge-inactive",
"Operations on a Subscriber\n" "Purge subscribers with a zero use count.\n")
{
- struct gsm_network *net = gsmnet_from_vty(vty);
- int purged;
-
- purged = subscr_purge_inactive(net->subscr_group);
- vty_out(vty, "%d subscriber(s) were purged.%s", purged, VTY_NEWLINE);
- return CMD_SUCCESS;
+ /* TODO: does this still have a use with the VLR? */
+ vty_out(vty, "%% 'subscriber purge-inactive' is no longer supported.%s"
+ "%% This is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(subscriber_update,
@@ -778,18 +638,9 @@ DEFUN(subscriber_update,
"subscriber " SUBSCR_TYPES " ID update",
SUBSCR_HELP "Update the subscriber data from the dabase.\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- struct gsm_subscriber *subscr = get_subscr_by_argv(gsmnet, argv[0], argv[1]);
-
- if (!subscr) {
- vty_out(vty, "%% No subscriber found for %s %s%s",
- argv[0], argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
-
- subscr_update_from_db(subscr);
- subscr_put(subscr);
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber update' is no longer supported.%s",
+ VTY_NEWLINE);
+ return CMD_WARNING;
}
static int scall_cbfn(unsigned int subsys, unsigned int signal,
@@ -1035,7 +886,7 @@ DEFUN(logging_fltr_imsi,
LOGGING_STR FILTER_STR
"Filter log messages by IMSI\n" "IMSI to be used as filter\n")
{
- struct gsm_subscriber *vlr_subscr;
+ struct vlr_subscr *vlr_subscr;
struct bsc_subscr *bsc_subscr;
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
struct log_target *tgt = osmo_log_vty2tgt(vty);
@@ -1044,7 +895,7 @@ DEFUN(logging_fltr_imsi,
if (!tgt)
return CMD_WARNING;
- vlr_subscr = subscr_get_by_imsi(gsmnet->subscr_group, imsi);
+ vlr_subscr = vlr_subscr_find_by_imsi(gsmnet->vlr, imsi);
bsc_subscr = bsc_subscr_find_by_imsi(gsmnet->bsc_subscribers, imsi);
if (!vlr_subscr && !bsc_subscr) {
@@ -1058,6 +909,50 @@ DEFUN(logging_fltr_imsi,
return CMD_SUCCESS;
}
+static struct cmd_node hlr_node = {
+ HLR_NODE,
+ "%s(config-hlr)# ",
+ 1,
+};
+
+DEFUN(cfg_hlr, cfg_hlr_cmd,
+ "hlr", "Configure connection to the HLR")
+{
+ vty->node = HLR_NODE;
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_hlr_remote_ip, cfg_hlr_remote_ip_cmd, "remote-ip A.B.C.D",
+ "Remote GSUP address of the HLR\n"
+ "Remote GSUP address (default: " MSC_HLR_REMOTE_IP_DEFAULT ")")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ talloc_free((void*)gsmnet->gsup_server_addr_str);
+ gsmnet->gsup_server_addr_str = talloc_strdup(gsmnet, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_hlr_remote_port, cfg_hlr_remote_port_cmd, "remote-port <1-65535>",
+ "Remote GSUP port of the HLR\n"
+ "Remote GSUP port (default: " OSMO_STRINGIFY(MSC_HLR_REMOTE_PORT_DEFAULT) ")")
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+ gsmnet->gsup_server_port = atoi(argv[0]);
+ return CMD_SUCCESS;
+}
+
+static int config_write_hlr(struct vty *vty)
+{
+ struct gsm_network *gsmnet = gsmnet_from_vty(vty);
+
+ vty_out(vty, "hlr%s", VTY_NEWLINE);
+ vty_out(vty, " remote-ip %s%s",
+ gsmnet->gsup_server_addr_str, VTY_NEWLINE);
+ vty_out(vty, " remote-port %u%s",
+ gsmnet->gsup_server_port, VTY_NEWLINE);
+ return CMD_SUCCESS;
+}
+
static struct cmd_node nitb_node = {
NITB_NODE,
"%s(config-nitb)# ",
@@ -1078,18 +973,10 @@ DEFUN(cfg_nitb_subscr_random, cfg_nitb_subscr_random_cmd,
"Set random parameters for a new record when a subscriber is first seen.\n"
"Minimum for subscriber extension\n""Maximum for subscriber extension\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- uint64_t mi = atoi(argv[0]), ma = atoi(argv[1]);
- gsmnet->auto_create_subscr = true;
- gsmnet->auto_assign_exten = true;
- if (mi >= ma) {
- vty_out(vty, "Incorrect range: %s >= %s, expected MIN < MAX%s",
- argv[0], argv[1], VTY_NEWLINE);
- return CMD_WARNING;
- }
- gsmnet->ext_min = mi;
- gsmnet->ext_max = ma;
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s"
+ "%% This is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
@@ -1097,19 +984,20 @@ DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd,
"Make a new record when a subscriber is first seen.\n"
"Do not automatically assign extension to created subscribers\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->auto_create_subscr = true;
- gsmnet->auto_assign_exten = argc ? false : true;
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s"
+ "%% This is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(cfg_nitb_no_subscr_create, cfg_nitb_no_subscr_create_cmd,
"no subscriber-create-on-demand",
NO_STR "Make a new record when a subscriber is first seen.\n")
{
- struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->auto_create_subscr = false;
- return CMD_SUCCESS;
+ vty_out(vty, "%% 'subscriber-create-on-demand' is no longer supported.%s"
+ "%% This is now up to osmo-hlr.%s",
+ VTY_NEWLINE, VTY_NEWLINE);
+ return CMD_WARNING;
}
DEFUN(cfg_nitb_assign_tmsi, cfg_nitb_assign_tmsi_cmd,
@@ -1117,7 +1005,7 @@ DEFUN(cfg_nitb_assign_tmsi, cfg_nitb_assign_tmsi_cmd,
"Assign TMSI during Location Updating.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->avoid_tmsi = 0;
+ gsmnet->vlr->cfg.assign_tmsi = true;
return CMD_SUCCESS;
}
@@ -1126,7 +1014,7 @@ DEFUN(cfg_nitb_no_assign_tmsi, cfg_nitb_no_assign_tmsi_cmd,
NO_STR "Assign TMSI during Location Updating.\n")
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
- gsmnet->avoid_tmsi = 1;
+ gsmnet->vlr->cfg.assign_tmsi = false;
return CMD_SUCCESS;
}
@@ -1147,7 +1035,7 @@ static int config_write_nitb(struct vty *vty)
PRIu64"%s", gsmnet->ext_min, gsmnet->ext_max,
VTY_NEWLINE);
vty_out(vty, " %sassign-tmsi%s",
- gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE);
+ gsmnet->vlr->cfg.assign_tmsi? "" : "no ", VTY_NEWLINE);
return CMD_SUCCESS;
}
@@ -1197,6 +1085,10 @@ int bsc_vty_init_extra(void)
install_element(CFG_LOG_NODE, &log_level_sms_cmd);
install_element(CFG_LOG_NODE, &logging_fltr_imsi_cmd);
+ install_element(CONFIG_NODE, &cfg_hlr_cmd);
+ install_node(&hlr_node, config_write_hlr);
+ install_element(HLR_NODE, &cfg_hlr_remote_ip_cmd);
+ install_element(HLR_NODE, &cfg_hlr_remote_port_cmd);
install_element(CONFIG_NODE, &cfg_nitb_cmd);
install_node(&nitb_node, config_write_nitb);
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 <openbsc/abis_rsl.h>
#include <openbsc/debug.h>
#include <openbsc/gsm_subscriber.h>
+#include <openbsc/vlr.h>
static int s_end = 0;
static struct gsm_subscriber_connection s_conn;
@@ -70,23 +71,25 @@ void test_request_chan(void)
network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL);
if (!network)
exit(1);
+ network->vlr = talloc_zero(network, struct vlr_instance);
+ network->vlr->user_ctx = network;
+ INIT_LLIST_HEAD(&network->vlr->subscribers);
+ INIT_LLIST_HEAD(&network->vlr->operations);
+
bts = gsm_bts_alloc(network);
bts->location_area_code = 23;
s_conn.network = network;
/* Create a dummy subscriber */
- struct gsm_subscriber *subscr = subscr_alloc();
- subscr->lac = 23;
- subscr->group = network->subscr_group;
-
- OSMO_ASSERT(subscr->group);
- OSMO_ASSERT(subscr->group->net == network);
+ struct vlr_subscr *vsub = vlr_subscr_alloc(network->vlr);
+ vsub->lac = 23;
/* Ask for a channel... */
struct subscr_request *sr;
- sr = subscr_request_channel(subscr, RSL_CHANNEED_TCH_F, subscr_cb, (void*)0x2342L);
+ sr = subscr_request_channel(vsub, RSL_CHANNEED_TCH_F, subscr_cb, (void*)0x2342L);
OSMO_ASSERT(sr);
OSMO_ASSERT(s_cbfn);
+ s_conn.network = network;
s_cbfn(101, 200, (void*)0x1323L, &s_conn, s_data);
OSMO_ASSERT(s_end);
@@ -140,5 +143,13 @@ void gsm48_secure_channel() {}
void paging_request_stop() {}
void vty_out() {}
-struct tlv_definition nm_att_tlvdef;
+void ipa_client_conn_clear_queue() {}
+void ipa_client_conn_close() {}
+void ipa_client_conn_create() {}
+void ipa_client_conn_destroy() {}
+void ipa_client_conn_open() {}
+void ipa_client_conn_send() {}
+void ipa_msg_push_header() {}
+void ipaccess_bts_handle_ccm() {}
+struct tlv_definition nm_att_tlvdef;
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 <jluebbe@debian.org>
- * (C) 2009 by Holger Hans Peter Freyther <zecke@selfish.org>
- * (C) 2014 by Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
- * All Rights Reserved
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <openbsc/debug.h>
-#include <openbsc/db.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/gsm_04_11.h>
-
-#include <osmocom/core/application.h>
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-static struct gsm_network dummy_net;
-static struct gsm_subscriber_group dummy_sgrp;
-
-static void test_subscr(void)
-{
- struct gsm_subscriber *subscr;
- const char *imsi = "1234567890";
-
- printf("Test subscriber allocation and deletion\n");
-
- /* Don't keep subscr */
-
- dummy_sgrp.keep_subscr = 0;
-
- OSMO_ASSERT(llist_empty(&active_subscribers));
-
- subscr = subscr_get_or_create(&dummy_sgrp, imsi);
-
- OSMO_ASSERT(!llist_empty(&active_subscribers));
- OSMO_ASSERT(subscr->use_count == 1);
-
- subscr_put(subscr);
-
- OSMO_ASSERT(llist_empty(&active_subscribers));
-
- /* Keep subscr */
-
- dummy_sgrp.keep_subscr = 1;
-
- subscr = subscr_get_or_create(&dummy_sgrp, imsi);
-
- OSMO_ASSERT(!llist_empty(&active_subscribers));
- OSMO_ASSERT(subscr->use_count == 1);
-
- subscr_put(subscr);
- OSMO_ASSERT(!llist_empty(&active_subscribers));
- OSMO_ASSERT(subscr->use_count == 0);
-
- subscr_get(subscr);
- OSMO_ASSERT(subscr->use_count == 1);
-
- subscr_purge_inactive(&dummy_sgrp);
-
- OSMO_ASSERT(!llist_empty(&active_subscribers));
- OSMO_ASSERT(subscr->use_count == 1);
-
- subscr_put(subscr);
- OSMO_ASSERT(!llist_empty(&active_subscribers));
- OSMO_ASSERT(subscr->use_count == 0);
-
- subscr_purge_inactive(&dummy_sgrp);
-
- OSMO_ASSERT(llist_empty(&active_subscribers));
-
- /* Test force_no_keep */
-
- dummy_sgrp.keep_subscr = 0;
-
- subscr = subscr_get_or_create(&dummy_sgrp, imsi);
- OSMO_ASSERT(subscr);
- subscr->keep_in_ram = 1;
-
- OSMO_ASSERT(!llist_empty(&active_subscribers));
- OSMO_ASSERT(subscr->use_count == 1);
-
- subscr->keep_in_ram = 0;
-
- subscr_put(subscr);
- OSMO_ASSERT(llist_empty(&active_subscribers));
-}
-
-int main()
-{
- printf("Testing subscriber core code.\n");
- osmo_init_logging(&log_info);
- log_set_print_filename(osmo_stderr_target, 0);
-
- dummy_net.subscr_group = &dummy_sgrp;
- dummy_sgrp.net = &dummy_net;
-
- test_subscr();
-
- printf("Done\n");
- return 0;
-}
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")