diff options
Diffstat (limited to 'openbsc')
-rw-r--r-- | openbsc/include/openbsc/gsm_data.h | 1 | ||||
-rw-r--r-- | openbsc/include/openbsc/transaction.h | 4 | ||||
-rw-r--r-- | openbsc/src/chan_alloc.c | 8 | ||||
-rw-r--r-- | openbsc/src/handover_logic.c | 30 | ||||
-rw-r--r-- | openbsc/src/transaction.c | 26 |
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; -} |