diff options
28 files changed, 447 insertions, 268 deletions
diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index 532328cb7..0e0df4204 100644 --- a/openbsc/include/openbsc/Makefile.am +++ b/openbsc/include/openbsc/Makefile.am @@ -54,6 +54,7 @@ noinst_HEADERS = \ misdn.h \ mncc.h \ mncc_int.h \ + msc_ifaces.h \ nat_rewrite_trie.h \ network_listen.h \ oap_client.h \ diff --git a/openbsc/include/openbsc/gsm_04_08.h b/openbsc/include/openbsc/gsm_04_08.h index c40d96d65..05aa6c00e 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -65,6 +65,8 @@ int decode_bcd_number(char *output, int output_len, const uint8_t *bcd_lv, int send_siemens_mrpci(struct gsm_lchan *lchan, uint8_t *classmark2_lv); int gsm48_extract_mi(uint8_t *classmark2, int length, char *mi_string, uint8_t *mi_type); int gsm48_paging_extract_mi(struct gsm48_pag_resp *pag, int length, char *mi_string, uint8_t *mi_type); + +/* TODO MSCSPLIT remove gsm48_handle_paging_resp() */ int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn, struct msgb *msg, struct bsc_subscr *bsub); diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h index 3d4c9dced..f0e2e9226 100644 --- a/openbsc/include/openbsc/gsm_data.h +++ b/openbsc/include/openbsc/gsm_data.h @@ -26,6 +26,7 @@ struct gsm_subscriber_group; struct bsc_subscr; struct vlr_instance; struct vlr_subscr; +struct ue_conn_ctx; #define OBSC_LINKID_CB(__msgb) (__msgb)->cb[3] @@ -117,6 +118,12 @@ struct gsm_classmark { uint8_t classmark3[14]; }; +enum integrity_protection_state { + INTEGRITY_PROTECTION_NONE = 0, + INTEGRITY_PROTECTION_IK = 1, + INTEGRITY_PROTECTION_IK_CK = 2, +}; + /* active radio connection of a mobile subscriber */ struct gsm_subscriber_connection { /* global linked list of subscriber_connections */ @@ -176,6 +183,15 @@ struct gsm_subscriber_connection { enum ran_type via_ran; struct gsm_classmark classmark; + + uint16_t lac; + struct gsm_encr encr; + + /* which Iu-CS connection, if any. */ + struct { + struct ue_conn_ctx *ue_ctx; + int integrity_protection; + } iu; }; @@ -311,6 +327,12 @@ struct gsm_tz { }; struct gsm_network { + /* TODO MSCSPLIT the gsm_network struct is basically a kitchen sink for + * global settings and variables, "madly" mixing BSC and MSC stuff. Split + * this in e.g. struct osmo_bsc and struct osmo_msc, with the things + * these have in common, like country and network code, put in yet + * separate structs and placed as members in osmo_bsc and osmo_msc. */ + /* global parameters */ uint16_t country_code; uint16_t network_code; @@ -421,6 +443,9 @@ struct gsm_network { uint16_t gsup_server_port; struct vlr_instance *vlr; + + /* Periodic location update default value */ + uint8_t t3212; }; struct osmo_esme; @@ -476,10 +501,6 @@ extern void talloc_ctx_init(void *ctx_root); int gsm_set_bts_type(struct gsm_bts *bts, enum gsm_bts_type type); -/* Get reference to a neighbor cell on a given BCCH ARFCN */ -struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, - uint16_t arfcn, uint8_t bsic); - enum gsm_bts_type parse_btstype(const char *arg); const char *btstype2str(enum gsm_bts_type type); struct gsm_bts *gsm_bts_by_lac(struct gsm_network *net, unsigned int lac, @@ -562,7 +583,6 @@ int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode); int gsm48_ra_id_by_bts(uint8_t *buf, struct gsm_bts *bts); void gprs_ra_id_by_bts(struct gprs_ra_id *raid, struct gsm_bts *bts); -struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan); int gsm_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features feat); int gsm_bts_model_register(struct gsm_bts_model *model); diff --git a/openbsc/include/openbsc/gsm_subscriber.h b/openbsc/include/openbsc/gsm_subscriber.h index c65b8a315..4124e0624 100644 --- a/openbsc/include/openbsc/gsm_subscriber.h +++ b/openbsc/include/openbsc/gsm_subscriber.h @@ -19,8 +19,6 @@ #define GSM_SUBSCRIBER_NO_EXPIRATION 0x0 -struct subscr_request; - enum gsm_subscriber_field { GSM_SUBSCRIBER_IMSI, GSM_SUBSCRIBER_TMSI, @@ -34,14 +32,29 @@ enum gsm_subscriber_update_reason { GSM_SUBSCRIBER_UPDATE_EQUIPMENT, }; -int subscr_update(struct vlr_subscr *vsub, struct gsm_bts *bts, int reason); +/* + * 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; +}; + +int subscr_update(struct vlr_subscr *vsub, int reason); /* * Paging handling with authentication */ -struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub, - int channel_type, - gsm_cbfn *cbfn, void *param); +struct subscr_request *subscr_request_conn(struct vlr_subscr *vsub, + int channel_type, + gsm_cbfn *cbfn, void *param); + void subscr_remove_request(struct subscr_request *req); int subscr_paging_dispatch(unsigned int hooknum, unsigned int event, diff --git a/openbsc/include/openbsc/msc_ifaces.h b/openbsc/include/openbsc/msc_ifaces.h new file mode 100644 index 000000000..83aad92a4 --- /dev/null +++ b/openbsc/include/openbsc/msc_ifaces.h @@ -0,0 +1,47 @@ +#pragma once + +#include <osmocom/core/msgb.h> +#include <openbsc/gsm_data.h> + +/* These are the interfaces of the MSC layer towards (from?) the BSC and RNC, + * i.e. in the direction towards the mobile device (MS aka UE). + * + * 2G will use the A-interface, + * 3G aka UMTS will use the Iu-interface (for the MSC, it's IuCS). + * + * To allow linking parts of the MSC code without having to include entire + * infrastructures of external libraries, the core transmitting and receiving + * functions are left unimplemented. For example, a unit test does not need to + * link against external ASN1 libraries if it is never going to encode actual + * outgoing messages. It is up to each building scope to implement real world + * functions or to plug mere dummy implementations. + * + * For example, msc_tx_dtap(conn, msg), depending on conn->via_iface, will call + * either iu_tx() or a_tx() [note: at time of writing, the A-interface is not + * yet implemented]. When you try to link against libmsc, you will find that + * the compiler complains about an undefined reference to iu_tx(). If you, + * however, link against libiu as well as the osmo-iuh libs (etc.), iu_tx() is + * available. A unit test may instead simply implement a dummy iu_tx() function + * and not link against osmo-iuh. + */ + +/* Each main linkage must implement this function (see comment above). */ +extern int iu_tx(struct msgb *msg, uint8_t sapi); + +/* So far this is a dummy implemented in libmsc/a_iface.c. When A-interface + * gets implemented, it should be in a separate lib (like libiu), this function + * should move there, and the following comment should remain here: " + * Each main linkage must implement this function (see comment above). + * " */ +extern int a_tx(struct msgb *msg); + +int msc_tx_dtap(struct gsm_subscriber_connection *conn, + struct msgb *msg); + +int msc_gsm48_tx_mm_serv_ack(struct gsm_subscriber_connection *conn); +int msc_gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn, + enum gsm48_reject_value value); + +/* TODO: specific to A interface, move this away */ +int msc_gsm0808_tx_cipher_mode(struct gsm_subscriber_connection *conn, int cipher, + const uint8_t *key, int len, int include_imeisv); diff --git a/openbsc/include/openbsc/osmo_msc.h b/openbsc/include/openbsc/osmo_msc.h index 166732ebf..6096e0b3e 100644 --- a/openbsc/include/openbsc/osmo_msc.h +++ b/openbsc/include/openbsc/osmo_msc.h @@ -50,6 +50,11 @@ static inline const char *subscr_conn_from_name(enum subscr_conn_from val) return get_value_string(subscr_conn_from_names, val); } +enum msc_compl_l3_rc { + MSC_CONN_ACCEPT = 0, + MSC_CONN_REJECT = 1, +}; + struct bsc_api *msc_bsc_api(); diff --git a/openbsc/src/libbsc/abis_rsl.c b/openbsc/src/libbsc/abis_rsl.c index 2a0b9a9a4..441b3861b 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1382,8 +1382,6 @@ static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr) if (lchan && lchan->conn) { if (lchan->conn->bsub) name = bsc_subscr_name(lchan->conn->bsub); - else if (lchan->conn->subscr) - name = lchan->conn->subscr->imsi; else name = lchan->name; } @@ -1425,6 +1423,19 @@ static void print_meas_rep(struct gsm_lchan *lchan, struct gsm_meas_rep *mr) } } +static struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) +{ + struct gsm_meas_rep *meas_rep; + + meas_rep = &lchan->meas_rep[lchan->meas_rep_idx]; + memset(meas_rep, 0, sizeof(*meas_rep)); + meas_rep->lchan = lchan; + lchan->meas_rep_idx = (lchan->meas_rep_idx + 1) + % ARRAY_SIZE(lchan->meas_rep); + + return meas_rep; +} + static int rsl_rx_meas_res(struct msgb *msg) { struct abis_rsl_dchan_hdr *dh = msgb_l2(msg); diff --git a/openbsc/src/libbsc/bsc_vty.c b/openbsc/src/libbsc/bsc_vty.c index 91f01591d..dcb1e6ee7 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -597,18 +597,12 @@ static void config_write_bts_single(struct vty *vty, struct gsm_bts *bts) (sp->penalty_time*20)+20, VTY_NEWLINE); } - /* Is periodic LU enabled or disabled? */ - if (bts->si_common.chan_desc.t3212 == 0) - vty_out(vty, " no periodic location update%s", VTY_NEWLINE); - else - vty_out(vty, " periodic location update %u%s", - bts->si_common.chan_desc.t3212 * 6, VTY_NEWLINE); - if (gsm_bts_get_radio_link_timeout(bts) < 0) vty_out(vty, " radio-link-timeout infinite%s", VTY_NEWLINE); else vty_out(vty, " radio-link-timeout %d%s", gsm_bts_get_radio_link_timeout(bts), VTY_NEWLINE); + vty_out(vty, " channel allocator %s%s", bts->chan_alloc_reverse ? "descending" : "ascending", VTY_NEWLINE); @@ -850,6 +844,11 @@ static int config_write_net(struct vty *vty) vty_out(vty, " timezone %d %d%s", gsmnet->tz.hr, gsmnet->tz.mn, VTY_NEWLINE); } + if (gsmnet->t3212 == 0) + vty_out(vty, " no periodic location update%s", VTY_NEWLINE); + else + vty_out(vty, " periodic location update %u%s", + gsmnet->t3212 * 6, VTY_NEWLINE); return CMD_SUCCESS; } @@ -4138,7 +4137,6 @@ int bsc_vty_init(struct gsm_network *network) install_element_ve(&show_paging_group_cmd); logging_vty_add_cmds(NULL); - osmo_stats_vty_add_cmds(); install_element(GSMNET_NODE, &cfg_net_neci_cmd); install_element(GSMNET_NODE, &cfg_net_handover_cmd); diff --git a/openbsc/src/libbsc/gsm_04_08_utils.c b/openbsc/src/libbsc/gsm_04_08_utils.c index 3447d27cb..f9a613601 100644 --- a/openbsc/src/libbsc/gsm_04_08_utils.c +++ b/openbsc/src/libbsc/gsm_04_08_utils.c @@ -270,30 +270,6 @@ int send_siemens_mrpci(struct gsm_lchan *lchan, return rsl_siemens_mrpci(lchan, &mrpci); } -int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type) -{ - /* Check the size for the classmark */ - if (length < 1 + *classmark2_lv) - return -1; - - uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1; - if (length < 2 + *classmark2_lv + mi_lv[0]) - return -2; - - *mi_type = mi_lv[1] & GSM_MI_TYPE_MASK; - return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv); -} - -int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length, - char *mi_string, uint8_t *mi_type) -{ - static const uint32_t classmark_offset = - offsetof(struct gsm48_pag_resp, classmark2); - uint8_t *classmark2_lv = (uint8_t *) &resp->classmark2; - return gsm48_extract_mi(classmark2_lv, length - classmark_offset, - mi_string, mi_type); -} - int gsm48_handle_paging_resp(struct gsm_subscriber_connection *conn, struct msgb *msg, struct bsc_subscr *bsub) { diff --git a/openbsc/src/libbsc/handover_decision.c b/openbsc/src/libbsc/handover_decision.c index 0f07bcac6..8d7e047b7 100644 --- a/openbsc/src/libbsc/handover_decision.c +++ b/openbsc/src/libbsc/handover_decision.c @@ -33,6 +33,27 @@ #include <openbsc/handover.h> #include <osmocom/gsm/gsm_utils.h> +/* Get reference to a neighbor cell on a given BCCH ARFCN */ +static struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, + uint16_t arfcn, uint8_t bsic) +{ + struct gsm_bts *neigh; + /* FIXME: use some better heuristics here to determine which cell + * using this ARFCN really is closest to the target cell. For + * now we simply assume that each ARFCN will only be used by one + * cell */ + + llist_for_each_entry(neigh, &bts->network->bts_list, list) { + /* FIXME: this is probably returning the same bts again!? */ + if (neigh->c0->arfcn == arfcn && + neigh->bsic == bsic) + return neigh; + } + + return NULL; +} + + /* issue handover to a cell identified by ARFCN and BSIC */ static int handover_to_arfcn_bsic(struct gsm_lchan *lchan, uint16_t arfcn, uint8_t bsic) diff --git a/openbsc/src/libcommon-cs/common_cs.c b/openbsc/src/libcommon-cs/common_cs.c index 20fbab8c4..d94381b4c 100644 --- a/openbsc/src/libcommon-cs/common_cs.c +++ b/openbsc/src/libcommon-cs/common_cs.c @@ -59,6 +59,9 @@ struct gsm_network *gsm_network_init(void *ctx, net->country_code = country_code; net->network_code = network_code; + /* Use 30 min periodic update interval as sane default */ + net->t3212 = 5; + INIT_LLIST_HEAD(&net->trans_list); INIT_LLIST_HEAD(&net->upqueue); INIT_LLIST_HEAD(&net->subscr_conns); @@ -112,6 +115,30 @@ struct msgb *gsm48_create_loc_upd_rej(uint8_t cause) return msg; } +int gsm48_extract_mi(uint8_t *classmark2_lv, int length, char *mi_string, uint8_t *mi_type) +{ + /* Check the size for the classmark */ + if (length < 1 + *classmark2_lv) + return -1; + + uint8_t *mi_lv = classmark2_lv + *classmark2_lv + 1; + if (length < 2 + *classmark2_lv + mi_lv[0]) + return -2; + + *mi_type = mi_lv[1] & GSM_MI_TYPE_MASK; + return gsm48_mi_to_string(mi_string, GSM48_MI_SIZE, mi_lv+1, *mi_lv); +} + +int gsm48_paging_extract_mi(struct gsm48_pag_resp *resp, int length, + char *mi_string, uint8_t *mi_type) +{ + static const uint32_t classmark_offset = + offsetof(struct gsm48_pag_resp, classmark2); + uint8_t *classmark2_lv = (uint8_t *) &resp->classmark2; + return gsm48_extract_mi(classmark2_lv, length - classmark_offset, + mi_string, mi_type); +} + uint8_t sms_next_rp_msg_ref(uint8_t *next_rp_ref) { const uint8_t rp_msg_ref = *next_rp_ref; diff --git a/openbsc/src/libcommon-cs/common_cs_vty.c b/openbsc/src/libcommon-cs/common_cs_vty.c index 19ea6e830..4b11f2c0a 100644 --- a/openbsc/src/libcommon-cs/common_cs_vty.c +++ b/openbsc/src/libcommon-cs/common_cs_vty.c @@ -305,6 +305,8 @@ int common_cs_vty_init(struct gsm_network *network, OSMO_ASSERT(vty_global_gsm_network == NULL); vty_global_gsm_network = network; + osmo_stats_vty_add_cmds(); + install_element(CONFIG_NODE, &cfg_net_cmd); install_node(&net_node, config_write_net); vty_install_default(GSMNET_NODE); diff --git a/openbsc/src/libcommon/gsm_data.c b/openbsc/src/libcommon/gsm_data.c index 7c717a40f..f6fde37bd 100644 --- a/openbsc/src/libcommon/gsm_data.c +++ b/openbsc/src/libcommon/gsm_data.c @@ -71,25 +71,6 @@ int gsm_bts_model_register(struct gsm_bts_model *model) return 0; } -/* Get reference to a neighbor cell on a given BCCH ARFCN */ -struct gsm_bts *gsm_bts_neighbor(const struct gsm_bts *bts, - uint16_t arfcn, uint8_t bsic) -{ - struct gsm_bts *neigh; - /* FIXME: use some better heuristics here to determine which cell - * using this ARFCN really is closest to the target cell. For - * now we simply assume that each ARFCN will only be used by one - * cell */ - - llist_for_each_entry(neigh, &bts->network->bts_list, list) { - if (neigh->c0->arfcn == arfcn && - neigh->bsic == bsic) - return neigh; - } - - return NULL; -} - const struct value_string bts_type_descs[_NUM_GSM_BTS_TYPE+1] = { { GSM_BTS_TYPE_UNKNOWN, "Unknown BTS Type" }, { GSM_BTS_TYPE_BS11, "Siemens BTS (BS-11 or compatible)" }, @@ -210,19 +191,6 @@ int bts_gprs_mode_is_compat(struct gsm_bts *bts, enum bts_gprs_mode mode) return 1; } -struct gsm_meas_rep *lchan_next_meas_rep(struct gsm_lchan *lchan) -{ - struct gsm_meas_rep *meas_rep; - - meas_rep = &lchan->meas_rep[lchan->meas_rep_idx]; - memset(meas_rep, 0, sizeof(*meas_rep)); - meas_rep->lchan = lchan; - lchan->meas_rep_idx = (lchan->meas_rep_idx + 1) - % ARRAY_SIZE(lchan->meas_rep); - - return meas_rep; -} - int gsm_btsmodel_set_feature(struct gsm_bts_model *model, enum gsm_bts_features feat) { OSMO_ASSERT(_NUM_BTS_FEAT < MAX_BTS_FEATURES); @@ -322,7 +290,7 @@ struct gsm_bts *gsm_bts_alloc_register(struct gsm_network *net, enum gsm_bts_typ bts->si_common.chan_desc.att = 1; /* attachment required */ bts->si_common.chan_desc.bs_pa_mfrms = RSL_BS_PA_MFRMS_5; /* paging frames */ bts->si_common.chan_desc.bs_ag_blks_res = 1; /* reserved AGCH blocks */ - bts->si_common.chan_desc.t3212 = 5; /* Use 30 min periodic update interval as sane default */ + bts->si_common.chan_desc.t3212 = net->t3212; /* Use network's current value */ gsm_bts_set_radio_link_timeout(bts, 32); /* Use RADIO LINK TIMEOUT of 32 */ llist_add_tail(&bts->list, &net->bts_list); diff --git a/openbsc/src/libmsc/Makefile.am b/openbsc/src/libmsc/Makefile.am index 3f4174ca5..7ab30d029 100644 --- a/openbsc/src/libmsc/Makefile.am +++ b/openbsc/src/libmsc/Makefile.am @@ -23,6 +23,7 @@ noinst_LIBRARIES = \ $(NULL) libmsc_a_SOURCES = \ + a_iface.c \ auth.c \ db.c \ gsm_04_08.c \ @@ -32,6 +33,7 @@ libmsc_a_SOURCES = \ mncc.c \ mncc_builtin.c \ mncc_sock.c \ + msc_ifaces.c \ rrlp.c \ silent_call.c \ sms_queue.c \ diff --git a/openbsc/src/libmsc/a_iface.c b/openbsc/src/libmsc/a_iface.c new file mode 100644 index 000000000..1f471f97b --- /dev/null +++ b/openbsc/src/libmsc/a_iface.c @@ -0,0 +1,45 @@ +/* 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> +#include <openbsc/debug.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 msc_gsm0808_tx_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; +} diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index 9591ddb0a..f8d47e4da 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -59,6 +59,7 @@ #include <osmocom/abis/e1_input.h> #include <osmocom/core/bitvec.h> #include <openbsc/vlr.h> +#include <openbsc/msc_ifaces.h> #include <osmocom/gsm/gsm48.h> #include <osmocom/gsm/gsm0480.h> @@ -71,10 +72,17 @@ #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; +#if BEFORE_MSCSPLIT static int tch_rtp_signal(struct gsm_lchan *lchan, int signal); +#endif static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, uint32_t send_tmsi); @@ -87,29 +95,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) @@ -126,27 +111,6 @@ 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); @@ -187,7 +151,6 @@ 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; msg = gsm48_create_loc_upd_rej(cause); @@ -196,11 +159,8 @@ int gsm0408_loc_upd_rej(struct gsm_subscriber_connection *conn, uint8_t cause) return -1; } - msg->lchan = conn->lchan; - - LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT " - "LAC=%u BTS=%u\n", vlr_subscr_name(conn->vsub), - bts->location_area_code, bts->nr); + LOGP(DMM, LOGL_INFO, "Subscriber %s: LOCATION UPDATING REJECT\n", + vlr_subscr_name(conn->vsub)); return gsm48_conn_sendmsg(msg, conn, NULL); } @@ -214,8 +174,6 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, 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; @@ -223,7 +181,7 @@ static int gsm0408_loc_upd_acc(struct gsm_subscriber_connection *conn, lai = (struct gsm48_loc_area_id *) msgb_put(msg, sizeof(*lai)); gsm48_generate_lai(lai, conn->network->country_code, conn->network->network_code, - conn->bts->location_area_code); + conn->lac); if (send_tmsi == GSM_RESERVED_TMSI) { /* we did not allocate a TMSI to the MS, so we need to @@ -258,8 +216,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; @@ -437,8 +393,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; @@ -588,7 +542,6 @@ int gsm48_tx_mm_auth_req(struct gsm_subscriber_connection *conn, uint8_t *rand, if (autn) DEBUGP(DMM, " AUTH REQ (autn = %s)\n", osmo_hexdump_nospc(autn, 16)); - msg->lchan = conn->lchan; gh->proto_discr = GSM48_PDISC_MM; gh->msg_type = GSM48_MT_MM_AUTH_REQ; @@ -669,7 +622,7 @@ accept_reuse: * 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 * * Keep this function non-static for direct invocation by unit tests. */ @@ -699,14 +652,14 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms DEBUGP(DMM, "<- CM SERVICE REQUEST "); if (msg->data_len < sizeof(struct gsm48_service_request*)) { DEBUGPC(DMM, "wrong sized message\n"); - return gsm48_tx_mm_serv_rej(conn, - GSM48_REJECT_INCORRECT_MESSAGE); + return msc_gsm48_tx_mm_serv_rej(conn, + GSM48_REJECT_INCORRECT_MESSAGE); } if (msg->data_len < req->mi_len + 6) { DEBUGPC(DMM, "does not fit in packet\n"); - return gsm48_tx_mm_serv_rej(conn, - GSM48_REJECT_INCORRECT_MESSAGE); + return msc_gsm48_tx_mm_serv_rej(conn, + GSM48_REJECT_INCORRECT_MESSAGE); } gsm48_mi_to_string(mi_string, sizeof(mi_string), mi, mi_len); @@ -722,8 +675,8 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms mi_string); } else { DEBUGPC(DMM, "mi_type is not expected: %d\n", mi_type); - return gsm48_tx_mm_serv_rej(conn, - GSM48_REJECT_INCORRECT_MESSAGE); + return msc_gsm48_tx_mm_serv_rej(conn, + GSM48_REJECT_INCORRECT_MESSAGE); } osmo_signal_dispatch(SS_SUBSCR, S_SUBSCR_IDENTITY, (classmark2 + classmark2_len)); @@ -748,8 +701,12 @@ int gsm48_rx_mm_serv_req(struct gsm_subscriber_connection *conn, struct msgb *ms return rc; } +#if BEFORE_MSCSPLIT + /* see mail on openbsc@ 9 Feb 2016 22:30:15 +0100 + * We need to hook sending of MRPCI to Siemens BS11 somewhere else */ if (is_siemens_bts(conn->bts)) send_siemens_mrpci(msg->lchan, classmark2-1); +#endif vlr_proc_acc_req(conn->conn_fsm, SUBSCR_CONN_E_ACCEPTED, @@ -801,7 +758,6 @@ static int gsm48_rx_mm_imsi_detach_ind(struct gsm_subscriber_connection *conn, s break; } - /* TODO? We used to remember the subscriber's classmark1 here and * stored it in the old sqlite db, but now we store it in a conn that * will be discarded anyway: */ @@ -1195,8 +1151,6 @@ 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); @@ -1288,8 +1242,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; @@ -1311,6 +1263,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) " @@ -1328,6 +1281,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; @@ -1371,8 +1325,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); @@ -1386,13 +1342,12 @@ 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", vlr_subscr_msisdn_or_name(transt->vsub)); OSMO_ASSERT(conn); - /* Assign lchan */ + /* Assign conn */ transt->conn = conn; /* send SETUP request to called party */ gsm48_cc_tx_setup(transt, &transt->cc.msg); @@ -1421,6 +1376,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) @@ -1488,77 +1444,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) @@ -1647,6 +1532,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) @@ -1663,13 +1549,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(LOG_CTX_VLR_SUBSCR, trans1->vsub); +#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; @@ -1738,6 +1630,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) @@ -1877,7 +1773,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) @@ -1893,7 +1793,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)) { @@ -2033,7 +1932,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 */ @@ -2047,7 +1950,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)) { @@ -2737,7 +2639,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); @@ -2780,7 +2681,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); @@ -2821,7 +2721,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)) { @@ -2926,6 +2825,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; @@ -2941,8 +2841,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) @@ -2999,9 +2905,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; @@ -3055,10 +2963,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; @@ -3096,8 +3009,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; @@ -3145,6 +3063,7 @@ static int tch_rtp_signal(struct gsm_lchan *lchan, int signal) return 0; } +#endif static struct downstate { @@ -3214,7 +3133,9 @@ 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; +#if BEFORE_MSCSPLIT struct gsm_bts *bts = NULL; +#endif struct gsm_mncc *data = arg, rel; DEBUGP(DMNCC, "receive message %s\n", get_mncc_name(msg_type)); @@ -3252,6 +3173,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; @@ -3281,6 +3203,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)); @@ -3356,14 +3282,15 @@ 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(vsub); - /* 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->vsub != vsub) continue; @@ -3395,6 +3322,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg) vlr_subscr_put(vsub); return 0; } + /* Assign lchan */ trans->conn = msc_subscr_conn_get(conn); vlr_subscr_put(vsub); @@ -3408,7 +3336,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", vlr_subscr_msisdn_or_name(trans->vsub), get_mncc_name(msg_type)); @@ -3423,9 +3351,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, vlr_subscr_msisdn_or_name(trans->conn->vsub), get_mncc_name(msg_type), trans->cc.state, @@ -3522,12 +3449,14 @@ 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, vlr_subscr_msisdn_or_name(conn->vsub), gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0, gsm48_cc_state_name(trans?(trans->cc.state):0)); +#endif /* Create transaction */ if (!trans) { @@ -3845,6 +3774,7 @@ int msc_vlr_start(struct gsm_network *net) net->gsup_server_port); } +#if BEFORE_MSCSPLIT /* * This will be run by the linker when loading the DSO. We use it to * do system initialization, e.g. registration of signal handlers. @@ -3853,3 +3783,4 @@ static __attribute__((constructor)) void on_dso_load_0408(void) { osmo_signal_register_handler(SS_ABISIP, handle_abisip_signal, NULL); } +#endif diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c index 6ad944b50..3255a3b6f 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -878,7 +878,7 @@ 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) { @@ -1004,7 +1004,7 @@ int gsm411_send_sms_subscr(struct vlr_subscr *vsub, 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(vsub); if (conn) { @@ -1016,8 +1016,8 @@ int gsm411_send_sms_subscr(struct vlr_subscr *vsub, /* if not, we have to start paging */ LOGP(DLSMS, LOGL_DEBUG, "Sending SMS: no connection open, start paging %s\n", vlr_subscr_name(vsub)); - res = subscr_request_channel(vsub, RSL_CHANNEED_SDCCH, - paging_cb_send_sms, sms); + res = subscr_request_conn(vsub, RSL_CHANNEED_SDCCH, paging_cb_send_sms, + sms); if (!res) { send_signal(S_SMS_UNKNOWN_ERROR, NULL, sms, GSM_PAGING_BUSY); sms_free(sms); diff --git a/openbsc/src/libmsc/gsm_subscriber.c b/openbsc/src/libmsc/gsm_subscriber.c index e9b2e0e5d..f425058f0 100644 --- a/openbsc/src/libmsc/gsm_subscriber.c +++ b/openbsc/src/libmsc/gsm_subscriber.c @@ -46,21 +46,6 @@ void *tall_sub_req_ctx; 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 bsc_subscr *vlr_subscr_to_bsc_sub(struct llist_head *bsc_subscribers, struct vlr_subscr *vsub) { @@ -74,6 +59,10 @@ static struct bsc_subscr *vlr_subscr_to_bsc_sub(struct llist_head *bsc_subscribe return sub; } +#if 0 +TODO implement paging response in libmsc! +Excluding this to be able to link without libbsc: + /* * We got the channel assigned and can now hand this channel * over to one of our callbacks. @@ -139,9 +128,16 @@ struct subscr_request *subscr_request_channel(struct vlr_subscr *vsub, if (!vsub->cs.is_paging) { LOGP(DMM, LOGL_DEBUG, "Subscriber %s not paged yet.\n", vlr_subscr_name(vsub)); +#if 0 + TODO implement paging response in libmsc! + Excluding this to be able to link without libbsc: + bsub = vlr_subscr_to_bsc_sub(net->bsc_subscribers, vsub); rc = paging_request(net, bsub, channel_type, NULL, NULL); bsc_subscr_put(bsub); +#else + rc = -ENOTSUP; +#endif if (rc <= 0) { LOGP(DMM, LOGL_ERROR, "Subscriber %s paging failed: %d\n", vlr_subscr_name(vsub), rc); @@ -181,3 +177,4 @@ struct gsm_subscriber_connection *connection_for_subscr(struct vlr_subscr *vsub) return NULL; } +#endif diff --git a/openbsc/src/libmsc/mncc_builtin.c b/openbsc/src/libmsc/mncc_builtin.c index 067cc92f8..7f613c4a4 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_ifaces.c b/openbsc/src/libmsc/msc_ifaces.c new file mode 100644 index 000000000..500c99c2e --- /dev/null +++ b/openbsc/src/libmsc/msc_ifaces.c @@ -0,0 +1,83 @@ +/* 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 + * + * 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/gsm_data.h> +#include <openbsc/msc_ifaces.h> + +static int msc_tx(struct gsm_subscriber_connection *conn, struct msgb *msg) +{ + switch (conn->via_ran) { + case RAN_GERAN_A: + msg->dst = conn; + return a_tx(msg); + + case RAN_UTRAN_IU: + msg->dst = conn->iu.ue_ctx; + return iu_tx(msg, 0); + + default: + LOGP(DMSC, LOGL_ERROR, + "msc_tx(): conn->via_ran invalid (%d)\n", + conn->via_ran); + return -1; + } +} + + +int msc_tx_dtap(struct gsm_subscriber_connection *conn, + struct msgb *msg) +{ + return msc_tx(conn, msg); +} + + +/* 9.2.5 CM service accept */ +int msc_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 msc_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/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c index 21c8ec246..ab53b0be7 100644 --- a/openbsc/src/libmsc/osmo_msc.c +++ b/openbsc/src/libmsc/osmo_msc.c @@ -21,6 +21,7 @@ * */ +#include <openbsc/osmo_msc.h> #include <openbsc/bsc_api.h> #include <openbsc/debug.h> #include <openbsc/transaction.h> @@ -69,9 +70,10 @@ static void subscr_conn_bump(struct gsm_subscriber_connection *conn) osmo_fsm_inst_dispatch(conn->conn_fsm, SUBSCR_CONN_E_BUMP, NULL); } -/* Receive a COMPLETE LAYER3 INFO from BSC */ -static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg, - uint16_t chosen_channel) +/* receive a Level 3 Complete message and return MSC_CONN_ACCEPT or + * MSC_CONN_REJECT */ +enum msc_compl_l3_rc msc_compl_l3(struct gsm_subscriber_connection *conn, + struct msgb *msg, uint16_t chosen_channel) { /* Ownership of the gsm_subscriber_connection is still a bit mucky * between libbsc and libmsc. In libmsc, we use ref counting, but not @@ -87,7 +89,7 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg /* keep the use_count reserved, libbsc will discard. If we * released the ref count and discarded here, libbsc would * double-free. And we will not change bsc_api semantics. */ - return BSC_API_CONN_POL_REJECT; + return MSC_CONN_REJECT; } DEBUGP(DMM, "compl_l3: Keeping conn\n"); @@ -96,7 +98,7 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg /* If this should be kept, the conn->conn_fsm has placed a use_count */ msc_subscr_conn_put(conn); - return BSC_API_CONN_POL_ACCEPT; + return MSC_CONN_ACCEPT; #if 0 /* @@ -105,14 +107,14 @@ static int msc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg * pending transaction or ongoing operation. */ if (conn->silent_call) - return BSC_API_CONN_POL_ACCEPT; - if (conn->sec_operation || conn->anch_operation) - return BSC_API_CONN_POL_ACCEPT; + return MSC_CONN_ACCEPT; + if (conn->loc_operation || conn->sec_operation || conn->anch_operation) + return MSC_CONN_ACCEPT; if (trans_has_conn(conn)) - return BSC_API_CONN_POL_ACCEPT; + return MSC_CONN_ACCEPT; LOGP(DRR, LOGL_INFO, "MSC Complete L3: Rejecting connection.\n"); - return BSC_API_CONN_POL_REJECT; + return MSC_CONN_REJECT; #endif } diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c index 6f3fbf264..76816c29d 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; msc_subscr_conn_get(conn); /* increment lchan reference count */ @@ -126,7 +128,10 @@ int gsm_silent_call_start(struct vlr_subscr *vsub, void *data, int type) { struct subscr_request *req; - req = subscr_request_channel(vsub, 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(vsub, type, paging_cb_silent, data); return req != NULL; } @@ -143,8 +148,10 @@ int gsm_silent_call_stop(struct vlr_subscr *vsub) 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_subscr_conn_put(conn); diff --git a/openbsc/src/libmsc/smpp_openbsc.c b/openbsc/src/libmsc/smpp_openbsc.c index f06eb7d93..42ba7f990 100644 --- a/openbsc/src/libmsc/smpp_openbsc.c +++ b/openbsc/src/libmsc/smpp_openbsc.c @@ -423,6 +423,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) { @@ -461,6 +462,7 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan) (uint8_t *)vsub->imei, imei_len+1); } } +#endif struct { uint32_t smpp_status_code; @@ -680,8 +682,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 ret = smpp_tx_deliver(esme, &deliver); if (ret < 0) diff --git a/openbsc/src/libmsc/vty_interface_layer3.c b/openbsc/src/libmsc/vty_interface_layer3.c index faadbb16e..df2d1e4ad 100644 --- a/openbsc/src/libmsc/vty_interface_layer3.c +++ b/openbsc/src/libmsc/vty_interface_layer3.c @@ -559,6 +559,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; @@ -602,6 +603,10 @@ DEFUN(ena_subscr_handover, vlr_subscr_put(vsub); return CMD_SUCCESS; +#else + vty_out(vty, "%% Not implemented!%s", VTY_NEWLINE); + return -1; +#endif } #define A3A8_ALG_TYPES "(none|xor|comp128v1)" @@ -647,6 +652,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; @@ -661,6 +667,10 @@ static int scall_cbfn(unsigned int subsys, unsigned int signal, break; } return 0; +#else + /* not implemented yet! */ + return -1; +#endif } DEFUN(show_stats, @@ -670,7 +680,11 @@ DEFUN(show_stats, { struct gsm_network *net = gsmnet_from_vty(vty); +#if 0 + TODO implement statistics specifically for libmsc! + Excluding this to be able to link without libbsc: openbsc_vty_print_statistics(vty, net); +#endif vty_out(vty, "Location Update : %lu attach, %lu normal, %lu periodic%s", net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_ATTACH].current, net->msc_ctrs->ctr[MSC_CTR_LOC_UPDATE_TYPE_NORMAL].current, diff --git a/openbsc/tests/bsc/Makefile.am b/openbsc/tests/bsc/Makefile.am index 9de4145b7..904bdfcd7 100644 --- a/openbsc/tests/bsc/Makefile.am +++ b/openbsc/tests/bsc/Makefile.am @@ -32,7 +32,6 @@ bsc_test_SOURCES = \ bsc_test_LDADD = \ $(top_builddir)/src/libbsc/libbsc.a \ - $(top_builddir)/src/libmsc/libmsc.a \ $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ $(top_builddir)/src/libmgcp/libmgcp.a \ $(top_builddir)/src/libtrau/libtrau.a \ diff --git a/openbsc/tests/channel/Makefile.am b/openbsc/tests/channel/Makefile.am index c7164b475..dd78bdcf9 100644 --- a/openbsc/tests/channel/Makefile.am +++ b/openbsc/tests/channel/Makefile.am @@ -24,7 +24,6 @@ channel_test_SOURCES = \ $(NULL) channel_test_LDADD = \ - $(top_builddir)/src/libmsc/libmsc.a \ $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libvlr/libvlr.a \ $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ diff --git a/openbsc/tests/db/Makefile.am b/openbsc/tests/db/Makefile.am index 0eed5cd55..df421d86c 100644 --- a/openbsc/tests/db/Makefile.am +++ b/openbsc/tests/db/Makefile.am @@ -32,9 +32,7 @@ db_test_SOURCES = \ $(NULL) db_test_LDADD = \ - $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libmsc/libmsc.a \ - $(top_builddir)/src/libbsc/libbsc.a \ $(top_builddir)/src/libcommon-cs/libcommon-cs.a \ $(top_builddir)/src/libtrau/libtrau.a \ $(top_builddir)/src/libcommon/libcommon.a \ diff --git a/openbsc/tests/gsm0408/gsm0408_test.c b/openbsc/tests/gsm0408/gsm0408_test.c index 5a8c6ca52..1b326ee54 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.c +++ b/openbsc/tests/gsm0408/gsm0408_test.c @@ -182,7 +182,7 @@ static inline void test_si2q_mu(void) static inline void test_si2q_u(void) { struct gsm_bts *bts; - struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL); + struct gsm_network *network = bsc_network_init(NULL, 1, 1, NULL); printf("Testing SYSINFO_TYPE_2quater UARFCN generation:\n"); if (!network) @@ -210,7 +210,7 @@ static inline void test_si2q_u(void) static inline void test_si2q_e(void) { struct gsm_bts *bts; - struct gsm_network *network = bsc_network_init(tall_bsc_ctx, 1, 1, NULL); + struct gsm_network *network = bsc_network_init(NULL, 1, 1, NULL); printf("Testing SYSINFO_TYPE_2quater EARFCN generation:\n"); if (!network) |