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:
Holger Hans Peter Freyther 2010-06-28 17:09:29 +08:00
parent 2412a07965
commit 4049455d74
15 changed files with 78 additions and 106 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -6,5 +6,6 @@
#include "bsc_api.h"
struct bsc_api *msc_bsc_api();
void msc_release_connection(struct gsm_subscriber_connection *conn);
#endif

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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