From 83d2d38a3c348168873a9d977641ee4381b01fa3 Mon Sep 17 00:00:00 2001 From: Holger Hans Peter Freyther Date: Thu, 9 Jun 2011 17:37:04 +0200 Subject: bsc: Inspect a CC Setup message and attempt to reroute the traffic Inspect the CC Setup messages and if the dialed number is matching the regexp of the local MSC the connection will be rerouted. The original MSC will get a GSM0808 CLEAR REQUEST, a new connection with a CC Setup message will be opened. --- openbsc/src/osmo-bsc/osmo_bsc_api.c | 116 +++++++++++++++++++++++++++++++++++- 1 file changed, 113 insertions(+), 3 deletions(-) (limited to 'openbsc/src/osmo-bsc/osmo_bsc_api.c') diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c index 7acb00afc..c25725997 100644 --- a/openbsc/src/osmo-bsc/osmo_bsc_api.c +++ b/openbsc/src/osmo-bsc/osmo_bsc_api.c @@ -45,6 +45,10 @@ } \ bsc_queue_for_msc(conn->sccp_con, resp); +static int bsc_clear_request(struct gsm_subscriber_connection *conn, uint32_t cause); +static int complete_layer3(struct gsm_subscriber_connection *conn, + struct msgb *msg, struct osmo_msc_data *msc); + static uint16_t get_network_code_for_msc(struct osmo_msc_data *msc) { if (msc->core_ncc != -1) @@ -88,10 +92,7 @@ static void bsc_cipher_mode_compl(struct gsm_subscriber_connection *conn, static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg, uint16_t chosen_channel) { - struct msgb *resp; struct osmo_msc_data *msc; - uint16_t network_code; - uint16_t country_code; LOGP(DMSC, LOGL_INFO, "Tx MSC COMPL L3\n"); @@ -102,6 +103,16 @@ static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg return -1; } + return complete_layer3(conn, msg, msc); +} + +static int complete_layer3(struct gsm_subscriber_connection *conn, + struct msgb *msg, struct osmo_msc_data *msc) +{ + struct msgb *resp; + uint16_t network_code; + uint16_t country_code; + /* allocate resource for a new connection */ if (bsc_create_new_connection(conn, msc) != 0) return BSC_API_CONN_POL_REJECT; @@ -130,6 +141,96 @@ static int bsc_compl_l3(struct gsm_subscriber_connection *conn, struct msgb *msg return BSC_API_CONN_POL_ACCEPT; } +/* + * Plastic surgery... we want to give up the current connection + */ +static int move_to_msc(struct gsm_subscriber_connection *_conn, + struct msgb *msg, struct osmo_msc_data *msc) +{ + struct osmo_bsc_sccp_con *old_con = _conn->sccp_con; + + /* + * 1. Give up the old connection. + * This happens by sending a clear request to the MSC, + * it should end with the MSC releasing the connection. + */ + old_con->conn = NULL; + bsc_clear_request(_conn, 0); + + /* + * 2. Attempt to create a new connection to the local + * MSC. If it fails the caller will need to handle this + * properly. + */ + _conn->sccp_con = NULL; + if (complete_layer3(_conn, msg, msc) != BSC_API_CONN_POL_ACCEPT) { + gsm0808_clear(_conn); + subscr_con_free(_conn); + return 1; + } + + return 2; +} + +static int handle_cc_setup(struct gsm_subscriber_connection *conn, + struct msgb *msg) +{ + struct gsm48_hdr *gh = msgb_l3(msg); + uint8_t pdisc = gh->proto_discr & 0x0f; + uint8_t mtype = gh->msg_type & 0xbf; + + struct osmo_msc_data *msc; + struct gsm_mncc_number called; + struct tlv_parsed tp; + unsigned payload_len; + + char _dest_nr[35]; + + /* + * Do we have a setup message here? if not return fast. + */ + if (pdisc != GSM48_PDISC_CC || mtype != GSM48_MT_CC_SETUP) + return 0; + + payload_len = msgb_l3len(msg) - sizeof(*gh); + + tlv_parse(&tp, &gsm48_att_tlvdef, gh->data, payload_len, 0, 0); + if (!TLVP_PRESENT(&tp, GSM48_IE_CALLED_BCD)) { + LOGP(DMSC, LOGL_ERROR, "Called BCD not present in setup.\n"); + return -1; + } + + memset(&called, 0, sizeof(called)); + gsm48_decode_called(&called, + TLVP_VAL(&tp, GSM48_IE_CALLED_BCD) - 1); + + if (called.plan != 1) + return 0; + + if (called.type == 1) { + _dest_nr[0] = _dest_nr[1] = '0'; + memcpy(_dest_nr + 2, called.number, sizeof(called.number)); + } else + memcpy(_dest_nr, called.number, sizeof(called.number)); + + /* + * Check if the connection should be moved... + */ + llist_for_each_entry(msc, &conn->bts->network->bsc_data->mscs, entry) { + if (msc->type != MSC_CON_TYPE_LOCAL) + continue; + if (!msc->local_pref) + continue; + if (regexec(&msc->local_pref_reg, _dest_nr, 0, NULL, 0) != 0) + continue; + + return move_to_msc(conn, msg, msc); + } + + return 0; +} + + static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, struct msgb *msg) { struct msgb *resp; @@ -137,7 +238,16 @@ static void bsc_dtap(struct gsm_subscriber_connection *conn, uint8_t link_id, st LOGP(DMSC, LOGL_INFO, "Tx MSC DTAP LINK_ID=0x%02x\n", link_id); + /* + * We might want to move this connection to a new MSC. Ask someone + * to handle it. If it was handled we will return. + */ + if (handle_cc_setup(conn, msg) > 1) + return; + bsc_scan_bts_msg(conn, msg); + + resp = gsm0808_create_dtap(msg, link_id); queue_msg_or_return(resp); } -- cgit v1.2.3