handover: Attempt to use the same gsm_subscriber_conn for new/old channel

The transaction should not know on which lchan we are operating
as this can change due handover. Add untested code to share the
subscriber connection of the new and old lchan and move the pointer
in case of success/failure. Also on a clear command we will free
any resources allocated...

This code is not tested and needs to be debugged, but it should
have the right structure. I am going to fix a potential memleak
in the next commit.
This commit is contained in:
Holger Hans Peter Freyther
2010-06-30 12:40:10 +08:00
parent d06516557a
commit e071ab70e9
5 changed files with 34 additions and 35 deletions

View File

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

View File

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

View File

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

View File

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

View File

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