aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--openbsc/doc/channel_release.txt2
-rw-r--r--openbsc/include/openbsc/bsc_api.h1
-rw-r--r--openbsc/include/openbsc/chan_alloc.h4
-rw-r--r--openbsc/include/openbsc/gsm_data.h27
-rw-r--r--openbsc/include/openbsc/osmo_msc.h1
-rw-r--r--openbsc/src/bsc_api.c11
-rw-r--r--openbsc/src/bsc_vty.c4
-rw-r--r--openbsc/src/chan_alloc.c51
-rw-r--r--openbsc/src/gsm_04_08.c24
-rw-r--r--openbsc/src/gsm_04_11.c5
-rw-r--r--openbsc/src/gsm_subscriber_base.c2
-rw-r--r--openbsc/src/handover_logic.c3
-rw-r--r--openbsc/src/osmo_msc.c28
-rw-r--r--openbsc/src/silent_call.c4
-rw-r--r--openbsc/src/transaction.c17
15 files changed, 78 insertions, 106 deletions
diff --git a/openbsc/doc/channel_release.txt b/openbsc/doc/channel_release.txt
index bacf09c8d..a10e9d50f 100644
--- a/openbsc/doc/channel_release.txt
+++ b/openbsc/doc/channel_release.txt
@@ -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()
diff --git a/openbsc/include/openbsc/bsc_api.h b/openbsc/include/openbsc/bsc_api.h
index e92da216a..da942d268 100644
--- a/openbsc/include/openbsc/bsc_api.h
+++ b/openbsc/include/openbsc/bsc_api.h
@@ -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
diff --git a/openbsc/include/openbsc/chan_alloc.h b/openbsc/include/openbsc/chan_alloc.h
index bbbe5362a..3afcb3c47 100644
--- a/openbsc/include/openbsc/chan_alloc.h
+++ b/openbsc/include/openbsc/chan_alloc.h
@@ -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;
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index b1091cdb2..491cca12a 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -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;
};
diff --git a/openbsc/include/openbsc/osmo_msc.h b/openbsc/include/openbsc/osmo_msc.h
index d5d8917df..beb3f5e4c 100644
--- a/openbsc/include/openbsc/osmo_msc.h
+++ b/openbsc/include/openbsc/osmo_msc.h
@@ -6,5 +6,6 @@
#include "bsc_api.h"
struct bsc_api *msc_bsc_api();
+void msc_release_connection(struct gsm_subscriber_connection *conn);
#endif
diff --git a/openbsc/src/bsc_api.c b/openbsc/src/bsc_api.c
index 92fe66118..46a3343e0 100644
--- a/openbsc/src/bsc_api.c
+++ b/openbsc/src/bsc_api.c
@@ -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;
}
diff --git a/openbsc/src/bsc_vty.c b/openbsc/src/bsc_vty.c
index 321574504..a308ec475 100644
--- a/openbsc/src/bsc_vty.c
+++ b/openbsc/src/bsc_vty.c
@@ -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
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index f5c4ec65e..62d476ad9 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -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);
diff --git a/openbsc/src/gsm_04_08.c b/openbsc/src/gsm_04_08.c
index e8070522d..c1b438ef5 100644
--- a/openbsc/src/gsm_04_08.c
+++ b/openbsc/src/gsm_04_08.c
@@ -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 */
diff --git a/openbsc/src/gsm_04_11.c b/openbsc/src/gsm_04_11.c
index d4df989d1..6cce57db1 100644
--- a/openbsc/src/gsm_04_11.c
+++ b/openbsc/src/gsm_04_11.c
@@ -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:
diff --git a/openbsc/src/gsm_subscriber_base.c b/openbsc/src/gsm_subscriber_base.c
index 264f12855..50e6865bf 100644
--- a/openbsc/src/gsm_subscriber_base.c
+++ b/openbsc/src/gsm_subscriber_base.c
@@ -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);
}
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
index b75dc98ba..baf03b34b 100644
--- a/openbsc/src/handover_logic.c
+++ b/openbsc/src/handover_logic.c
@@ -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;
diff --git a/openbsc/src/osmo_msc.c b/openbsc/src/osmo_msc.c
index 569634d55..6a94e7abb 100644
--- a/openbsc/src/osmo_msc.c
+++ b/openbsc/src/osmo_msc.c
@@ -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);
+}
diff --git a/openbsc/src/silent_call.c b/openbsc/src/silent_call.c
index 397a3e4b9..7ba451b65 100644
--- a/openbsc/src/silent_call.c
+++ b/openbsc/src/silent_call.c
@@ -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;
}
diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c
index c7478d668..ffabdd316 100644
--- a/openbsc/src/transaction.c
+++ b/openbsc/src/transaction.c
@@ -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++;
}
}