diff options
author | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2017-09-13 13:41:09 +0300 |
---|---|---|
committer | Ivan Kluchnikov <kluchnikovi@gmail.com> | 2017-11-24 15:47:30 +0300 |
commit | 254a94ea9d3a25e2f48fc3cd772413e252ac87c2 (patch) | |
tree | ef0c0b9ea85ecac152cf316eb1051b31fb498585 /openbsc/src | |
parent | 0ca2faafe03fd80baedd380d8b627fd59c1565ce (diff) |
handover: Implement proper handover procedure handling at any stage of the callusers/kluchnikov/wip-handover
Change-Id: Ia7e95e5e0c8c1c4218dab52a4020912bd3d327f6
Diffstat (limited to 'openbsc/src')
-rw-r--r-- | openbsc/src/libbsc/bsc_api.c | 8 | ||||
-rw-r--r-- | openbsc/src/libbsc/handover_logic.c | 12 | ||||
-rw-r--r-- | openbsc/src/libmsc/gsm_04_08.c | 71 |
3 files changed, 90 insertions, 1 deletions
diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c index 0c16db303..01fe589af 100644 --- a/openbsc/src/libbsc/bsc_api.c +++ b/openbsc/src/libbsc/bsc_api.c @@ -265,11 +265,14 @@ struct gsm_subscriber_connection *bsc_subscr_con_allocate(struct gsm_lchan *lcha conn->via_ran = RAN_GERAN_A; lchan->conn = conn; llist_add_tail(&conn->entry, &net->subscr_conns); + INIT_LLIST_HEAD(&conn->ho_queue); return conn; } void bsc_subscr_con_free(struct gsm_subscriber_connection *conn) { + struct msgb *msg; + if (!conn) return; @@ -295,6 +298,11 @@ void bsc_subscr_con_free(struct gsm_subscriber_connection *conn) conn->secondary_lchan->conn = NULL; } + while (!llist_empty(&conn->ho_queue)) { + msg = msgb_dequeue(&conn->ho_queue); + msgb_free(msg); + } + llist_del(&conn->entry); talloc_free(conn); } diff --git a/openbsc/src/libbsc/handover_logic.c b/openbsc/src/libbsc/handover_logic.c index ceaf62abc..ebe9d44d2 100644 --- a/openbsc/src/libbsc/handover_logic.c +++ b/openbsc/src/libbsc/handover_logic.c @@ -186,10 +186,17 @@ static void ho_T3103_cb(void *_ho) { struct bsc_handover *ho = _ho; struct gsm_network *net = ho->new_lchan->ts->trx->bts->network; + struct msgb *msg; DEBUGP(DHO, "HO T3103 expired\n"); rate_ctr_inc(&net->bsc_ctrs->ctr[BSC_CTR_HANDOVER_TIMEOUT]); + ho->new_lchan->conn->in_handover = 0; + while (!llist_empty(&ho->new_lchan->conn->ho_queue)) { + msg = msgb_dequeue(&ho->new_lchan->conn->ho_queue); + msgb_free(msg); + } + ho->new_lchan->conn->ho_lchan = NULL; ho->new_lchan->conn = NULL; lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END); @@ -214,13 +221,16 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan) gsm48_send_ho_cmd(ho->old_lchan, new_lchan, 0, ho->ho_ref); + new_lchan->conn->in_handover = 1; + /* start T3103. We can continue either with T3103 expiration, * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */ osmo_timer_setup(&ho->T3103, ho_T3103_cb, ho); osmo_timer_schedule(&ho->T3103, 10, 0); /* create a RTP connection */ - if (is_ipaccess_bts(new_lchan->ts->trx->bts)) + if (is_ipaccess_bts(new_lchan->ts->trx->bts) && + new_lchan->tch_mode != GSM48_CMODE_SIGN) rsl_ipacc_crcx(new_lchan); return 0; diff --git a/openbsc/src/libmsc/gsm_04_08.c b/openbsc/src/libmsc/gsm_04_08.c index d34f64e4d..8fc4c1a53 100644 --- a/openbsc/src/libmsc/gsm_04_08.c +++ b/openbsc/src/libmsc/gsm_04_08.c @@ -148,6 +148,15 @@ static int gsm48_conn_sendmsg(struct msgb *msg, struct gsm_subscriber_connection sign_link->trx->bts->nr, sign_link->trx->nr, msg->lchan->ts->nr, gh->proto_discr, gh->msg_type); + + if (conn->in_handover) { + msgb_enqueue(&conn->ho_queue, msg); + DEBUGP(DCC, "(bts %d trx %d ts %d) Suspend message sending to MS, " + "active HO procedure.\n", + sign_link->trx->bts->nr, + sign_link->trx->nr, msg->lchan->ts->nr); + return 0; + } } return gsm0808_submit_dtap(conn, msg, 0, 0); @@ -3811,6 +3820,11 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0, gsm48_cc_state_name(trans?(trans->cc.state):0)); + if (conn->in_handover) { + DEBUGP(DCC, "Message unhandled, handover procedure.\n"); + return 0; + } + /* Create transaction */ if (!trans) { DEBUGP(DCC, "Unknown transaction ID %x, " @@ -4035,6 +4049,59 @@ static int ho_detect(struct gsm_lchan *new_lchan) return ho_switch_audio_rtp_proxy(old_lchan, new_lchan); } +static void ho_queue_clean(struct gsm_subscriber_connection *conn) +{ + struct msgb *msg; + while (!llist_empty(&conn->ho_queue)) { + msg = msgb_dequeue(&conn->ho_queue); + msgb_free(msg); + } +} + +static void ho_resumption(struct gsm_lchan *lchan, struct gsm_trans *trans) +{ + struct msgb *msg; + + while (!llist_empty(&lchan->conn->ho_queue)) { + msg = msgb_dequeue(&lchan->conn->ho_queue); + gsm48_conn_sendmsg(msg, lchan->conn, trans); + } +} + +static int ho_fail(struct gsm_lchan *old_lchan) +{ + struct gsm_trans *trans; + + old_lchan->conn->in_handover = 0; + trans = trans_find_by_lchan(old_lchan); + if (trans) + ho_resumption(old_lchan, trans); + else { + LOGP(DHO, LOGL_ERROR, "%s HO fail, but no transaction for old_lchan.\n", + gsm_lchan_name(old_lchan)); + ho_queue_clean(old_lchan->conn); + } + + return 0; +} + +static int ho_complete(struct gsm_lchan *new_lchan) +{ + struct gsm_trans *trans; + + new_lchan->conn->in_handover = 0; + trans = trans_find_by_lchan(new_lchan); + if (!trans) { + LOGP(DHO, LOGL_ERROR, "%s HO detected, but no transaction for new_lchan.\n", + gsm_lchan_name(new_lchan)); + ho_queue_clean(new_lchan->conn); + return 0; + } + + ho_resumption(new_lchan, trans); + return 0; +} + /* some other part of the code sends us a signal */ static int handle_lchan_signal(unsigned int subsys, unsigned int signal, void *handler_data, void *signal_data) @@ -4049,6 +4116,10 @@ static int handle_lchan_signal(unsigned int subsys, unsigned int signal, switch (signal) { case S_LCHAN_HANDOVER_DETECT: return ho_detect(lchan); + case S_LCHAN_HANDOVER_COMPL: + return ho_complete(lchan); + case S_LCHAN_HANDOVER_FAIL: + return ho_fail(lchan); } break; } |