bsc_msc: Remove use_count from the subscriber connection
A channel will be released in case of * Errors via the clear_request callback... * no more transactions and operations are going on. This means that if we do something without a transaction the channel might be closed down right away. The bug fix will be to create a transaction/operation.
This commit is contained in:
parent
2412a07965
commit
4049455d74
|
@ -31,6 +31,8 @@ GSM 04.08 3.4.13: RR connection release procedure
|
|||
|
||||
== Implementation in OpenBSC ==
|
||||
|
||||
THIS IS OUTDATED and will be updated...
|
||||
|
||||
chan_alloc.c:lchan_auto_release()
|
||||
* checks if use count still > 0 (abort)
|
||||
* calls gsm48_send_rr_release()
|
||||
|
|
|
@ -28,5 +28,6 @@ int bsc_api_init(struct gsm_network *network, struct bsc_api *api);
|
|||
int gsm0808_submit_dtap(struct gsm_subscriber_connection *conn, struct msgb *msg, int link_id);
|
||||
int gsm0808_page(struct gsm_bts *bts, unsigned int page_group,
|
||||
unsigned int mi_len, uint8_t *mi, int chan_type);
|
||||
int gsm0808_clear(struct gsm_subscriber_connection *conn);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -46,8 +46,8 @@ struct gsm_lchan *lchan_alloc(struct gsm_bts *bts, enum gsm_chan_t type);
|
|||
void lchan_free(struct gsm_lchan *lchan);
|
||||
void lchan_reset(struct gsm_lchan *lchan);
|
||||
|
||||
/* Consider releasing the channel */
|
||||
int lchan_auto_release(struct gsm_lchan *lchan);
|
||||
/* Release the given lchan */
|
||||
int lchan_release(struct gsm_lchan *lchan, int sach_deact, int reason);
|
||||
|
||||
struct load_counter {
|
||||
unsigned int total;
|
||||
|
|
|
@ -120,26 +120,6 @@ typedef int gsm_cbfn(unsigned int hooknum,
|
|||
struct msgb *msg,
|
||||
void *data, void *param);
|
||||
|
||||
/*
|
||||
* Use the channel. As side effect the lchannel recycle timer
|
||||
* will be started.
|
||||
*/
|
||||
#define LCHAN_RELEASE_TIMEOUT 20, 0
|
||||
#define use_subscr_con(con) \
|
||||
do { (con)->use_count++; \
|
||||
DEBUGP(DREF, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) increases usage to: %d\n", \
|
||||
(con)->lchan->ts->trx->bts->nr, (con)->lchan->ts->trx->nr, (con)->lchan->ts->nr, \
|
||||
(con)->lchan->nr, (con)->use_count); \
|
||||
bsc_schedule_timer(&(con)->release_timer, LCHAN_RELEASE_TIMEOUT); } while(0);
|
||||
|
||||
#define put_subscr_con(con) \
|
||||
do { (con)->use_count--; \
|
||||
DEBUGP(DREF, "lchan (bts=%d,trx=%d,ts=%d,ch=%d) decreases usage to: %d\n", \
|
||||
(con)->lchan->ts->trx->bts->nr, (con)->lchan->ts->trx->nr, (con)->lchan->ts->nr, \
|
||||
(con)->lchan->nr, (con)->use_count); \
|
||||
} while(0);
|
||||
|
||||
|
||||
/* Real authentication information containing Ki */
|
||||
enum gsm_auth_algo {
|
||||
AUTH_ALGO_NONE,
|
||||
|
@ -239,22 +219,17 @@ struct gsm_subscriber_connection {
|
|||
/* To whom we are allocated at the moment */
|
||||
struct gsm_subscriber *subscr;
|
||||
|
||||
/* Timer started to release the channel */
|
||||
struct timer_list release_timer;
|
||||
|
||||
/*
|
||||
* Operations that have a state and might be pending
|
||||
*/
|
||||
struct gsm_loc_updating_operation *loc_operation;
|
||||
struct gsm_security_operation *sec_operation;
|
||||
|
||||
/* use count. how many users use this channel */
|
||||
unsigned int use_count;
|
||||
|
||||
/* Are we part of a special "silent" call */
|
||||
int silent_call;
|
||||
|
||||
/* back pointers */
|
||||
int in_release;
|
||||
struct gsm_lchan *lchan;
|
||||
struct gsm_bts *bts;
|
||||
};
|
||||
|
|
|
@ -6,5 +6,6 @@
|
|||
#include "bsc_api.h"
|
||||
|
||||
struct bsc_api *msc_bsc_api();
|
||||
void msc_release_connection(struct gsm_subscriber_connection *conn);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -104,13 +104,20 @@ int gsm0408_rcvmsg(struct msgb *msg, uint8_t link_id)
|
|||
|
||||
if (rc != BSC_API_CONN_POL_ACCEPT) {
|
||||
subscr_con_free(lchan->conn);
|
||||
lchan_auto_release(lchan);
|
||||
lchan_release(lchan, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int gsm0808_clear(struct gsm_subscriber_connection* conn)
|
||||
{
|
||||
subscr_con_free(conn);
|
||||
lchan_release(conn->lchan, 1, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id)
|
||||
{
|
||||
struct bsc_api *api;
|
||||
|
@ -155,12 +162,12 @@ static int bsc_handle_lchan_signal(unsigned int subsys, unsigned int signal,
|
|||
if (!lchan || !lchan->conn)
|
||||
return 0;
|
||||
|
||||
|
||||
bsc = lchan->ts->trx->bts->network->bsc_api;
|
||||
if (!bsc || !bsc->clear_request)
|
||||
return 0;
|
||||
|
||||
bsc->clear_request(lchan->conn, 0);
|
||||
subscr_con_free(lchan->conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -700,8 +700,8 @@ static void lchan_dump_full_vty(struct vty *vty, struct gsm_lchan *lchan)
|
|||
lchan->nr, lchan->ts->nr, lchan->ts->trx->nr,
|
||||
lchan->ts->trx->bts->nr, gsm_lchant_name(lchan->type),
|
||||
VTY_NEWLINE);
|
||||
vty_out(vty, " Use Count: %u, State: %s%s",
|
||||
lchan->conn ? lchan->conn->use_count : -23,
|
||||
vty_out(vty, " Connection: %u, State: %s%s",
|
||||
lchan->conn ? 1: 0,
|
||||
gsm_lchans_name(lchan->state), VTY_NEWLINE);
|
||||
vty_out(vty, " BS Power: %u dBm, MS Power: %u dBm%s",
|
||||
lchan->ts->trx->nominal_power - lchan->ts->trx->max_power_red
|
||||
|
|
|
@ -35,8 +35,6 @@
|
|||
|
||||
#include <osmocore/talloc.h>
|
||||
|
||||
static void auto_release_channel(void *_lchan);
|
||||
|
||||
static int ts_is_usable(struct gsm_bts_trx_ts *ts)
|
||||
{
|
||||
/* FIXME: How does this behave for BS-11 ? */
|
||||
|
@ -296,18 +294,8 @@ void lchan_free(struct gsm_lchan *lchan)
|
|||
|
||||
|
||||
if (lchan->conn) {
|
||||
if (lchan->conn->subscr) {
|
||||
subscr_put(lchan->conn->subscr);
|
||||
lchan->conn->subscr = NULL;
|
||||
}
|
||||
|
||||
/* We might kill an active channel... */
|
||||
if (lchan->conn->use_count != 0) {
|
||||
dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
|
||||
lchan->conn->use_count = 0;
|
||||
}
|
||||
/* stop the timer */
|
||||
bsc_del_timer(&lchan->conn->release_timer);
|
||||
dispatch_signal(SS_LCHAN, S_LCHAN_UNEXPECTED_RELEASE, lchan);
|
||||
}
|
||||
|
||||
|
||||
|
@ -334,6 +322,7 @@ void lchan_free(struct gsm_lchan *lchan)
|
|||
dispatch_signal(SS_CHALLOC, S_CHALLOC_FREED, &sig);
|
||||
|
||||
if (lchan->conn) {
|
||||
LOGP(DRLL, LOGL_ERROR, "the subscriber connection should be gone.\n");
|
||||
subscr_con_free(lchan->conn);
|
||||
lchan->conn = NULL;
|
||||
}
|
||||
|
@ -364,40 +353,19 @@ void lchan_reset(struct gsm_lchan *lchan)
|
|||
|
||||
|
||||
/* Consider releasing the channel now */
|
||||
int lchan_auto_release(struct gsm_lchan *lchan)
|
||||
int lchan_release(struct gsm_lchan *lchan, int sach_deact, int reason)
|
||||
{
|
||||
if (!lchan->conn)
|
||||
return 0;
|
||||
|
||||
if (lchan->conn->use_count > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assume we have GSM04.08 running and send a release */
|
||||
if (lchan->conn->subscr) {
|
||||
if (sach_deact) {
|
||||
gsm48_send_rr_release(lchan);
|
||||
}
|
||||
|
||||
/* spoofed? message */
|
||||
if (lchan->conn->use_count < 0)
|
||||
LOGP(DRLL, LOGL_ERROR, "Channel count is negative: %d\n",
|
||||
lchan->conn->use_count);
|
||||
|
||||
DEBUGP(DRLL, "%s Recycling Channel\n", gsm_lchan_name(lchan));
|
||||
rsl_lchan_set_state(lchan, LCHAN_S_REL_REQ);
|
||||
rsl_release_request(lchan, 0, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Auto release the channel when the use count is zero */
|
||||
static void auto_release_channel(void *_lchan)
|
||||
{
|
||||
struct gsm_lchan *lchan = _lchan;
|
||||
|
||||
if (!lchan_auto_release(lchan))
|
||||
bsc_schedule_timer(&lchan->conn->release_timer, LCHAN_RELEASE_TIMEOUT);
|
||||
}
|
||||
|
||||
static struct gsm_lchan* lchan_find(struct gsm_bts *bts, struct gsm_subscriber *subscr) {
|
||||
struct gsm_bts_trx *trx;
|
||||
int ts_no, lchan_no;
|
||||
|
@ -490,10 +458,6 @@ struct gsm_subscriber_connection *subscr_con_allocate(struct gsm_lchan *lchan)
|
|||
/* Configure the time and start it so it will be closed */
|
||||
conn->lchan = lchan;
|
||||
conn->bts = lchan->ts->trx->bts;
|
||||
conn->release_timer.cb = auto_release_channel;
|
||||
conn->release_timer.data = lchan;
|
||||
bsc_schedule_timer(&conn->release_timer, LCHAN_RELEASE_TIMEOUT);
|
||||
|
||||
lchan->conn = conn;
|
||||
return conn;
|
||||
}
|
||||
|
@ -507,6 +471,13 @@ void subscr_con_free(struct gsm_subscriber_connection *conn)
|
|||
if (!conn)
|
||||
return;
|
||||
|
||||
|
||||
if (conn->subscr) {
|
||||
subscr_put(conn->subscr);
|
||||
conn->subscr = NULL;
|
||||
}
|
||||
|
||||
|
||||
lchan = conn->lchan;
|
||||
talloc_free(conn);
|
||||
|
||||
|
|
|
@ -109,13 +109,11 @@ static void release_security_operation(struct gsm_subscriber_connection *conn)
|
|||
|
||||
talloc_free(conn->sec_operation);
|
||||
conn->sec_operation = NULL;
|
||||
put_subscr_con(conn);
|
||||
msc_release_connection(conn);
|
||||
}
|
||||
|
||||
static void allocate_security_operation(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
use_subscr_con(conn)
|
||||
|
||||
conn->sec_operation = talloc_zero(tall_authciphop_ctx,
|
||||
struct gsm_security_operation);
|
||||
}
|
||||
|
@ -222,12 +220,13 @@ static void release_loc_updating_req(struct gsm_subscriber_connection *conn)
|
|||
bsc_del_timer(&conn->loc_operation->updating_timer);
|
||||
talloc_free(conn->loc_operation);
|
||||
conn->loc_operation = 0;
|
||||
put_subscr_con(conn);
|
||||
msc_release_connection(conn);
|
||||
}
|
||||
|
||||
static void allocate_loc_updating_req(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
use_subscr_con(conn)
|
||||
if (conn->loc_operation)
|
||||
LOGP(DMM, LOGL_ERROR, "Connection already had operation.\n");
|
||||
release_loc_updating_req(conn);
|
||||
|
||||
conn->loc_operation = talloc_zero(tall_locop_ctx,
|
||||
|
@ -263,7 +262,6 @@ static int _gsm0408_authorize_sec_cb(unsigned int hooknum, unsigned int event,
|
|||
|
||||
/* try to close channel ASAP */
|
||||
release_loc_updating_req(conn);
|
||||
lchan_auto_release(conn->lchan);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -285,6 +283,10 @@ static int gsm0408_authorize(struct gsm_subscriber_connection *conn, struct msgb
|
|||
void gsm0408_clear_request(struct gsm_subscriber_connection* conn, uint32_t cause)
|
||||
{
|
||||
struct gsm_trans *trans, *temp;
|
||||
|
||||
/* avoid someone issuing a clear */
|
||||
conn->in_release = 1;
|
||||
|
||||
/*
|
||||
* Cancel any outstanding location updating request
|
||||
* operation taking place on the subscriber connection.
|
||||
|
@ -424,7 +426,6 @@ static void loc_upd_rej_cb(void *data)
|
|||
|
||||
gsm0408_loc_upd_rej(conn, bts->network->reject_cause);
|
||||
release_loc_updating_req(conn);
|
||||
lchan_auto_release(lchan);
|
||||
}
|
||||
|
||||
static void schedule_reject(struct gsm_subscriber_connection *conn)
|
||||
|
@ -710,7 +711,6 @@ static int gsm48_tx_mm_serv_rej(struct gsm_subscriber_connection *conn,
|
|||
|
||||
DEBUGP(DMM, "-> CM SERVICE Reject cause: %d\n", value);
|
||||
msg->lchan = conn->lchan;
|
||||
use_subscr_con(conn);
|
||||
return gsm48_conn_sendmsg(msg, conn, NULL);
|
||||
}
|
||||
|
||||
|
@ -871,8 +871,6 @@ static int gsm48_rx_mm_imsi_detach_ind(struct msgb *msg)
|
|||
* imagine an IMSI DETACH happening during an active call! */
|
||||
|
||||
/* subscriber is detached: should we release lchan? */
|
||||
lchan_auto_release(msg->lchan);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1385,7 +1383,6 @@ static int setup_trig_pag_evt(unsigned int hooknum, unsigned int event,
|
|||
/* Assign lchan */
|
||||
if (!transt->conn) {
|
||||
transt->conn = conn;
|
||||
use_subscr_con(transt->conn);
|
||||
}
|
||||
/* send SETUP request to called party */
|
||||
gsm48_cc_tx_setup(transt, &transt->cc.msg);
|
||||
|
@ -2289,9 +2286,6 @@ static int gsm48_cc_rx_release_compl(struct gsm_trans *trans, struct msgb *msg)
|
|||
case GSM_CSTATE_RELEASE_REQ:
|
||||
rc = mncc_recvmsg(trans->subscr->net, trans,
|
||||
MNCC_REL_CNF, &rel);
|
||||
/* FIXME: in case of multiple calls, we can't simply
|
||||
* hang up here ! */
|
||||
lchan_auto_release(msg->lchan);
|
||||
break;
|
||||
default:
|
||||
rc = mncc_recvmsg(trans->subscr->net, trans,
|
||||
|
@ -2924,7 +2918,6 @@ int mncc_send(struct gsm_network *net, int msg_type, void *arg)
|
|||
}
|
||||
/* Assign lchan */
|
||||
trans->conn = conn;
|
||||
use_subscr_con(trans->conn);
|
||||
subscr_put(subscr);
|
||||
}
|
||||
|
||||
|
@ -3065,7 +3058,6 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m
|
|||
}
|
||||
/* Assign transaction */
|
||||
trans->conn = conn;
|
||||
use_subscr_con(trans->conn);
|
||||
}
|
||||
|
||||
/* find function for current state and message */
|
||||
|
|
|
@ -943,7 +943,6 @@ int gsm0411_rcv_sms(struct gsm_subscriber_connection *conn,
|
|||
trans->sms.link_id = UM_SAPI_SMS;
|
||||
|
||||
trans->conn = conn;
|
||||
use_subscr_con(trans->conn);
|
||||
}
|
||||
|
||||
switch(msg_type) {
|
||||
|
@ -1066,7 +1065,6 @@ static int gsm411_send_sms(struct gsm_subscriber_connection *conn, struct gsm_sm
|
|||
trans->sms.link_id = UM_SAPI_SMS; /* FIXME: main or SACCH ? */
|
||||
|
||||
trans->conn = conn;
|
||||
use_subscr_con(trans->conn);
|
||||
|
||||
/* Hardcode SMSC Originating Address for now */
|
||||
data = (u_int8_t *)msgb_put(msg, 8);
|
||||
|
@ -1122,7 +1120,6 @@ static int paging_cb_send_sms(unsigned int hooknum, unsigned int event,
|
|||
|
||||
switch (event) {
|
||||
case GSM_PAGING_SUCCEEDED:
|
||||
use_subscr_con(conn);
|
||||
gsm411_send_sms(conn, sms);
|
||||
break;
|
||||
case GSM_PAGING_EXPIRED:
|
||||
|
@ -1147,7 +1144,6 @@ int gsm411_send_sms_subscr(struct gsm_subscriber *subscr,
|
|||
* if yes, send the SMS this way */
|
||||
conn = connection_for_subscr(subscr);
|
||||
if (conn) {
|
||||
use_subscr_con(conn);
|
||||
return gsm411_send_sms(conn, sms);
|
||||
}
|
||||
|
||||
|
@ -1174,7 +1170,6 @@ static int subscr_sig_cb(unsigned int subsys, unsigned int signal,
|
|||
sms = db_sms_get_unsent_for_subscr(subscr);
|
||||
if (!sms)
|
||||
break;
|
||||
use_subscr_con(conn);
|
||||
gsm411_send_sms(conn, sms);
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -205,8 +205,6 @@ void subscr_put_channel(struct gsm_subscriber_connection *conn)
|
|||
* will listen to the paging requests before we timeout
|
||||
*/
|
||||
|
||||
put_subscr_con(conn);
|
||||
|
||||
if (conn->subscr && !llist_empty(&conn->subscr->requests))
|
||||
subscr_send_paging_request(conn->subscr);
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
|
|||
trans_lchan_change(ho->old_lchan->conn, new_lchan->conn);
|
||||
|
||||
rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
|
||||
lchan_auto_release(ho->old_lchan);
|
||||
lchan_release(ho->old_lchan, 0, 1);
|
||||
|
||||
/* do something to re-route the actual speech frames ! */
|
||||
|
||||
|
@ -259,7 +259,6 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
|
|||
bsc_del_timer(&ho->T3103);
|
||||
llist_del(&ho->list);
|
||||
conn = ho->new_lchan->conn;
|
||||
put_subscr_con(conn);
|
||||
talloc_free(ho);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <openbsc/bsc_api.h>
|
||||
#include <openbsc/debug.h>
|
||||
#include <openbsc/transaction.h>
|
||||
|
||||
#include <openbsc/gsm_04_11.h>
|
||||
|
||||
|
@ -64,3 +65,30 @@ static struct bsc_api msc_handler = {
|
|||
struct bsc_api *msc_bsc_api() {
|
||||
return &msc_handler;
|
||||
}
|
||||
|
||||
/* lchan release handling */
|
||||
void msc_release_connection(struct gsm_subscriber_connection *conn)
|
||||
{
|
||||
struct gsm_trans *trans;
|
||||
|
||||
/* 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;
|
||||
|
||||
/* check if there is a pending operation */
|
||||
if (conn->loc_operation || conn->sec_operation)
|
||||
return;
|
||||
|
||||
llist_for_each_entry(trans, &conn->bts->network->trans_list, entry) {
|
||||
if (trans->conn == conn)
|
||||
return;
|
||||
}
|
||||
|
||||
/* no more connections, asking to release the channel */
|
||||
conn->in_release = 1;
|
||||
gsm0808_clear(conn);
|
||||
}
|
||||
|
|
|
@ -57,7 +57,6 @@ static int paging_cb_silent(unsigned int hooknum, unsigned int event,
|
|||
conn->silent_call = 1;
|
||||
/* increment lchan reference count */
|
||||
dispatch_signal(SS_SCALL, S_SCALL_SUCCESS, &sigdata);
|
||||
use_subscr_con(conn);
|
||||
break;
|
||||
case GSM_PAGING_EXPIRED:
|
||||
DEBUGP(DSMS, "expired\n");
|
||||
|
@ -135,7 +134,8 @@ int gsm_silent_call_stop(struct gsm_subscriber *subscr)
|
|||
if (!conn->silent_call)
|
||||
return -EINVAL;
|
||||
|
||||
put_subscr_con(conn);
|
||||
conn->silent_call = 0;
|
||||
msc_release_connection(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -95,9 +95,6 @@ void trans_free(struct gsm_trans *trans)
|
|||
break;
|
||||
}
|
||||
|
||||
if (trans->conn)
|
||||
put_subscr_con(trans->conn);
|
||||
|
||||
if (!trans->conn && trans->subscr && trans->subscr->net) {
|
||||
/* Stop paging on all bts' */
|
||||
paging_request_stop(NULL, trans->subscr, NULL);
|
||||
|
@ -108,6 +105,10 @@ void trans_free(struct gsm_trans *trans)
|
|||
|
||||
llist_del(&trans->entry);
|
||||
|
||||
if (trans->conn)
|
||||
msc_release_connection(trans->conn);
|
||||
|
||||
|
||||
talloc_free(trans);
|
||||
}
|
||||
|
||||
|
@ -155,15 +156,17 @@ int trans_lchan_change(struct gsm_subscriber_connection *conn_old,
|
|||
struct gsm_trans *trans;
|
||||
int num = 0;
|
||||
|
||||
if (conn_old == conn_new) {
|
||||
LOGP(DCC, LOGL_ERROR, "Exchanging transaction with itself.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
llist_for_each_entry(trans, &net->trans_list, entry) {
|
||||
if (trans->conn == conn_old) {
|
||||
msc_release_connection(conn_old);
|
||||
|
||||
/* drop old channel use count */
|
||||
put_subscr_con(conn_old);
|
||||
/* assign new channel */
|
||||
trans->conn = conn_new;
|
||||
/* bump new channel use count */
|
||||
use_subscr_con(conn_new);
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue