<div dir="ltr"><div>Hi Neels,</div><div><br></div><div>Sorry for silence, I need to find time to dig into HO code again.</div><div>I will reply in the next few days.</div></div><div class="gmail_extra"><br><div class="gmail_quote">2018-01-16 0:45 GMT+03:00 Neels Hofmeyr <span dir="ltr"><<a href="mailto:nhofmeyr@sysmocom.de" target="_blank">nhofmeyr@sysmocom.de</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi Ivan,<br>
<br>
as I'm working towards load-based handover and incorporating your patches, I<br>
found that most of it is concerned with libmsc. In contrast, I am currently<br>
working on osmo-bsc, in libbsc, and would like to ask your advice.<br>
<br>
Some parts of the patch aren't easy to understand for me, and I'd like to make<br>
sure that I am not dismissing parts of it as non-applicable to libbsc even<br>
though they might be important.<br>
<br>
Since your patches were written, the code has changed. Now that we have the<br>
separate osmo-bsc, we will need two layers of handover: intra-BSC and<br>
inter-BSC.<br>
<br>
Intra-BSC is a handover between two cells that are serviced by the same BSC,<br>
and the higher layers (MSC) should not even notice that anything has happened<br>
-- MSC has asked the BSC to service a call by BSSAP Assignment, and the BSC is<br>
free to choose and change around the lchans it assigns to that. That is the<br>
layer I'm currently dug into.<br>
<br>
Inter-BSC is a handover between cells that are serviced by two different BSCs.<br>
That seems to be the land your patch is improving. The MSC is involved and so<br>
is MNCC.<br>
<br>
(Both MSC and BSC levels will need their own DTAP cache, and they are by<br>
definition completely independent -- MSC caches the DTAP coming from MNCC<br>
during Inter-BSC handover, BSC caches DTAP from MSC during Intra-BSC handover.)<br>
<br>
Since your patch is applied onto openbsc.git, where all of BSC and MSC are<br>
still one osmo-nitb, I want to make sure that I sort your patch right. Do some<br>
of its semantics apply to osmo-bsc master, even if the code changed?<br>
<br>
The smaller patches are either already applied to osmo-bsc master, or I've<br>
submitted them on gerrit just now:<br>
<br>
handover_decision: Add more log messages to get more information about HO causes in logs<br>
handover_decision: Fix condition for power budget handover attempt<br>
handover_logic: set correct link to bts for subscriber_connection in case of moving this connection to another bts<br>
<br>
Remaining are a small and *the* complex one:<br>
<br>
transaction: Add new function trans_find_by_lchan<br>
handover: Implement proper handover procedure handling at any stage of the call<br>
<br>
Here is the last one with inline questions, I hope they are not too stupid; or<br>
too long, it ended up being a lot to read. Thanks in advance for taking a look:<br>
<br>
<br>
> commit f7f4dc5e3b0dd61b8322946597147b<wbr>aef5d0464b<br>
> Author: Ivan Kluchnikov <<a href="mailto:kluchnikovi@gmail.com">kluchnikovi@gmail.com</a>><br>
> Date: Wed Aug 23 18:09:50 2017 +0300<br>
><br>
> handover: Implement proper handover procedure handling at any stage of the call<br>
><br>
> Enhancements for each stage of handover procedure should be implemented in order to support handover at any stage of the call.<br>
> For these purposes new in_handover state and ho_queue for call control messages was introduced for gsm_subscriber_connection.<br>
><br>
> Stage 1: HO-Command is sent to MS<br>
> gsm_subscriber_connection state should be changed to in_handover=1.<br>
> In this state all transmission of signalling layer messages (except RR messages needed for handover procedure)<br>
> should be suspended until resuming is indicated.<br>
> All call control messages for connection received from network side should be buffered in ho_queue.<br>
> All call control messages for connection received from MS side should be ignored.<br>
> Channel mode modification procedures should be also suspended.<br>
><br>
> Stage 2: HO-Detect is received from MS<br>
> Audio path should be switched on network side.<br>
><br>
> Stage 3-1: HO-Complete is received from MS<br>
> Resumption procedure after successful handover should be performed:<br>
> - gsm_subscriber_connection state should be changed to normal (in_handover=0).<br>
> - all buffered call control messages (ho_queue) should be sent to MS on new lchan.<br>
> - suspended channel mode modification procedures should be performed on new lchan.<br>
><br>
> Stage 3-2: HO-Fail is received from MS<br>
> Resumption procedure after failed handover should be performed:<br>
> - gsm_subscriber_connection state should be changed to normal (in_handover=0).<br>
> - all buffered call control messages (ho_queue) should be sent to MS on old lchan.<br>
> - suspended channel mode modification procedures should be performed on old lchan.<br>
><br>
> Stage 3-3: T3103 expired: Handover has failed without HO-Complete or HO-Fail<br>
> Resumption procedure should not be performed in case of T3103 expired:<br>
> - gsm_subscriber_connection state should be changed to normal (in_handover=0).<br>
> - all buffered call control messages (ho_queue) should be cleaned without sending them to MS.<br>
> - suspended channel mode modification procedures should not be performed.<br>
><br>
> Change-Id: Icb9b5c35ef0c894af2ea762e539f1<wbr>a9216447fb7<br>
><br>
> diff --git a/openbsc/include/openbsc/bsc_<wbr>api.h b/openbsc/include/openbsc/bsc_<wbr>api.h<br>
> index 3a931199..baacbeda 100644<br>
> --- a/openbsc/include/openbsc/bsc_<wbr>api.h<br>
> +++ b/openbsc/include/openbsc/bsc_<wbr>api.h<br>
> @@ -51,5 +51,6 @@ int gsm0808_cipher_mode(struct gsm_subscriber_connection *conn, int cipher,<br>
> int gsm0808_page(struct gsm_bts *bts, unsigned int page_group,<br>
> unsigned int mi_len, uint8_t *mi, int chan_type);<br>
> int gsm0808_clear(struct gsm_subscriber_connection *conn);<br>
> +int gsm0808_ho_clear(struct gsm_subscriber_connection *conn);<br>
><br>
> #endif<br>
> diff --git a/openbsc/include/openbsc/gsm_<wbr>data.h b/openbsc/include/openbsc/gsm_<wbr>data.h<br>
> index ac573c49..542b2611 100644<br>
> --- a/openbsc/include/openbsc/gsm_<wbr>data.h<br>
> +++ b/openbsc/include/openbsc/gsm_<wbr>data.h<br>
> @@ -138,6 +138,8 @@ struct gsm_subscriber_connection {<br>
> struct gsm_network *network;<br>
><br>
> int in_release;<br>
> + int in_handover;<br>
> + struct llist_head ho_queue;<br>
> struct gsm_lchan *lchan; /* BSC */<br>
> struct gsm_lchan *ho_lchan; /* BSC */<br>
> struct gsm_bts *bts; /* BSC */<br>
> diff --git a/openbsc/src/libbsc/bsc_api.c b/openbsc/src/libbsc/bsc_api.c<br>
> index 8a4c85ff..71e82d03 100644<br>
> --- a/openbsc/src/libbsc/bsc_api.c<br>
> +++ b/openbsc/src/libbsc/bsc_api.c<br>
> @@ -253,11 +253,14 @@ struct gsm_subscriber_connection *bsc_subscr_con_allocate(<wbr>struct gsm_lchan *lcha<br>
> conn->bts = lchan->ts->trx->bts;<br>
> lchan->conn = conn;<br>
> llist_add_tail(&conn->entry, &net->subscr_conns);<br>
> + INIT_LLIST_HEAD(&conn->ho_<wbr>queue);<br>
> return conn;<br>
> }<br>
><br>
> void bsc_subscr_con_free(struct gsm_subscriber_connection *conn)<br>
> {<br>
> + struct msgb *msg;<br>
> +<br>
> if (!conn)<br>
> return;<br>
><br>
> @@ -283,6 +286,11 @@ void bsc_subscr_con_free(struct gsm_subscriber_connection *conn)<br>
> conn->secondary_lchan->conn = NULL;<br>
> }<br>
><br>
> + while (!llist_empty(&conn->ho_queue)<wbr>) {<br>
> + msg = msgb_dequeue(&conn->ho_queue);<br>
> + msgb_free(msg);<br>
> + }<br>
> +<br>
> llist_del(&conn->entry);<br>
> talloc_free(conn);<br>
> }<br>
> @@ -747,6 +755,17 @@ int gsm0808_clear(struct gsm_subscriber_connection *conn)<br>
> return 0;<br>
> }<br>
><br>
> +/*<br>
> + * Release handover RF Channel.<br>
> + */<br>
> +int gsm0808_ho_clear(struct gsm_subscriber_connection *conn)<br>
> +{<br>
> + if (conn->ho_lchan)<br>
> + bsc_clear_handover(conn, 1);<br>
> +<br>
> + return 0;<br>
> +}<br>
> +<br>
> static void send_sapi_reject(struct gsm_subscriber_connection *conn, int link_id)<br>
> {<br>
> struct bsc_api *api;<br>
> diff --git a/openbsc/src/libbsc/handover_<wbr>logic.c b/openbsc/src/libbsc/handover_<wbr>logic.c<br>
> index af4e8013..b7085c34 100644<br>
> --- a/openbsc/src/libbsc/handover_<wbr>logic.c<br>
> +++ b/openbsc/src/libbsc/handover_<wbr>logic.c<br>
> @@ -186,10 +186,17 @@ static void ho_T3103_cb(void *_ho)<br>
> {<br>
> struct bsc_handover *ho = _ho;<br>
> struct gsm_network *net = ho->new_lchan->ts->trx->bts-><wbr>network;<br>
> + struct msgb *msg;<br>
><br>
> DEBUGP(DHO, "HO T3103 expired\n");<br>
> rate_ctr_inc(&net->bsc_ctrs-><wbr>ctr[BSC_CTR_HANDOVER_TIMEOUT])<wbr>;<br>
><br>
> + ho->new_lchan->conn->in_<wbr>handover = 0;<br>
> + while (!llist_empty(&ho->new_lchan-><wbr>conn->ho_queue)) {<br>
> + msg = msgb_dequeue(&ho->new_lchan-><wbr>conn->ho_queue);<br>
> + msgb_free(msg);<br>
> + }<br>
> +<br>
<br>
(Your ho_queue seems to live in libbsc, while most of the patch seems to be<br>
concerned with libmsc. But nevermind, from jolly's patches I already have a<br>
similar queue in osmo-bsc, and we'll probably use yours for libmsc.)<br>
<br>
> ho->new_lchan->conn->ho_lchan = NULL;<br>
> ho->new_lchan->conn = NULL;<br>
> lchan_release(ho->new_lchan, 0, RSL_REL_LOCAL_END);<br>
> @@ -214,6 +221,8 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan)<br>
><br>
> gsm48_send_ho_cmd(ho->old_<wbr>lchan, new_lchan, 0, ho->ho_ref);<br>
><br>
> + new_lchan->conn->in_handover = 1;<br>
> +<br>
<br>
In current osmo-bsc master, we already set conn->ho_lchan before sending out<br>
the chan activation request. I'd actually assume setting the flag only now,<br>
after the activ ack, is a bit too late?<br>
<br>
> /* start T3103. We can continue either with T3103 expiration,<br>
> * 04.08 HANDOVER COMPLETE or 04.08 HANDOVER FAIL */<br>
> ho->T3103.cb = ho_T3103_cb;<br>
> @@ -221,7 +230,8 @@ static int ho_chan_activ_ack(struct gsm_lchan *new_lchan)<br>
> osmo_timer_schedule(&ho-><wbr>T3103, 10, 0);<br>
><br>
> /* create a RTP connection */<br>
> - if (is_ipaccess_bts(new_lchan-><wbr>ts->trx->bts))<br>
> + if (is_ipaccess_bts(new_lchan-><wbr>ts->trx->bts) &&<br>
> + new_lchan->tch_mode != GSM48_CMODE_SIGN)<br>
> rsl_ipacc_crcx(new_lchan);<br>
<br>
Please explain ... what case / behavior is this fixing?<br>
Do we ever see CMODE_SIGN handovers?<br>
Would we also need to check for GSM48_CMODE_DATA_*?<br>
<br>
> @@ -273,6 +283,11 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)<br>
> if (is_e1_bts(new_lchan->conn-><wbr>bts))<br>
> switch_trau_mux(ho->old_lchan, new_lchan);<br>
><br>
> + if (ho->old_lchan->conn->mncc_<wbr>rtp_connect_pending) {<br>
> + new_lchan->abis_ip.connect_<wbr>port = ho->old_lchan->abis_ip.<wbr>connect_port;<br>
> + new_lchan->abis_ip.connect_ip = ho->old_lchan->abis_ip.<wbr>connect_ip;<br>
> + }<br>
> +<br>
<br>
So if an RTP connect to MNCC is pending, we copy the old lchan's RTP port and<br>
IP? Which is this, the MNCC / call router side IP and port?<br>
Why not set this at the initiation of the HO already?<br>
<br>
<br>
> @@ -295,27 +310,9 @@ static int ho_gsm48_ho_compl(struct gsm_lchan *new_lchan)<br>
> static int ho_gsm48_ho_fail(struct gsm_lchan *old_lchan)<br>
> {<br>
> struct gsm_network *net = old_lchan->ts->trx->bts-><wbr>network;<br>
> - struct bsc_handover *ho;<br>
> - struct gsm_lchan *new_lchan;<br>
> -<br>
> - ho = bsc_ho_by_old_lchan(old_lchan)<wbr>;<br>
> - if (!ho) {<br>
> - LOGP(DHO, LOGL_ERROR, "unable to find HO record\n");<br>
> - return -ENODEV;<br>
> - }<br>
><br>
> rate_ctr_inc(&net->bsc_ctrs-><wbr>ctr[BSC_CTR_HANDOVER_FAILED]);<br>
><br>
> - new_lchan = ho->new_lchan;<br>
> -<br>
> - /* release the channel and forget about it */<br>
> - ho->new_lchan->conn->ho_lchan = NULL;<br>
> - ho->new_lchan->conn = NULL;<br>
> - handover_free(ho);<br>
> -<br>
> - lchan_release(new_lchan, 0, RSL_REL_LOCAL_END);<br>
> -<br>
> -<br>
<br>
I'm puzzled by this removal. No actions during ho_fail? Is this really<br>
intended, or just some rebase artifact?<br>
<br>
> return 0;<br>
> }<br>
><br>
> diff --git a/openbsc/src/libmsc/gsm_04_<wbr>08.c b/openbsc/src/libmsc/gsm_04_<wbr>08.c<br>
> index e5402d0a..84338d72 100644<br>
> --- a/openbsc/src/libmsc/gsm_04_<wbr>08.c<br>
> +++ b/openbsc/src/libmsc/gsm_04_<wbr>08.c<br>
> @@ -147,6 +147,15 @@ static int gsm48_conn_sendmsg(struct msgb *msg, struct gsm_subscriber_connection<br>
> sign_link->trx->bts->nr,<br>
> sign_link->trx->nr, msg->lchan->ts->nr,<br>
> gh->proto_discr, gh->msg_type);<br>
> +<br>
> + if (conn->in_handover) {<br>
> + msgb_enqueue(&conn->ho_queue, msg);<br>
> + DEBUGP(DCC, "(bts %d trx %d ts %d) Suspend message sending to MS, "<br>
> + "active HO procedure.\n",<br>
> + sign_link->trx->bts->nr,<br>
> + sign_link->trx->nr, msg->lchan->ts->nr);<br>
> + return 0;<br>
> + }<br>
<br>
(here DTAP handled in libmsc ends up in the ho_queue that otherwise seems to<br>
live in libbsc ... as I said above this queue will probably move to libmsc<br>
altogether to become part of osmo-msc master.)<br>
<br>
> }<br>
><br>
> return gsm0808_submit_dtap(conn, msg, 0, 0);<br>
> @@ -1749,11 +1758,8 @@ static int switch_for_handover(struct gsm_lchan *old_lchan,<br>
> struct rtp_socket *old_rs, *new_rs, *other_rs;<br>
><br>
> /* Ask the new socket to send to the already known port. */<br>
> - if (new_lchan->conn->mncc_rtp_<wbr>bridge) {<br>
> - LOGP(DHO, LOGL_DEBUG, "Forwarding RTP\n");<br>
> - rsl_ipacc_mdcx(new_lchan,<br>
> - old_lchan->abis_ip.connect_ip,<br>
> - old_lchan->abis_ip.connect_<wbr>port, 0);<br>
> + if (new_lchan->ts->trx->bts-><wbr>network->mncc_state) {<br>
> + /* Audio path should be switched after receiving ho detect message.*/<br>
> return 0;<br>
> }<br>
<br>
I notice that in the current head, the entire switch_for_handover() has been<br>
dropped; it was doing libbsc lchan stuff from within libmsc. Hence we must have<br>
added similar logic in osmo-bsc.git and completely dropped this.<br>
<br>
I think the commit re-implementing handover in osmo-bsc is<br>
<a href="http://git.osmocom.org/osmo-bsc/commit/?id=39c609b7c924524172ad311bdf89f92b7ccf175a" rel="noreferrer" target="_blank">http://git.osmocom.org/osmo-<wbr>bsc/commit/?id=<wbr>39c609b7c924524172ad311bdf89f9<wbr>2b7ccf175a</a><br>
<br>
It appears that lchan->abis_ip.connect_ip and connect_port aren't used at all<br>
in osmo-bsc master, but are still present in the struct. I'll ask others about<br>
that.<br>
<br>
In any case, the code base has changed substantially, and this patch hunk no<br>
longer applies at all.<br>
<br>
Am I interpreting this hunk correctly: it moves the ipacc_mdcx to tell the new<br>
lchan about its RTP peer to a later stage?<br>
<br>
In current osmo-bsc master, it seems that this ipacc_mdcx happens as soon as<br>
the ipacc_crcx is complete, seen in osmo-bsc/src/osmo-bsc/osmo_<wbr>bsc_audio.c in<br>
handle_abisip_signal(), always using the IP:port the MSC sent us.<br>
<br>
<br>
><br>
> @@ -1821,8 +1827,10 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,<br>
> if (subsys != SS_ABISIP)<br>
> return 0;<br>
><br>
> + net = lchan->ts->trx->bts->network;<br>
> +<br>
> /* RTP bridge handling */<br>
> - if (lchan->conn && lchan->conn->mncc_rtp_bridge)<br>
> + if (lchan->conn && net->mncc_state)<br>
> return tch_rtp_signal(lchan, signal);<br>
<br>
What are the semantics here? It seems odd to move from a check of a<br>
conn-specific state (conn->mncc_rtp_bridge) to a check of a global value<br>
(net->mncc_state).<br>
<br>
In any case, this is MNCC related and should not impact Intra-BSC handover,<br>
right?<br>
<br>
><br>
> /* in case we use direct BTS-to-BTS RTP */<br>
> @@ -1851,7 +1859,6 @@ static int handle_abisip_signal(unsigned int subsys, unsigned int signal,<br>
><br>
> /* check if any transactions on this lchan still have<br>
> * a tch_recv_mncc request pending */<br>
> - net = lchan->ts->trx->bts->network;<br>
> llist_for_each_entry(trans, &net->trans_list, entry) {<br>
> if (trans->conn && trans->conn->lchan == lchan && trans->tch_recv) {<br>
> DEBUGP(DCC, "pending tch_recv_mncc request\n");<br>
> @@ -2017,6 +2024,13 @@ static int tch_recv_mncc(struct gsm_network *net, uint32_t callref, int enable)<br>
> switch (bts->type) {<br>
> case GSM_BTS_TYPE_NANOBTS:<br>
> case GSM_BTS_TYPE_OSMO_SYSMO:<br>
> if (ipacc_rtp_direct) {<br>
> LOGP(DCC, LOGL_ERROR, "Error: RTP proxy is disabled\n");<br>
> return -EINVAL;<br>
> }<br>
> + /* RTP bridge handling */<br>
> + if (lchan->conn && net->mncc_state) {<br>
> + return 0;<br>
> + }<br>
<br>
If we have a conn and using external MNCC, don't continue at all? I'm not<br>
following, would be nice if the comment explained why we need to drop out here.<br>
<br>
(added some more code context manually)<br>
<br>
> /* In case, we don't have a RTP socket to the BTS yet, the BTS<br>
> * will not be connected to our RTP proxy and the socket will<br>
> * not be assigned to the application interface. This method<br>
> * will be called again, once the audio socket is created and<br>
> * connected. */<br>
> if (!lchan->abis_ip.rtp_socket) {<br>
> DEBUGP(DCC, "queue tch_recv_mncc request (%d)\n", enable);<br>
> return 0;<br>
> }<br>
> if (enable) {<br>
> /* connect the TCH's to our RTP proxy */<br>
> rc = rsl_ipacc_mdcx_to_rtpsock(<wbr>lchan);<br>
> if (rc < 0)<br>
> return rc;<br>
> /* assign socket to application interface */<br>
> rtp_socket_upstream(lchan-><wbr>abis_ip.rtp_socket,<br>
> net, callref);<br>
> } else<br>
> rtp_socket_upstream(lchan-><wbr>abis_ip.rtp_socket,<br>
> net, 0);<br>
> break;<br>
><br>
<br>
<br>
<br>
> @@ -3325,6 +3339,41 @@ static void mncc_recv_rtp_err(struct gsm_network *net, uint32_t callref, int cmd<br>
> return mncc_recv_rtp(net, callref, cmd, 0, 0, 0, 0);<br>
> }<br>
><br>
> +static void mncc_recv_rtp_modify(struct gsm_lchan *lchan, uint32_t callref)<br>
<br>
This is to tell the call router that the payload type has changed, right? I've<br>
asked in the redmine about whether/how we'd convey an RTP payload change to the<br>
MNCC in case of an Intra-BSC handover...<br>
<br>
<a href="https://osmocom.org/issues/1606#note-45" rel="noreferrer" target="_blank">https://osmocom.org/issues/<wbr>1606#note-45</a><br>
<br>
> +{<br>
> + int msg_type;<br>
> + struct gsm_network *net = lchan->ts->trx->bts->network;<br>
> +<br>
> + LOGP(DMNCC, LOGL_NOTICE, "%s sending pending RTP modify ind.\n",<br>
> + gsm_lchan_name(lchan));<br>
> +<br>
> + switch (lchan->abis_ip.rtp_payload) {<br>
> + case RTP_PT_GSM_FULL:<br>
> + msg_type = GSM_TCHF_FRAME;<br>
> + break;<br>
> + case RTP_PT_GSM_EFR:<br>
> + msg_type = GSM_TCHF_FRAME_EFR;<br>
> + break;<br>
> + case RTP_PT_GSM_HALF:<br>
> + msg_type = GSM_TCHH_FRAME;<br>
> + break;<br>
> + case RTP_PT_AMR:<br>
> + msg_type = GSM_TCH_FRAME_AMR;<br>
> + break;<br>
> + default:<br>
> + LOGP(DMNCC, LOGL_ERROR, "%s unknown payload type %d\n",<br>
> + gsm_lchan_name(lchan), lchan->abis_ip.rtp_payload);<br>
> + msg_type = 0;<br>
> + break;<br>
> + }<br>
> +<br>
> + mncc_recv_rtp(net, callref, MNCC_RTP_MODIFY,<br>
> + lchan->abis_ip.bound_ip,<br>
> + lchan->abis_ip.bound_port,<br>
> + lchan->abis_ip.rtp_payload,<br>
> + msg_type);<br>
> +}<br>
> +<br>
> static int tch_rtp_create(struct gsm_network *net, uint32_t callref)<br>
> {<br>
> struct gsm_bts *bts;<br>
> @@ -3374,6 +3423,9 @@ static int tch_rtp_create(struct gsm_network *net, uint32_t callref)<br>
> LOGP(DMNCC, LOGL_DEBUG, "RTP create: codec=%s, chan_type=%s\n",<br>
> get_value_string(gsm48_chan_<wbr>mode_names, m),<br>
> get_value_string(gsm_chan_t_<wbr>names, lchan->type));<br>
> + if (trans->conn->in_handover) {<br>
> + return 0;<br>
> + }<br>
<br>
Am I reading right: if we're doing handover, the MSC shouldn't sent another<br>
BSSAP Assignment to the BSC; instead, the BSC level figures out another lchan<br>
and done ... ?<br>
<br>
> return gsm0808_assign_req(trans-><wbr>conn, m,<br>
> lchan->type != GSM_LCHAN_TCH_H);<br>
> }<br>
> @@ -3420,23 +3472,21 @@ static int tch_rtp_connect(struct gsm_network *net, void *arg)<br>
> * same package!<br>
> */<br>
> trans->conn->mncc_rtp_connect_<wbr>pending = 1;<br>
> + if (trans->conn->in_handover) {<br>
> + lchan->abis_ip.connect_port = rtp->port;<br>
> + lchan->abis_ip.connect_ip = rtp->ip;<br>
> + return 0;<br>
> + }<br>
> return rsl_ipacc_mdcx(lchan, rtp->ip, rtp->port, 0);<br>
<br>
We're not telling the BTS about the call router's IP:port anymore?<br>
Please explain...<br>
<br>
> }<br>
><br>
> static int tch_rtp_signal(struct gsm_lchan *lchan, int signal)<br>
> {<br>
> struct gsm_network *net;<br>
> - struct gsm_trans *tmp, *trans = NULL;<br>
> + struct gsm_trans *trans;<br>
><br>
> net = lchan->ts->trx->bts->network;<br>
> - llist_for_each_entry(tmp, &net->trans_list, entry) {<br>
> - if (!tmp->conn)<br>
> - continue;<br>
> - if (tmp->conn->lchan != lchan && tmp->conn->ho_lchan != lchan)<br>
> - continue;<br>
> - trans = tmp;<br>
> - break;<br>
> - }<br>
> + trans = trans_find_by_lchan(lchan);<br>
><br>
> if (!trans) {<br>
> LOGP(DMNCC, LOGL_ERROR, "%s IPA abis signal but no transaction.\n",<br>
> @@ -3459,7 +3509,7 @@ static int tch_rtp_signal(struct gsm_lchan *lchan, int signal)<br>
> maybe_switch_for_handover(<wbr>lchan);<br>
> break;<br>
> case S_ABISIP_MDCX_ACK:<br>
> - if (lchan->conn->mncc_rtp_<wbr>connect_pending) {<br>
> + if (lchan->conn->mncc_rtp_<wbr>connect_pending && !lchan->conn->in_handover) {<br>
<br>
if we're in handover, we don't need to tell MNCC that RTP got connected,<br>
because that already happened when the call got established initially?<br>
So mncc_rtp_connect_pending has a second meaning during handover?<br>
<br>
> lchan->conn->mncc_rtp_connect_<wbr>pending = 0;<br>
> LOGP(DMNCC, LOGL_NOTICE, "%s sending pending RTP connect ind.\n",<br>
> gsm_lchan_name(lchan));<br>
> mncc_recv_rtp_sock(net, trans, MNCC_RTP_CONNECT);<br>
> }<br>
> break;<br>
<br>
> @@ -3471,6 +3521,134 @@ static int tch_rtp_signal(struct gsm_lchan *lchan, int signal)<br>
> return 0;<br>
> }<br>
><br>
> +static void ho_queue_clean(struct gsm_subscriber_connection *conn)<br>
> +{<br>
> + struct msgb *msg;<br>
> + while (!llist_empty(&conn->ho_queue)<wbr>) {<br>
> + msg = msgb_dequeue(&conn->ho_queue);<br>
> + msgb_free(msg);<br>
> + }<br>
> +}<br>
> +<br>
> +static void ho_resumption(struct gsm_lchan *lchan, struct gsm_trans *trans)<br>
> +{<br>
> + struct msgb *msg;<br>
> + enum gsm48_chan_mode m;<br>
> +<br>
> + while (!llist_empty(&lchan->conn-><wbr>ho_queue)) {<br>
> + msg = msgb_dequeue(&lchan->conn->ho_<wbr>queue);<br>
> + gsm48_conn_sendmsg(msg, lchan->conn, trans);<br>
> + }<br>
> +<br>
> + if (trans->conn->mncc_rtp_create_<wbr>pending &&<br>
> + lchan->tch_mode == GSM48_CMODE_SIGN) {<br>
> + m = mncc_codec_for_mode(lchan-><wbr>type);<br>
> + gsm0808_assign_req(lchan-><wbr>conn, m, lchan->type != GSM_LCHAN_TCH_H);<br>
<br>
Wait, now we *do* send a BSSAP Assignment after all?<br>
(excuse if I'm being noob, I'm still finding my way through handover in general)<br>
<br>
shouldn't we rather dequeue the cached DTAP after this instead of before?<br>
<br>
> + }<br>
> +<br>
> + if (trans->conn->mncc_rtp_<wbr>connect_pending) {<br>
> + rsl_ipacc_mdcx(lchan, lchan->abis_ip.connect_ip, lchan->abis_ip.connect_port, 0);<br>
> + }<br>
> +}<br>
> +<br>
> +static int ho_complete(struct gsm_lchan *new_lchan)<br>
> +{<br>
> + struct gsm_trans *trans;<br>
> +<br>
> + new_lchan->conn->in_handover = 0;<br>
> + trans = trans_find_by_lchan(new_lchan)<wbr>;<br>
> + if (!trans) {<br>
> + LOGP(DHO, LOGL_ERROR, "%s HO detected, but no transaction for new_lchan.\n",<br>
> + gsm_lchan_name(new_lchan));<br>
> + ho_queue_clean(new_lchan-><wbr>conn);<br>
> + return 0;<br>
> + }<br>
> +<br>
> + ho_resumption(new_lchan, trans);<br>
> + return 0;<br>
> +}<br>
> +<br>
> +static int ho_fail(struct gsm_lchan *old_lchan)<br>
> +{<br>
> + struct gsm_trans *trans;<br>
> +<br>
> + old_lchan->conn->in_handover = 0;<br>
> + trans = trans_find_by_lchan(old_lchan)<wbr>;<br>
> + if (trans)<br>
> + ho_resumption(old_lchan, trans);<br>
> + else {<br>
> + LOGP(DHO, LOGL_ERROR, "%s HO fail, but no transaction for old_lchan.\n",<br>
> + gsm_lchan_name(old_lchan));<br>
> + ho_queue_clean(old_lchan-><wbr>conn);<br>
> + }<br>
> +<br>
> + gsm0808_ho_clear(old_lchan-><wbr>conn);<br>
> + return 0;<br>
> +}<br>
> +<br>
> +static int ho_detect(struct gsm_lchan *new_lchan)<br>
> +{<br>
> + struct gsm_trans *trans;<br>
> + struct gsm_lchan *old_lchan;<br>
> +<br>
> + trans = trans_find_by_lchan(new_lchan)<wbr>;<br>
> +<br>
> + if (!trans) {<br>
> + LOGP(DHO, LOGL_ERROR, "%s HO detected, but no transaction for new_lchan"<br>
> + " with enabled tch_recv.\n",<br>
> + gsm_lchan_name(new_lchan));<br>
> + return 0;<br>
> + }<br>
> +<br>
> + if (!new_lchan->conn->mncc_rtp_<wbr>bridge) {<br>
> + LOGP(DHO, LOGL_ERROR, "%s HO detected, but connection not in mncc_rtp_bridge mode.\n",<br>
> + gsm_lchan_name(new_lchan));<br>
> + return 0;<br>
> + }<br>
> +<br>
> + old_lchan = bsc_handover_pending(new_<wbr>lchan);<br>
> + if (!old_lchan) {<br>
> + LOGP(DHO, LOGL_ERROR, "%s HO detected, but no old_lchan for handover.\n",<br>
> + gsm_lchan_name(new_lchan));<br>
> + return 0;<br>
> + }<br>
> +<br>
> + LOGP(DHO, LOGL_DEBUG, "HO detected, forwarding RTP\n");<br>
> + rsl_ipacc_mdcx(new_lchan,<br>
> + old_lchan->abis_ip.connect_ip,<br>
> + old_lchan->abis_ip.connect_<wbr>port, 0);<br>
> +<br>
> + mncc_recv_rtp_modify(new_<wbr>lchan, trans->callref);<br>
> +<br>
> + return 0;<br>
> +}<br>
> +<br>
> +/* some other part of the code sends us a signal */<br>
> +static int handle_lchan_signal(unsigned int subsys, unsigned int signal,<br>
> + void *handler_data, void *signal_data)<br>
> +{<br>
> + struct lchan_signal_data *lchan_data;<br>
> + struct gsm_lchan *lchan;<br>
> +<br>
> + lchan_data = signal_data;<br>
> + switch (subsys) {<br>
> + case SS_LCHAN:<br>
> + lchan = lchan_data->lchan;<br>
> + if (!lchan->conn)<br>
> + return 0;<br>
> + switch (signal) {<br>
> + case S_LCHAN_HANDOVER_DETECT:<br>
> + return ho_detect(lchan);<br>
> + case S_LCHAN_HANDOVER_COMPL:<br>
> + return ho_complete(lchan);<br>
> + case S_LCHAN_HANDOVER_FAIL:<br>
> + return ho_fail(lchan);<br>
> + }<br>
> + break;<br>
> + }<br>
> +<br>
> + return 0;<br>
> +}<br>
><br>
> static struct downstate {<br>
> uint32_t states;<br>
> @@ -3853,6 +4031,11 @@ static int gsm0408_rcv_cc(struct gsm_subscriber_connection *conn, struct msgb *m<br>
> gsm48_cc_msg_name(msg_type), trans?(trans->cc.state):0,<br>
> gsm48_cc_state_name(trans?(<wbr>trans->cc.state):0));<br>
><br>
> + if (conn->in_handover) {<br>
> + DEBUGP(DCC, "Message unhandled, handover procedure.\n");<br>
> + return 0;<br>
> + }<br>
> +<br>
<br>
If in handover, drop all CC on the floor?<br>
<br>
How about a call release, i.e. I hang up while I'm coincidentally being<br>
handovered?<br>
<br>
> /* Create transaction */<br>
> if (!trans) {<br>
> DEBUGP(DCC, "Unknown transaction ID %x, "<br>
><br>
><br>
><br>
<br>
<br>
Thanks again!<br>
<span class="HOEnZb"><font color="#888888"><br>
~N<br>
</font></span></blockquote></div><br></div>