aboutsummaryrefslogtreecommitdiffstats
path: root/src/osmo-bsc/osmo_bsc_sigtran.c
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2018-01-28 02:45:46 +0100
committerHarald Welte <laforge@gnumonks.org>2018-02-19 08:20:35 +0000
commit519c7e1d428bfba728a76885c9c5394185a6497d (patch)
treefb802b82931eba0351c29cdeea8cf5054f4180a8 /src/osmo-bsc/osmo_bsc_sigtran.c
parentc1db52f1326bd136862ff4a789fe1be27556658f (diff)
Structural reform: Get rid of osmo_bsc_sccp_con
There was always a 1:1 correspondence between gsm_subscriber_connection and osmo_bsc_sccp_con, so there's really no point in having two separate dynamically allocated data structures with pointers back and forth and another linked list around. Let's merge osmo_bsc_sccp_con into gsm_subscriber_connection for simplicity. The resulting code might not be elegant in places, but I've tried to do only the most simple changes in this patch, while further simplifications can be done in later subsequent patches. As a side-effect, this patch also fixes lchan clearing if the MSC (or the local SCCP provider) hard-disconnects the SCCP connection. Change-Id: Idd2b733477ee90d24dec369755a00f1c39c93f39
Diffstat (limited to 'src/osmo-bsc/osmo_bsc_sigtran.c')
-rw-r--r--src/osmo-bsc/osmo_bsc_sigtran.c144
1 files changed, 58 insertions, 86 deletions
diff --git a/src/osmo-bsc/osmo_bsc_sigtran.c b/src/osmo-bsc/osmo_bsc_sigtran.c
index 5b065105f..0ffc14687 100644
--- a/src/osmo-bsc/osmo_bsc_sigtran.c
+++ b/src/osmo-bsc/osmo_bsc_sigtran.c
@@ -38,28 +38,26 @@
* (a copy of the pointer location submitted with osmo_bsc_sigtran_init() */
static struct llist_head *msc_list;
+extern struct gsm_network *bsc_gsmnet;
+
#define RESET_INTERVAL 1 /* sek */
#define SCCP_MSG_MAXSIZE 1024
#define CS7_POINTCODE_DEFAULT_OFFSET 2
-/* Internal list with connections we currently maintain. This
- * list is of type struct osmo_bsc_sccp_con */
-static LLIST_HEAD(active_connections);
-
/* The SCCP stack will not assign connection IDs to us automatically, we
* will do this ourselves using a counter variable, that counts one up
* for every new connection */
static uint32_t conn_id_counter;
/* Helper function to Check if the given connection id is already assigned */
-static struct osmo_bsc_sccp_con *get_bsc_conn_by_conn_id(int conn_id)
+static struct gsm_subscriber_connection *get_bsc_conn_by_conn_id(int conn_id)
{
conn_id &= 0xFFFFFF;
- struct osmo_bsc_sccp_con *bsc_con;
+ struct gsm_subscriber_connection *conn;
- llist_for_each_entry(bsc_con, &active_connections, entry) {
- if (bsc_con->conn_id == conn_id)
- return bsc_con;
+ llist_for_each_entry(conn, &bsc_gsmnet->subscr_conns, entry) {
+ if (conn->sccp.conn_id == conn_id)
+ return conn;
}
return NULL;
@@ -131,12 +129,12 @@ static struct bsc_msc_data *get_msc_by_addr(const struct osmo_sccp_addr *msc_add
/* Send data to MSC, use the connection id which MSC it is */
static int handle_data_from_msc(int conn_id, struct msgb *msg)
{
- struct osmo_bsc_sccp_con *bsc_con = get_bsc_conn_by_conn_id(conn_id);
+ struct gsm_subscriber_connection *conn = get_bsc_conn_by_conn_id(conn_id);
int rc = -EINVAL;
- if (bsc_con) {
+ if (conn) {
msg->l3h = msgb_l2(msg);
- rc = bsc_handle_dt(bsc_con, msg, msgb_l2len(msg));
+ rc = bsc_handle_dt(conn, msg, msgb_l2len(msg));
} else
LOGP(DMSC, LOGL_NOTICE, "incoming data from unknown connection id: %i\n", conn_id);
@@ -168,7 +166,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
{
struct osmo_scu_prim *scu_prim = (struct osmo_scu_prim *)oph;
struct osmo_sccp_user *scu = _scu;
- struct osmo_bsc_sccp_con *bsc_con;
+ struct gsm_subscriber_connection *conn;
int rc = 0;
switch (OSMO_PRIM_HDR(&scu_prim->oph)) {
@@ -187,6 +185,9 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
case OSMO_PRIM(OSMO_SCU_PRIM_N_CONNECT, PRIM_OP_CONFIRM):
/* Handle outbound connection confirmation */
+ conn = get_bsc_conn_by_conn_id(scu_prim->u.connect.conn_id);
+ if (conn)
+ conn->sccp.state = SUBSCR_SCCP_ST_CONNECTED;
if (msgb_l2len(oph->msg) > 0) {
DEBUGP(DMSC, "N-CONNECT.cnf(%u, %s)\n", scu_prim->u.connect.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
@@ -201,32 +202,28 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)));
/* Incoming data is a sign of a vital connection */
- bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
- if (bsc_con)
- a_reset_conn_success(bsc_con->msc->a.reset);
+ conn = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
+ if (conn)
+ a_reset_conn_success(conn->sccp.msc->a.reset);
rc = handle_data_from_msc(scu_prim->u.data.conn_id, oph->msg);
break;
case OSMO_PRIM(OSMO_SCU_PRIM_N_DISCONNECT, PRIM_OP_INDICATION):
/* indication of disconnect */
+ conn = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
+ if (conn)
+ conn->sccp.state = SUBSCR_SCCP_ST_NONE;
if (msgb_l2len(oph->msg) > 0) {
DEBUGP(DMSC, "N-DISCONNECT.ind(%u, %s, cause=%i)\n", scu_prim->u.disconnect.conn_id,
osmo_hexdump(msgb_l2(oph->msg), msgb_l2len(oph->msg)), scu_prim->u.disconnect.cause);
handle_data_from_msc(scu_prim->u.disconnect.conn_id, oph->msg);
- } else
+ } else {
DEBUGP(DRANAP, "N-DISCONNECT.ind(%u, cause=%i)\n", scu_prim->u.disconnect.conn_id,
scu_prim->u.disconnect.cause);
-
- bsc_con = get_bsc_conn_by_conn_id(scu_prim->u.disconnect.conn_id);
- if (bsc_con) {
- /* We might have a connectivity problem. Maybe we need to go
- * through the reset procedure again? */
- if (scu_prim->u.disconnect.cause == 0)
- a_reset_conn_fail(bsc_con->msc->a.reset);
-
- rc = osmo_bsc_sigtran_del_conn(bsc_con);
}
+ if (conn)
+ rc = osmo_bsc_sigtran_del_conn(conn);
break;
default:
@@ -244,9 +241,7 @@ static int sccp_sap_up(struct osmo_prim_hdr *oph, void *_scu)
enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, struct bsc_msc_data *msc)
{
struct osmo_ss7_instance *ss7;
- struct osmo_bsc_sccp_con *bsc_con;
struct gsm_bts *bts = conn_get_bts(conn);
- int conn_id;
OSMO_ASSERT(conn);
OSMO_ASSERT(msc);
@@ -266,30 +261,13 @@ enum bsc_con osmo_bsc_sigtran_new_conn(struct gsm_subscriber_connection *conn, s
return BSC_CON_REJECT_RF_GRACE;
}
- bsc_con = talloc_zero(bts, struct osmo_bsc_sccp_con);
- if (!bsc_con) {
- LOGP(DMSC, LOGL_ERROR, "Failed to allocate new SIGTRAN connection.\n");
- return BSC_CON_NO_MEM;
- }
-
- bsc_con->msc = msc;
- bsc_con->conn = conn;
- llist_add_tail(&bsc_con->entry, &active_connections);
- conn->sccp_con = bsc_con;
-
- /* Pick a free connection id */
- conn_id = pick_free_conn_id(msc);
- if (conn_id < 0)
- return BSC_CON_REJECT_NO_LINK;
- bsc_con->conn_id = conn_id;
-
- LOGP(DMSC, LOGL_NOTICE, "Allocated new connection id: %i\n", conn_id);
+ conn->sccp.msc = msc;
return BSC_CON_SUCCESS;
}
/* Open a new connection oriented sigtran connection */
-int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb *msg)
+int osmo_bsc_sigtran_open_conn(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
struct osmo_ss7_instance *ss7;
struct bsc_msc_data *msc;
@@ -298,16 +276,22 @@ int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb
OSMO_ASSERT(conn);
OSMO_ASSERT(msg);
- OSMO_ASSERT(conn->msc);
+ OSMO_ASSERT(conn->sccp.msc);
+ OSMO_ASSERT(conn->sccp.conn_id == -1);
- msc = conn->msc;
+ msc = conn->sccp.msc;
if (a_reset_conn_ready(msc->a.reset) == false) {
LOGP(DMSC, LOGL_ERROR, "MSC is not connected. Dropping.\n");
return -EINVAL;
}
- conn_id = conn->conn_id;
+ conn->sccp.conn_id = conn_id = pick_free_conn_id(msc);
+ if (conn->sccp.conn_id < 0) {
+ LOGP(DMSC, LOGL_ERROR, "Unable to allocate SCCP Connection ID\n");
+ return -1;
+ }
+ LOGP(DMSC, LOGL_DEBUG, "Allocated new connection id: %d\n", conn->sccp.conn_id);
ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
OSMO_ASSERT(ss7);
LOGP(DMSC, LOGL_NOTICE, "Opening new SIGTRAN connection (id=%i) to MSC: %s\n", conn_id,
@@ -315,12 +299,14 @@ int osmo_bsc_sigtran_open_conn(const struct osmo_bsc_sccp_con *conn, struct msgb
rc = osmo_sccp_tx_conn_req_msg(msc->a.sccp_user, conn_id, &msc->a.bsc_addr,
&msc->a.msc_addr, msg);
+ if (rc >= 0)
+ conn->sccp.state = SUBSCR_SCCP_ST_WAIT_CONN_CONF;
return rc;
}
/* Send data to MSC */
-int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg)
+int osmo_bsc_sigtran_send(struct gsm_subscriber_connection *conn, struct msgb *msg)
{
struct osmo_ss7_instance *ss7;
int conn_id;
@@ -329,9 +315,9 @@ int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg
OSMO_ASSERT(conn);
OSMO_ASSERT(msg);
- OSMO_ASSERT(conn->msc);
+ OSMO_ASSERT(conn->sccp.msc);
- msc = conn->msc;
+ msc = conn->sccp.msc;
/* Log the type of the message we are sending. This is just
* informative, do not stop if detecting the type fails */
@@ -354,7 +340,7 @@ int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg
return -EINVAL;
}
- conn_id = conn->conn_id;
+ conn_id = conn->sccp.conn_id;
ss7 = osmo_ss7_instance_find(msc->a.cs7_instance);
OSMO_ASSERT(ss7);
@@ -369,80 +355,66 @@ int osmo_bsc_sigtran_send(const struct osmo_bsc_sccp_con *conn, struct msgb *msg
/* Delete a connection from the list with open connections
* (called by osmo_bsc_api.c on failing open connections and
* locally, when a connection is closed by the MSC */
-int osmo_bsc_sigtran_del_conn(struct osmo_bsc_sccp_con *conn)
+int osmo_bsc_sigtran_del_conn(struct gsm_subscriber_connection *conn)
{
if (!conn)
return 0;
- if (conn->conn) {
- LOGP(DMSC, LOGL_ERROR,
- "sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n",
- conn->conn_id);
- bsc_subscr_con_free(conn->conn);
- conn->conn = NULL;
+ LOGP(DMSC, LOGL_ERROR,
+ "sccp connection (id=%i) not cleared (gsm subscriber connection still active) -- forcefully clearing it now!\n", conn->sccp.conn_id);
- /* This bahaviour might be caused by a bad connection. Maybe we
- * will have to go through the reset procedure again */
- a_reset_conn_fail(conn->msc->a.reset);
- }
+ /* This bahaviour might be caused by a bad connection. Maybe we
+ * will have to go through the reset procedure again */
+ a_reset_conn_fail(conn->sccp.msc->a.reset);
/* Remove mgcp context if existant */
if (conn->user_plane.mgcp_ctx)
mgcp_free_ctx(conn->user_plane.mgcp_ctx);
- llist_del(&conn->entry);
- talloc_free(conn);
+ /* free the "conn" and make sure any pending lchans are also free'd */
+ bsc_subscr_con_free(conn);
return 0;
}
/* Send an USSD notification in case we loose the connection to the MSC */
-static void bsc_notify_msc_lost(const struct osmo_bsc_sccp_con *conn)
+static void bsc_notify_msc_lost(struct gsm_subscriber_connection *conn)
{
- struct gsm_subscriber_connection *subscr_conn;
-
/* Check if sccp conn is still present */
if (!conn)
return;
- subscr_conn = conn->conn;
-
- /* send USSD notification if string configured and conn->data is set */
- if (!subscr_conn)
- return;
/* check for config string */
- if (!conn->msc->ussd_msc_lost_txt)
+ if (!conn->sccp.msc->ussd_msc_lost_txt)
return;
- if (conn->msc->ussd_msc_lost_txt[0] == '\0')
+ if (conn->sccp.msc->ussd_msc_lost_txt[0] == '\0')
return;
/* send USSD notification */
- bsc_send_ussd_notify(subscr_conn, 1, subscr_conn->sccp_con->msc->ussd_msc_lost_txt);
- bsc_send_ussd_release_complete(subscr_conn);
+ bsc_send_ussd_notify(conn, 1, conn->sccp.msc->ussd_msc_lost_txt);
+ bsc_send_ussd_release_complete(conn);
}
/* Close all open sigtran connections and channels */
void osmo_bsc_sigtran_reset(const struct bsc_msc_data *msc)
{
- struct osmo_bsc_sccp_con *conn;
- struct osmo_bsc_sccp_con *conn_temp;
+ struct gsm_subscriber_connection *conn, *conn_temp;
OSMO_ASSERT(msc);
/* Close all open connections */
- llist_for_each_entry_safe(conn, conn_temp, &active_connections, entry) {
+ llist_for_each_entry_safe(conn, conn_temp, &bsc_gsmnet->subscr_conns, entry) {
/* We only may close connections which actually belong to this
* MSC. All other open connections are left untouched */
- if (conn->msc == msc) {
+ if (conn->sccp.msc == msc) {
/* Notify active connection users via USSD that the MSC is down */
bsc_notify_msc_lost(conn);
/* Take down all occopied RF channels */
- if (conn->conn)
- gsm0808_clear(conn->conn);
+ gsm0808_clear(conn);
/* Disconnect all Sigtran connections */
- osmo_sccp_tx_disconn(msc->a.sccp_user, conn->conn_id, &msc->a.bsc_addr, 0);
+ osmo_sccp_tx_disconn(msc->a.sccp_user, conn->sccp.conn_id, &msc->a.bsc_addr, 0);
/* Delete subscriber connection */
osmo_bsc_sigtran_del_conn(conn);