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
This commit is contained in:
Harald Welte
2016-06-19 18:06:02 +02:00
committed by Neels Hofmeyr
parent 7564acac24
commit e005619dc6
8 changed files with 64 additions and 20 deletions

View File

@@ -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;

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;
}