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