aboutsummaryrefslogtreecommitdiffstats
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>2013-01-07 15:47:32 +0100
commit83d2d38a3c348168873a9d977641ee4381b01fa3 (patch)
tree4aa7bbe9c3358db2462f0473d6d348aa2a3a40b8
parentea46b77f3ed5ab4fbf8bbfee27525f9ae83253fe (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.
-rw-r--r--openbsc/include/openbsc/osmo_msc_data.h7
-rw-r--r--openbsc/src/osmo-bsc/osmo_bsc_api.c116
2 files changed, 120 insertions, 3 deletions
diff --git a/openbsc/include/openbsc/osmo_msc_data.h b/openbsc/include/openbsc/osmo_msc_data.h
index 0bda66225..6eebcdd41 100644
--- a/openbsc/include/openbsc/osmo_msc_data.h
+++ b/openbsc/include/openbsc/osmo_msc_data.h
@@ -27,6 +27,8 @@
#include <osmocom/core/timer.h>
+#include <regex.h>
+
struct osmo_bsc_rf;
struct gsm_network;
@@ -49,6 +51,11 @@ struct osmo_msc_data {
int allow_emerg;
int type;
+ /* local call routing */
+ char *local_pref;
+ regex_t local_pref_reg;
+
+
/* Connection data */
char *bsc_token;
int ping_timeout;
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);
}