From ebff45e2ee89bd8c3cb106a58da3b172c01467e1 Mon Sep 17 00:00:00 2001 From: Neels Hofmeyr Date: Mon, 8 May 2017 15:12:20 +0200 Subject: mscsplit: various preparations to separate MSC from BSC Disable large parts of the code that depend on BSC presence. Don't set msg->lchan nor msg->dst. Don't use lchan in libmsc. Decouple lac from bts. Prepare entry/exit point for MSC -> BSC and MSC -> RNC communication: Add msc_ifaces.[hc], a_iface.c, with a general msc_tx_dtap() to redirect to different interfaces depending on the actual subscriber connection. While iu_tx() is going to be functional fairly soon, the a_tx() is going to be just a dummy for some time (see comment). Add Iu specific fields in gsm_subscriber_connection: the UE connection pointer and an indicator for the Integrity Protection status on Iu (to be fully implemented in later commits). Add lac member to gsm_subscriber_connection, to allow decoupling from bts->location_area_code. The conn->lac will actually be set in iu.c in an upcoming commit ("add iucs.[hc]"). move to libcommon-cs: gsm48_extract_mi(), gsm48_paging_extract_mi(). libmsc: duplicate gsm0808 / gsm48 functions (towards BSC). In osmo-nitb, libmsc would directly call the functions on the BSC level, not always via the bsc_api. When separating libmsc from libbsc, some functions are missing from the linkage. Hence duplicate these functions to libmsc, add an msc_ prefix for clarity, also add a _tx to gsm0808_cipher_mode(): * add msc_gsm0808_tx_cipher_mode() (dummy/stub) * add msc_gsm48_tx_mm_serv_ack() * add msc_gsm48_tx_mm_serv_rej() Call these from libmsc instead of * gsm0808_cipher_mode() * gsm48_tx_mm_serv_ack() * gsm48_tx_mm_serv_rej() Also add a comment related to msc_gsm0808_tx_cipher_mode() in two places. Temporarily disable all paging to be able to link libmsc without libbsc. Skip the paging part of channel_test because the paging is now disabled. In osmo-nitb, paging is done on BSC level and MSC level "at the same time". When the new MSC is fully operational, paging will be controlled separately on the MSC level, and the BSC (RNC) level will be instructed over an IuCS or A-interface to negotiate paging with the MS (UE). This MSC level paging does not yet exist and will be added in subsequent commits. msc_compl_l3(): publish in .h, tweak return value. Use new libmsc enum values for return val, to avoid dependency on libbsc headers. Make callable from other scopes: publish in osmo_msc.h and remove 'static' in osmo_msc.c add gsm_encr to subscr_conn move subscr_request to gsm_subscriber.h subscr_request_channel() -> subscr_request_conn() move to libmsc: osmo_stats_vty_add_cmds() gsm_04_08: remove apply_codec_restrictions() gsm0408_test: use NULL for root ctx move to libbsc: gsm_bts_neighbor() move to libbsc: lchan_next_meas_rep() move vty config for t3212 to network level (periodic lu) remove unneccessary linking from some tests remove handle_abisip_signal() abis_rsl.c: don't use libvlr from libbsc Change-Id: I9cf80f9c2c8a53a29e42f000029e680a9922cb41 --- openbsc/include/openbsc/Makefile.am | 1 + openbsc/include/openbsc/gsm_04_08.h | 2 + openbsc/include/openbsc/gsm_data.h | 30 +++- openbsc/include/openbsc/gsm_subscriber.h | 25 +++- openbsc/include/openbsc/msc_ifaces.h | 47 ++++++ openbsc/include/openbsc/osmo_msc.h | 5 + openbsc/src/libbsc/abis_rsl.c | 15 +- openbsc/src/libbsc/bsc_vty.c | 13 +- openbsc/src/libbsc/gsm_04_08_utils.c | 24 --- openbsc/src/libbsc/handover_decision.c | 21 +++ openbsc/src/libcommon-cs/common_cs.c | 27 ++++ openbsc/src/libcommon-cs/common_cs_vty.c | 2 + openbsc/src/libcommon/gsm_data.c | 34 +---- openbsc/src/libmsc/Makefile.am | 2 + openbsc/src/libmsc/a_iface.c | 45 ++++++ openbsc/src/libmsc/gsm_04_08.c | 239 +++++++++++------------------- openbsc/src/libmsc/gsm_04_11.c | 8 +- openbsc/src/libmsc/gsm_subscriber.c | 27 ++-- openbsc/src/libmsc/mncc_builtin.c | 7 + openbsc/src/libmsc/msc_ifaces.c | 83 +++++++++++ openbsc/src/libmsc/osmo_msc.c | 22 +-- openbsc/src/libmsc/silent_call.c | 9 +- openbsc/src/libmsc/smpp_openbsc.c | 4 + openbsc/src/libmsc/vty_interface_layer3.c | 14 ++ openbsc/tests/bsc/Makefile.am | 1 - openbsc/tests/channel/Makefile.am | 1 - openbsc/tests/db/Makefile.am | 2 - openbsc/tests/gsm0408/gsm0408_test.c | 4 +- 28 files changed, 446 insertions(+), 268 deletions(-) create mode 100644 openbsc/include/openbsc/msc_ifaces.h create mode 100644 openbsc/src/libmsc/a_iface.c create mode 100644 openbsc/src/libmsc/msc_ifaces.c diff --git a/openbsc/include/openbsc/Makefile.am b/openbsc/include/openbsc/Makefile.am index b903782b3..1091e8a04 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 ceaed7c5a..bf3f84236 100644 --- a/openbsc/include/openbsc/gsm_04_08.h +++ b/openbsc/include/openbsc/gsm_04_08.h @@ -79,6 +79,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 f2b7fa307..da61070f8 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] @@ -110,6 +111,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 */ @@ -169,6 +176,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; }; @@ -304,6 +320,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; @@ -414,6 +436,9 @@ struct gsm_network { uint16_t gsup_server_port; struct vlr_instance *vlr; + + /* Periodic location update default value */ + uint8_t t3212; }; struct osmo_esme; @@ -464,10 +489,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, @@ -550,7 +571,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 +#include + +/* 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 6227c0c5f..d4fdaedbd 100644 --- a/openbsc/src/libbsc/abis_rsl.c +++ b/openbsc/src/libbsc/abis_rsl.c @@ -1373,8 +1373,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; } @@ -1416,6 +1414,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 106874e10..46f27e826 100644 --- a/openbsc/src/libbsc/bsc_vty.c +++ b/openbsc/src/libbsc/bsc_vty.c @@ -594,13 +594,6 @@ 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); - vty_out(vty, " radio-link-timeout %d%s", get_radio_link_timeout(&bts->si_common.cell_options), VTY_NEWLINE); @@ -843,6 +836,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; } @@ -3951,7 +3949,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 db9dabb25..52c6b27b6 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 #include +/* 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 10fdc11ef..00d55c54a 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 89acc6b9c..837742120 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_names[_NUM_GSM_BTS_TYPE+1] = { { GSM_BTS_TYPE_UNKNOWN, "unknown" }, { GSM_BTS_TYPE_BS11, "bs11" }, @@ -230,19 +211,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 *bts, enum gsm_bts_features feat) { return bitvec_set_bit_pos(&bts->features, feat, 1); @@ -340,7 +308,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 */ set_radio_link_timeout(&bts->si_common.cell_options, 32); /* Use RADIO LINK TIMEOUT of 32 seconds */ 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 + * + * 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 . + * + */ + +#include +#include + +#include + +#include +#include +#include + +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 30c2cc34a..e1e5f6fab 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -71,10 +72,17 @@ #include + +/* 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) @@ -1878,7 +1774,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) @@ -1894,7 +1794,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)) { @@ -2034,7 +1933,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 */ @@ -2048,7 +1951,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)) { @@ -2738,7 +2640,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); @@ -2781,7 +2682,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); @@ -2822,7 +2722,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)) { @@ -2927,6 +2826,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; @@ -2942,8 +2842,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) @@ -3000,9 +2906,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; @@ -3056,10 +2964,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; @@ -3097,8 +3010,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; @@ -3146,6 +3064,7 @@ static int tch_rtp_signal(struct gsm_lchan *lchan, int signal) return 0; } +#endif static struct downstate { @@ -3215,7 +3134,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)); @@ -3253,6 +3174,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; @@ -3282,6 +3204,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)); @@ -3357,14 +3283,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; @@ -3396,6 +3323,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); @@ -3409,7 +3337,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)); @@ -3424,9 +3352,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, @@ -3523,12 +3450,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) { @@ -3846,6 +3775,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. @@ -3854,3 +3784,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 a67a7c600..7183d2391 100644 --- a/openbsc/src/libmsc/gsm_04_11.c +++ b/openbsc/src/libmsc/gsm_04_11.c @@ -872,7 +872,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) { @@ -998,7 +998,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) { @@ -1010,8 +1010,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 + * + * 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 . + */ + +#include + +#include +#include +#include + +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 #include #include #include @@ -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 8281071f9..d232cff19 100644 --- a/openbsc/src/libmsc/smpp_openbsc.c +++ b/openbsc/src/libmsc/smpp_openbsc.c @@ -422,6 +422,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) { @@ -460,6 +461,7 @@ static void append_osmo_tlvs(tlv_t **req_tlv, const struct gsm_lchan *lchan) (uint8_t *)vsub->imei, imei_len+1); } } +#endif static int deliver_to_esme(struct osmo_esme *esme, struct gsm_sms *sms, struct gsm_subscriber_connection *conn) @@ -535,8 +537,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/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 81dc177d7..01b7bf5a4 100644 --- a/openbsc/tests/gsm0408/gsm0408_test.c +++ b/openbsc/tests/gsm0408/gsm0408_test.c @@ -157,7 +157,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) @@ -184,7 +184,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) -- cgit v1.2.3