aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gprs/sgsn_main.c3
-rw-r--r--src/libbsc/abis_rsl.c4
-rw-r--r--src/libbsc/bsc_api.c10
-rw-r--r--src/libbsc/bsc_init.c7
-rw-r--r--src/libbsc/bsc_vty.c40
-rw-r--r--src/libbsc/handover_logic.c3
-rw-r--r--src/libbsc/paging.c1
-rw-r--r--src/libcommon-cs/common_cs.c12
-rw-r--r--src/libcommon-cs/common_cs_vty.c27
-rw-r--r--src/libcommon/debug.c23
-rw-r--r--src/libcommon/gsm_data.c10
-rw-r--r--src/libcommon/gsm_subscriber_base.c141
-rw-r--r--src/libcommon/gsup_client.c8
-rw-r--r--src/libcommon/gsup_test_client.c2
-rw-r--r--src/libmsc/Makefile.am2
-rw-r--r--src/libmsc/auth.c115
-rw-r--r--src/libmsc/ctrl_commands.c170
-rw-r--r--src/libmsc/db.c1025
-rw-r--r--src/libmsc/gsm_04_08.c1301
-rw-r--r--src/libmsc/gsm_04_11.c57
-rw-r--r--src/libmsc/gsm_subscriber.c313
-rw-r--r--src/libmsc/meas_feed.c11
-rw-r--r--src/libmsc/osmo_msc.c316
-rw-r--r--src/libmsc/rrlp.c6
-rw-r--r--src/libmsc/silent_call.c11
-rw-r--r--src/libmsc/smpp_openbsc.c65
-rw-r--r--src/libmsc/smpp_smsc.h2
-rw-r--r--src/libmsc/sms_queue.c116
-rw-r--r--src/libmsc/subscr_conn.c191
-rw-r--r--src/libmsc/token_auth.c160
-rw-r--r--src/libmsc/transaction.c81
-rw-r--r--src/libmsc/ussd.c18
-rw-r--r--src/libmsc/vty_interface_layer3.c561
-rw-r--r--src/libvlr/vlr_access_req_fsm.c1
-rw-r--r--src/osmo-nitb/bsc_hack.c18
35 files changed, 1633 insertions, 3198 deletions
diff --git a/src/gprs/sgsn_main.c b/src/gprs/sgsn_main.c
index 04f2825f..41cebefb 100644
--- a/src/gprs/sgsn_main.c
+++ b/src/gprs/sgsn_main.c
@@ -40,6 +40,8 @@
#include <osmocom/core/logging.h>
#include <osmocom/core/stats.h>
+#include <osmocom/gsm/gsup.h>
+
#include <osmocom/gprs/gprs_ns.h>
#include <osmocom/gprs/gprs_bssgp.h>
@@ -83,6 +85,7 @@ static struct sgsn_instance sgsn_inst = {
.cfg = {
.gtp_statedir = "./",
.auth_policy = SGSN_AUTH_POLICY_CLOSED,
+ .gsup_server_port = OSMO_GSUP_PORT,
},
};
struct sgsn_instance *sgsn = &sgsn_inst;
diff --git a/src/libbsc/abis_rsl.c b/src/libbsc/abis_rsl.c
index 6ae790f6..7ae3eebd 100644
--- a/src/libbsc/abis_rsl.c
+++ b/src/libbsc/abis_rsl.c
@@ -160,7 +160,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;
}
@@ -1382,8 +1382,6 @@ static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr)
if (lchan && lchan->conn) {
if (lchan->conn->bsub)
name = bsc_subscr_name(lchan->conn->bsub);
- else if (lchan->conn->subscr)
- name = lchan->conn->subscr->imsi;
else
name = lchan->name;
}
diff --git a/src/libbsc/bsc_api.c b/src/libbsc/bsc_api.c
index 7613cac9..947644eb 100644
--- a/src/libbsc/bsc_api.c
+++ b/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>
@@ -273,13 +274,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/src/libbsc/bsc_init.c b/src/libbsc/bsc_init.c
index ec87a7bc..b7135f1b 100644
--- a/src/libbsc/bsc_init.c
+++ b/src/libbsc/bsc_init.c
@@ -38,6 +38,7 @@
#include <openbsc/e1_config.h>
#include <openbsc/common_bsc.h>
#include <openbsc/pcu_if.h>
+#include <openbsc/osmo_msc.h>
#include <limits.h>
/* global pointer to the gsm network data structure */
@@ -512,6 +513,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/src/libbsc/bsc_vty.c b/src/libbsc/bsc_vty.c
index 9fc28950..3bd56eaf 100644
--- a/src/libbsc/bsc_vty.c
+++ b/src/libbsc/bsc_vty.c
@@ -54,8 +54,8 @@
#include <openbsc/bsc_msc_data.h>
#include <openbsc/osmo_bsc_rf.h>
#include <openbsc/pcu_if.h>
-
#include <openbsc/common_cs.h>
+#include <openbsc/vlr.h>
#include <inttypes.h>
@@ -173,10 +173,6 @@ static void net_dump_vty(struct vty *vty, struct gsm_network *net)
if (net->authorized_reg_str)
vty_out(vty, ", authorized regexp: %s", net->authorized_reg_str);
vty_out(vty, "%s", VTY_NEWLINE);
- vty_out(vty, " Auto create subscriber: %s%s",
- net->auto_create_subscr ? "yes" : "no", VTY_NEWLINE);
- vty_out(vty, " Auto assign extension: %s%s",
- net->auto_assign_exten ? "yes" : "no", VTY_NEWLINE);
vty_out(vty, " Location updating reject cause: %u%s",
net->reject_cause, VTY_NEWLINE);
vty_out(vty, " Encryption: A5/%u%s", net->a5_encryption,
@@ -801,6 +797,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),
@@ -833,8 +832,6 @@ static int config_write_net(struct vty *vty)
vty_out(vty, " timer t3141 %u%s", gsmnet->T3141, VTY_NEWLINE);
vty_out(vty, " dyn_ts_allow_tch_f %d%s",
gsmnet->dyn_ts_allow_tch_f ? 1 : 0, VTY_NEWLINE);
- 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",
@@ -1018,21 +1015,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)
@@ -1160,9 +1160,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/src/libbsc/handover_logic.c b/src/libbsc/handover_logic.c
index 4dd913b1..c03563f6 100644
--- a/src/libbsc/handover_logic.c
+++ b/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;
@@ -260,7 +261,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/src/libbsc/paging.c b/src/libbsc/paging.c
index 78e39c55..8c1445cc 100644
--- a/src/libbsc/paging.c
+++ b/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/src/libcommon-cs/common_cs.c b/src/libcommon-cs/common_cs.c
index 7905802b..fc9caafa 100644
--- a/src/libcommon-cs/common_cs.c
+++ b/src/libcommon-cs/common_cs.c
@@ -49,20 +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;
-
net->country_code = country_code;
net->network_code = network_code;
@@ -78,8 +68,6 @@ struct gsm_network *gsm_network_init(void *ctx,
net->active_calls = osmo_counter_alloc("msc.active_calls");
net->mncc_recv = mncc_recv;
- net->ext_min = GSM_MIN_EXTEN;
- net->ext_max = GSM_MAX_EXTEN;
net->dyn_ts_allow_tch_f = true;
diff --git a/src/libcommon-cs/common_cs_vty.c b/src/libcommon-cs/common_cs_vty.c
index bcc001d5..86b4c53e 100644
--- a/src/libcommon-cs/common_cs_vty.c
+++ b/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"
@@ -209,17 +223,6 @@ DEFUN(cfg_net_dyn_ts_allow_tch_f,
return CMD_SUCCESS;
}
-DEFUN(cfg_net_subscr_keep,
- cfg_net_subscr_keep_cmd,
- "subscriber-keep-in-ram (0|1)",
- "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;
-}
-
DEFUN(cfg_net_timezone,
cfg_net_timezone_cmd,
"timezone <-19-19> (0|15|30|45)",
@@ -301,9 +304,9 @@ 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);
install_element(GSMNET_NODE, &cfg_net_timezone_cmd);
install_element(GSMNET_NODE, &cfg_net_timezone_dst_cmd);
install_element(GSMNET_NODE, &cfg_net_no_timezone_cmd);
diff --git a/src/libcommon/debug.c b/src/libcommon/debug.c
index 088902a6..dc79a843 100644
--- a/src/libcommon/debug.c
+++ b/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 */
@@ -189,13 +188,13 @@ static const struct log_info_cat default_categories[] = {
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
@@ -220,21 +219,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/src/libcommon/gsm_data.c b/src/libcommon/gsm_data.c
index db7de082..7c717a40 100644
--- a/src/libcommon/gsm_data.c
+++ b/src/libcommon/gsm_data.c
@@ -471,3 +471,13 @@ void gsm_bts_set_radio_link_timeout(struct gsm_bts *bts, int value)
cell_options->radio_link_timeout = (value >> 2) - 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/src/libcommon/gsm_subscriber_base.c b/src/libcommon/gsm_subscriber_base.c
index 1ecdee5a..018ed210 100644
--- a/src/libcommon/gsm_subscriber_base.c
+++ b/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/src/libcommon/gsup_client.c b/src/libcommon/gsup_client.c
index 46f25bb9..258f230c 100644
--- a/src/libcommon/gsup_client.c
+++ b/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 ||
@@ -331,11 +331,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/src/libcommon/gsup_test_client.c b/src/libcommon/gsup_test_client.c
index 1b39670d..b6a8d6b7 100644
--- a/src/libcommon/gsup_test_client.c
+++ b/src/libcommon/gsup_test_client.c
@@ -271,7 +271,7 @@ int main(int argc, char **argv)
{
unsigned long long i;
char *server_host = "127.0.0.1";
- uint16_t server_port = 2222;
+ uint16_t server_port = OSMO_GSUP_PORT;
osmo_init_logging(&gsup_test_client_log_info);
diff --git a/src/libmsc/Makefile.am b/src/libmsc/Makefile.am
index 9d966dbc..bb2a4a18 100644
--- a/src/libmsc/Makefile.am
+++ b/src/libmsc/Makefile.am
@@ -35,13 +35,13 @@ libmsc_a_SOURCES = \
rrlp.c \
silent_call.c \
sms_queue.c \
- token_auth.c \
ussd.c \
vty_interface_layer3.c \
transaction.c \
osmo_msc.c \
ctrl_commands.c \
meas_feed.c \
+ subscr_conn.c \
$(NULL)
if BUILD_SMPP
diff --git a/src/libmsc/auth.c b/src/libmsc/auth.c
index 19def1ec..9064ce6c 100644
--- a/src/libmsc/auth.c
+++ b/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/src/libmsc/ctrl_commands.c b/src/libmsc/ctrl_commands.c
index c99dde44..9d1f0d4f 100644
--- a/src/libmsc/ctrl_commands.c
+++ b/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,55 +46,40 @@ 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;
+ 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");
- subscr = subscr_get_by_imsi(net->subscr_group, cmd->value);
- if (!subscr) {
- cmd->reply = "Failed to find subscriber";
- return CTRL_CMD_ERROR;
- }
+static int get_subscriber_list(struct ctrl_cmd *cmd, void *d)
+{
+ struct vlr_subscr *vsub;
- if (subscr->use_count != 1) {
- LOGP(DCTRL, LOGL_NOTICE, "Going to remove active subscriber.\n");
- was_used = 1;
+ if (!msc_ctrl_net) {
+ cmd->reply = "MSC CTRL commands not initialized";
+ return CTRL_CMD_ERROR;
}
- rc = db_subscriber_delete(subscr);
- subscr_put(subscr);
-
- if (rc != 0) {
- cmd->reply = "Failed to remove subscriber";
+ if (!msc_ctrl_net->vlr) {
+ cmd->reply = "VLR not initialized";
return CTRL_CMD_ERROR;
}
- cmd->reply = was_used ? "Removed active subscriber" : "Removed";
- return CTRL_CMD_REPLY;
-}
-CTRL_CMD_DEFINE_WO_NOVRF(subscriber_delete, "subscriber-delete-v1");
-
-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)
-{
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_RO(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/src/libmsc/db.c b/src/libmsc/db.c
index 5fe2a3c6..28e97821 100644
--- a/src/libmsc/db.c
+++ b/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;
- uint64_t try;
-
- for (;;) {
- try = (rand() % (smax - smin + 1) + smin);
- result = dbi_conn_queryf(conn,
- "SELECT * FROM Subscriber "
- "WHERE extension = %"PRIu64,
- 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, "%"PRIu64, try);
- DEBUGP(DDB, "Allocated extension %"PRIu64 " 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");
@@ -1542,20 +643,21 @@ struct gsm_sms *db_sms_get(struct gsm_network *net, unsigned long long id)
return sms;
}
-/* retrieve the next unsent SMS with ID >= min_id */
-struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long min_id)
+struct gsm_sms *db_sms_get_next_unsent(struct gsm_network *net,
+ unsigned long long min_sms_id,
+ unsigned int max_failed)
{
dbi_result result;
struct gsm_sms *sms;
result = dbi_conn_queryf(conn,
- "SELECT SMS.* "
- "FROM SMS JOIN Subscriber ON "
- "SMS.dest_addr = Subscriber.extension "
- "WHERE SMS.id >= %llu AND SMS.sent IS NULL "
- "AND Subscriber.lac > 0 "
- "ORDER BY SMS.id LIMIT 1",
- min_id);
+ "SELECT * FROM SMS"
+ " WHERE sent IS NULL"
+ " AND id >= %llu"
+ " AND deliver_attempts <= %u"
+ " ORDER BY id LIMIT 1",
+ min_sms_id, max_failed);
+
if (!result)
return NULL;
@@ -1571,21 +673,24 @@ struct gsm_sms *db_sms_get_unsent(struct gsm_network *net, unsigned long long mi
return sms;
}
-struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net,
- unsigned long long min_subscr_id,
- unsigned int failed)
+/* retrieve the next unsent SMS for a given subscriber */
+struct gsm_sms *db_sms_get_unsent_for_subscr(struct vlr_subscr *vsub,
+ unsigned int max_failed)
{
+ struct gsm_network *net = vsub->vlr->user_ctx;
dbi_result result;
struct gsm_sms *sms;
+ if (!vsub->lu_complete)
+ return NULL;
+
result = dbi_conn_queryf(conn,
- "SELECT SMS.* "
- "FROM SMS JOIN Subscriber ON "
- "SMS.dest_addr = Subscriber.extension "
- "WHERE Subscriber.id >= %llu AND SMS.sent IS NULL "
- "AND Subscriber.lac > 0 AND SMS.deliver_attempts < %u "
- "ORDER BY Subscriber.id, SMS.id LIMIT 1",
- min_subscr_id, failed);
+ "SELECT * FROM SMS"
+ " WHERE sent IS NULL"
+ " AND dest_addr=%s"
+ " AND deliver_attempts <= %u"
+ " ORDER BY id LIMIT 1",
+ vsub->msisdn, max_failed);
if (!result)
return NULL;
@@ -1601,20 +706,20 @@ struct gsm_sms *db_sms_get_unsent_by_subscr(struct gsm_network *net,
return sms;
}
-/* 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_next_unsent_rr_msisdn(struct gsm_network *net,
+ const char *last_msisdn,
+ unsigned int max_failed)
{
dbi_result result;
struct gsm_sms *sms;
result = dbi_conn_queryf(conn,
- "SELECT SMS.* "
- "FROM SMS JOIN Subscriber ON "
- "SMS.dest_addr = Subscriber.extension "
- "WHERE Subscriber.id = %llu AND SMS.sent IS NULL "
- "AND Subscriber.lac > 0 "
- "ORDER BY SMS.id LIMIT 1",
- subscr->id);
+ "SELECT * FROM SMS"
+ " WHERE sent IS NULL"
+ " AND dest_addr > '%s'"
+ " AND deliver_attempts <= %u"
+ " ORDER BY dest_addr, id LIMIT 1",
+ last_msisdn, max_failed);
if (!result)
return NULL;
@@ -1623,7 +728,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 +772,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/src/libmsc/gsm_04_08.c b/src/libmsc/gsm_04_08.c
index fb02de20..6cea2420 100644
--- a/src/libmsc/gsm_04_08.c
+++ b/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;
@@ -169,298 +169,7 @@ int gsm48_cc_tx_notify_ss(struct gsm_trans *trans, const char *message)
return gsm48_conn_sendmsg(ss_notify, trans->conn, trans);
}
-void release_security_operation(struct gsm_subscriber_connection *conn)
-{
- if (!conn->sec_operation)
- return;
-
- talloc_free(conn->sec_operation);
- conn->sec_operation = NULL;
- msc_release_connection(conn);
-}
-
-void allocate_security_operation(struct gsm_subscriber_connection *conn)
-{
- conn->sec_operation = talloc_zero(tall_authciphop_ctx,
- struct gsm_security_operation);
-}
-
-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;
- if (release)
- msc_release_connection(conn);
-}
-
-static void loc_updating_failure(struct gsm_subscriber_connection *conn, int release)
-{
- if (!conn->loc_operation)
- return;
- LOGP(DMM, LOGL_ERROR, "Location Updating failed for %s\n",
- subscr_name(conn->subscr));
- rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_FAILED]);
- _release_loc_updating_req(conn, release);
-}
-
-static void loc_updating_success(struct gsm_subscriber_connection *conn, int release)
-{
- if (!conn->loc_operation)
- return;
- LOGP(DMM, LOGL_INFO, "Location Updating completed for %s\n",
- subscr_name(conn->subscr));
- rate_ctr_inc(&conn->network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_COMPLETED]);
- _release_loc_updating_req(conn, release);
-}
-
-static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn)
-{
- if (conn->loc_operation)
- LOGP(DMM, LOGL_ERROR, "Connection already had operation.\n");
- loc_updating_failure(conn, 0);
-
- conn->loc_operation = talloc_zero(tall_locop_ctx,
- struct gsm_loc_updating_operation);
-}
-
-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 == true, we don't send a TMSI, we don't
- * expect a reply and Location Updating is done.
- */
- if (avoid_tmsi)
- loc_updating_success(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:
- loc_updating_failure(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;
-}
-
-void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
-{
- struct gsm_trans *trans, *temp;
-
- /* avoid someone issuing a clear */
- conn->in_release = 1;
-
- /*
- * Cancel any outstanding location updating request
- * operation taking place on the subscriber connection.
- */
- loc_updating_failure(conn, 0);
-
- /* We might need to cancel the paging response or such. */
- if (conn->sec_operation && conn->sec_operation->cb) {
- conn->sec_operation->cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED,
- NULL, conn, conn->sec_operation->cb_data);
- }
-
- release_security_operation(conn);
- release_anchor(conn);
-
- /*
- * Free all transactions that are associated with the released
- * connection. The transaction code will inform the CC or SMS
- * facilities that will send the release indications. As part of
- * the CC REL_IND the remote leg might be released and this will
- * trigger the call to trans_free. This is something the llist
- * macro can not handle and we will need to re-iterate the list.
- *
- * TODO: Move the trans_list into the subscriber connection and
- * create a pending list for MT transactions. These exist before
- * we have a subscriber connection.
- */
-restart:
- llist_for_each_entry_safe(trans, temp, &conn->network->trans_list, entry) {
- if (trans->conn == conn) {
- trans_free(trans);
- goto 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;
@@ -490,14 +199,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;
@@ -515,16 +225,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");
@@ -547,82 +268,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);
- loc_updating_failure(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);
- loc_updating_failure(conn, 1);
-}
-
-static void schedule_reject(struct gsm_subscriber_connection *conn)
-{
- osmo_timer_setup(&conn->loc_operation->updating_timer, loc_upd_rej_cb,
- 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" },
@@ -630,14 +298,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;
@@ -645,97 +322,95 @@ 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);
- loc_updating_failure(conn, 0); /* FIXME: set release == true? */
- 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,
+ net->vlr->cfg.assign_tmsi);
+ 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? */
+
+ 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;
+ }
- /* 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);
+ return 0;
}
/* Turn int into semi-octet representation: 98 => 0x89 */
+/* FIXME: libosmocore/libosmogsm */
static uint8_t bcdify(uint8_t value)
{
uint8_t ret;
@@ -939,53 +614,46 @@ int gsm48_tx_mm_auth_rej(struct gsm_subscriber_connection *conn)
return gsm48_tx_simple(conn, GSM48_PDISC_MM, GSM48_MT_MM_AUTH_REJ);
}
-/*
- * At the 30C3 phones miss their periodic update
- * interval a lot and then remain unreachable. In case
- * we still know the TMSI we can just attach it again.
- */
-static void implit_attach(struct gsm_subscriber_connection *conn)
-{
- if (conn->subscr->lac != GSM_LAC_RESERVED_DETACHED)
- return;
-
- subscr_update(conn->subscr, conn->bts,
- GSM_SUBSCRIBER_UPDATE_ATTACHED);
-}
-
+static int msc_vlr_tx_cm_serv_acc(void *msc_conn_ref);
+static int msc_vlr_tx_cm_serv_rej(void *msc_conn_ref, enum vlr_proc_arq_result result);
-static int _gsm48_rx_mm_serv_req_sec_cb(
- unsigned int hooknum, unsigned int event,
- struct msgb *msg, void *data, void *param)
+static int cm_serv_reuse_conn(struct gsm_subscriber_connection *conn, const uint8_t *mi_lv)
{
- 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;
+ uint8_t mi_type;
+ char mi_string[GSM48_MI_SIZE];
+ uint32_t tmsi;
- case GSM_SECURITY_NOAVAIL:
- case GSM_SECURITY_ALREADY:
- rc = gsm48_tx_mm_serv_ack(conn);
- implit_attach(conn);
- break;
+ gsm48_mi_to_string(mi_string, sizeof(mi_string), mi_lv+1, mi_lv[0]);
+ mi_type = mi_lv[1] & GSM_MI_TYPE_MASK;
- case GSM_SECURITY_SUCCEEDED:
- /* nothing to do. CIPHER MODE COMMAND is
- * implicit CM SERV ACK */
- implit_attach(conn);
- break;
+ switch (mi_type) {
+ case GSM_MI_TYPE_IMSI:
+ if (vlr_subscr_matches_imsi(conn->vsub, mi_string))
+ goto accept_reuse;
+ break;
+ case GSM_MI_TYPE_TMSI:
+ tmsi = osmo_load32be(mi_lv+2);
+ if (vlr_subscr_matches_tmsi(conn->vsub, tmsi))
+ goto accept_reuse;
+ break;
+ case GSM_MI_TYPE_IMEI:
+ if (vlr_subscr_matches_imei(conn->vsub, mi_string))
+ goto accept_reuse;
+ break;
+ default:
+ break;
+ }
- default:
- rc = -EINVAL;
- };
+ LOGP(DMM, LOGL_ERROR, "%s: CM Service Request with mismatching mobile identity: %s %s\n",
+ vlr_subscr_name(conn->vsub), gsm48_mi_type_name(mi_type), mi_string);
+ msc_vlr_tx_cm_serv_rej(conn, VLR_PR_ARQ_RES_ILLEGAL_SUBSCR);
+ return -EINVAL;
- return rc;
+accept_reuse:
+ DEBUGP(DMM, "%s: re-using already accepted connection\n",
+ vlr_subscr_name(conn->vsub));
+ conn->received_cm_service_request = true;
+ return conn->network->vlr->ops.tx_cm_serv_acc(conn);
}
/*
@@ -996,14 +664,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;
@@ -1012,6 +683,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*)) {
@@ -1033,14 +710,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,
@@ -1048,34 +721,40 @@ 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));
+ memcpy(conn->classmark.classmark2, classmark2, classmark2_len);
+ conn->classmark.classmark2_len = classmark2_len;
+
+ if (conn->conn_fsm) {
+ if (msc_subscr_conn_is_accepted(conn))
+ return cm_serv_reuse_conn(conn, mi-1);
+ LOGP(DMM, LOGL_ERROR, "%s: connection already in use\n",
+ vlr_subscr_name(conn->vsub));
+ msc_vlr_tx_cm_serv_rej(conn, VLR_PR_ARQ_RES_UNKNOWN_ERROR);
+ return -EINVAL;
+ }
- if (is_siemens_bts(conn->bts))
- send_siemens_mrpci(msg->lchan, classmark2-1);
-
-
- /* 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);
-
- 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);
+ rc = msc_create_conn_fsm(conn, mi_string);
+ if (rc) {
+ msc_vlr_tx_cm_serv_rej(conn, VLR_PR_ARQ_RES_UNKNOWN_ERROR);
+ /* logging already happened in msc_create_conn_fsm() */
+ return rc;
}
- 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)
@@ -1086,51 +765,51 @@ 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",
- gsm48_mi_type_name(mi_type), mi_string);
+ DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s\n",
+ gsm48_mi_type_name(mi_type), mi_string);
rate_ctr_inc(&network->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_DETACH]);
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:
/* no sim card... FIXME: what to do ? */
- DEBUGPC(DMM, ": unimplemented mobile identity type\n");
+ LOGP(DMM, LOGL_ERROR, "MI(%s)=%s: unimplemented mobile identity type\n",
+ gsm48_mi_type_name(mi_type), mi_string);
break;
default:
- DEBUGPC(DMM, ": unknown mobile identity type\n");
+ LOGP(DMM, LOGL_ERROR, "MI(%s)=%s: unknown mobile identity type\n",
+ gsm48_mi_type_name(mi_type), mi_string);
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);
- subscr_put(subscr);
- } else
- DEBUGP(DMM, "Unknown Subscriber ?!?\n");
+ /* 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;
- /* FIXME: iterate over all transactions and release them,
- * imagine an IMSI DETACH happening during an active call! */
+ if (!vsub) {
+ LOGP(DMM, LOGL_ERROR, "IMSI DETACH for unknown subscriber MI(%s)=%s\n",
+ gsm48_mi_type_name(mi_type), mi_string);
+ } else {
+ LOGP(DMM, LOGL_INFO, "IMSI DETACH for %s\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_subscr_conn_close(conn, 0);
return 0;
}
@@ -1154,7 +833,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;
}
@@ -1187,7 +866,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;
}
@@ -1197,7 +876,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;
}
@@ -1206,7 +885,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;
}
@@ -1218,17 +897,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_subscr_conn_close(conn, GSM_CAUSE_AUTH_FAILED);
return -EINVAL;
}
@@ -1242,56 +919,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_subscr_conn_close(conn, GSM_CAUSE_AUTH_FAILED);
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)
@@ -1301,20 +940,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_subscr_conn_close(conn, GSM_CAUSE_AUTH_FAILED);
return -EINVAL;
}
@@ -1322,9 +952,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_subscr_conn_close(conn, GSM_CAUSE_AUTH_FAILED);
return -EINVAL;
}
@@ -1333,10 +962,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
@@ -1347,9 +975,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_subscr_conn_close(conn, GSM_CAUSE_AUTH_FAILED);
return -EINVAL;
}
@@ -1364,10 +991,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_subscr_conn_close(conn, GSM_CAUSE_AUTH_FAILED);
return -EINVAL;
}
@@ -1375,9 +1001,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_subscr_conn_close(conn, GSM_CAUSE_AUTH_FAILED);
return -EINVAL;
}
@@ -1385,15 +1010,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 */
@@ -1404,7 +1035,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:
@@ -1417,9 +1047,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));
- loc_updating_success(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);
@@ -1442,18 +1070,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 = conn->bts->location_area_code; /* (will be replaced by conn->lac soon) */
resp = (struct gsm48_pag_resp *) &gh->data[0];
gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh),
@@ -1461,55 +1108,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;
}
@@ -1527,7 +1150,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 */
@@ -1681,12 +1309,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 -) "
@@ -1752,7 +1380,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;
@@ -1762,7 +1391,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,
@@ -2023,7 +1652,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);
@@ -2044,7 +1673,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;
@@ -2247,9 +1876,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)) {
@@ -2298,7 +1926,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]);
@@ -2335,7 +1963,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 */
@@ -2426,8 +2054,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);
@@ -2580,9 +2207,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)) {
@@ -3379,7 +3005,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);
@@ -3435,7 +3061,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);
@@ -3612,7 +3238,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;
@@ -3656,7 +3282,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) "
@@ -3679,17 +3305,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,
@@ -3700,22 +3325,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,
@@ -3723,7 +3348,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) {
@@ -3731,15 +3356,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;
}
@@ -3747,24 +3372,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 = conn;
- subscr_put(subscr);
+ trans->conn = msc_subscr_conn_get(conn);
+ 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)
@@ -3774,7 +3401,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);
@@ -3791,7 +3418,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));
@@ -3878,8 +3505,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;
}
@@ -3889,7 +3516,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(conn->vsub),
gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0,
gsm48_cc_state_name(trans?(trans->cc.state):0));
@@ -3898,7 +3525,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) {
@@ -3909,7 +3536,8 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m
return -ENOMEM;
}
/* Assign transaction */
- trans->conn = conn;
+ trans->conn = msc_subscr_conn_get(conn);
+ cm_service_request_concludes(conn, msg);
}
/* find function for current state and message */
@@ -3922,70 +3550,74 @@ 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)
+static bool msg_is_initially_permitted(const struct gsm48_hdr *hdr)
{
- if (!conn->anch_operation)
- return;
+ uint8_t pdisc = gsm48_hdr_pdisc(hdr);
+ uint8_t msg_type = gsm48_hdr_msg_type(hdr);
- osmo_timer_del(&conn->anch_operation->timeout);
- talloc_free(conn->anch_operation);
- conn->anch_operation = NULL;
-}
-
-static void anchor_timeout(void *_data)
-{
- struct gsm_subscriber_connection *con = _data;
+ 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;
+ }
- release_anchor(con);
- msc_release_connection(con);
+ return false;
}
-int gsm0408_new_conn(struct gsm_subscriber_connection *conn)
+void cm_service_request_concludes(struct gsm_subscriber_connection *conn,
+ struct msgb *msg)
{
- conn->anch_operation = talloc_zero(conn, struct gsm_anchor_operation);
- if (!conn->anch_operation)
- return -1;
-
- osmo_timer_setup(&conn->anch_operation->timeout, anchor_timeout, conn);
- osmo_timer_schedule(&conn->anch_operation->timeout, 5, 0);
- return 0;
-}
-struct gsm_subscriber_connection *msc_subscr_con_allocate(struct gsm_network *network)
-{
- struct gsm_subscriber_connection *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. */
- 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_con_free(struct gsm_subscriber_connection *conn)
-{
- if (!conn)
+ 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)
{
@@ -3997,6 +3629,16 @@ 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);
@@ -4004,7 +3646,6 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg)
switch (pdisc) {
case GSM48_PDISC_CC:
- release_anchor(conn);
rc = gsm0408_rcv_cc(conn, msg);
break;
case GSM48_PDISC_MM:
@@ -4014,7 +3655,6 @@ 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);
rc = gsm0411_rcv_sms(conn, msg);
break;
case GSM48_PDISC_MM_GPRS:
@@ -4024,7 +3664,6 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg)
rc = -ENOTSUP;
break;
case GSM48_PDISC_NC_SS:
- release_anchor(conn);
rc = handle_rcv_ussd(conn, msg);
break;
default:
@@ -4037,6 +3676,166 @@ 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;
+ conn->received_cm_service_request = false;
+
+ 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("MSC", 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/src/libmsc/gsm_04_11.c b/src/libmsc/gsm_04_11.c
index aa2030f8..6ad944b5 100644
--- a/src/libmsc/gsm_04_11.c
+++ b/src/libmsc/gsm_04_11.c
@@ -56,6 +56,8 @@
#include <openbsc/bsc_rll.h>
#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"
@@ -74,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);
@@ -83,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();
@@ -92,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);
@@ -297,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[
@@ -310,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 */
@@ -325,7 +327,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[
@@ -469,13 +471,12 @@ static int gsm340_rx_tpdu(struct gsm_trans *trans, struct msgb *msg,
}
}
- 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 :
@@ -634,7 +635,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) {
@@ -804,7 +805,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 */
@@ -824,7 +825,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) {
@@ -837,9 +838,10 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
gsm411_smr_init(&trans->sms.smr_inst, 0, 1,
gsm411_rl_recv, gsm411_mn_send);
- trans->conn = conn;
+ trans->conn = msc_subscr_conn_get(conn);
new_trans = 1;
+ cm_service_request_concludes(conn, msg);
}
/* 5.4: For MO, if a CP-DATA is received for a new
@@ -866,6 +868,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);
@@ -886,7 +890,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");
@@ -899,7 +903,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) {
@@ -916,7 +920,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
gsm411_rl_recv, gsm411_mn_send);
trans->sms.sms = sms;
- trans->conn = conn;
+ trans->conn = msc_subscr_conn_get(conn);
/* Hardcode SMSC Originating Address for now */
data = (uint8_t *)msgb_put(msg, 8);
@@ -994,7 +998,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;
@@ -1002,18 +1006,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);
@@ -1040,6 +1044,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/src/libmsc/gsm_subscriber.c b/src/libmsc/gsm_subscriber.c
index 1a03cf76..e9b2e0e5 100644
--- a/src/libmsc/gsm_subscriber.c
+++ b/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,105 +114,52 @@ 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;
}
-static int subscr_paging_sec_cb(unsigned int hooknum, unsigned int event,
- struct msgb *msg, void *data, void *param)
-{
- int rc;
-
- switch (event) {
- case GSM_SECURITY_AUTH_FAILED:
- /* Dispatch as paging failure */
- rc = subscr_paging_dispatch(
- GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED,
- msg, data, param);
- break;
-
- case GSM_SECURITY_NOAVAIL:
- case GSM_SECURITY_SUCCEEDED:
- /* Dispatch as paging failure */
- rc = subscr_paging_dispatch(
- GSM_HOOK_RR_PAGING, GSM_PAGING_SUCCEEDED,
- msg, data, param);
- break;
-
- default:
- rc = -EINVAL;
- }
-
- return rc;
-}
-
-static int subscr_paging_cb(unsigned int hooknum, unsigned int event,
- struct msgb *msg, void *data, void *param)
-{
- struct gsm_subscriber_connection *conn = data;
- struct gsm48_hdr *gh;
- struct gsm48_pag_resp *pr;
-
- /* Other cases mean problem, dispatch direclty */
- if (event != GSM_PAGING_SUCCEEDED)
- return subscr_paging_dispatch(hooknum, event, msg, data, param);
-
- /* Get paging response */
- gh = msgb_l3(msg);
- pr = (struct gsm48_pag_resp *)gh->data;
-
- /* We _really_ have a channel, secure it now ! */
- 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;
- rc = paging_request(net, bsub, channel_type, subscr_paging_cb,
- subscr);
+ vlr_subscr_name(vsub));
+ bsub = vlr_subscr_to_bsc_sub(net->bsc_subscribers, vsub);
+ rc = paging_request(net, bsub, channel_type, NULL, NULL);
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 +169,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/src/libmsc/meas_feed.c b/src/libmsc/meas_feed.c
index 3ddcdc39..1e7b4cd5 100644
--- a/src/libmsc/meas_feed.c
+++ b/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/src/libmsc/osmo_msc.c b/src/libmsc/osmo_msc.c
index 2389980d..95e58182 100644
--- a/src/libmsc/osmo_msc.c
+++ b/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,66 @@ static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci)
gsm411_sapi_n_reject(conn);
}
-static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
+static bool keep_conn(struct gsm_subscriber_connection *conn)
{
- gsm0408_clear_request(conn, cause);
- return 1;
+ /* 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;
+ }
+}
+
+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 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);
+ /* Ownership of the gsm_subscriber_connection is still a bit mucky
+ * between libbsc and libmsc. In libmsc, we use ref counting, but not
+ * in libbsc. This will become simpler with the MSCSPLIT. */
+
+ /* reserve for the duration of this function */
+ msc_subscr_conn_get(conn);
+
gsm0408_dispatch(conn, msg);
+ if (!keep_conn(conn)) {
+ DEBUGP(DMM, "compl_l3: Discarding conn\n");
+ /* keep the use_count reserved, libbsc will discard. If we
+ * released the ref count and discarded here, libbsc would
+ * double-free. And we will not change bsc_api semantics. */
+ return BSC_API_CONN_POL_REJECT;
+ }
+ DEBUGP(DMM, "compl_l3: Keeping conn\n");
+
+ /* Bump whether the conn wants to be closed */
+ subscr_conn_bump(conn);
+
+ /* If this should be kept, the conn->conn_fsm has placed a use_count */
+ msc_subscr_conn_put(conn);
+ 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 +106,28 @@ 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
}
+/* Receive a DTAP message from BSC */
static void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg)
{
+ msc_subscr_conn_get(conn);
gsm0408_dispatch(conn, msg);
+
+ /* Bump whether the conn wants to be closed */
+ subscr_conn_bump(conn);
+ msc_subscr_conn_put(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 +135,150 @@ 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 CHANGE 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);
+ if (cm2 && cm2_len) {
+ if (cm2_len > sizeof(conn->classmark.classmark2)) {
+ LOGP(DRR, LOGL_NOTICE, "%s: classmark2 is %u bytes, truncating at %zu bytes\n",
+ vlr_subscr_name(conn->vsub), cm2_len, sizeof(conn->classmark.classmark2));
+ cm2_len = sizeof(conn->classmark.classmark2);
}
- db_sync_equipment(&subscr->equipment);
+ conn->classmark.classmark2_len = cm2_len;
+ memcpy(conn->classmark.classmark2, cm2, cm2_len);
+ }
+ if (cm3 && cm3_len) {
+ if (cm3_len > sizeof(conn->classmark.classmark3)) {
+ LOGP(DRR, LOGL_NOTICE, "%s: classmark3 is %u bytes, truncating at %zu bytes\n",
+ vlr_subscr_name(conn->vsub), cm3_len, sizeof(conn->classmark.classmark3));
+ cm3_len = sizeof(conn->classmark.classmark3);
+ }
+ 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;
+
+ 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);
}
+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);
+}
+
+/* Receive a CLEAR REQUEST from BSC */
+static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause)
+{
+ msc_subscr_conn_close(conn, cause);
+ return 1;
+}
+/* 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,41 +288,108 @@ 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 */
-void msc_release_connection(struct gsm_subscriber_connection *conn)
+static void msc_subscr_conn_release_all(struct gsm_subscriber_connection *conn, uint32_t cause)
{
- /* skip when we are in release, e.g. due an error */
if (conn->in_release)
return;
+ conn->in_release = true;
+
+ /* If we're closing in a middle of a trans, we need to clean up */
+ trans_conn_closed(conn);
+
+ switch (conn->via_ran) {
+ case RAN_UTRAN_IU:
+ /* future: iu_tx_release(conn->iu.ue_ctx, NULL); */
+ break;
+ case RAN_GERAN_A:
+ /* future: a_iface_tx_clear_cmd(conn); */
+ break;
+ default:
+ LOGP(DMM, LOGL_ERROR, "%s: Unknown RAN type, cannot tx release/clear\n",
+ vlr_subscr_name(conn->vsub));
+ break;
+ }
+}
- /* skip releasing of silent calls as they have no transaction */
- if (conn->silent_call)
+/* If the conn->conn_fsm is still present, dispatch SUBSCR_CONN_E_CN_CLOSE
+ * event to gracefully terminate the connection. If the conn_fsm is already
+ * cleared, call msc_subscr_conn_release_all() to take release actions.
+ * \param cause a GSM_CAUSE_* constant, e.g. GSM_CAUSE_AUTH_FAILED.
+ */
+void msc_subscr_conn_close(struct gsm_subscriber_connection *conn,
+ uint32_t cause)
+{
+ if (!conn)
return;
-
- /* check if there is a pending operation */
- if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
+ if (conn->in_release) {
+ DEBUGP(DMM, "msc_subscr_conn_close(vsub=%s, cause=%u):"
+ " already dispatching release, ignore.\n",
+ vlr_subscr_name(conn->vsub), cause);
return;
-
- if (trans_has_conn(conn))
+ }
+ if (!conn->conn_fsm) {
+ DEBUGP(DMM, "msc_subscr_conn_close(vsub=%s, cause=%u): no conn fsm,"
+ " releasing directly without release event.\n",
+ vlr_subscr_name(conn->vsub), cause);
+ /* In case of an IMSI Detach, we don't have conn_fsm. Release
+ * anyway to ensure a timely Iu Release / BSSMAP Clear. */
+ msc_subscr_conn_release_all(conn, cause);
return;
+ }
+ if (conn->conn_fsm->state == SUBSCR_CONN_S_RELEASED) {
+ DEBUGP(DMM, "msc_subscr_conn_close(vsub=%s, cause=%u):"
+ " conn fsm already releasing, ignore.\n",
+ vlr_subscr_name(conn->vsub), cause);
+ return;
+ }
+ osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_CN_CLOSE, &cause);
+}
- /* no more connections, asking to release the channel */
+/* increment the ref-count. Needs to be called by every user */
+struct gsm_subscriber_connection *
+_msc_subscr_conn_get(struct gsm_subscriber_connection *conn,
+ const char *file, int line)
+{
+ OSMO_ASSERT(conn);
- /*
- * 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);
+ if (conn->in_release)
+ return NULL;
- conn->in_release = 1;
- gsm0808_clear(conn);
- msc_subscr_con_free(conn);
+ conn->use_count++;
+ LOGPSRC(DREF, LOGL_DEBUG, file, line,
+ "%s: MSC conn use + 1 == %u\n",
+ vlr_subscr_name(conn->vsub), conn->use_count);
+
+ return conn;
+}
+
+/* decrement the ref-count. Once it reaches zero, we release */
+void _msc_subscr_conn_put(struct gsm_subscriber_connection *conn,
+ const char *file, int line)
+{
+ OSMO_ASSERT(conn);
+
+ if (conn->use_count == 0) {
+ LOGPSRC(DREF, LOGL_ERROR, file, line,
+ "%s: MSC conn use - 1 failed: is already 0\n",
+ vlr_subscr_name(conn->vsub));
+ return;
+ }
+
+ conn->use_count--;
+ LOGPSRC(DREF, LOGL_DEBUG, file, line,
+ "%s: MSC conn use - 1 == %u\n",
+ vlr_subscr_name(conn->vsub), conn->use_count);
+
+ if (conn->use_count == 0) {
+ gsm0808_clear(conn);
+ bsc_subscr_con_free(conn);
+ }
}
diff --git a/src/libmsc/rrlp.c b/src/libmsc/rrlp.c
index e695daac..cd3da066 100644
--- a/src/libmsc/rrlp.c
+++ b/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/src/libmsc/silent_call.c b/src/libmsc/silent_call.c
index 590d01bb..6f3fbf26 100644
--- a/src/libmsc/silent_call.c
+++ b/src/libmsc/silent_call.c
@@ -55,6 +55,7 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
DEBUGPC(DLSMS, "success, using Timeslot %u on ARFCN %u\n",
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
conn->silent_call = 1;
+ msc_subscr_conn_get(conn);
/* increment lchan reference count */
osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
break;
@@ -121,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;
@@ -146,7 +147,7 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr)
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
conn->silent_call = 0;
- msc_release_connection(conn);
+ msc_subscr_conn_put(conn);
return 0;
}
diff --git a/src/libmsc/smpp_openbsc.c b/src/libmsc/smpp_openbsc.c
index f94968a3..f06eb7d9 100644
--- a/src/libmsc/smpp_openbsc.c
+++ b/src/libmsc/smpp_openbsc.c
@@ -45,31 +45,32 @@
#include <openbsc/transaction.h>
#include <openbsc/gsm_subscriber.h>
#include <openbsc/chan_alloc.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 */
@@ -88,7 +89,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;
@@ -111,7 +112,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;
@@ -122,7 +123,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;
}
@@ -134,7 +135,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;
@@ -252,7 +253,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;
@@ -265,11 +266,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);
}
}
}
@@ -316,7 +317,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;
@@ -325,7 +326,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;
}
@@ -336,7 +337,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;
@@ -352,7 +353,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;
}
@@ -452,12 +453,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);
}
}
@@ -496,7 +497,7 @@ static void smpp_cmd_free(struct osmo_smpp_cmd *cmd)
{
osmo_timer_del(&cmd->response_timer);
llist_del(&cmd->list);
- subscr_put(cmd->subscr);
+ vlr_subscr_put(cmd->vsub);
sms_free(cmd->sms);
talloc_free(cmd);
}
@@ -514,7 +515,7 @@ void smpp_cmd_ack(struct osmo_smpp_cmd *cmd)
struct gsm_subscriber_connection *conn;
struct gsm_trans *trans;
- conn = connection_for_subscr(cmd->subscr);
+ conn = connection_for_subscr(cmd->vsub);
if (!conn) {
LOGP(DSMPP, LOGL_ERROR, "No connection to subscriber anymore\n");
return;
@@ -538,7 +539,7 @@ void smpp_cmd_err(struct osmo_smpp_cmd *cmd, uint32_t status)
struct gsm_trans *trans;
int gsm411_cause;
- conn = connection_for_subscr(cmd->subscr);
+ conn = connection_for_subscr(cmd->vsub);
if (!conn) {
LOGP(DSMPP, LOGL_ERROR, "No connection to subscriber anymore\n");
return;
@@ -566,7 +567,7 @@ static void smpp_deliver_sm_cb(void *data)
}
static int smpp_cmd_enqueue(struct osmo_esme *esme,
- struct gsm_subscriber *subscr, struct gsm_sms *sms,
+ struct vlr_subscr *vsub, struct gsm_sms *sms,
uint32_t sequence_number, bool *deferred)
{
struct osmo_smpp_cmd *cmd;
@@ -577,7 +578,7 @@ static int smpp_cmd_enqueue(struct osmo_esme *esme,
cmd->sequence_nr = sequence_number;
cmd->sms = sms;
- cmd->subscr = subscr_get(subscr);
+ cmd->vsub = vlr_subscr_get(vsub);
/* FIXME: No predefined value for this response_timer as specified by
* SMPP 3.4 specs, section 7.2. Make this configurable? Don't forget
@@ -623,13 +624,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;
@@ -686,7 +687,7 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms,
if (ret < 0)
return ret;
- return smpp_cmd_enqueue(esme, conn->subscr, sms,
+ return smpp_cmd_enqueue(esme, conn->vsub, sms,
deliver.sequence_number, deferred);
}
diff --git a/src/libmsc/smpp_smsc.h b/src/libmsc/smpp_smsc.h
index d8e82e42..4bee59b6 100644
--- a/src/libmsc/smpp_smsc.h
+++ b/src/libmsc/smpp_smsc.h
@@ -88,7 +88,7 @@ struct osmo_smpp_route {
struct osmo_smpp_cmd {
struct llist_head list;
- struct gsm_subscriber *subscr;
+ struct vlr_subscr *vsub;
struct gsm_sms *sms;
uint32_t sequence_nr;
struct osmo_timer_list response_timer;
diff --git a/src/libmsc/sms_queue.c b/src/libmsc/sms_queue.c
index dc7f6e8c..fe7a608b 100644
--- a/src/libmsc/sms_queue.c
+++ b/src/libmsc/sms_queue.c
@@ -28,6 +28,8 @@
* things up by collecting data from other parts of the system.
*/
+#include <limits.h>
+
#include <openbsc/sms_queue.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/db.h>
@@ -36,6 +38,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 +50,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;
@@ -62,7 +65,8 @@ struct gsm_sms_queue {
int pending;
struct llist_head pending_sms;
- unsigned long long last_subscr_id;
+
+ char last_msisdn[GSM_EXTENSION_LENGTH+1];
};
static int sms_subscr_cb(unsigned int, unsigned int, void *, void *);
@@ -88,12 +92,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 +105,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 +119,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 +149,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);
@@ -186,23 +192,49 @@ static void sms_resend_pending(void *_data)
}
}
-static struct gsm_sms *take_next_sms(struct gsm_sms_queue *smsq)
+/* Find the next pending SMS by cycling through the recipients. We could also
+ * cycle through the pending SMS, but that might cause us to keep trying to
+ * send SMS to the same few subscribers repeatedly while not servicing other
+ * subscribers for a long time. By walking the list of recipient MSISDNs, we
+ * ensure that all subscribers get their fair time to receive SMS. */
+struct gsm_sms *smsq_take_next_sms(struct gsm_network *net,
+ char *last_msisdn,
+ size_t last_msisdn_buflen)
{
struct gsm_sms *sms;
+ int wrapped = 0;
+ int sanity = 100;
+ char started_with_msisdn[last_msisdn_buflen];
+
+ osmo_strlcpy(started_with_msisdn, last_msisdn,
+ sizeof(started_with_msisdn));
+
+ while (wrapped < 2 && (--sanity)) {
+ /* If we wrapped around and passed the first msisdn, we're
+ * through the entire SMS DB; end it. */
+ if (wrapped && strcmp(last_msisdn, started_with_msisdn) >= 0)
+ break;
+
+ sms = db_sms_get_next_unsent_rr_msisdn(net, last_msisdn, 9);
+ if (!sms) {
+ last_msisdn[0] = '\0';
+ wrapped ++;
+ continue;
+ }
+
+ /* Whatever happens, next time around service another recipient
+ */
+ osmo_strlcpy(last_msisdn, sms->dst.addr, last_msisdn_buflen);
+
+ /* Is the subscriber attached? If not, go to next SMS */
+ if (!sms->receiver || !sms->receiver->lu_complete)
+ continue;
- sms = db_sms_get_unsent_by_subscr(smsq->network, smsq->last_subscr_id, 10);
- if (sms) {
- smsq->last_subscr_id = sms->receiver->id + 1;
return sms;
}
- /* need to wrap around */
- smsq->last_subscr_id = 0;
- sms = db_sms_get_unsent_by_subscr(smsq->network,
- smsq->last_subscr_id, 10);
- if (sms)
- smsq->last_subscr_id = sms->receiver->id + 1;
- return sms;
+ DEBUGP(DLSMS, "SMS queue: no SMS to be sent\n");
+ return NULL;
}
/**
@@ -224,7 +256,8 @@ static void sms_submit_pending(void *_data)
struct gsm_sms *sms;
- sms = take_next_sms(smsq);
+ sms = smsq_take_next_sms(smsq->network, smsq->last_msisdn,
+ sizeof(smsq->last_msisdn));
if (!sms) {
LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (%d attempted)\n",
attempted);
@@ -289,21 +322,22 @@ 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, UINT_MAX);
if (!sms)
goto no_pending_sms;
- /* No sms should be scheduled right now */
+ /* The sms should not be scheduled right now */
OSMO_ASSERT(!sms_is_in_pending(smsq, sms));
/* Remember that we deliver this SMS and send it */
@@ -322,7 +356,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);
}
/*
@@ -362,7 +396,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;
@@ -383,20 +417,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, UINT_MAX);
if (!sms)
return -1;
gsm411_send_sms(conn, sms);
@@ -406,13 +440,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,
@@ -421,7 +455,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) {
@@ -447,11 +481,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;
@@ -508,7 +542,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;
}
@@ -535,7 +569,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/src/libmsc/subscr_conn.c b/src/libmsc/subscr_conn.c
index 91ffe406..b28a5112 100644
--- a/src/libmsc/subscr_conn.c
+++ b/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,14 +55,21 @@ 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)
{
struct gsm_subscriber_connection *conn = fi->priv;
enum subscr_conn_from from = SUBSCR_CONN_FROM_INVALID;
- enum gsm_paging_event pe;
+ bool success;
if (data) {
from = *(enum subscr_conn_from*)data;
@@ -67,12 +79,12 @@ 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:
@@ -81,23 +93,27 @@ void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data)
break;
}
- /* if appropriate, signal paging success or failure */
- if (from == SUBSCR_CONN_FROM_PAGING_RESP) {
- pe = (fi->state == SUBSCR_CONN_S_ACCEPTED)?
- GSM_PAGING_SUCCEEDED : GSM_PAGING_EXPIRED;
- paging_resp(conn, pe);
- }
+ success = (fi->state == SUBSCR_CONN_S_ACCEPTED);
+
+ if (from == SUBSCR_CONN_FROM_LU)
+ rate_ctr_inc(&conn->network->msc_ctrs->ctr[
+ success ? MSC_CTR_LOC_UPDATE_COMPLETED
+ : MSC_CTR_LOC_UPDATE_FAILED]);
+
+ /* signal paging success or failure in case this was a paging */
+ if (from == SUBSCR_CONN_FROM_PAGING_RESP)
+ paging_resp(conn,
+ success ? GSM_PAGING_SUCCEEDED
+ : GSM_PAGING_EXPIRED);
/* On failure, discard the conn */
- if (fi->state != SUBSCR_CONN_S_ACCEPTED) {
+ if (!success) {
/* TODO: on MO_CLOSE or CN_CLOSE, first go to RELEASING and
* await BSC confirmation? */
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
return;
}
- /* On success, handle pending requests and/or close conn */
-
if (from == SUBSCR_CONN_FROM_CM_SERVICE_REQ) {
conn->received_cm_service_request = true;
LOGPFSM(fi, "received_cm_service_request = true\n");
@@ -106,33 +122,6 @@ void subscr_conn_fsm_new(struct osmo_fsm_inst *fi, uint32_t event, void *data)
osmo_fsm_inst_dispatch(fi, SUBSCR_CONN_E_BUMP, data);
}
-#if 0
- case SUBSCR_CONN_E_PARQ_SUCCESS:
- osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_ACCEPTED, 0, 0);
- accept_conn = true;
- /* fall through */
- case SUBSCR_CONN_E_PARQ_FAILURE:
- parq_type = data ? *(enum vlr_parq_type*)data : VLR_PR_ARQ_T_INVALID;
- switch (parq_type) {
-
- case VLR_PR_ARQ_T_CM_SERV_REQ:
- accept_conn = handle_cm_serv_result(fi, accept_conn);
- break;
-
- case VLR_PR_ARQ_T_PAGING_RESP:
- accept_conn = handle_paging_result(fi, accept_conn);
- break;
-
- default:
- LOGPFSML(fi, LOGL_ERROR,
- "Invalid VLR Process Access Request type"
- " %d\n", parq_type);
- accept_conn = false;
- break;
- }
- break;
-#endif
-
static void subscr_conn_fsm_bump(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
struct gsm_subscriber_connection *conn = fi->priv;
@@ -143,8 +132,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 +141,19 @@ static void subscr_conn_fsm_bump(struct osmo_fsm_inst *fi, uint32_t event, void
osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_RELEASED, 0, 0);
}
+static void subscr_conn_fsm_accepted_enter(struct osmo_fsm_inst *fi, uint32_t prev_state)
+{
+ struct gsm_subscriber_connection *conn = fi->priv;
+ osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_ATTACHED, conn->vsub);
+}
+
static void subscr_conn_fsm_accepted(struct osmo_fsm_inst *fi, uint32_t event, void *data)
{
switch (event) {
+ case SUBSCR_CONN_E_COMMUNICATING:
+ osmo_fsm_inst_state_chg(fi, SUBSCR_CONN_S_COMMUNICATING, 0, 0);
+ return;
+
case SUBSCR_CONN_E_BUMP:
subscr_conn_fsm_bump(fi, event, data);
return;
@@ -169,34 +167,68 @@ 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)
{
- struct gsm_subscriber_connection *conn = fi->priv;
- if (!conn)
+ switch (event) {
+ case SUBSCR_CONN_E_COMMUNICATING:
+ /* no-op */
return;
- /* 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));
+ 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;
+
+ conn->conn_fsm = NULL;
+ msc_subscr_conn_close(conn, cause);
+ msc_subscr_conn_put(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;
+}
- DEBUGP(DMM, "%s calling bsc_subscr_con_free(), owned_by_msc = true\n",
- subscr_name(conn->subscr));
- gsm0808_clear(conn);
- bsc_subscr_con_free(conn);
+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 +236,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 +271,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 +286,14 @@ 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,
+ msc_subscr_conn_get(conn),
+ LOGL_DEBUG, id);
if (!fi) {
LOGP(DMM, LOGL_ERROR,
@@ -247,6 +301,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 +309,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/src/libmsc/token_auth.c b/src/libmsc/token_auth.c
deleted file mode 100644
index 5af1e980..00000000
--- a/src/libmsc/token_auth.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/* SMS based token authentication for ad-hoc GSM networks */
-
-/* (C) 2009 by Harald Welte <laforge@gnumonks.org>
- *
- * 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 Affero 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 <stdio.h>
-#include <osmocom/core/talloc.h>
-#include <openbsc/signal.h>
-#include <openbsc/gsm_data.h>
-#include <openbsc/gsm_04_11.h>
-#include <openbsc/gsm_04_08.h>
-#include <openbsc/gsm_subscriber.h>
-#include <openbsc/chan_alloc.h>
-#include <openbsc/db.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."
-
-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);
- 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);
- sms_str[len-1] = '\0';
-
- return sms_str;
-}
-
-static int token_subscr_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct gsm_subscriber *subscr = signal_data;
- struct gsm_sms *sms;
- int rc = 0;
-
- if (signal != S_SUBSCR_ATTACHED)
- return 0;
-
- if (subscr->group->net->auth_policy != GSM_AUTH_POLICY_TOKEN)
- return 0;
-
- if (subscr->flags & GSM_SUBSCRIBER_FIRST_CONTACT) {
- struct gsm_subscriber *sender;
- uint32_t token;
- char *sms_str;
-
- /* we've seen this subscriber for the first time. */
- rc = db_subscriber_alloc_token(subscr, &token);
- if (rc != 0) {
- rc = -EIO;
- goto unauth;
- }
-
- sms_str = build_sms_string(subscr, token);
- if (!sms_str) {
- rc = -ENOMEM;
- goto unauth;
- }
-
-
- /* FIXME: don't use ID 1 static */
- sender = subscr_get_by_id(subscr->group, 1);
-
- sms = sms_from_text(subscr, sender, 0, sms_str);
-
- subscr_put(sender);
- talloc_free(sms_str);
- if (!sms) {
- rc = -ENOMEM;
- goto unauth;
- }
-
- rc = gsm411_send_sms_subscr(subscr, sms);
-
- /* FIXME: else, delete the subscirber from database */
-unauth:
-
- /* make sure we don't allow him in again unless he clicks the web UI */
- subscr->authorized = 0;
- db_sync_subscriber(subscr);
- if (rc) {
- struct gsm_subscriber_connection *conn = connection_for_subscr(subscr);
- if (conn) {
- uint8_t auth_rand[16];
- /* kick the subscriber off the network */
- gsm48_tx_mm_auth_req(conn, auth_rand, NULL, 0);
- gsm48_tx_mm_auth_rej(conn);
- /* FIXME: close the channel early ?*/
- //gsm48_send_rr_Release(lchan);
- }
- }
- }
-
- return rc;
-}
-
-static int token_sms_cb(unsigned int subsys, unsigned int signal,
- void *handler_data, void *signal_data)
-{
- struct sms_signal_data *sig = signal_data;
- struct gsm_sms *sms = sig->sms;;
- struct gsm_subscriber_connection *conn;
- uint8_t auth_rand[16];
-
-
- if (signal != S_SMS_DELIVERED)
- return 0;
-
-
- /* these are not the droids we've been looking for */
- if (!sms->receiver ||
- !(sms->receiver->flags & GSM_SUBSCRIBER_FIRST_CONTACT))
- return 0;
-
-
- if (sms->receiver->group->net->auth_policy != GSM_AUTH_POLICY_TOKEN)
- return 0;
-
-
- conn = connection_for_subscr(sms->receiver);
- if (conn) {
- /* kick the subscriber off the network */
- gsm48_tx_mm_auth_req(conn, auth_rand, NULL, 0);
- gsm48_tx_mm_auth_rej(conn);
- /* FIXME: close the channel early ?*/
- //gsm48_send_rr_Release(lchan);
- }
-
- return 0;
-}
-
-//static __attribute__((constructor)) void on_dso_load_token(void)
-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);
-}
diff --git a/src/libmsc/transaction.c b/src/libmsc/transaction.c
index dba4bed1..d157f546 100644
--- a/src/libmsc/transaction.c
+++ b/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,27 @@ 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 = vlr_subscr_get(vsub);
trans->protocol = protocol;
trans->transaction_id = trans_id;
@@ -87,6 +104,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,23 +123,28 @@ 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);
if (trans->conn)
- msc_release_connection(trans->conn);
+ msc_subscr_conn_put(trans->conn);
trans->conn = NULL;
talloc_free(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,
+/*! allocate an unused transaction ID for the given subscriber
+ * 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 +156,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 +176,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 +190,25 @@ int trans_has_conn(const struct gsm_subscriber_connection *conn)
return 0;
}
+
+/*! Free all transactions associated with a connection, presumably when the
+ * conn is being closed. The transaction code will inform the CC or SMS
+ * facilities, which will then send the necessary release indications.
+ * \param[in] conn Connection that is going to be closed.
+ */
+void trans_conn_closed(struct gsm_subscriber_connection *conn)
+{
+ struct gsm_trans *trans;
+
+ /* As part of the CC REL_IND the remote leg might be released and this
+ * will trigger another call to trans_free. This is something the llist
+ * macro can not handle and we need to re-iterate the list every time.
+ */
+restart:
+ llist_for_each_entry(trans, &conn->network->trans_list, entry) {
+ if (trans->conn == conn) {
+ trans_free(trans);
+ goto restart;
+ }
+ }
+}
diff --git a/src/libmsc/ussd.c b/src/libmsc/ussd.c
index f12c1f28..81a35669 100644
--- a/src/libmsc/ussd.c
+++ b/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#";
@@ -48,13 +49,19 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
struct ss_request req;
struct gsm48_hdr *gh;
+ /* TODO: Use subscriber_connection ref-counting if we ever want
+ * to keep the connection alive due ot ongoing USSD exchange.
+ * As we answer everytying synchronously so far, there's no need
+ * yet */
+
+ cm_service_request_concludes(conn, msg);
+
memset(&req, 0, sizeof(req));
gh = msgb_l3(msg);
rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
if (!rc) {
DEBUGP(DMM, "Unhandled SS\n");
rc = gsm0480_send_ussd_reject(conn, msg, &req);
- msc_release_connection(conn);
return rc;
}
@@ -63,13 +70,13 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
if (req.ss_code > 0) {
/* Assume interrogateSS or modification of it and reject */
rc = gsm0480_send_ussd_reject(conn, msg, &req);
- msc_release_connection(conn);
return rc;
}
/* Still assuming a Release-Complete and returning */
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);
@@ -78,17 +85,18 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
rc = gsm0480_send_ussd_reject(conn, msg, &req);
}
- /* check if we can release it */
- msc_release_connection(conn);
return rc;
}
/* 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/src/libmsc/vty_interface_layer3.c b/src/libmsc/vty_interface_layer3.c
index 99d7fb94..c393a8fa 100644
--- a/src/libmsc/vty_interface_layer3.c
+++ b/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;
@@ -147,25 +158,27 @@ DEFUN(sms_send_pend,
{
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
struct gsm_sms *sms;
- int id = 0;
+ unsigned long long sms_id = 0;
while (1) {
- sms = db_sms_get_unsent_by_subscr(gsmnet, id, UINT_MAX);
+ sms = db_sms_get_next_unsent(gsmnet, sms_id, UINT_MAX);
if (!sms)
break;
- gsm411_send_sms_subscr(sms->receiver, sms);
+ if (sms->receiver)
+ gsm411_send_sms_subscr(sms->receiver, sms);
- id = sms->receiver->id + 1;
+ sms_id = sms->id + 1;
}
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 +193,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 +224,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 +248,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 +259,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_for_subscr(vsub, UINT_MAX);
if (sms)
gsm411_send_sms_subscr(sms->receiver, sms);
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_SUCCESS;
}
@@ -292,12 +284,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 +304,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 +324,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 +344,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 +371,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 +389,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 +409,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 +441,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 +453,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 +469,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 +477,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 +491,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 +523,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 +535,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 +547,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 +563,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 +584,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 +600,7 @@ DEFUN(ena_subscr_handover,
VTY_NEWLINE);
}
- subscr_put(subscr);
+ vlr_subscr_put(vsub);
return CMD_SUCCESS;
}
@@ -695,69 +616,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 +627,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 +639,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 +887,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 +896,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) {
@@ -1053,10 +905,55 @@ DEFUN(logging_fltr_imsi,
return CMD_WARNING;
}
+ log_set_filter_vlr_subscr(tgt, vlr_subscr);
log_set_filter_bsc_subscr(tgt, bsc_subscr);
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)# ",
@@ -1077,18 +974,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 = atoll(argv[0]), ma = atoll(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,
@@ -1096,19 +985,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,
@@ -1116,7 +1006,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;
}
@@ -1125,7 +1015,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;
}
@@ -1134,19 +1024,8 @@ static int config_write_nitb(struct vty *vty)
struct gsm_network *gsmnet = gsmnet_from_vty(vty);
vty_out(vty, "nitb%s", VTY_NEWLINE);
- if (!gsmnet->auto_create_subscr)
- vty_out(vty, " no subscriber-create-on-demand%s", VTY_NEWLINE);
- else
- vty_out(vty, " subscriber-create-on-demand%s%s",
- gsmnet->auto_assign_exten ? "" : " no-extension",
- VTY_NEWLINE);
-
- if (gsmnet->ext_min != GSM_MIN_EXTEN || gsmnet->ext_max != GSM_MAX_EXTEN)
- vty_out(vty, " subscriber-create-on-demand random %"PRIu64" %"
- 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;
}
@@ -1196,6 +1075,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/src/libvlr/vlr_access_req_fsm.c b/src/libvlr/vlr_access_req_fsm.c
index 4e63e299..279e3d49 100644
--- a/src/libvlr/vlr_access_req_fsm.c
+++ b/src/libvlr/vlr_access_req_fsm.c
@@ -343,6 +343,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/src/osmo-nitb/bsc_hack.c b/src/osmo-nitb/bsc_hack.c
index 17b23b2b..89bbb5e6 100644
--- a/src/osmo-nitb/bsc_hack.c
+++ b/src/osmo-nitb/bsc_hack.c
@@ -44,7 +44,6 @@
#include <openbsc/vty.h>
#include <openbsc/bss.h>
#include <openbsc/mncc.h>
-#include <openbsc/token_auth.h>
#include <openbsc/handover_decision.h>
#include <openbsc/rrlp.h>
#include <osmocom/ctrl/control_if.h>
@@ -240,7 +239,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 +260,6 @@ int main(int argc, char **argv)
tall_bsc_ctx = talloc_named_const(NULL, 1, "openbsc");
talloc_ctx_init(tall_bsc_ctx);
- on_dso_load_token();
on_dso_load_rrlp();
on_dso_load_ho_dec();
@@ -285,6 +283,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)
@@ -342,7 +344,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;
}
@@ -356,6 +358,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;