aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc/src
diff options
context:
space:
mode:
authorHolger Hans Peter Freyther <zecke@selfish.org>2011-06-09 17:37:04 +0200
committerHolger Hans Peter Freyther <zecke@selfish.org>2012-05-02 19:24:29 +0200
commit819d09e7e1ad6415dddf6f41cabd769d2ca46950 (patch)
tree77e2a394bd5fafb2948657ee94ac347d7cfa6718 /openbsc/src
parentd3d79fb9cdd7efacab5301ea27ec94352c68fb56 (diff)
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.
Diffstat (limited to 'openbsc/src')
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_api.c119
1 files changed, 115 insertions, 4 deletions
diff --git a/openbsc/src/osmo-bsc/osmo_bsc_api.c b/openbsc/src/osmo-bsc/osmo_bsc_api.c
index 067ebabf5..132dcebc9 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,14 +103,25 @@ 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;
+ bsc_scan_bts_msg(conn, msg);
+
network_code = get_network_code_for_msc(conn->sccp_con->msc);
country_code = get_country_code_for_msc(conn->sccp_con->msc);
- bsc_scan_bts_msg(conn, msg);
resp = gsm0808_create_layer3(msg, network_code, country_code,
conn->bts->location_area_code,
conn->bts->cell_identity);
@@ -130,6 +142,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 +239,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);
}