From e005619dc6cbfcbd260cab6b2535d10eb0e75c6d Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 19 Jun 2016 18:06:02 +0200 Subject: 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 --- openbsc/include/openbsc/gsm_data.h | 5 +++++ openbsc/include/openbsc/osmo_msc.h | 3 ++- openbsc/src/libmsc/gsm_04_08.c | 16 +++++++++------ openbsc/src/libmsc/gsm_04_11.c | 5 +++-- openbsc/src/libmsc/osmo_msc.c | 41 +++++++++++++++++++++++++++++++++----- openbsc/src/libmsc/silent_call.c | 3 ++- openbsc/src/libmsc/transaction.c | 2 +- openbsc/src/libmsc/ussd.c | 9 +++++---- 8 files changed, 64 insertions(+), 20 deletions(-) (limited to 'openbsc') 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 #include #include +#include #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; } -- cgit v1.2.3