aboutsummaryrefslogtreecommitdiffstats
path: root/openbsc
diff options
context:
space:
mode:
Diffstat (limited to 'openbsc')
-rw-r--r--openbsc/include/openbsc/gsm_data.h1
-rw-r--r--openbsc/include/openbsc/transaction.h4
-rw-r--r--openbsc/src/chan_alloc.c8
-rw-r--r--openbsc/src/handover_logic.c30
-rw-r--r--openbsc/src/transaction.c26
5 files changed, 34 insertions, 35 deletions
diff --git a/openbsc/include/openbsc/gsm_data.h b/openbsc/include/openbsc/gsm_data.h
index 491cca12a..e03ad3a78 100644
--- a/openbsc/include/openbsc/gsm_data.h
+++ b/openbsc/include/openbsc/gsm_data.h
@@ -231,6 +231,7 @@ struct gsm_subscriber_connection {
/* back pointers */
int in_release;
struct gsm_lchan *lchan;
+ struct gsm_lchan *ho_lchan;
struct gsm_bts *bts;
};
diff --git a/openbsc/include/openbsc/transaction.h b/openbsc/include/openbsc/transaction.h
index 90a008bdc..0ad7504e7 100644
--- a/openbsc/include/openbsc/transaction.h
+++ b/openbsc/include/openbsc/transaction.h
@@ -69,8 +69,4 @@ void trans_free(struct gsm_trans *trans);
int trans_assign_trans_id(struct gsm_subscriber *subscr,
u_int8_t protocol, u_int8_t ti_flag);
-/* update all transactions to use a different LCHAN, e.g.
- * after handover has succeeded */
-int trans_lchan_change(struct gsm_subscriber_connection *conn_old,
- struct gsm_subscriber_connection *conn_new);
#endif
diff --git a/openbsc/src/chan_alloc.c b/openbsc/src/chan_alloc.c
index 62d476ad9..675cbbb1d 100644
--- a/openbsc/src/chan_alloc.c
+++ b/openbsc/src/chan_alloc.c
@@ -478,6 +478,14 @@ void subscr_con_free(struct gsm_subscriber_connection *conn)
}
+ /* Release a handover that might be in operation */
+ if (conn->ho_lchan) {
+ conn->ho_lchan->conn = NULL;
+ lchan_release(conn->ho_lchan, 0, 1);
+ conn->ho_lchan = NULL;
+ }
+
+
lchan = conn->lchan;
talloc_free(conn);
diff --git a/openbsc/src/handover_logic.c b/openbsc/src/handover_logic.c
index baf03b34b..42dc5d8e6 100644
--- a/openbsc/src/handover_logic.c
+++ b/openbsc/src/handover_logic.c
@@ -99,6 +99,11 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
counter_inc(bts->network->stats.handover.attempted);
+ if (!old_lchan->conn) {
+ LOGP(DHO, LOGL_ERROR, "Old lchan lacks connection data.\n");
+ return -ENOSPC;
+ }
+
new_lchan = lchan_alloc(bts, old_lchan->type);
if (!new_lchan) {
LOGP(DHO, LOGL_NOTICE, "No free channel\n");
@@ -122,13 +127,16 @@ int bsc_handover_start(struct gsm_lchan *old_lchan, struct gsm_bts *bts)
new_lchan->bs_power = old_lchan->bs_power;
new_lchan->rsl_cmode = old_lchan->rsl_cmode;
new_lchan->tch_mode = old_lchan->tch_mode;
- new_lchan->conn->subscr = subscr_get(old_lchan->conn->subscr);
+
+ new_lchan->conn = old_lchan->conn;
+ new_lchan->conn->ho_lchan = new_lchan;
/* FIXME: do we have a better idea of the timing advance? */
rc = rsl_chan_activate_lchan(new_lchan, RSL_ACT_INTER_ASYNC, 0,
ho->ho_ref);
if (rc < 0) {
LOGP(DHO, LOGL_ERROR, "could not activate channel\n");
+ new_lchan->conn->ho_lchan = NULL;
talloc_free(ho);
lchan_free(new_lchan);
return rc;
@@ -227,8 +235,16 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
bsc_del_timer(&ho->T3103);
- /* update lchan pointer of transaction */
- trans_lchan_change(ho->old_lchan->conn, new_lchan->conn);
+ /* Replace the ho lchan with the primary one */
+ if (ho->old_lchan != new_lchan->conn->lchan)
+ LOGP(DHO, LOGL_ERROR, "Primary lchan changed during handover.\n");
+
+ if (new_lchan != new_lchan->conn->ho_lchan)
+ LOGP(DHO, LOGL_ERROR, "Handover channel changed during this handover.\n");
+
+ new_lchan->conn->ho_lchan = NULL;
+ new_lchan->conn->lchan = new_lchan;
+ ho->old_lchan->conn = NULL;
rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE);
lchan_release(ho->old_lchan, 0, 1);
@@ -244,7 +260,6 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)
/* GSM 04.08 HANDOVER FAIL has been received */
static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)
{
- struct gsm_subscriber_connection *conn;
struct gsm_network *net = old_lchan->ts->trx->bts->network;
struct bsc_handover *ho;
@@ -258,7 +273,12 @@ 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;
+
+ /* release the channel and forget about it */
+ ho->new_lchan->conn->ho_lchan = NULL;
+ ho->new_lchan->conn = NULL;
+ lchan_release(ho->new_lchan, 0, 1);
+
talloc_free(ho);
return 0;
diff --git a/openbsc/src/transaction.c b/openbsc/src/transaction.c
index ffabdd316..a29c07d7a 100644
--- a/openbsc/src/transaction.c
+++ b/openbsc/src/transaction.c
@@ -147,29 +147,3 @@ int trans_assign_trans_id(struct gsm_subscriber *subscr,
return -1;
}
-/* update all transactions to use a different LCHAN, e.g.
- * after handover has succeeded */
-int trans_lchan_change(struct gsm_subscriber_connection *conn_old,
- struct gsm_subscriber_connection *conn_new)
-{
- struct gsm_network *net = conn_old->bts->network;
- 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);
-
- /* assign new channel */
- trans->conn = conn_new;
- num++;
- }
- }
-
- return num;
-}