mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-mgw.git
synced 2025-11-01 20:43:47 +00:00
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:
committed by
Neels Hofmeyr
parent
7564acac24
commit
e005619dc6
@@ -115,8 +115,13 @@ enum ran_type {
|
|||||||
|
|
||||||
/* active radio connection of a mobile subscriber */
|
/* active radio connection of a mobile subscriber */
|
||||||
struct gsm_subscriber_connection {
|
struct gsm_subscriber_connection {
|
||||||
|
/* global linked list of subscriber_connections */
|
||||||
struct llist_head entry;
|
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 */
|
/* To whom we are allocated at the moment */
|
||||||
struct gsm_subscriber *subscr;
|
struct gsm_subscriber *subscr;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "bsc_api.h"
|
#include "bsc_api.h"
|
||||||
|
|
||||||
struct bsc_api *msc_bsc_api();
|
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
|
#endif
|
||||||
|
|||||||
@@ -176,13 +176,15 @@ void release_security_operation(struct gsm_subscriber_connection *conn)
|
|||||||
|
|
||||||
talloc_free(conn->sec_operation);
|
talloc_free(conn->sec_operation);
|
||||||
conn->sec_operation = NULL;
|
conn->sec_operation = NULL;
|
||||||
msc_release_connection(conn);
|
subscr_con_put(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void allocate_security_operation(struct gsm_subscriber_connection *conn)
|
void allocate_security_operation(struct gsm_subscriber_connection *conn)
|
||||||
{
|
{
|
||||||
conn->sec_operation = talloc_zero(tall_authciphop_ctx,
|
conn->sec_operation = talloc_zero(tall_authciphop_ctx,
|
||||||
struct gsm_security_operation);
|
struct gsm_security_operation);
|
||||||
|
if (conn->sec_operation)
|
||||||
|
subscr_con_get(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gsm48_secure_channel(struct gsm_subscriber_connection *conn, int key_seq,
|
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);
|
osmo_timer_del(&conn->loc_operation->updating_timer);
|
||||||
talloc_free(conn->loc_operation);
|
talloc_free(conn->loc_operation);
|
||||||
conn->loc_operation = NULL;
|
conn->loc_operation = NULL;
|
||||||
if (release)
|
subscr_con_put(conn);
|
||||||
msc_release_connection(conn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void allocate_loc_updating_req(struct gsm_subscriber_connection *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,
|
conn->loc_operation = talloc_zero(tall_locop_ctx,
|
||||||
struct gsm_loc_updating_operation);
|
struct gsm_loc_updating_operation);
|
||||||
|
if (conn->loc_operation)
|
||||||
|
subscr_con_get(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int finish_lu(struct gsm_subscriber_connection *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;
|
return 0;
|
||||||
}
|
}
|
||||||
/* Assign lchan */
|
/* Assign lchan */
|
||||||
trans->conn = conn;
|
trans->conn = subscr_con_get(conn);
|
||||||
subscr_put(subscr);
|
subscr_put(subscr);
|
||||||
} else {
|
} else {
|
||||||
/* update the subscriber we deal with */
|
/* 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;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
/* Assign transaction */
|
/* Assign transaction */
|
||||||
trans->conn = conn;
|
trans->conn = subscr_con_get(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find function for current state and message */
|
/* 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);
|
osmo_timer_del(&conn->anch_operation->timeout);
|
||||||
talloc_free(conn->anch_operation);
|
talloc_free(conn->anch_operation);
|
||||||
conn->anch_operation = NULL;
|
conn->anch_operation = NULL;
|
||||||
|
subscr_con_put(conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void anchor_timeout(void *_data)
|
static void anchor_timeout(void *_data)
|
||||||
@@ -3928,7 +3932,6 @@ static void anchor_timeout(void *_data)
|
|||||||
struct gsm_subscriber_connection *con = _data;
|
struct gsm_subscriber_connection *con = _data;
|
||||||
|
|
||||||
release_anchor(con);
|
release_anchor(con);
|
||||||
msc_release_connection(con);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int gsm0408_new_conn(struct gsm_subscriber_connection *conn)
|
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)
|
if (!conn->anch_operation)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
subscr_con_get(conn);
|
||||||
conn->anch_operation->timeout.data = conn;
|
conn->anch_operation->timeout.data = conn;
|
||||||
conn->anch_operation->timeout.cb = anchor_timeout;
|
conn->anch_operation->timeout.cb = anchor_timeout;
|
||||||
osmo_timer_schedule(&conn->anch_operation->timeout, 5, 0);
|
osmo_timer_schedule(&conn->anch_operation->timeout, 5, 0);
|
||||||
|
|||||||
@@ -56,6 +56,7 @@
|
|||||||
#include <openbsc/bsc_rll.h>
|
#include <openbsc/bsc_rll.h>
|
||||||
#include <openbsc/chan_alloc.h>
|
#include <openbsc/chan_alloc.h>
|
||||||
#include <openbsc/bsc_api.h>
|
#include <openbsc/bsc_api.h>
|
||||||
|
#include <openbsc/osmo_msc.h>
|
||||||
|
|
||||||
#ifdef BUILD_SMPP
|
#ifdef BUILD_SMPP
|
||||||
#include "smpp_smsc.h"
|
#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_smr_init(&trans->sms.smr_inst, 0, 1,
|
||||||
gsm411_rl_recv, gsm411_mn_send);
|
gsm411_rl_recv, gsm411_mn_send);
|
||||||
|
|
||||||
trans->conn = conn;
|
trans->conn = subscr_con_get(conn);
|
||||||
|
|
||||||
new_trans = 1;
|
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);
|
gsm411_rl_recv, gsm411_mn_send);
|
||||||
trans->sms.sms = sms;
|
trans->sms.sms = sms;
|
||||||
|
|
||||||
trans->conn = conn;
|
trans->conn = subscr_con_get(conn);
|
||||||
|
|
||||||
/* Hardcode SMSC Originating Address for now */
|
/* Hardcode SMSC Originating Address for now */
|
||||||
data = (uint8_t *)msgb_put(msg, 8);
|
data = (uint8_t *)msgb_put(msg, 8);
|
||||||
|
|||||||
@@ -144,22 +144,21 @@ struct bsc_api *msc_bsc_api() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* lchan release handling */
|
/* 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 */
|
/* skip when we are in release, e.g. due an error */
|
||||||
if (conn->in_release)
|
if (conn->in_release)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* skip releasing of silent calls as they have no transaction */
|
|
||||||
if (conn->silent_call)
|
if (conn->silent_call)
|
||||||
return;
|
LOGP(DMSC, LOGL_ERROR, "release_connection() but silent_call active?!?\n");
|
||||||
|
|
||||||
/* check if there is a pending operation */
|
/* check if there is a pending operation */
|
||||||
if (conn->loc_operation || conn->sec_operation || conn->anch_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))
|
if (trans_has_conn(conn))
|
||||||
return;
|
LOGP(DMSC, LOGL_ERROR, "release_conncetion() but transactions alive?!?\n");
|
||||||
|
|
||||||
/* no more connections, asking to release the channel */
|
/* no more connections, asking to release the channel */
|
||||||
|
|
||||||
@@ -175,3 +174,35 @@ void msc_release_connection(struct gsm_subscriber_connection *conn)
|
|||||||
gsm0808_clear(conn);
|
gsm0808_clear(conn);
|
||||||
msc_subscr_con_free(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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -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",
|
DEBUGPC(DLSMS, "success, using Timeslot %u on ARFCN %u\n",
|
||||||
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
|
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
|
||||||
conn->silent_call = 1;
|
conn->silent_call = 1;
|
||||||
|
subscr_con_get(conn);
|
||||||
/* increment lchan reference count */
|
/* increment lchan reference count */
|
||||||
osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
|
osmo_signal_dispatch(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
|
||||||
break;
|
break;
|
||||||
@@ -146,7 +147,7 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr)
|
|||||||
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
|
conn->lchan->ts->nr, conn->lchan->ts->trx->arfcn);
|
||||||
|
|
||||||
conn->silent_call = 0;
|
conn->silent_call = 0;
|
||||||
msc_release_connection(conn);
|
subscr_con_put(conn);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ void trans_free(struct gsm_trans *trans)
|
|||||||
llist_del(&trans->entry);
|
llist_del(&trans->entry);
|
||||||
|
|
||||||
if (trans->conn)
|
if (trans->conn)
|
||||||
msc_release_connection(trans->conn);
|
subscr_con_put(trans->conn);
|
||||||
|
|
||||||
trans->conn = NULL;
|
trans->conn = NULL;
|
||||||
talloc_free(trans);
|
talloc_free(trans);
|
||||||
|
|||||||
@@ -48,13 +48,17 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
|
|||||||
struct ss_request req;
|
struct ss_request req;
|
||||||
struct gsm48_hdr *gh;
|
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));
|
memset(&req, 0, sizeof(req));
|
||||||
gh = msgb_l3(msg);
|
gh = msgb_l3(msg);
|
||||||
rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
|
rc = gsm0480_decode_ss_request(gh, msgb_l3len(msg), &req);
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
DEBUGP(DMM, "Unhandled SS\n");
|
DEBUGP(DMM, "Unhandled SS\n");
|
||||||
rc = gsm0480_send_ussd_reject(conn, msg, &req);
|
rc = gsm0480_send_ussd_reject(conn, msg, &req);
|
||||||
msc_release_connection(conn);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +67,6 @@ int handle_rcv_ussd(struct gsm_subscriber_connection *conn, struct msgb *msg)
|
|||||||
if (req.ss_code > 0) {
|
if (req.ss_code > 0) {
|
||||||
/* Assume interrogateSS or modification of it and reject */
|
/* Assume interrogateSS or modification of it and reject */
|
||||||
rc = gsm0480_send_ussd_reject(conn, msg, &req);
|
rc = gsm0480_send_ussd_reject(conn, msg, &req);
|
||||||
msc_release_connection(conn);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
/* Still assuming a Release-Complete and returning */
|
/* 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);
|
rc = gsm0480_send_ussd_reject(conn, msg, &req);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check if we can release it */
|
|
||||||
msc_release_connection(conn);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user