diff options
Diffstat (limited to 'openbsc/src/libmsc')
-rw-r--r-- | openbsc/src/libmsc/Makefile.am | 10 | ||||
-rw-r--r-- | openbsc/src/libmsc/a_iface.c | 77 | ||||
-rw-r--r-- | openbsc/src/libmsc/auth.c | 4 | ||||
-rw-r--r-- | openbsc/src/libmsc/cscn_vty.c | 100 | ||||
-rw-r--r-- | openbsc/src/libmsc/db.c | 2 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 594 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_11.c | 39 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_80.c | 34 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_subscriber.c | 193 | ||||
-rw-r--r-- | openbsc/src/libmsc/iu_cs.c | 173 | ||||
-rw-r--r-- | openbsc/src/libmsc/mncc_builtin.c | 7 | ||||
-rw-r--r-- | openbsc/src/libmsc/msc_api.c | 56 | ||||
-rw-r--r-- | openbsc/src/libmsc/msc_ifaces.c (renamed from openbsc/src/libmsc/gsm_04_11_helper.c) | 45 | ||||
-rw-r--r-- | openbsc/src/libmsc/osmo_msc.c | 30 | ||||
-rw-r--r-- | openbsc/src/libmsc/rrlp.c | 2 | ||||
-rw-r--r-- | openbsc/src/libmsc/silent_call.c | 9 | ||||
-rw-r--r-- | openbsc/src/libmsc/smpp_openbsc.c | 4 | ||||
-rw-r--r-- | openbsc/src/libmsc/sms_queue.c | 9 | ||||
-rw-r--r-- | openbsc/src/libmsc/transaction.c | 4 | ||||
-rw-r--r-- | openbsc/src/libmsc/vty_interface_layer3.c | 92 |
20 files changed, 989 insertions, 495 deletions
diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index 51958905c..9be24589e 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -1,4 +1,5 @@ -AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) +AM_CPPFLAGS = $(all_includes) -I$(top_srcdir)/include -I$(top_builddir) \ + -DCOMPILING_LIBMSC=1 AM_CFLAGS=-Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) \ $(LIBOSMOABIS_CFLAGS) $(COVERAGE_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBSMPP34_CFLAGS) @@ -8,7 +9,7 @@ noinst_LIBRARIES = libmsc.a libmsc_a_SOURCES = auth.c \ db.c \ - gsm_04_08.c gsm_04_11.c gsm_04_11_helper.c \ + gsm_04_08.c gsm_04_11.c \ gsm_04_80.c \ gsm_subscriber.c \ mncc.c mncc_builtin.c mncc_sock.c \ @@ -18,8 +19,11 @@ libmsc_a_SOURCES = auth.c \ token_auth.c \ ussd.c \ vty_interface_layer3.c \ + cscn_vty.c \ transaction.c \ - osmo_msc.c ctrl_commands.c meas_feed.c + osmo_msc.c ctrl_commands.c meas_feed.c \ + msc_api.c msc_ifaces.c iu_cs.c \ + a_iface.c if BUILD_SMPP noinst_HEADERS += smpp_smsc.h diff --git a/openbsc/src/libmsc/a_iface.c b/openbsc/src/libmsc/a_iface.c new file mode 100644 index 000000000..d0423fec1 --- /dev/null +++ b/openbsc/src/libmsc/a_iface.c @@ -0,0 +1,77 @@ +/* A-interface implementation, from MSC to BSC */ + +/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de> + * + * 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 <osmocom/core/msgb.h> +#include <osmocom/core/logging.h> + +#include <openbsc/debug.h> + +#include <openbsc/gsm_data.h> +#include <openbsc/msc_ifaces.h> + +int a_tx(struct msgb *msg) +{ + LOGP(DMSC, LOGL_ERROR, "message to be sent to BSC, but A-interface" + " not implemented.\n%s\n", osmo_hexdump(msg->data, msg->len)); + return -1; +} + +int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher, + const uint8_t *key, int len, int include_imeisv) +{ + /* TODO generalize for A- and Iu interfaces, don't name after 08.08 */ + LOGP(DMSC, LOGL_ERROR, "gsm0808_cipher_mode(): message to be sent to" + " BSC, but A interface not yet implemented.\n"); + return -1; +} + +/* from gsm_04_08_utils.c *****/ + +/* 9.2.5 CM service accept */ +int gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn) +{ + struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 SERV ACC"); + struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); + + gh->proto_discr = GSM48_PDISC_MM; + gh->msg_type = GSM48_MT_MM_CM_SERV_ACC; + + DEBUGP(DMM, "-> CM SERVICE ACCEPT\n"); + + return msc_tx_dtap(conn, msg); +} + +/* 9.2.6 CM service reject */ +int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn, + enum gsm48_reject_value value) +{ + struct msgb *msg; + + msg = gsm48_create_mm_serv_rej(value); + if (!msg) { + LOGP(DMM, LOGL_ERROR, "Failed to allocate CM Service Reject.\n"); + return -1; + } + + DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value); + + return msc_tx_dtap(conn, msg); +} diff --git a/openbsc/src/libmsc/auth.c b/openbsc/src/libmsc/auth.c index 9191ae8b3..cc96e8f28 100644 --- a/openbsc/src/libmsc/auth.c +++ b/openbsc/src/libmsc/auth.c @@ -91,8 +91,6 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple, /* 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, skipping auth\n"); return rc == -ENOENT ? AUTH_NOT_AVAIL : AUTH_ERROR; } @@ -134,11 +132,13 @@ int auth_get_tuple_for_subscr(struct gsm_auth_tuple *atuple, case AUTH_ALGO_XOR: if (_use_xor(&ainfo, atuple)) + /* non-zero return value means failure */ return AUTH_NOT_AVAIL; break; case AUTH_ALGO_COMP128v1: if (_use_comp128_v1(&ainfo, atuple)) + /* non-zero return value means failure */ return AUTH_NOT_AVAIL; break; diff --git a/openbsc/src/libmsc/cscn_vty.c b/openbsc/src/libmsc/cscn_vty.c new file mode 100644 index 000000000..31d8c3873 --- /dev/null +++ b/openbsc/src/libmsc/cscn_vty.c @@ -0,0 +1,100 @@ +/* MSC interface to quagga VTY */ +/* (C) 2016 by sysmocom s.m.f.c. GmbH <info@sysmocom.de> + * Based on OpenBSC interface to quagga VTY (libmsc/vty_interface_layer3.c) + * (C) 2009 by Harald Welte <laforge@gnumonks.org> + * (C) 2009-2011 by Holger Hans Peter Freyther + * 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/>. + * + */ + +/* NOTE: I would have liked to call this the MSC_NODE instead of the CSCN_NODE, + * but MSC_NODE already exists to configure a remote MSC for osmo-bsc. */ + +#include <osmocom/vty/command.h> +#include <openbsc/vty.h> + +#include <openbsc/gsm_data.h> + +static struct cmd_node cscn_node = { + CSCN_NODE, + "%s(config-cscn)# ", + 1, +}; + +DEFUN(cfg_cscn, cfg_cscn_cmd, + "cscn", "Configure CSCN options") +{ + vty->node = CSCN_NODE; + return CMD_SUCCESS; +} + +DEFUN(cfg_cscn_subscr_create, cfg_cscn_subscr_create_cmd, + "subscriber-create-on-demand", + "Make a new record when a subscriber is first seen.\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->create_subscriber = 1; + return CMD_SUCCESS; +} + +DEFUN(cfg_cscn_no_subscr_create, cfg_cscn_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->create_subscriber = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_cscn_assign_tmsi, cfg_cscn_assign_tmsi_cmd, + "assign-tmsi", + "Assign TMSI during Location Updating.\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->avoid_tmsi = 0; + return CMD_SUCCESS; +} + +DEFUN(cfg_cscn_no_assign_tmsi, cfg_cscn_no_assign_tmsi_cmd, + "no assign-tmsi", + NO_STR "Assign TMSI during Location Updating.\n") +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + gsmnet->avoid_tmsi = 1; + return CMD_SUCCESS; +} + +static int config_write_cscn(struct vty *vty) +{ + struct gsm_network *gsmnet = gsmnet_from_vty(vty); + vty_out(vty, "cscn%s", VTY_NEWLINE); + vty_out(vty, " %ssubscriber-create-on-demand%s", + gsmnet->create_subscriber ? "" : "no ", VTY_NEWLINE); + vty_out(vty, " %sassign-tmsi%s", + gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE); + return CMD_SUCCESS; +} + + +void cscn_vty_init(void) +{ + install_element(CONFIG_NODE, &cfg_cscn_cmd); + install_node(&cscn_node, config_write_cscn); + install_element(CSCN_NODE, &cfg_cscn_subscr_create_cmd); + install_element(CSCN_NODE, &cfg_cscn_no_subscr_create_cmd); + install_element(CSCN_NODE, &cfg_cscn_assign_tmsi_cmd); + install_element(CSCN_NODE, &cfg_cscn_no_assign_tmsi_cmd); +} diff --git a/openbsc/src/libmsc/db.c b/openbsc/src/libmsc/db.c index e5017ae7b..b555905ed 100644 --- a/openbsc/src/libmsc/db.c +++ b/openbsc/src/libmsc/db.c @@ -891,7 +891,7 @@ struct gsm_subscriber *db_get_subscriber(enum gsm_subscriber_field field, 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 %u, EXTEN '%s', LAC %hu, AUTH %u\n", + 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); diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index f02f784fe..8c1cf9adb 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -28,6 +28,7 @@ #include <errno.h> #include <time.h> #include <netinet/in.h> +#include <openssl/rand.h> #include "bscconfig.h" @@ -63,14 +64,21 @@ #include <osmocom/core/msgb.h> #include <osmocom/core/talloc.h> #include <osmocom/gsm/tlv.h> +#include <osmocom/crypt/auth.h> + +#include <openbsc/msc_ifaces.h> +#include <openbsc/iu.h> #include <assert.h> + +/* These debug statements were removed during the BSC/MSC split. It may make + * sense to replace them with debug statements that do not access BTS data. */ +#define BEFORE_MSCSPLIT 0 + void *tall_locop_ctx; 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 gsm48_tx_simple(struct gsm_subscriber_connection *conn, uint8_t pdisc, uint8_t msg_type); @@ -83,29 +91,6 @@ struct gsm_lai { uint16_t lac; }; -static int apply_codec_restrictions(struct gsm_bts *bts, - struct gsm_mncc_bearer_cap *bcap) -{ - int i, j; - - /* remove unsupported speech versions from list */ - for (i = 0, j = 0; bcap->speech_ver[i] >= 0; i++) { - if (bcap->speech_ver[i] == GSM48_BCAP_SV_FR) - bcap->speech_ver[j++] = GSM48_BCAP_SV_FR; - if (bcap->speech_ver[i] == GSM48_BCAP_SV_EFR && bts->codec.efr) - bcap->speech_ver[j++] = GSM48_BCAP_SV_EFR; - if (bcap->speech_ver[i] == GSM48_BCAP_SV_AMR_F && bts->codec.amr) - bcap->speech_ver[j++] = GSM48_BCAP_SV_AMR_F; - if (bcap->speech_ver[i] == GSM48_BCAP_SV_HR && bts->codec.hr) - bcap->speech_ver[j++] = GSM48_BCAP_SV_HR; - if (bcap->speech_ver[i] == GSM48_BCAP_SV_AMR_H && bts->codec.amr) - bcap->speech_ver[j++] = GSM48_BCAP_SV_AMR_H; - } - bcap->speech_ver[j] = -1; - - return 0; -} - static uint32_t new_callref = 0x80000001; void cc_tx_to_mncc(struct gsm_network *net, struct msgb *msg) @@ -122,30 +107,9 @@ static int gsm48_conn_sendmsg(struct msgb *msg, struct gsm_subscriber_connection * work that the caller no longer has to do */ if (trans) { gh->proto_discr = trans->protocol | (trans->transaction_id << 4); - msg->lchan = trans->conn->lchan; } - if (msg->lchan) { - struct e1inp_sign_link *sign_link = - msg->lchan->ts->trx->rsl_link; - - msg->dst = sign_link; - if (gsm48_hdr_pdisc(gh) == GSM48_PDISC_CC) - DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x) " - "Sending '%s' to MS.\n", - sign_link->trx->bts->nr, - sign_link->trx->nr, msg->lchan->ts->nr, - gh->proto_discr & 0xf0, - gsm48_cc_msg_name(gh->msg_type)); - else - DEBUGP(DCC, "(bts %d trx %d ts %d pd %02x) " - "Sending 0x%02x to MS.\n", - sign_link->trx->bts->nr, - sign_link->trx->nr, msg->lchan->ts->nr, - gh->proto_discr, gh->msg_type); - } - - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } int gsm48_cc_tx_notify_ss(struct gsm_trans *trans, const char *message) @@ -181,10 +145,33 @@ void allocate_security_operation(struct gsm_subscriber_connection *conn) struct gsm_security_operation); } +int iu_hack__get_hardcoded_auth_tuple(struct gsm_auth_tuple *atuple) +{ + unsigned char tmp_rand[16]; + /* Ki 000102030405060708090a0b0c0d0e0f */ + struct osmo_sub_auth_data auth = { + .type = OSMO_AUTH_TYPE_GSM, + .algo = OSMO_AUTH_ALG_COMP128v1, + .u.gsm.ki = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, + 0x0e, 0x0f + }, + }; + + RAND_bytes(tmp_rand, sizeof(tmp_rand)); + + memset(&atuple->vec, 0, sizeof(atuple->vec)); + osmo_auth_gen_vec(&atuple->vec, &auth, tmp_rand); + + atuple->key_seq = 0; + return AUTH_DO_AUTH; +} + int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, gsm_cbfn *cb, void *cb_data) { - struct gsm_network *net = conn->bts->network; + struct gsm_network *net = conn->network; struct gsm_subscriber *subscr = conn->subscr; struct gsm_security_operation *op; struct gsm_auth_tuple atuple; @@ -196,8 +183,15 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, * - 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)) { + if (conn->via_iface == IFACE_IU) { + DEBUGP(DMM, "No A5 encryption configured, but doing" + " authentication as required by Iu\n"); + status = -1; + } else { + DEBUGP(DMM, "No A5 encryption configured\n"); + status = GSM_SECURITY_NOAVAIL; + } + } else if (conn->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, @@ -208,20 +202,47 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, /* 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; + /* DEV HACK: hardcode keys for Iu */ + if (conn->via_iface == IFACE_IU) + rc = iu_hack__get_hardcoded_auth_tuple(&atuple); + else + rc = auth_get_tuple_for_subscr(&atuple, subscr, key_seq); + DEBUGP(DMM, "auth_get_tuple_for_subscr(%s) == %d\n", + subscr_name(subscr), rc); + if (rc <= 0) { + if (conn->via_iface == IFACE_IU) { + LOGP(DMM, LOGL_ERROR, + "Iu requires authentication but no" + " retreivable Ki for subscriber %s\n", + subscr_name(subscr)); + status = GSM_SECURITY_AUTH_FAILED; + } else { + LOGP(DMM, LOGL_NOTICE, + "No retrievable Ki for subscriber," + " skipping auth\n"); + status = GSM_SECURITY_NOAVAIL; + } + } } /* Are we done yet ? */ - if (status >= 0) + if (status >= 0) { + DEBUGP(DMM, "gsm48_secure_channel(%s) returning with status %d\n", + subscr_name(subscr), status); 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) + if (conn->sec_operation) { + DEBUGP(DMM, "gsm48_secure_channel(%s) error: attempt to start" + " second security operation\n", + subscr_name(subscr)); return -EBUSY; + } + DEBUGP(DMM, "gsm48_secure_channel(%s) starting security operation\n", + subscr_name(subscr)); allocate_security_operation(conn); op = conn->sec_operation; @@ -229,14 +250,18 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, op->cb_data = cb_data; memcpy(&op->atuple, &atuple, sizeof(struct gsm_auth_tuple)); - /* FIXME: Should start a timer for completion ... */ + /* FIXME: Should start a timer for completion ... */ /* Then do whatever is needed ... */ - if (rc == AUTH_DO_AUTH_THEN_CIPH) { + if ((rc == AUTH_DO_AUTH_THEN_CIPH) || (rc == AUTH_DO_AUTH)) { /* Start authentication */ + DEBUGP(DMM, "gsm48_secure_channel(%s) starting authentication\n", + subscr_name(subscr)); return gsm48_tx_mm_auth_req(conn, op->atuple.vec.rand, op->atuple.key_seq); } else if (rc == AUTH_DO_CIPH) { /* Start ciphering directly */ + DEBUGP(DMM, "gsm48_secure_channel(%s) starting ciphering\n", + subscr_name(subscr)); return gsm0808_cipher_mode(conn, net->a5_encryption, op->atuple.vec.kc, 8, 0); } @@ -244,32 +269,29 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, return -EINVAL; /* not reached */ } -static int authorize_subscriber(struct gsm_loc_updating_operation *loc, - struct gsm_subscriber *subscriber) +static bool authorize_subscriber(struct gsm_loc_updating_operation *loc, + struct gsm_subscriber *subscriber) { - if (!subscriber) - return 0; + if (!subscriber) { + LOGP(DMM, LOGL_DEBUG, "authorize_subscriber() on NULL subscriber\n"); + return false; + } /* * 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_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; + if (loc && (loc->waiting_for_imsi || loc->waiting_for_imei)) { + LOGP(DMM, LOGL_DEBUG, "authorize_subscriber() failed:" + " still waiting for%s%s of subscriber %s\n", + loc->waiting_for_imsi? " IMSI": "", + loc->waiting_for_imei? " IMEI": "", + subscr_name(subscriber)); + return false; } + + return subscr_authorized(subscriber); } static void release_loc_updating_req(struct gsm_subscriber_connection *conn, int release) @@ -300,7 +322,7 @@ static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn) static int finish_lu(struct gsm_subscriber_connection *conn) { int rc = 0; - int avoid_tmsi = conn->bts->network->avoid_tmsi; + int avoid_tmsi = conn->network->avoid_tmsi; /* We're all good */ if (avoid_tmsi) { @@ -311,7 +333,7 @@ static int finish_lu(struct gsm_subscriber_connection *conn) } rc = gsm0408_loc_upd_acc(conn); - if (conn->bts->network->send_mm_info) { + if (conn->network->send_mm_info) { /* send MM INFO with network name */ rc = gsm48_tx_mm_info(conn); } @@ -319,7 +341,7 @@ static int finish_lu(struct gsm_subscriber_connection *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, + subscr_update(conn->network, conn->subscr, conn->lac, GSM_SUBSCRIBER_UPDATE_ATTACHED); /* @@ -340,10 +362,6 @@ static int _gsm0408_authorize_sec_cb(unsigned int hooknum, unsigned int event, int rc = 0; switch (event) { - case GSM_SECURITY_AUTH_FAILED: - release_loc_updating_req(conn, 1); - break; - case GSM_SECURITY_ALREADY: LOGP(DMM, LOGL_ERROR, "We don't expect LOCATION " "UPDATING after CM SERVICE REQUEST\n"); @@ -354,22 +372,40 @@ static int _gsm0408_authorize_sec_cb(unsigned int hooknum, unsigned int event, rc = finish_lu(conn); break; + case GSM_SECURITY_AUTH_FAILED: + /* + * gsm48_secure_channel() will pass only + * GSM_SECURITY_NOAVAIL in case of failure. If future + * code should add a GSM_SECURITY_AUTH_FAILED status in + * this code path, letting the Location Update time out + * will do all necessary error messaging and logging, + * see loc_upd_rej_cb(). + */ + LOGP(DMM, LOGL_ERROR, + "Authorization failed for subscriber %s\n", + subscr_name(conn->subscr)); + rc = -1; + break; + default: + LOGP(DMM, LOGL_DEBUG, "invalid authorization event\n"); rc = -EINVAL; }; return rc; } -static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb *msg) +int gsm0408_authorize(struct gsm_subscriber_connection *conn) { - if (!conn->loc_operation) + if (!conn->loc_operation) { + LOGP(DMM, LOGL_DEBUG, "gsm0408_authorize() failed:" + " no location update operation pending\n"); 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 gsm48_secure_channel(conn, conn->loc_operation->key_seq, + _gsm0408_authorize_sec_cb, NULL); return 0; } @@ -384,7 +420,7 @@ void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t caus * Cancel any outstanding location updating request * operation taking place on the subscriber connection. */ - release_loc_updating_req(conn, 1); + release_loc_updating_req(conn, 0); /* We might need to cancel the paging response or such. */ if (conn->sec_operation && conn->sec_operation->cb) { @@ -408,12 +444,14 @@ void gsm0408_clear_request(struct gsm_subscriber_connection *conn, uint32_t caus * we have a subscriber connection. */ restart: - llist_for_each_entry_safe(trans, temp, &conn->bts->network->trans_list, entry) { + llist_for_each_entry_safe(trans, temp, &conn->network->trans_list, entry) { if (trans->conn == conn) { trans_free(trans); goto restart; } } + + msc_subscr_con_free(conn); } void gsm0408_clear_all_trans(struct gsm_network *net, int protocol) @@ -433,23 +471,24 @@ void gsm0408_clear_all_trans(struct gsm_network *net, int protocol) /* Chapter 9.2.14 : Send LOCATION UPDATING REJECT */ int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause) { - struct gsm_bts *bts = conn->bts; struct msgb *msg; - osmo_counter_inc(bts->network->stats.loc_upd_resp.reject); + osmo_counter_inc(conn->network->stats.loc_upd_resp.reject); msg = gsm48_create_loc_upd_rej(cause); if (!msg) { LOGP(DMM, LOGL_ERROR, "Failed to create msg for LOCATION UPDATING REJECT.\n"); return -1; } - - msg->lchan = conn->lchan; +#if BEFORE_MSCSPLIT LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT " - "LAC=%u BTS=%u\n", conn->subscr ? - subscr_name(conn->subscr) : "unknown", + "LAC=%u BTS=%u\n", subscr_name(conn->subscr), bts->location_area_code, bts->nr); +#else + LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT\n", + subscr_name(conn->subscr)); +#endif return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -457,21 +496,18 @@ int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause) /* Chapter 9.2.13 : Send LOCATION UPDATE ACCEPT */ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn) { - struct gsm_bts *bts = conn->bts; struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 LOC UPD ACC"); struct gsm48_hdr *gh; struct gsm48_loc_area_id *lai; uint8_t *mid; - - msg->lchan = conn->lchan; gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_LOC_UPD_ACCEPT; lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai)); - gsm48_generate_lai(lai, bts->network->country_code, - bts->network->network_code, bts->location_area_code); + gsm48_generate_lai(lai, conn->network->country_code, + conn->network->network_code, conn->lac); if (conn->subscr->tmsi == GSM_RESERVED_TMSI) { uint8_t mi[10]; @@ -486,7 +522,7 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn) DEBUGP(DMM, "-> LOCATION UPDATE ACCEPT\n"); - osmo_counter_inc(bts->network->stats.loc_upd_resp.accept); + osmo_counter_inc(conn->network->stats.loc_upd_resp.accept); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -497,8 +533,6 @@ static int mm_tx_identity_req(struct gsm_subscriber_connection *conn, uint8_t id struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 ID REQ"); struct gsm48_hdr *gh; - msg->lchan = conn->lchan; - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 1); gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_ID_REQ; @@ -512,9 +546,7 @@ static int mm_tx_identity_req(struct gsm_subscriber_connection *conn, uint8_t id static int mm_rx_id_resp(struct gsm_subscriber_connection *conn, struct msgb *msg) { struct gsm48_hdr *gh = msgb_l3(msg); - struct gsm_lchan *lchan = msg->lchan; - struct gsm_bts *bts = lchan->ts->trx->bts; - struct gsm_network *net = bts->network; + struct gsm_network *net = conn->network; uint8_t mi_type = gh->data[1] & GSM_MI_TYPE_MASK; char mi_string[GSM48_MI_SIZE]; @@ -535,7 +567,7 @@ static int mm_rx_id_resp(struct gsm_subscriber_connection *conn, struct msgb *ms net->subscr_group, mi_string); } if (!conn->subscr && conn->loc_operation) { - gsm0408_loc_upd_rej(conn, bts->network->reject_cause); + gsm0408_loc_upd_rej(conn, net->reject_cause); release_loc_updating_req(conn, 1); return 0; } @@ -555,18 +587,16 @@ static int mm_rx_id_resp(struct gsm_subscriber_connection *conn, struct msgb *ms } /* Check if we can let the mobile station enter */ - return gsm0408_authorize(conn, msg); + return gsm0408_authorize(conn); } static void loc_upd_rej_cb(void *data) { struct gsm_subscriber_connection *conn = data; - struct gsm_lchan *lchan = conn->lchan; - struct gsm_bts *bts = lchan->ts->trx->bts; LOGP(DMM, LOGL_DEBUG, "Location Updating Request procedure timedout.\n"); - gsm0408_loc_upd_rej(conn, bts->network->reject_cause); + gsm0408_loc_upd_rej(conn, conn->network->reject_cause); release_loc_updating_req(conn, 1); } @@ -590,7 +620,6 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_loc_upd_req *lu; struct gsm_subscriber *subscr = NULL; - struct gsm_bts *bts = conn->bts; uint8_t mi_type; char mi_string[GSM48_MI_SIZE]; @@ -607,13 +636,13 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb switch (lu->type) { case GSM48_LUPD_NORMAL: - osmo_counter_inc(bts->network->stats.loc_upd_type.normal); + osmo_counter_inc(conn->network->stats.loc_upd_type.normal); break; case GSM48_LUPD_IMSI_ATT: - osmo_counter_inc(bts->network->stats.loc_upd_type.attach); + osmo_counter_inc(conn->network->stats.loc_upd_type.attach); break; case GSM48_LUPD_PERIODIC: - osmo_counter_inc(bts->network->stats.loc_upd_type.periodic); + osmo_counter_inc(conn->network->stats.loc_upd_type.periodic); break; } @@ -640,13 +669,13 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb conn->loc_operation->waiting_for_imei = 1; /* look up subscriber based on IMSI, create if not found */ - subscr = subscr_get_by_imsi(bts->network->subscr_group, mi_string); - if (!subscr && bts->network->create_subscriber) { + subscr = subscr_get_by_imsi(conn->network->subscr_group, mi_string); + if (!subscr && conn->network->create_subscriber) { subscr = subscr_create_subscriber( - bts->network->subscr_group, mi_string); + conn->network->subscr_group, mi_string); } if (!subscr) { - gsm0408_loc_upd_rej(conn, bts->network->reject_cause); + gsm0408_loc_upd_rej(conn, conn->network->reject_cause); release_loc_updating_req(conn, 0); return 0; } @@ -654,7 +683,7 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb 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(bts->network->subscr_group, + subscr = subscr_get_by_tmsi(conn->network->subscr_group, tmsi_from_string(mi_string)); if (!subscr) { /* send IDENTITY REQUEST message to get IMSI */ @@ -689,7 +718,7 @@ static int mm_rx_loc_upd_req(struct gsm_subscriber_connection *conn, struct msgb /* 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 gsm0408_authorize(conn); } /* Turn int into semi-octet representation: 98 => 0x89 */ @@ -709,8 +738,7 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) { struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 MM INF"); struct gsm48_hdr *gh; - struct gsm_network *net = conn->bts->network; - struct gsm_bts *bts = conn->bts; + struct gsm_network *net = conn->network; uint8_t *ptr8; int name_len, name_pad; @@ -720,8 +748,6 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) int tzunits; int dst = 0; - msg->lchan = conn->lchan; - gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_INFO; @@ -798,23 +824,24 @@ int gsm48_tx_mm_info(struct gsm_subscriber_connection *conn) ptr8[5] = bcdify(gmt_time->tm_min); ptr8[6] = bcdify(gmt_time->tm_sec); - if (bts->tz.override) { + // MSCSPLIT bts->tz move to BSC? + if (net->tz.override) { /* Convert tz.hr and tz.mn to units */ - if (bts->tz.hr < 0) { - tzunits = ((bts->tz.hr/-1)*4); - tzunits = tzunits + (bts->tz.mn/15); + if (net->tz.hr < 0) { + tzunits = ((net->tz.hr/-1)*4); + tzunits = tzunits + (net->tz.mn/15); ptr8[7] = bcdify(tzunits); /* Set negative time */ ptr8[7] |= 0x08; } else { - tzunits = bts->tz.hr*4; - tzunits = tzunits + (bts->tz.mn/15); + tzunits = net->tz.hr*4; + tzunits = tzunits + (net->tz.mn/15); ptr8[7] = bcdify(tzunits); } /* Convert DST value */ - if (bts->tz.dst >= 0 && bts->tz.dst <= 2) - dst = bts->tz.dst; + if (net->tz.dst >= 0 && net->tz.dst <= 2) + dst = net->tz.dst; } else { /* Need to get GSM offset and convert into 15 min units */ @@ -861,7 +888,6 @@ int gsm48_tx_mm_auth_req(struct gsm_subscriber_connection *conn, uint8_t *rand, DEBUGP(DMM, "-> AUTH REQ (rand = %s)\n", osmo_hexdump(rand, 16)); - msg->lchan = conn->lchan; gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_AUTH_REQ; @@ -891,7 +917,7 @@ static void implit_attach(struct gsm_subscriber_connection *conn) if (conn->subscr->lac != GSM_LAC_RESERVED_DETACHED) return; - subscr_update(conn->subscr, conn->bts, + subscr_update(conn->network, conn->subscr, conn->lac, GSM_SUBSCRIBER_UPDATE_ATTACHED); } @@ -937,14 +963,14 @@ static int _gsm48_rx_mm_serv_req_sec_cb( * b) Try to parse the TMSI. If we do not have one reject * 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 + * d) Set the subscriber on the conn and accept */ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *msg) { uint8_t mi_type; char mi_string[GSM48_MI_SIZE]; - struct gsm_bts *bts = conn->bts; + struct gsm_network *network = conn->network; struct gsm_subscriber *subscr; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_service_request *req = @@ -975,13 +1001,13 @@ 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(bts->network->subscr_group, + 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(bts->network->subscr_group, + 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); @@ -991,8 +1017,11 @@ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct m osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, (classmark2 + classmark2_len)); +#if BEFORE_MSCSPLIT + /* see mail on openbsc@ 9 Feb 2016 22:30:15 +0100 */ if (is_siemens_bts(bts)) send_siemens_mrpci(msg->lchan, classmark2-1); +#endif /* FIXME: if we don't know the TMSI, inquire abit IMSI and allocate new TMSI */ @@ -1003,7 +1032,7 @@ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct m if (!conn->subscr) conn->subscr = subscr; else if (conn->subscr == subscr) - subscr_put(subscr); /* lchan already has a ref, don't need another one */ + subscr_put(subscr); /* conn already has a ref, don't need another one */ else { DEBUGP(DMM, "<- CM Channel already owned by someone else?\n"); subscr_put(subscr); @@ -1022,7 +1051,7 @@ static int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct m static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, struct msgb *msg) { - struct gsm_bts *bts = conn->bts; + struct gsm_network *network = conn->network; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_imsi_detach_ind *idi = (struct gsm48_imsi_detach_ind *) gh->data; @@ -1034,17 +1063,17 @@ static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, s DEBUGP(DMM, "IMSI DETACH INDICATION: MI(%s)=%s", gsm48_mi_type_name(mi_type), mi_string); - osmo_counter_inc(bts->network->stats.loc_upd_type.detach); + osmo_counter_inc(network->stats.loc_upd_type.detach); switch (mi_type) { case GSM_MI_TYPE_TMSI: DEBUGPC(DMM, "\n"); - subscr = subscr_get_by_tmsi(bts->network->subscr_group, + subscr = subscr_get_by_tmsi(network->subscr_group, tmsi_from_string(mi_string)); break; case GSM_MI_TYPE_IMSI: DEBUGPC(DMM, "\n"); - subscr = subscr_get_by_imsi(bts->network->subscr_group, + subscr = subscr_get_by_imsi(network->subscr_group, mi_string); break; case GSM_MI_TYPE_IMEI: @@ -1058,7 +1087,7 @@ static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, s } if (subscr) { - subscr_update(subscr, bts, + subscr_update(network, subscr, conn->lac, GSM_SUBSCRIBER_UPDATE_DETACHED); DEBUGP(DMM, "Subscriber: %s\n", subscr_name(subscr)); @@ -1090,7 +1119,8 @@ static int gsm48_rx_mm_auth_resp(struct gsm_subscriber_connection *conn, struct { struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_auth_resp *ar = (struct gsm48_auth_resp*) gh->data; - struct gsm_network *net = conn->bts->network; + struct gsm_network *net = conn->network; + gsm_cbfn *cb; DEBUGP(DMM, "MM AUTHENTICATION RESPONSE (sres = %s): ", osmo_hexdump(ar->sres, 4)); @@ -1101,11 +1131,11 @@ static int gsm48_rx_mm_auth_resp(struct gsm_subscriber_connection *conn, struct return -EIO; } + cb = conn->sec_operation->cb; + /* Validate SRES */ if (memcmp(conn->sec_operation->atuple.vec.sres, ar->sres,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)); @@ -1120,9 +1150,34 @@ static int gsm48_rx_mm_auth_resp(struct gsm_subscriber_connection *conn, struct DEBUGPC(DMM, "OK\n"); - /* Start ciphering */ - return gsm0808_cipher_mode(conn, net->a5_encryption, - conn->sec_operation->atuple.vec.kc, 8, 0); + /* TODO separate enable flags and/or A5 algos for auth and encryption */ + if (net->a5_encryption) + /* Start ciphering */ + /* TODO gsm0808_cipher_mode() is still a dummy, and no code + * to receive a Ciphering Mode Complete exists in the MSC. + * As soon as such a receiver exists, it must call + * iu_tx_sec_mode_cmd() as below. */ + return gsm0808_cipher_mode(conn, net->a5_encryption, + conn->sec_operation->atuple.vec.kc, 8, 0); + + if (conn->via_iface == IFACE_IU + && !conn->iu.integrity_protection) { + LOGP(DIUCS, LOGL_DEBUG, + "Requesting integrity protection for %s\n", + subscr_name(conn->subscr)); + + /* send Security Mode Command (IK) to start integrity + * protection */ + return iu_tx_sec_mode_cmd(conn->iu.ue_ctx, + &conn->sec_operation->atuple, 0, 1); + } + + /* Only authentication requested, and we're done. */ + if (cb) + cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_SUCCEEDED, NULL, + conn, conn->sec_operation->cb_data); + release_security_operation(conn); + return 0; } /* Receive a GSM 04.08 Mobility Management (MM) message */ @@ -1147,9 +1202,7 @@ static int gsm0408_rcv_mm(struct gsm_subscriber_connection *conn, struct msgb *m break; case GSM48_MT_MM_TMSI_REALL_COMPL: DEBUGP(DMM, "TMSI Reallocation Completed. Subscriber: %s\n", - conn->subscr ? - subscr_name(conn->subscr) : - "unknown subscriber"); + subscr_name(conn->subscr)); release_loc_updating_req(conn, 1); break; case GSM48_MT_MM_IMSI_DETACH_IND: @@ -1170,17 +1223,37 @@ static int gsm0408_rcv_mm(struct gsm_subscriber_connection *conn, struct msgb *m return rc; } +static int handle_paging_resp(struct msgb *msg, + struct gsm_subscriber_connection *conn, + struct gsm_subscriber *subscr) +{ + if (!conn->subscr) { + conn->subscr = subscr; + } else if (conn->subscr != subscr) { + LOGP(DPAG, LOGL_ERROR, + "Connection already owned by another subscriber?\n"); + subscr_put(subscr); + return -EINVAL; + } else { + DEBUGP(DPAG, "Connection already owned by the subscriber\n"); + subscr_put(subscr); + subscr = conn->subscr; + } + + osmo_counter_inc(conn->network->stats.paging.completed); + + return subscr_rx_paging_response(msg, conn); +} + /* Receive a PAGING RESPONSE message from the MS */ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct msgb *msg) { - struct gsm_bts *bts = conn->bts; struct gsm48_hdr *gh = msgb_l3(msg); struct gsm48_pag_resp *resp; uint8_t *classmark2_lv = gh->data + 1; uint8_t mi_type; char mi_string[GSM48_MI_SIZE]; struct gsm_subscriber *subscr = NULL; - int rc = 0; resp = (struct gsm48_pag_resp *) &gh->data[0]; gsm48_paging_extract_mi(resp, msgb_l3len(msg) - sizeof(*gh), @@ -1190,11 +1263,11 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m switch (mi_type) { case GSM_MI_TYPE_TMSI: - subscr = subscr_get_by_tmsi(bts->network->subscr_group, + subscr = subscr_get_by_tmsi(conn->network->subscr_group, tmsi_from_string(mi_string)); break; case GSM_MI_TYPE_IMSI: - subscr = subscr_get_by_imsi(bts->network->subscr_group, + subscr = subscr_get_by_imsi(conn->network->subscr_group, mi_string); break; } @@ -1215,8 +1288,11 @@ static int gsm48_rx_rr_pag_resp(struct gsm_subscriber_connection *conn, struct m /* We received a paging */ conn->expire_timer_stopped = 1; - rc = gsm48_handle_paging_resp(conn, msg, subscr); - return rc; +#if BEFORE_MSCSPLIT + return gsm48_handle_paging_resp(conn, msg, subscr); +#else + return handle_paging_resp(msg, conn, subscr); +#endif } static int gsm48_rx_rr_app_info(struct gsm_subscriber_connection *conn, struct msgb *msg) @@ -1264,11 +1340,9 @@ int gsm48_send_rr_app_info(struct gsm_subscriber_connection *conn, uint8_t apdu_ struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 APP INF"); struct gsm48_hdr *gh; - msg->lchan = conn->lchan; - DEBUGP(DRR, "TX APPLICATION INFO id=0x%02x, len=%u\n", apdu_id, apdu_len); - + gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh) + 2 + apdu_len); gh->proto_discr = GSM48_PDISC_RR; gh->msg_type = GSM48_MT_RR_APP_INFO; @@ -1323,8 +1397,6 @@ static int gsm48_tx_simple(struct gsm_subscriber_connection *conn, struct msgb *msg = gsm48_msgb_alloc_name("GSM 04.08 TX SIMPLE"); struct gsm48_hdr *gh = (struct gsm48_hdr *) msgb_put(msg, sizeof(*gh)); - msg->lchan = conn->lchan; - gh->proto_discr = pdisc; gh->msg_type = msg_type; @@ -1346,6 +1418,7 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans, struct msgb *msg; unsigned char *data; +#if BEFORE_MSCSPLIT if (trans) if (trans->conn && trans->conn->lchan) DEBUGP(DCC, "(bts %d trx %d ts %d ti %x sub %s) " @@ -1363,6 +1436,7 @@ static int mncc_recvmsg(struct gsm_network *net, struct gsm_trans *trans, else DEBUGP(DCC, "(bts - trx - ts - ti -- sub -) " "Sending '%s' to MNCC.\n", get_mncc_name(msg_type)); +#endif mncc->msg_type = msg_type; @@ -1406,8 +1480,10 @@ void _gsm48_cc_trans_free(struct gsm_trans *trans) } if (trans->cc.state != GSM_CSTATE_NULL) new_cc_state(trans, GSM_CSTATE_NULL); +#if BEFORE_MSCSPLIT if (trans->conn) trau_mux_unmap(&trans->conn->lchan->ts->e1_link, trans->callref); +#endif } static int gsm48_cc_tx_setup(struct gsm_trans *trans, void *arg); @@ -1421,12 +1497,11 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, OSMO_ASSERT(!transt->conn); - /* check all tranactions (without lchan) for subscriber */ switch (event) { case GSM_PAGING_SUCCEEDED: DEBUGP(DCC, "Paging subscr %s succeeded!\n", transt->subscr->extension); OSMO_ASSERT(conn); - /* Assign lchan */ + /* Assign conn */ transt->conn = conn; /* send SETUP request to called party */ gsm48_cc_tx_setup(transt, &transt->cc.msg); @@ -1455,6 +1530,7 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event, static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable); +#if BEFORE_MSCSPLIT /* handle audio path for handover */ static int switch_for_handover(struct gsm_lchan *old_lchan, struct gsm_lchan *new_lchan) @@ -1522,77 +1598,6 @@ static void maybe_switch_for_handover(struct gsm_lchan *lchan) switch_for_handover(old_lchan, lchan); } -/* some other part of the code sends us a signal */ -static int handle_abisip_signal(unsigned int subsys, unsigned int signal, - void *handler_data, void *signal_data) -{ - struct gsm_lchan *lchan = signal_data; - int rc; - struct gsm_network *net; - struct gsm_trans *trans; - - if (subsys != SS_ABISIP) - return 0; - - /* RTP bridge handling */ - if (lchan->conn && lchan->conn->mncc_rtp_bridge) - return tch_rtp_signal(lchan, signal); - - /* in case we use direct BTS-to-BTS RTP */ - if (ipacc_rtp_direct) - return 0; - - switch (signal) { - case S_ABISIP_CRCX_ACK: - /* in case we don't use direct BTS-to-BTS RTP */ - /* the BTS has successfully bound a TCH to a local ip/port, - * which means we can connect our UDP socket to it */ - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - - lchan->abis_ip.rtp_socket = rtp_socket_create(); - if (!lchan->abis_ip.rtp_socket) - return -EIO; - - rc = rtp_socket_connect(lchan->abis_ip.rtp_socket, - lchan->abis_ip.bound_ip, - lchan->abis_ip.bound_port); - if (rc < 0) - return -EIO; - - /* check if any transactions on this lchan still have - * a tch_recv_mncc request pending */ - net = lchan->ts->trx->bts->network; - llist_for_each_entry(trans, &net->trans_list, entry) { - if (trans->conn && trans->conn->lchan == lchan && trans->tch_recv) { - DEBUGP(DCC, "pending tch_recv_mncc request\n"); - tch_recv_mncc(net, trans->callref, 1); - } - } - - /* - * TODO: this appears to be too early? Why not until after - * the handover detect or the handover complete? - * - * Do we have a handover pending for this new lchan? In that - * case re-route the audio from the old channel to the new one. - */ - maybe_switch_for_handover(lchan); - break; - case S_ABISIP_DLCX_IND: - /* the BTS tells us a RTP stream has been disconnected */ - if (lchan->abis_ip.rtp_socket) { - rtp_socket_free(lchan->abis_ip.rtp_socket); - lchan->abis_ip.rtp_socket = NULL; - } - - break; - } - - return 0; -} /* map two ipaccess RTP streams onto each other */ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) @@ -1681,6 +1686,7 @@ static int tch_map(struct gsm_lchan *lchan, struct gsm_lchan *remote_lchan) return 0; } +#endif /* bridge channels of two transactions */ static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge) @@ -1697,13 +1703,19 @@ static int tch_bridge(struct gsm_network *net, struct gsm_mncc_bridge *bridge) /* Which subscriber do we want to track trans1 or trans2? */ log_set_context(BSC_CTX_SUBSCR, trans1->subscr); +#if BEFORE_MSCSPLIT /* through-connect channel */ return tch_map(trans1->conn->lchan, trans2->conn->lchan); +#else + /* not implemented yet! */ + return -1; +#endif } /* enable receive of channels to MNCC upqueue */ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) { +#if BEFORE_MSCSPLIT struct gsm_trans *trans; struct gsm_lchan *lchan; struct gsm_bts *bts; @@ -1772,6 +1784,10 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable) } return 0; +#else + /* not implemented yet! */ + return -1; +#endif } static int gsm48_cc_rx_status_enq(struct gsm_trans *trans, struct msgb *msg) @@ -1912,7 +1928,11 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) memset(&setup, 0, sizeof(struct gsm_mncc)); setup.callref = trans->callref; +#if BEFORE_MSCSPLIT setup.lchan_type = trans->conn->lchan->type; +#else + setup.lchan_type = GSM_LCHAN_NONE; +#endif tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); /* emergency setup is identified by msg_type */ if (msg_type == GSM48_MT_CC_EMERG_SETUP) @@ -1930,7 +1950,6 @@ static int gsm48_cc_rx_setup(struct gsm_trans *trans, struct msgb *msg) setup.fields |= MNCC_F_BEARER_CAP; gsm48_decode_bearer_cap(&setup.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); - apply_codec_restrictions(trans->conn->bts, &setup.bearer_cap); } /* facility */ if (TLVP_PRESENT(&tp, GSM48_IE_FACILITY)) { @@ -2070,7 +2089,11 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) memset(&call_conf, 0, sizeof(struct gsm_mncc)); call_conf.callref = trans->callref; +#if BEFORE_MSCSPLIT call_conf.lchan_type = trans->conn->lchan->type; +#else + call_conf.lchan_type = GSM_LCHAN_NONE; +#endif tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); #if 0 /* repeat */ @@ -2084,7 +2107,6 @@ static int gsm48_cc_rx_call_conf(struct gsm_trans *trans, struct msgb *msg) call_conf.fields |= MNCC_F_BEARER_CAP; gsm48_decode_bearer_cap(&call_conf.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); - apply_codec_restrictions(trans->conn->bts, &call_conf.bearer_cap); } /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) { @@ -2777,7 +2799,6 @@ static int gsm48_cc_rx_modify(struct gsm_trans *trans, struct msgb *msg) modify.fields |= MNCC_F_BEARER_CAP; gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); - apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap); } new_cc_state(trans, GSM_CSTATE_MO_ORIG_MODIFY); @@ -2820,7 +2841,6 @@ static int gsm48_cc_rx_modify_complete(struct gsm_trans *trans, struct msgb *msg modify.fields |= MNCC_F_BEARER_CAP; gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); - apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap); } new_cc_state(trans, GSM_CSTATE_ACTIVE); @@ -2861,7 +2881,6 @@ static int gsm48_cc_rx_modify_reject(struct gsm_trans *trans, struct msgb *msg) modify.fields |= GSM48_IE_BEARER_CAP; gsm48_decode_bearer_cap(&modify.bearer_cap, TLVP_VAL(&tp, GSM48_IE_BEARER_CAP)-1); - apply_codec_restrictions(trans->conn->bts, &modify.bearer_cap); } /* cause */ if (TLVP_PRESENT(&tp, GSM48_IE_CAUSE)) { @@ -2966,6 +2985,7 @@ static int gsm48_cc_rx_userinfo(struct gsm_trans *trans, struct msgb *msg) static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg) { +#if BEFORE_MSCSPLIT struct gsm_mncc *mode = arg; struct gsm_lchan *lchan = trans->conn->lchan; @@ -2981,8 +3001,14 @@ static int _gsm48_lchan_modify(struct gsm_trans *trans, void *arg) return gsm0808_assign_req(trans->conn, mode->lchan_mode, trans->conn->lchan->type != GSM_LCHAN_TCH_H); +#else + /* not implemented yet! */ + return -1; +#endif + } +#if BEFORE_MSCSPLIT static void mncc_recv_rtp(struct gsm_network *net, uint32_t callref, int cmd, uint32_t addr, uint16_t port, uint32_t payload_type, uint32_t payload_msg_type) @@ -3039,9 +3065,11 @@ static void mncc_recv_rtp_err(struct gsm_network *net, uint32_t callref, int cmd { return mncc_recv_rtp(net, callref, cmd, 0, 0, 0, 0); } +#endif static int tch_rtp_create(struct gsm_network *net, uint32_t callref) { +#if BEFORE_MSCSPLIT struct gsm_bts *bts; struct gsm_lchan *lchan; struct gsm_trans *trans; @@ -3095,10 +3123,15 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref) mncc_recv_rtp_sock(trans->net, trans, MNCC_RTP_CREATE); return 0; +#else + /* not implemented yet! */ + return -1; +#endif } static int tch_rtp_connect(struct gsm_network *net, void *arg) { +#if BEFORE_MSCSPLIT struct gsm_lchan *lchan; struct gsm_trans *trans; struct gsm_mncc_rtp *rtp = arg; @@ -3136,8 +3169,13 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg) */ trans->conn->mncc_rtp_connect_pending = 1; return rsl_ipacc_mdcx(lchan, rtp->ip, rtp->port, 0); +#else + /* not implemented yet! */ + return -1; +#endif } +#if BEFORE_MSCSPLIT static int tch_rtp_signal(struct gsm_lchan *lchan, int signal) { struct gsm_network *net; @@ -3185,6 +3223,7 @@ static int tch_rtp_signal(struct gsm_lchan *lchan, int signal) return 0; } +#endif static struct downstate { @@ -3254,7 +3293,6 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) int i, rc = 0; struct gsm_trans *trans = NULL, *transt; struct gsm_subscriber_connection *conn = NULL; - struct gsm_bts *bts = NULL; struct gsm_mncc *data = arg, rel; DEBUGP(DMNCC, "receive message %s\n", get_mncc_name(msg_type)); @@ -3292,6 +3330,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without conn\n"); return 0; } +#if BEFORE_MSCSPLIT if (!trans->conn->lchan) { LOGP(DMNCC, LOGL_NOTICE, "TCH frame for trans without lchan\n"); return 0; @@ -3321,6 +3360,10 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) LOGP(DCC, LOGL_ERROR, "Unknown BTS type %u\n", bts->type); } return -EINVAL; +#else + /* not implemented yet! */ + return -1; +#endif } memset(&rel, 0, sizeof(struct gsm_mncc)); @@ -3397,14 +3440,14 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) GSM48_CC_CAUSE_RESOURCE_UNAVAIL); return -ENOMEM; } - /* Find lchan */ + /* Find conn */ conn = connection_for_subscr(subscr); - /* If subscriber has no lchan */ + /* If subscriber has no conn */ if (!conn) { /* find transaction with this subscriber already paging */ llist_for_each_entry(transt, &net->trans_list, entry) { - /* Transaction of our lchan? */ + /* Transaction of our conn? */ if (transt == trans || transt->subscr != subscr) continue; @@ -3418,12 +3461,12 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) trans_free(trans); return 0; } - /* store setup informations until paging was successfull */ + /* store setup information until paging succeeds */ 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_conn(subscr, + setup_trig_pag_evt, trans); if (!trans->paging_request) { LOGP(DCC, LOGL_ERROR, "Failed to allocate paging token.\n"); @@ -3434,7 +3477,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) subscr_put(subscr); return 0; } - /* Assign lchan */ + /* Assign conn */ trans->conn = conn; subscr_put(subscr); } else { @@ -3447,7 +3490,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) /* if paging did not respond yet */ if (!conn) { - DEBUGP(DCC, "(bts - trx - ts - ti -- sub %s) " + DEBUGP(DCC, "(sub %s) " "Received '%s' from MNCC in paging state\n", (trans->subscr)?(trans->subscr->extension):"-", get_mncc_name(msg_type)); @@ -3462,9 +3505,8 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) return rc; } - DEBUGP(DCC, "(bts %d trx %d ts %d ti %02x sub %s) " + DEBUGP(DCC, "(ti %02x sub %s) " "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):"-", get_mncc_name(msg_type), trans->cc.state, @@ -3556,19 +3598,21 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m /* Find transaction */ trans = trans_find_by_id(conn, GSM48_PDISC_CC, transaction_id); +#if BEFORE_MSCSPLIT 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):"-", gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0, gsm48_cc_state_name(trans?(trans->cc.state):0)); +#endif /* Create transaction */ if (!trans) { DEBUGP(DCC, "Unknown transaction ID %x, " "creating new trans.\n", transaction_id); /* Create transaction */ - trans = trans_alloc(conn->bts->network, conn->subscr, + trans = trans_alloc(conn->network, conn->subscr, GSM48_PDISC_CC, transaction_id, new_callref++); if (!trans) { @@ -3630,6 +3674,33 @@ int gsm0408_new_conn(struct gsm_subscriber_connection *conn) return 0; } +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_con_free(struct gsm_subscriber_connection *conn) +{ + if (!conn) + return; + + if (conn->subscr) { + subscr_put(conn->subscr); + conn->subscr = NULL; + } + + llist_del(&conn->entry); + talloc_free(conn); +} + /* here we get data from the BSC level... */ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) { @@ -3637,6 +3708,9 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) uint8_t pdisc = gsm48_hdr_pdisc(gh); int rc = 0; + OSMO_ASSERT(conn); + OSMO_ASSERT(msg); + LOGP(DRLL, LOGL_DEBUG, "Dispatching 04.08 message, pdisc=%d\n", pdisc); if (silent_call_reroute(conn, msg)) return silent_call_rx(conn, msg); @@ -3660,6 +3734,7 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) case GSM48_PDISC_SM_GPRS: LOGP(DRLL, LOGL_NOTICE, "Unimplemented " "GSM 04.08 discriminator 0x%02x\n", pdisc); + rc = -1; break; case GSM48_PDISC_NC_SS: release_anchor(conn); @@ -3668,17 +3743,10 @@ int gsm0408_dispatch(struct gsm_subscriber_connection *conn, struct msgb *msg) default: LOGP(DRLL, LOGL_NOTICE, "Unknown " "GSM 04.08 discriminator 0x%02x\n", pdisc); + rc = -1; break; } return rc; } -/* - * This will be ran by the linker when loading the DSO. We use it to - * do system initialization, e.g. registration of signal handlers. - */ -static __attribute__((constructor)) void on_dso_load_0408(void) -{ - osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, NULL); -} diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 20d18a959..22d4f6708 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -53,7 +53,7 @@ #include <openbsc/paging.h> #include <openbsc/bsc_rll.h> #include <openbsc/chan_alloc.h> -#include <openbsc/bsc_api.h> +#include <openbsc/msc_ifaces.h> #ifdef BUILD_SMPP #include "smpp_smsc.h" @@ -124,7 +124,7 @@ static int gsm411_sendmsg(struct gsm_subscriber_connection *conn, struct msgb *m { DEBUGP(DLSMS, "GSM4.11 TX %s\n", osmo_hexdump(msg->data, msg->len)); msg->l3h = msg->data; - return gsm0808_submit_dtap(conn, msg, UM_SAPI_SMS, 1); + return msc_tx_dtap(conn, msg); } /* Prefix msg with a 04.08/04.11 CP header */ @@ -304,7 +304,7 @@ try_local: #endif /* determine gsms->receiver based on dialled number */ - gsms->receiver = subscr_get_by_extension(conn->bts->network->subscr_group, + gsms->receiver = subscr_get_by_extension(conn->network->subscr_group, gsms->dst.addr); if (!gsms->receiver) { #ifdef BUILD_SMPP @@ -315,14 +315,14 @@ try_local: rc = smpp_try_deliver(gsms, conn); if (rc == 1) { rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + osmo_counter_inc(conn->network->stats.sms.no_receiver); } else if (rc < 0) { rc = 21; /* cause 21: short message transfer rejected */ /* FIXME: handle the error somehow? */ } #else rc = 1; /* cause 1: unknown subscriber */ - osmo_counter_inc(conn->bts->network->stats.sms.no_receiver); + osmo_counter_inc(conn->network->stats.sms.no_receiver); #endif return rc; } @@ -363,7 +363,7 @@ static int gsm340_rx_tpdu(struct gsm_subscriber_connection *conn, struct msgb *m uint8_t address_lv[12]; /* according to 03.40 / 9.1.2.5 */ int rc = 0; - osmo_counter_inc(conn->bts->network->stats.sms.submitted); + osmo_counter_inc(conn->network->stats.sms.submitted); gsms = sms_alloc(); if (!gsms) @@ -605,7 +605,7 @@ static int gsm411_rx_rp_ack(struct msgb *msg, struct gsm_trans *trans, static int gsm411_rx_rp_error(struct msgb *msg, struct gsm_trans *trans, struct gsm411_rp_hdr *rph) { - struct gsm_network *net = trans->conn->bts->network; + struct gsm_network *net = trans->conn->network; struct gsm_sms *sms = trans->sms.sms; uint8_t cause_len = rph->data[0]; uint8_t cause = rph->data[1]; @@ -805,7 +805,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn, if (!trans) { DEBUGP(DLSMS, " -> (new transaction)\n"); - trans = trans_alloc(conn->bts->network, conn->subscr, + trans = trans_alloc(conn->network, conn->subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { @@ -855,19 +855,19 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn, } /* Take a SMS in gsm_sms structure and send it through an already - * existing lchan. We also assume that the caller ensured this lchan already + * existing conn. We also assume that the caller ensured this conn already * has a SAPI3 RLL connection! */ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms) { struct msgb *msg = gsm411_msgb_alloc(); struct gsm_trans *trans; uint8_t *data, *rp_ud_len; - uint8_t msg_ref = sms_next_rp_msg_ref(conn); + uint8_t msg_ref = sms_next_rp_msg_ref(&conn->next_rp_ref); int transaction_id; int rc; transaction_id = - trans_assign_trans_id(conn->bts->network, conn->subscr, + trans_assign_trans_id(conn->network, conn->subscr, GSM48_PDISC_SMS, 0); if (transaction_id == -1) { LOGP(DLSMS, LOGL_ERROR, "No available transaction ids\n"); @@ -877,10 +877,10 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms) return -EBUSY; } - DEBUGP(DLSMS, "send_sms_lchan()\n"); + DEBUGP(DLSMS, "gsm411_send_sms()\n"); /* FIXME: allocate transaction with message reference */ - trans = trans_alloc(conn->bts->network, conn->subscr, + trans = trans_alloc(conn->network, conn->subscr, GSM48_PDISC_SMS, transaction_id, new_callref++); if (!trans) { @@ -932,7 +932,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms) DEBUGP(DLSMS, "TX: SMS DELIVER\n"); - osmo_counter_inc(conn->bts->network->stats.sms.delivered); + osmo_counter_inc(conn->network->stats.sms.delivered); db_sms_inc_deliver_attempts(trans->sms.sms); return gsm411_rp_sendmsg(&trans->sms.smr_inst, msg, @@ -981,16 +981,19 @@ int gsm411_send_sms_subscr(struct gsm_subscriber *subscr, struct gsm_subscriber_connection *conn; void *res; - /* check if we already have an open lchan to the subscriber. + /* check if we already have an open conn to the subscriber. * if yes, send the SMS this way */ conn = connection_for_subscr(subscr); if (conn) { + LOGP(DLSMS, LOGL_DEBUG, "Sending SMS via already open connection %p to %s\n", + conn, subscr_name(subscr)); return gsm411_send_sms(conn, sms); } /* if not, we have to start paging */ - res = subscr_request_channel(subscr, RSL_CHANNEED_SDCCH, - paging_cb_send_sms, sms); + LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n", + subscr_name(subscr)); + res = subscr_request_conn(subscr, paging_cb_send_sms, sms); if (!res) { send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY); sms_free(sms); @@ -1022,7 +1025,7 @@ void gsm411_sapi_n_reject(struct gsm_subscriber_connection *conn) struct gsm_network *net; struct gsm_trans *trans, *tmp; - net = conn->bts->network; + net = conn->network; llist_for_each_entry_safe(trans, tmp, &net->trans_list, entry) { struct gsm_sms *sms; diff --git a/openbsc/src/libmsc/gsm_04_80.c b/openbsc/src/libmsc/gsm_04_80.c index f1d75f20d..13961a656 100644 --- a/openbsc/src/libmsc/gsm_04_80.c +++ b/openbsc/src/libmsc/gsm_04_80.c @@ -32,7 +32,7 @@ #include <openbsc/gsm_data.h> #include <openbsc/gsm_04_08.h> #include <openbsc/gsm_04_80.h> -#include <openbsc/bsc_api.h> +#include <openbsc/msc_ifaces.h> #include <osmocom/gsm/gsm0480.h> #include <osmocom/gsm/gsm_utils.h> @@ -106,7 +106,7 @@ int gsm0480_send_ussd_response(struct gsm_subscriber_connection *conn, | (1<<7); /* TI direction = 1 */ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, @@ -135,41 +135,21 @@ int gsm0480_send_ussd_reject(struct gsm_subscriber_connection *conn, gh->proto_discr |= req->transaction_id | (1<<7); /* TI direction = 1 */ gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } int gsm0480_send_ussdNotify(struct gsm_subscriber_connection *conn, int level, const char *text) { - struct gsm48_hdr *gh; - struct msgb *msg; - - msg = gsm0480_create_unstructuredSS_Notify(level, text); + struct msgb *msg = gsm0480_gen_ussdNotify(level, text); if (!msg) return -1; - - gsm0480_wrap_invoke(msg, GSM0480_OP_CODE_USS_NOTIFY, 0); - gsm0480_wrap_facility(msg); - - /* And finally pre-pend the L3 header */ - gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_NC_SS; - gh->msg_type = GSM0480_MTYPE_REGISTER; - - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } int gsm0480_send_releaseComplete(struct gsm_subscriber_connection *conn) { - struct gsm48_hdr *gh; - struct msgb *msg; - - msg = gsm48_msgb_alloc_name("GSM 04.08 USSD REL COMPL"); + struct msgb *msg = gsm0480_gen_releaseComplete(); if (!msg) return -1; - - gh = (struct gsm48_hdr *) msgb_push(msg, sizeof(*gh)); - gh->proto_discr = GSM48_PDISC_NC_SS; - gh->msg_type = GSM0480_MTYPE_RELEASE_COMPLETE; - - return gsm0808_submit_dtap(conn, msg, 0, 0); + return msc_tx_dtap(conn, msg); } diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index 57c10cf7e..7b66299ec 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -38,6 +38,7 @@ #include <openbsc/signal.h> #include <openbsc/db.h> #include <openbsc/chan_alloc.h> +#include <openbsc/iu.h> void *tall_sub_req_ctx; @@ -47,20 +48,6 @@ int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq, gsm_cbfn *cb, void *cb_data); -/* - * Struct for pending channel requests. This is managed in the - * llist_head requests of each subscriber. The reference counting - * should work in such a way that a subscriber with a pending request - * remains in memory. - */ -struct subscr_request { - struct llist_head entry; - - /* the callback data */ - gsm_cbfn *cbfn; - void *param; -}; - static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp, int type, const char *ident) { @@ -70,31 +57,32 @@ static struct gsm_subscriber *get_subscriber(struct gsm_subscriber_group *sgrp, return subscr; } -/* - * We got the channel assigned and can now hand this channel - * over to one of our callbacks. - */ +/* A connection is established and the paging callbacks may run now. */ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, - struct msgb *msg, void *data, void *param) + struct msgb *msg, void *data, void *param) { struct subscr_request *request, *tmp; struct gsm_subscriber_connection *conn = data; struct gsm_subscriber *subscr = param; struct paging_signal_data sig_data; - OSMO_ASSERT(subscr->is_paging); + OSMO_ASSERT(hooknum == GSM_HOOK_RR_PAGING); + OSMO_ASSERT(subscr); + OSMO_ASSERT(!(conn && (conn->subscr != subscr))); + OSMO_ASSERT(!((event == GSM_PAGING_SUCCEEDED) && !conn)); - /* - * Stop paging on all other BTS. E.g. if this is - * the first timeout on a BTS then the others will - * timeout soon as well. Let's just stop everything - * and forget we wanted to page. - */ - paging_request_stop(NULL, subscr, NULL, NULL); + LOGP(DPAG, LOGL_DEBUG, "Paging %s for %s (event=%d)\n", + event == GSM_PAGING_SUCCEEDED ? "success" : "failure", + subscr_name(subscr), event); + + if (!subscr->is_paging) { + LOGP(DPAG, LOGL_NOTICE, + "Paging Response received for subscriber" + " that is not paging.\n"); + } /* Inform parts of the system we don't know */ sig_data.subscr = subscr; - sig_data.bts = conn ? conn->bts : NULL; sig_data.conn = conn; sig_data.paging_result = event; osmo_signal_dispatch( @@ -106,83 +94,143 @@ static int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, llist_for_each_entry_safe(request, tmp, &subscr->requests, entry) { llist_del(&request->entry); - request->cbfn(hooknum, event, msg, data, request->param); + if (request->cbfn) { + LOGP(DPAG, LOGL_DEBUG, "Calling paging cbfn.\n"); + request->cbfn(hooknum, event, msg, data, request->param); + } else + LOGP(DPAG, LOGL_DEBUG, "Paging without action.\n"); talloc_free(request); } /* balanced with the moment we start paging */ subscr->is_paging = 0; + + /* balanced with the moment we receive a paging response */ subscr_put(subscr); return 0; } +static void paging_timeout_release(struct gsm_subscriber *subscr) +{ + DEBUGP(DPAG, "Paging timeout released for %s\n", subscr_name(subscr)); + osmo_timer_del(&subscr->paging_timeout); +} + +static void paging_timeout(void *data) +{ + struct gsm_subscriber *subscr = data; + DEBUGP(DPAG, "Paging timeout reached for %s\n", subscr_name(subscr)); + paging_timeout_release(subscr); + subscr_paging_dispatch(GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, + NULL, NULL, subscr); +} + +static void paging_timeout_start(struct gsm_subscriber *subscr) +{ + DEBUGP(DPAG, "Starting paging timeout for %s\n", subscr_name(subscr)); + subscr->paging_timeout.data = subscr; + subscr->paging_timeout.cb = paging_timeout; + osmo_timer_schedule(&subscr->paging_timeout, 10, 0); + /* TODO: configurable timeout duration? */ +} + + static int subscr_paging_sec_cb(unsigned int hooknum, unsigned int event, struct msgb *msg, void *data, void *param) { int rc; + struct gsm_subscriber_connection *conn = data; + OSMO_ASSERT(conn); switch (event) { case GSM_SECURITY_AUTH_FAILED: - /* Dispatch as paging failure */ + LOGP(DPAG, LOGL_ERROR, + "Dropping Paging Response:" + " authorization failed for subscriber %s\n", + subscr_name(conn->subscr)); rc = subscr_paging_dispatch( GSM_HOOK_RR_PAGING, GSM_PAGING_EXPIRED, - msg, data, param); + msg, conn, conn->subscr); 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); + msg, conn, conn->subscr); break; default: + LOGP(DPAG, LOGL_FATAL, + "Invalid authorization event: %d\n", event); rc = -EINVAL; } return rc; } -static int subscr_paging_cb(unsigned int hooknum, unsigned int event, - struct msgb *msg, void *data, void *param) +int subscr_rx_paging_response(struct msgb *msg, + struct gsm_subscriber_connection *conn) { - 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 */ + /* Get key_seq from Paging Response headers */ 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); + paging_timeout_release(conn->subscr); + + /* Secure the connection */ + if (subscr_authorized(conn->subscr)) + return gsm48_secure_channel(conn, pr->key_seq, + subscr_paging_sec_cb, NULL); + + /* Not authorized. Failure. */ + subscr_paging_sec_cb(GSM_HOOK_RR_SECURITY, GSM_SECURITY_AUTH_FAILED, + msg, conn, NULL); + return -1; +} + +static int msc_paging_request(struct gsm_subscriber *subscr) +{ + /* The subscriber was last seen in subscr->lac. Find out which + * BSCs/RNCs are responsible and send them a paging request via open + * SCCP connections (if any). */ + /* TODO Implementing only RNC paging, since this is code on the iu branch. + * Need to add BSC paging at some point. */ + return iu_page_cs(subscr->imsi, + subscr->tmsi == GSM_RESERVED_TMSI? + NULL : &subscr->tmsi, + subscr->lac); } -struct subscr_request *subscr_request_channel(struct gsm_subscriber *subscr, - int channel_type, gsm_cbfn *cbfn, void *param) +struct subscr_request *subscr_request_conn(struct gsm_subscriber *subscr, + gsm_cbfn *cbfn, void *param) { int rc; struct subscr_request *request; /* Start paging.. we know it is async so we can do it before */ if (!subscr->is_paging) { - LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n", + LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet, start paging.\n", subscr_name(subscr)); - rc = paging_request(subscr->group->net, subscr, channel_type, - subscr_paging_cb, subscr); + rc = msc_paging_request(subscr); if (rc <= 0) { LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n", subscr_name(subscr), rc); return NULL; } - /* reduced on the first paging callback */ + /* reduced in subscr_rx_paging_response() */ subscr_get(subscr); subscr->is_paging = 1; + LOGP(DMM, LOGL_DEBUG, "Paged subscriber %s.\n", + subscr_name(subscr)); + paging_timeout_start(subscr); + } + else { + LOGP(DMM, LOGL_DEBUG, "Subscriber %s already paged.\n", + subscr_name(subscr)); } /* TODO: Stop paging in case of memory allocation failure */ @@ -268,7 +316,7 @@ struct gsm_subscriber *subscr_get_by_id(struct gsm_subscriber_group *sgrp, return get_subscriber(sgrp, GSM_SUBSCRIBER_ID, buf); } -int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts) +int subscr_update_expire_lu(struct gsm_network *network, struct gsm_subscriber *s) { int rc; @@ -279,27 +327,27 @@ int subscr_update_expire_lu(struct gsm_subscriber *s, struct gsm_bts *bts) * Timeout is twice the t3212 value plus one minute */ /* Is expiration handling enabled? */ - if (bts->si_common.chan_desc.t3212 == 0) + if (network->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; + s->expire_lu = time(NULL) + (network->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 subscr_update(struct gsm_network *network, struct gsm_subscriber *s, + uint16_t lac, 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; + s->group = network->subscr_group; /* Indicate "attached to LAC" */ - s->lac = bts->location_area_code; + s->lac = lac; LOGP(DMM, LOGL_INFO, "Subscriber %s ATTACHED LAC=%u\n", subscr_name(s), s->lac); @@ -308,12 +356,12 @@ int subscr_update(struct gsm_subscriber *s, struct gsm_bts *bts, int reason) * 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); + rc = subscr_update_expire_lu(network, s); 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) + if (lac == s->lac) s->lac = GSM_LAC_RESERVED_DETACHED; LOGP(DMM, LOGL_INFO, "Subscriber %s DETACHED\n", subscr_name(s)); rc = db_sync_subscriber(s); @@ -352,7 +400,7 @@ static void subscr_expire_callback(void *data, long long unsigned int id) 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_update_expire_lu(conn->network, s); subscr_put(s); return; } @@ -370,3 +418,30 @@ void subscr_expire(struct gsm_subscriber_group *sgrp) { db_subscriber_expire(sgrp->net, subscr_expire_callback); } + +bool subscr_authorized(struct gsm_subscriber *subscriber) +{ + switch (subscriber->group->net->auth_policy) { + case GSM_AUTH_POLICY_CLOSED: + LOGP(DMM, LOGL_DEBUG, "subscriber %s authorized = %d\n", + subscr_name(subscriber), subscriber->authorized); + return subscriber->authorized ? true : false; + case GSM_AUTH_POLICY_TOKEN: + if (subscriber->authorized) { + LOGP(DMM, LOGL_DEBUG, + "subscriber %s authorized = %d\n", + subscr_name(subscriber), subscriber->authorized); + return subscriber->authorized; + } + LOGP(DMM, LOGL_DEBUG, "subscriber %s first contact = %d\n", + subscr_name(subscriber), + (int)(subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT)); + return (subscriber->flags & GSM_SUBSCRIBER_FIRST_CONTACT); + case GSM_AUTH_POLICY_ACCEPT_ALL: + return true; + default: + LOGP(DMM, LOGL_DEBUG, "unknown auth_policy, rejecting" + " subscriber %s\n", subscr_name(subscriber)); + return false; + } +} diff --git a/openbsc/src/libmsc/iu_cs.c b/openbsc/src/libmsc/iu_cs.c new file mode 100644 index 000000000..13f29d07c --- /dev/null +++ b/openbsc/src/libmsc/iu_cs.c @@ -0,0 +1,173 @@ +#include <inttypes.h> + +#include <osmocom/core/logging.h> +#include <openbsc/debug.h> + +#include <openbsc/gsm_data.h> +#include <openbsc/msc_api.h> +#include <openbsc/iu.h> +#include <openbsc/gsm_subscriber.h> + +/* For A-interface see libbsc/bsc_api.c subscr_con_allocate() */ +static struct gsm_subscriber_connection *subscr_conn_allocate_iu(struct gsm_network *network, + struct ue_conn_ctx *ue, + uint16_t lac) +{ + struct gsm_subscriber_connection *conn; + + DEBUGP(DIUCS, "Allocating IuCS subscriber conn: lac %d, link_id %p, conn_id %" PRIx32 "\n", + lac, ue->link, ue->conn_id); + + conn = talloc_zero(network, struct gsm_subscriber_connection); + if (!conn) + return NULL; + + conn->network = network; + conn->via_iface = IFACE_IU; + conn->iu.ue_ctx = ue; + conn->lac = lac; + + llist_add_tail(&conn->entry, &network->subscr_conns); + return conn; +} + +static int same_ue_conn(struct ue_conn_ctx *a, struct ue_conn_ctx *b) +{ + if (a == b) + return 1; + return (a->link == b->link) + && (a->conn_id == b->conn_id); +} + +static inline void log_subscribers(struct gsm_network *network) +{ + if (!log_check_level(DIUCS, LOGL_DEBUG)) + return; + + struct gsm_subscriber_connection *conn; + int i = 0; + llist_for_each_entry(conn, &network->subscr_conns, entry) { + DEBUGP(DIUCS, "%3d: %s", i, subscr_name(conn->subscr)); + switch (conn->via_iface) { + case IFACE_IU: + DEBUGPC(DIUCS, " Iu"); + if (conn->iu.ue_ctx) { + DEBUGPC(DIUCS, " link %p, conn_id %d", + conn->iu.ue_ctx->link, + conn->iu.ue_ctx->conn_id + ); + } + break; + case IFACE_A: + DEBUGPC(DIUCS, " A"); + /* TODO log A-interface connection details */ + break; + case IFACE_UNKNOWN: + DEBUGPC(DIUCS, " ?"); + break; + default: + DEBUGPC(DIUCS, " invalid"); + break; + } + DEBUGPC(DIUCS, "\n"); + i++; + } + DEBUGP(DIUCS, "subscribers registered: %d\n", i); +} + +/* Return an existing IuCS subscriber connection record for the given link and + * connection IDs, or return NULL if not found. */ +struct gsm_subscriber_connection *subscr_conn_lookup_iu( + struct gsm_network *network, + struct ue_conn_ctx *ue) +{ + struct gsm_subscriber_connection *conn; + + DEBUGP(DIUCS, "Looking for IuCS subscriber: link_id %p, conn_id %" PRIx32 "\n", + ue->link, ue->conn_id); + log_subscribers(network); + + llist_for_each_entry(conn, &network->subscr_conns, entry) { + if (conn->via_iface != IFACE_IU) + continue; + if (!same_ue_conn(conn->iu.ue_ctx, ue)) + continue; + DEBUGP(DIUCS, "Found IuCS subscriber for link_id %p, conn_id %" PRIx32 "\n", + ue->link, ue->conn_id); + return conn; + } + DEBUGP(DIUCS, "No IuCS subscriber found for link_id %p, conn_id %" PRIx32 "\n", + ue->link, ue->conn_id); + return NULL; +} + +/* Receive MM/CC/... message from IuCS (SCCP user SAP). + * msg->dst must reference a struct ue_conn_ctx, which identifies the peer that + * sent the msg. + * + * For A-interface see libbsc/bsc_api.c gsm0408_rcvmsg(). */ +int gsm0408_rcvmsg_iucs(struct gsm_network *network, struct msgb *msg, + uint16_t *lac) +{ + int rc; + struct ue_conn_ctx *ue_ctx; + struct gsm_subscriber_connection *conn; + + ue_ctx = (struct ue_conn_ctx*)msg->dst; + + /* TODO: are there message types that could allow us to skip this + * search? */ + conn = subscr_conn_lookup_iu(network, ue_ctx); + + if (conn && lac && (conn->lac != *lac)) { + LOGP(DIUCS, LOGL_ERROR, "IuCS subscriber has changed LAC" + " within the same connection, discarding connection:" + " %s from LAC %d to %d\n", + subscr_name(conn->subscr), conn->lac, *lac); + /* Deallocate conn with previous LAC */ + gsm0408_clear_request(conn, 0); + /* At this point we could be tolerant and allocate a new + * connection, but changing the LAC within the same connection + * is shifty. Rather cancel everything. */ + return -1; + } + + if (conn) { + /* if we already have a connection, handle DTAP. + gsm0408_dispatch() is aka msc_dtap() */ + + /* Make sure we don't receive RR over IuCS; otherwise all + * messages handled by gsm0408_dispatch() are of interest (CC, + * MM, SMS, NS_SS, maybe even MM_GPRS and SM_GPRS). */ + struct gsm48_hdr *gh = msgb_l3(msg); + uint8_t pdisc = gh->proto_discr & 0x0f; + OSMO_ASSERT(pdisc != GSM48_PDISC_RR); + + rc = gsm0408_dispatch(conn, msg); + } else { + /* allocate a new connection */ + + if (!lac) { + LOGP(DIUCS, LOGL_ERROR, "New IuCS subscriber" + " but no LAC available. Expecting an InitialUE" + " message containing a LAI IE." + " Dropping connection.\n"); + return -1; + } + + conn = subscr_conn_allocate_iu(network, ue_ctx, *lac); + if (!conn) + abort(); + + rc = msc_compl_l3(conn, msg, 0); + if (rc != MSC_CONN_ACCEPT) { + gsm0408_clear_request(conn, 0); + rc = -1; + } + else + rc = 0; + } + + return rc; +} + diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c index ee98d2dd9..c670ed2e5 100644 --- a/openbsc/src/libmsc/mncc_builtin.c +++ b/openbsc/src/libmsc/mncc_builtin.c @@ -207,9 +207,11 @@ static int mncc_setup_cnf(struct gsm_call *call, int msg_type, bridge.callref[1] = call->remote_ref; DEBUGP(DMNCC, "(call %x) Bridging with remote.\n", call->callref); +#if BEFORE_MSCSPLIT /* in direct mode, we always have to bridge the channels */ if (ipacc_rtp_direct) return mncc_tx_to_cc(call->net, MNCC_BRIDGE, &bridge); +#endif /* proxy mode */ if (!net->handover.active) { @@ -293,11 +295,16 @@ static int mncc_rcv_data(struct gsm_call *call, int msg_type, return -EIO; } +#if BEFORE_MSCSPLIT /* RTP socket of remote end has meanwhile died */ if (!remote_trans->conn->lchan->abis_ip.rtp_socket) return -EIO; return rtp_send_frame(remote_trans->conn->lchan->abis_ip.rtp_socket, dfr); +#else + /* not implemented yet! */ + return -1; +#endif } diff --git a/openbsc/src/libmsc/msc_api.c b/openbsc/src/libmsc/msc_api.c new file mode 100644 index 000000000..f02b4c669 --- /dev/null +++ b/openbsc/src/libmsc/msc_api.c @@ -0,0 +1,56 @@ +/* Implementations for receiving or sending MM|CC|... messages from/to the + * BSC|RNC direction, regardless of which particular external interface is + * actually involved (A or IuCS). */ + +/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de> + * + * Based on parts of osmo_msc.c: + * (C) 2010,2013 by Holger Hans Peter Freyther <zecke@selfish.org> + * (C) 2010 by On-Waves + * + * 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 <osmocom/core/logging.h> + +#include <openbsc/debug.h> + +#include <openbsc/msc_api.h> +#include <openbsc/gsm_data.h> +#include <openbsc/transaction.h> + +int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg, + uint16_t chosen_channel) +{ + gsm0408_new_conn(conn); + gsm0408_dispatch(conn, msg); + + /* + * 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 + * pending transaction or ongoing operation. + */ + if (conn->silent_call) + return MSC_CONN_ACCEPT; + if (conn->loc_operation || conn->sec_operation || conn->anch_operation) + return MSC_CONN_ACCEPT; + if (trans_has_conn(conn)) + return MSC_CONN_ACCEPT; + + LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n"); + return MSC_CONN_REJECT; +} + diff --git a/openbsc/src/libmsc/gsm_04_11_helper.c b/openbsc/src/libmsc/msc_ifaces.c index f48c6de0b..99f040e6a 100644 --- a/openbsc/src/libmsc/gsm_04_11_helper.c +++ b/openbsc/src/libmsc/msc_ifaces.c @@ -1,6 +1,6 @@ -/* Helpers for SMS/GSM 04.11 */ -/* - * (C) 2014 by Holger Hans Peter Freyther +/* Implementation for MSC decisions which interface to send messages out on. */ + +/* (C) 2016 by sysmocom s.m.f.c GmbH <info@sysmocom.de> * * All Rights Reserved * @@ -16,22 +16,37 @@ * * 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 <osmocom/core/logging.h> + +#include <openbsc/debug.h> #include <openbsc/gsm_data.h> -#include <openbsc/gsm_04_11.h> +#include <openbsc/msc_ifaces.h> + +static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg) +{ + switch (conn->via_iface) { + case IFACE_A: + msg->dst = conn; + return a_tx(msg); + + case IFACE_IU: + msg->dst = conn->iu.ue_ctx; + return iu_tx(msg, 0); + + default: + LOGP(DMSC, LOGL_ERROR, + "msc_tx(): conn->via_iface invalid (%d)\n", + conn->via_iface); + return -1; + } +} + -uint8_t sms_next_rp_msg_ref(struct gsm_subscriber_connection *conn) +int msc_tx_dtap(struct gsm_subscriber_connection *conn, + struct msgb *msg) { - const uint8_t rp_msg_ref = conn->next_rp_ref; - /* - * This should wrap as the valid range is 0 to 255. We only - * transfer one SMS at a time so we don't need to check if - * the id has been already assigned. - */ - conn->next_rp_ref += 1; - - return rp_msg_ref; + return msc_tx(conn, msg); } diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c index 604c100db..0e91512d7 100644 --- a/openbsc/src/libmsc/osmo_msc.c +++ b/openbsc/src/libmsc/osmo_msc.c @@ -26,6 +26,7 @@ #include <openbsc/transaction.h> #include <openbsc/db.h> +#include <openbsc/msc_api.h> #include <openbsc/gsm_04_11.h> static void msc_sapi_n_reject(struct gsm_subscriber_connection *conn, int dlci) @@ -42,28 +43,6 @@ static int msc_clear_request(struct gsm_subscriber_connection *conn, uint32_t ca return 1; } -static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg, - uint16_t chosen_channel) -{ - gsm0408_new_conn(conn); - gsm0408_dispatch(conn, msg); - - /* - * 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 - * pending transaction or ongoing operation. - */ - if (conn->silent_call) - return BSC_API_CONN_POL_ACCEPT; - if (conn->loc_operation || 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; -} - static void msc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) { gsm0408_dispatch(conn, msg); @@ -143,7 +122,7 @@ struct bsc_api *msc_bsc_api() { return &msc_handler; } -/* lchan release handling */ +/* conn release handling */ void msc_release_connection(struct gsm_subscriber_connection *conn) { /* skip when we are in release, e.g. due an error */ @@ -169,9 +148,8 @@ void msc_release_connection(struct gsm_subscriber_connection *conn) * to restarting the timer. Set the new expiration time. */ if (conn->expire_timer_stopped) - subscr_update_expire_lu(conn->subscr, conn->bts); + subscr_update_expire_lu(conn->network, conn->subscr); conn->in_release = 1; - gsm0808_clear(conn); - subscr_con_free(conn); + msc_subscr_con_free(conn); } diff --git a/openbsc/src/libmsc/rrlp.c b/openbsc/src/libmsc/rrlp.c index 161456a06..e695daac7 100644 --- a/openbsc/src/libmsc/rrlp.c +++ b/openbsc/src/libmsc/rrlp.c @@ -40,7 +40,7 @@ static const uint8_t ass_pref_pos_req[] = { 0x40, 0x03, 0x79, 0x50 }; static int send_rrlp_req(struct gsm_subscriber_connection *conn) { - struct gsm_network *net = conn->bts->network; + struct gsm_network *net = conn->network; const uint8_t *req; switch (net->rrlp.mode) { diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c index 131a1786b..5e637b627 100644 --- a/openbsc/src/libmsc/silent_call.c +++ b/openbsc/src/libmsc/silent_call.c @@ -52,8 +52,10 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event, switch (event) { case GSM_PAGING_SUCCEEDED: +#if BEFORE_MSCSPLIT DEBUGPC(DLSMS, "success, using Timeslot %u on ARFCN %u\n", conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn); +#endif conn->silent_call = 1; /* increment lchan reference count */ osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata); @@ -121,7 +123,10 @@ int gsm_silent_call_start(struct gsm_subscriber *subscr, void *data, int type) { struct subscr_request *req; - req = subscr_request_channel(subscr, type, paging_cb_silent, data); + /* FIXME the VTY command allows selecting a silent call channel type. + * This doesn't apply to the situation after MSCSPLIT with an + * A-interface. */ + req = subscr_request_conn(subscr, paging_cb_silent, data); return req != NULL; } @@ -138,8 +143,10 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr) if (!conn->silent_call) return -EINVAL; +#if BEFORE_MSCSPLIT DEBUGPC(DLSMS, "Stopping silent call using Timeslot %u on ARFCN %u\n", conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn); +#endif conn->silent_call = 0; msc_release_connection(conn); diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c index 0269f4b3b..7f28134d1 100644 --- a/openbsc/src/libmsc/smpp_openbsc.c +++ b/openbsc/src/libmsc/smpp_openbsc.c @@ -420,6 +420,7 @@ void append_tlv_u16(tlv_t **req_tlv, uint16_t tag, uint16_t val) build_tlv(req_tlv, &tlv); } +#if BEFORE_MSCSPLIT /* Append the Osmocom vendor-specific additional TLVs to a SMPP msg */ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan) { @@ -458,6 +459,7 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan) (uint8_t *)subscr->equipment.imei, imei_len+1); } } +#endif static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms, struct gsm_subscriber_connection *conn) @@ -533,8 +535,10 @@ static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms, memcpy(deliver.short_message, sms->user_data, deliver.sm_length); } +#if BEFORE_MSCSPLIT if (esme->acl && esme->acl->osmocom_ext && conn->lchan) append_osmo_tlvs(&deliver.tlv, conn->lchan); +#endif return smpp_tx_deliver(esme, &deliver); } diff --git a/openbsc/src/libmsc/sms_queue.c b/openbsc/src/libmsc/sms_queue.c index 5dbe81f2f..ebc53c239 100644 --- a/openbsc/src/libmsc/sms_queue.c +++ b/openbsc/src/libmsc/sms_queue.c @@ -225,10 +225,14 @@ static void sms_submit_pending(void *_data) sms = take_next_sms(smsq); - if (!sms) + if (!sms) { + LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (%d attempted)\n", + attempted); break; + } rounds += 1; + LOGP(DLSMS, LOGL_DEBUG, "Sending SMS round %d\n", rounds); /* * This code needs to detect a loop. It assumes that no SMS @@ -243,6 +247,8 @@ static void sms_submit_pending(void *_data) first_sub = sms->receiver->id; initialized = 1; } else if (first_sub == sms->receiver->id) { + LOGP(DLSMS, LOGL_DEBUG, "Sending SMS done (loop) (%d attempted)\n", + attempted); sms_free(sms); break; } @@ -324,6 +330,7 @@ no_pending_sms: */ int sms_queue_trigger(struct gsm_sms_queue *smsq) { + LOGP(DLSMS, LOGL_DEBUG, "Triggering SMS queue\n"); if (osmo_timer_pending(&smsq->push_queue)) return 0; diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c index a75036253..dba4bed17 100644 --- a/openbsc/src/libmsc/transaction.c +++ b/openbsc/src/libmsc/transaction.c @@ -37,7 +37,7 @@ 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->bts->network; + struct gsm_network *net = conn->network; struct gsm_subscriber *subscr = conn->subscr; llist_for_each_entry(trans, &net->trans_list, entry) { @@ -155,7 +155,7 @@ int trans_has_conn(const struct gsm_subscriber_connection *conn) { struct gsm_trans *trans; - llist_for_each_entry(trans, &conn->bts->network->trans_list, entry) + llist_for_each_entry(trans, &conn->network->trans_list, entry) if (trans->conn == conn) return 1; diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index 4c2088a0f..fdc7e8e6f 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -53,8 +53,6 @@ #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) { int rc; @@ -139,7 +137,7 @@ DEFUN(show_subscr_cache, DEFUN(sms_send_pend, sms_send_pend_cmd, "sms send pending", - "SMS related comamnds\n" "SMS Sending related commands\n" + "SMS related commands\n" "SMS Sending related commands\n" "Send all pending SMS") { struct gsm_network *gsmnet = gsmnet_from_vty(vty); @@ -174,6 +172,7 @@ static int _send_sms_str(struct gsm_subscriber *receiver, sms_free(sms); return CMD_WARNING; } + LOGP(DLSMS, LOGL_DEBUG, "SMS stored in DB\n"); sms_free(sms); sms_queue_trigger(receiver->group->net->sms_queue); @@ -197,10 +196,10 @@ static struct gsm_subscriber *get_subscr_by_argv(struct gsm_network *gsmnet, } #define SUBSCR_TYPES "(extension|imsi|tmsi|id)" #define SUBSCR_HELP "Operations on a Subscriber\n" \ - "Identify subscriber by his extension (phone number)\n" \ - "Identify subscriber by his IMSI\n" \ - "Identify subscriber by his TMSI\n" \ - "Identify subscriber by his database ID\n" \ + "Identify subscriber by extension (phone number)\n" \ + "Identify subscriber by IMSI\n" \ + "Identify subscriber by TMSI\n" \ + "Identify subscriber by database ID\n" \ "Identifier for the subscriber\n" DEFUN(show_subscr, @@ -611,6 +610,7 @@ DEFUN(ena_subscr_handover, SUBSCR_HELP "Handover the active connection\n" "Number of the BTS to handover to\n") { +#if BEFORE_MSCSPLIT int ret; struct gsm_subscriber_connection *conn; struct gsm_bts *bts; @@ -654,6 +654,10 @@ DEFUN(ena_subscr_handover, subscr_put(subscr); return CMD_SUCCESS; +#else + vty_out(vty, "%% Not implemented!%s", VTY_NEWLINE); + return -1; +#endif } #define A3A8_ALG_TYPES "(none|xor|comp128v1)" @@ -768,6 +772,7 @@ DEFUN(subscriber_update, static int scall_cbfn(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) { +#if BEFORE_MSCSPLIT struct scall_signal_data *sigdata = signal_data; struct vty *vty = sigdata->data; @@ -782,6 +787,10 @@ static int scall_cbfn(unsigned int subsys, unsigned int signal, break; } return 0; +#else + /* not implemented yet! */ + return -1; +#endif } DEFUN(show_stats, @@ -791,7 +800,6 @@ DEFUN(show_stats, { struct gsm_network *net = gsmnet_from_vty(vty); - openbsc_vty_print_statistics(vty, net); vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", osmo_counter_get(net->stats.loc_upd_type.attach), osmo_counter_get(net->stats.loc_upd_type.normal), @@ -1018,66 +1026,6 @@ DEFUN(logging_fltr_imsi, return CMD_SUCCESS; } -static struct cmd_node nitb_node = { - NITB_NODE, - "%s(config-nitb)# ", - 1, -}; - -DEFUN(cfg_nitb, cfg_nitb_cmd, - "nitb", "Configure NITB options") -{ - vty->node = NITB_NODE; - return CMD_SUCCESS; -} - -DEFUN(cfg_nitb_subscr_create, cfg_nitb_subscr_create_cmd, - "subscriber-create-on-demand", - "Make a new record when a subscriber is first seen.\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->create_subscriber = 1; - return CMD_SUCCESS; -} - -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->create_subscriber = 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_nitb_assign_tmsi, cfg_nitb_assign_tmsi_cmd, - "assign-tmsi", - "Assign TMSI during Location Updating.\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->avoid_tmsi = 0; - return CMD_SUCCESS; -} - -DEFUN(cfg_nitb_no_assign_tmsi, cfg_nitb_no_assign_tmsi_cmd, - "no assign-tmsi", - NO_STR "Assign TMSI during Location Updating.\n") -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - gsmnet->avoid_tmsi = 1; - return CMD_SUCCESS; -} - -static int config_write_nitb(struct vty *vty) -{ - struct gsm_network *gsmnet = gsmnet_from_vty(vty); - vty_out(vty, "nitb%s", VTY_NEWLINE); - vty_out(vty, " %ssubscriber-create-on-demand%s", - gsmnet->create_subscriber ? "" : "no ", VTY_NEWLINE); - vty_out(vty, " %sassign-tmsi%s", - gsmnet->avoid_tmsi ? "no " : "", VTY_NEWLINE); - return CMD_SUCCESS; -} - int bsc_vty_init_extra(void) { osmo_signal_register_handler(SS_SCALL, scall_cbfn, NULL); @@ -1123,13 +1071,5 @@ 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_nitb_cmd); - install_node(&nitb_node, config_write_nitb); - install_element(NITB_NODE, &cfg_nitb_subscr_create_cmd); - install_element(NITB_NODE, &cfg_nitb_no_subscr_create_cmd); - install_element(NITB_NODE, &cfg_nitb_assign_tmsi_cmd); - install_element(NITB_NODE, &cfg_nitb_no_assign_tmsi_cmd); - return 0; } |