diff options
author | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-12-17 21:21:36 +0100 |
---|---|---|
committer | Holger Hans Peter Freyther <holger@moiji-mobile.com> | 2014-12-17 21:21:36 +0100 |
commit | d30ed6b6f2d8eb56a035354694d12f4395103edc (patch) | |
tree | 1910cebcd518764cad7ec747f91696baba408399 /openbsc/src | |
parent | f7e23c5ff7d28c985d6c1e6d1dc0b9e8f5895a30 (diff) |
ho: Make sure the timer is always stopped
In case of a ho_chan_activ_nack (sent due another bug inside
both sysmobts and openbsc) the code would not stop the timer
but free the datastructure. This can lead to a clear segfault
when the timer has expired. Create a "free" function which is
responsible to detach the handover structure, stop the timer
(which is idempotent) and free the structure.
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/libbsc/handover_logic.c | 30 |
1 files changed, 16 insertions, 14 deletions
diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index 22f9883fd..9284f7ee3 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -54,6 +54,13 @@ struct bsc_handover { static LLIST_HEAD(bsc_handovers); +static void handover_free(struct bsc_handover *ho) +{ + osmo_timer_del(&ho->T3103); + llist_del(&ho->list); + talloc_free(ho); +} + static struct bsc_handover *bsc_ho_by_new_lchan(struct gsm_lchan *new_lchan) { struct bsc_handover *ho; @@ -169,9 +176,7 @@ void bsc_clear_handover(struct gsm_subscriber_connection *conn, int free_lchan) if (free_lchan) lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END); - osmo_timer_del(&ho->T3103); - llist_del(&ho->list); - talloc_free(ho); + handover_free(ho); } /* T3103 expired: Handover has failed without HO COMPLETE or HO FAIL */ @@ -186,8 +191,7 @@ static void ho_T3103_cb(void *_ho) ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END); - llist_del(&ho->list); - talloc_free(ho); + handover_free(ho); } /* RSL has acknowledged activation of the new lchan */ @@ -234,8 +238,7 @@ static int ho_chan_activ_nack(struct gsm_lchan *new_lchan) new_lchan->conn->ho_lchan = NULL; new_lchan->conn = NULL; - llist_del(&ho->list); - talloc_free(ho); + handover_free(ho); /* FIXME: maybe we should try to allocate a new LCHAN here? */ @@ -282,9 +285,7 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan) rsl_lchan_set_state(ho->old_lchan, LCHAN_S_INACTIVE); lchan_release(ho->old_lchan, 0, RSL_REL_LOCAL_END); - llist_del(&ho->list); - talloc_free(ho); - + handover_free(ho); return 0; } @@ -293,6 +294,7 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) { struct gsm_network *net = old_lchan->ts->trx->bts->network; struct bsc_handover *ho; + struct gsm_lchan *new_lchan; ho = bsc_ho_by_old_lchan(old_lchan); if (!ho) { @@ -302,15 +304,15 @@ static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan) osmo_counter_inc(net->stats.handover.failed); - osmo_timer_del(&ho->T3103); - llist_del(&ho->list); + new_lchan = ho->new_lchan; /* 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, RSL_REL_LOCAL_END); + handover_free(ho); + + lchan_release(new_lchan, 0, RSL_REL_LOCAL_END); - talloc_free(ho); return 0; } |