aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2016-06-19 18:06:02 +0200
committerNeels Hofmeyr <nhofmeyr@sysmocom.de>2017-03-15 15:06:09 +0100
commitc776f82ed7bcf183a17ce80e8c5e626462a37bf3 (patch)
tree6a587f82b3f6f89c98e43f939c28772dc0c6b67c
parente7bc9e0c73261760727c7e0992aee91d2ea58d12 (diff)
Introduce subscriber_connection ref-counting
This introduces a reference count for gsm_subscriber_connection. Every user of the connection needs to hold a reference until done. Once the reference count dorps to zero, the connection is cleared towards the BSC (which subsequently will clear any logical channels associated with it). Related: OS#1592 Change-Id: I8c05e6c81f246ff8b5bf91312f80410b1a85f15e
-rw-r--r--openbsc/include/openbsc/gsm_data.h5
-rw-r--r--openbsc/include/openbsc/osmo_msc.h3
-rw-r--r--openbsc/src/libmsc/gsm_04_08.c16
-rw-r--r--openbsc/src/libmsc/gsm_04_11.c5
-rw-r--r--openbsc/src/libmsc/osmo_msc.c41
-rw-r--r--openbsc/src/libmsc/silent_call.c3
-rw-r--r--openbsc/src/libmsc/transaction.c2
-rw-r--r--openbsc/src/libmsc/ussd.c9
8 files changed, 64 insertions, 20 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index e9ba173ce..5194b91f9 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -115,8 +115,13 @@ enum ran_type {
/* active radio connection of a mobile subscriber */
struct gsm_subscriber_connection {
+ /* global linked list of subscriber_connections */
struct llist_head entry;
+ /* usage count. If this drops to zero, we start the release
+ * towards A/Iu */
+ uint32_t use_count;
+
/* To whom we are allocated at the moment */
struct gsm_subscriber *subscr;
diff --git a/openbsc/include/openbsc/osmo_msc.h b/openbsc/include/openbsc/osmo_msc.h
index beb3f5e4c..8f57ce25f 100644
--- a/openbsc/include/openbsc/osmo_msc.h
+++ b/openbsc/include/openbsc/osmo_msc.h
@@ -6,6 +6,7 @@
#include "bsc_api.h"
struct bsc_api *msc_bsc_api();
-void msc_release_connection(struct gsm_subscriber_connection *conn);
+struct gsm_subscriber_connection *subscr_con_get(struct gsm_subscriber_connection *conn);
+void subscr_con_put(struct gsm_subscriber_connection *conn);
#endif
diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c
index 71ede0485..9e74b1e77 100644
--- a/openbsc/src/libmsc/gsm_04_08.c
+++ b/openbsc/src/libmsc/gsm_04_08.c
@@ -176,13 +176,15 @@ void release_security_operation(struct gsm_subscriber_connection *conn)
talloc_free(conn->sec_operation);
conn->sec_operation = NULL;
- msc_release_connection(conn);
+ subscr_con_put(conn);
}
void allocate_security_operation(struct gsm_subscriber_connection *conn)
{
conn->sec_operation = talloc_zero(tall_authciphop_ctx,
struct gsm_security_operation);
+ if (conn->sec_operation)
+ subscr_con_get(conn);
}
int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
@@ -306,8 +308,7 @@ static void release_loc_updating_req(struct gsm_subscriber_connection *conn, int
osmo_timer_del(&conn->loc_operation->updating_timer);
talloc_free(conn->loc_operation);
conn->loc_operation = NULL;
- if (release)
- msc_release_connection(conn);
+ subscr_con_put(conn);
}
static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn)
@@ -318,6 +319,8 @@ static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn)
conn->loc_operation = talloc_zero(tall_locop_ctx,
struct gsm_loc_updating_operation);
+ if (conn->loc_operation)
+ subscr_con_get(conn);
}
static int finish_lu(struct gsm_subscriber_connection *conn)
@@ -3743,7 +3746,7 @@ int mncc_tx_to_cc(struct gsm_network *net, int msg_type, void *arg)
return 0;
}
/* Assign lchan */
- trans->conn = conn;
+ trans->conn = subscr_con_get(conn);
subscr_put(subscr);
} else {
/* update the subscriber we deal with */
@@ -3892,7 +3895,7 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m
return -ENOMEM;
}
/* Assign transaction */
- trans->conn = conn;
+ trans->conn = subscr_con_get(conn);
}
/* find function for current state and message */
@@ -3921,6 +3924,7 @@ static void release_anchor(struct gsm_subscriber_connection *conn)
osmo_timer_del(&conn->anch_operation->timeout);
talloc_free(conn->anch_operation);
conn->anch_operation = NULL;
+ subscr_con_put(conn);
}
static void anchor_timeout(void *_data)
@@ -3928,7 +3932,6 @@ static void anchor_timeout(void *_data)
struct gsm_subscriber_connection *con = _data;
release_anchor(con);
- msc_release_connection(con);
}
int gsm0408_new_conn(struct gsm_subscriber_connection *conn)
@@ -3937,6 +3940,7 @@ int gsm0408_new_conn(struct gsm_subscriber_connection *conn)
if (!conn->anch_operation)
return -1;
+ subscr_con_get(conn);
conn->anch_operation->timeout.data = conn;
conn->anch_operation->timeout.cb = anchor_timeout;
osmo_timer_schedule(&conn->anch_operation->timeout, 5, 0);
diff --git a/openbsc/src/libmsc/gsm_04_11.c b/openbsc/src/libmsc/gsm_04_11.c
index 6164a0887..e395cd428 100644
--- a/openbsc/src/libmsc/gsm_04_11.c
+++ b/openbsc/src/libmsc/gsm_04_11.c
@@ -56,6 +56,7 @@
#include <openbsc/bsc_rll.h>
#include <openbsc/chan_alloc.h>
#include <openbsc/bsc_api.h>
+#include <openbsc/osmo_msc.h>
#ifdef BUILD_SMPP
#include "smpp_smsc.h"
@@ -831,7 +832,7 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
gsm411_smr_init(&trans->sms.smr_inst, 0, 1,
gsm411_rl_recv, gsm411_mn_send);
- trans->conn = conn;
+ trans->conn = subscr_con_get(conn);
new_trans = 1;
}
@@ -910,7 +911,7 @@ int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sms *sms)
gsm411_rl_recv, gsm411_mn_send);
trans->sms.sms = sms;
- trans->conn = conn;
+ trans->conn = subscr_con_get(conn);
/* Hardcode SMSC Originating Address for now */
data = (uint8_t *)msgb_put(msg, 8);
diff --git a/openbsc/src/libmsc/osmo_msc.c b/openbsc/src/libmsc/osmo_msc.c
index 2389980d3..92bc84650 100644
--- a/openbsc/src/libmsc/osmo_msc.c
+++ b/openbsc/src/libmsc/osmo_msc.c
@@ -144,22 +144,21 @@ struct bsc_api *msc_bsc_api() {
}
/* lchan release handling */
-void msc_release_connection(struct gsm_subscriber_connection *conn)
+static void msc_release_connection(struct gsm_subscriber_connection *conn)
{
/* skip when we are in release, e.g. due an error */
if (conn->in_release)
return;
- /* skip releasing of silent calls as they have no transaction */
if (conn->silent_call)
- return;
+ LOGP(DMSC, LOGL_ERROR, "release_connection() but silent_call active?!?\n");
/* check if there is a pending operation */
if (conn->loc_operation || conn->sec_operation || conn->anch_operation)
- return;
+ LOGP(DMSC, LOGL_ERROR, "relase_connection() but {loc,sec,anch}_operation alive?!?\n");
if (trans_has_conn(conn))
- return;
+ LOGP(DMSC, LOGL_ERROR, "release_conncetion() but transactions alive?!?\n");
/* no more connections, asking to release the channel */
@@ -175,3 +174,35 @@ void msc_release_connection(struct gsm_subscriber_connection *conn)
gsm0808_clear(conn);
msc_subscr_con_free(conn);
}
+
+/* increment the ref-count. Needs to be called by every user */
+struct gsm_subscriber_connection *subscr_con_get(struct gsm_subscriber_connection *conn)
+{
+ OSMO_ASSERT(conn);
+
+ if (conn->in_release)
+ return NULL;
+
+ conn->use_count++;
+ DEBUGP(DMSC, "increased subscr_con use_count to %u\n", conn->use_count);
+
+ return conn;
+}
+
+/* decrement the ref-count. Once it reaches zero, we release */
+void subscr_con_put(struct gsm_subscriber_connection *conn)
+{
+ OSMO_ASSERT(conn);
+
+ if (conn->use_count == 0) {
+ LOGP(DMSC, LOGL_ERROR, "tryin to decrement conn use count, but is alrady 0\n");
+ return;
+ }
+
+ conn->use_count--;
+ DEBUGP(DMSC, "decreased subscr_con use_count to %u\n", conn->use_count);
+
+ if (conn->use_count == 0) {
+ msc_release_connection(conn);
+ }
+}
diff --git a/openbsc/src/libmsc/silent_call.c b/openbsc/src/libmsc/silent_call.c
index 590d01bbf..2e9fd5123 100644
--- a/openbsc/src/libmsc/silent_call.c
+++ b/openbsc/src/libmsc/silent_call.c
@@ -55,6 +55,7 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
DEBUGPC(DLSMS, "success, using Timeslot %u on ARFCN %u\n",
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
conn->silent_call = 1;
+ subscr_con_get(conn);
/* increment lchan reference count */
osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
break;
@@ -146,7 +147,7 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr)
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
conn->silent_call = 0;
- msc_release_connection(conn);
+ subscr_con_put(conn);
return 0;
}
diff --git a/openbsc/src/libmsc/transaction.c b/openbsc/src/libmsc/transaction.c
index dba4bed17..4d0cdb1c3 100644
--- a/openbsc/src/libmsc/transaction.c
+++ b/openbsc/src/libmsc/transaction.c
@@ -111,7 +111,7 @@ void trans_free(struct gsm_trans *trans)
llist_del(&trans->entry);
if (trans->conn)
- msc_release_connection(trans->conn);
+ subscr_con_put(trans->conn);
trans->conn = NULL;
talloc_free(trans);
diff --git a/openbsc/src/libmsc/ussd.c b/openbsc/src/libmsc/ussd.c
index f12c1f281..a27b16376 100644
--- a/openbsc/src/libmsc/ussd.c
+++ b/openbsc/src/libmsc/ussd.c
@@ -48,13 +48,17 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
struct ss_request req;
struct gsm48_hdr *gh;
+ /* TODO: Use subscriber_connection ref-counting if we ever want
+ * to keep the connection alive due ot ongoing USSD exchange.
+ * As we answer everytying synchronously so far, there's no need
+ * yet */
+
memset(&req, 0, sizeof(req));
gh = msgb_l3(msg);
rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
if (!rc) {
DEBUGP(DMM, "Unhandled SS\n");
rc = gsm0480_send_ussd_reject(conn, msg, &req);
- msc_release_connection(conn);
return rc;
}
@@ -63,7 +67,6 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
if (req.ss_code > 0) {
/* Assume interrogateSS or modification of it and reject */
rc = gsm0480_send_ussd_reject(conn, msg, &req);
- msc_release_connection(conn);
return rc;
}
/* Still assuming a Release-Complete and returning */
@@ -78,8 +81,6 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
rc = gsm0480_send_ussd_reject(conn, msg, &req);
}
- /* check if we can release it */
- msc_release_connection(conn);
return rc;
}