summaryrefslogtreecommitdiffstats
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>2011-08-25 23:17:46 +0200
commit7c3524922b872cd5461dc16b8fca6753a4bb35e6 (patch)
treef5e01945595a8f229aaf94f3e174d867dfc4f343
parent735c714a74c542318fde061ba5c9459b02f320c0 (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.c119
2 files changed, 122 insertions, 4 deletions
diff --git a/openbsc/include/openbsc/osmo_msc_data.h b/openbsc/include/openbsc/osmo_msc_data.h
index 0bda662..6eebcdd 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 067ebab..132dceb 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);
}