<p>pespin has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/c/osmo-bsc/+/24876">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">WIP: avoid switching dyn ts to sdcch8 if it starves later TCH<br><br>Add a 2nd step lchan target, which provides information on channel type<br>required after the 1st one is used. This is used to avoid selecting a<br>dynamic timeslot to be switched to SDCCH8 when doing so would end up<br>with the BTS having no free TCH channels to be used later on when the<br>call is negotiated in SDCCH8. In that case, we avoid the PDCH->SDCCH8<br>dyn TS switch and instead let upper layers look for a TCH as a next<br>step. This way we ensure that the call is possible.<br><br>Related: SYS#5309<br>Change-Id: I3b32968949a7bdcbebf5a823359295bac51d8e08<br>---<br>M include/osmocom/bsc/lchan_select.h<br>M src/osmo-bsc/abis_rsl.c<br>M src/osmo-bsc/assignment_fsm.c<br>M src/osmo-bsc/bsc_vty.c<br>M src/osmo-bsc/handover_decision_2.c<br>M src/osmo-bsc/handover_fsm.c<br>M src/osmo-bsc/lchan_select.c<br>M tests/handover/handover_test.c<br>8 files changed, 159 insertions(+), 57 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;">git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/76/24876/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/lchan_select.h b/include/osmocom/bsc/lchan_select.h</span><br><span>index aa2f40e..11ee34b 100644</span><br><span>--- a/include/osmocom/bsc/lchan_select.h</span><br><span>+++ b/include/osmocom/bsc/lchan_select.h</span><br><span>@@ -1,8 +1,12 @@</span><br><span> /* Select a suitable lchan from a given cell. */</span><br><span> #pragma once</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type, enum gsm_chan_t step2_type);</span><br><span> enum gsm_chan_t chan_mode_to_chan_type(enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate);</span><br><span> struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,</span><br><span>                                          enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate);</span><br><span style="color: hsl(0, 100%, 40%);">-struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type, bool log);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_lchan *lchan_select_by_chan_mode_list(struct gsm_bts *bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                            const struct channel_mode_and_rate *chan_mode_rate_list,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              unsigned int chan_mode_rate_list_len,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 struct channel_mode_and_rate *selected_chan_mode_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type, enum gsm_chan_t step2_type, bool log);</span><br><span>diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c</span><br><span>index f0adc56..71e6b7a 100644</span><br><span>--- a/src/osmo-bsc/abis_rsl.c</span><br><span>+++ b/src/osmo-bsc/abis_rsl.c</span><br><span>@@ -1778,12 +1778,12 @@</span><br><span> </span><br><span>     /* First check the situation on the BTS, if we have TCH/H or TCH/F resources available for another (EMERGENCY)</span><br><span>        * call. If yes, then no (further) action has to be carried out. */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_F, true)) {</span><br><span style="color: hsl(120, 100%, 40%);">+        if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_F, GSM_LCHAN_NONE, true)) {</span><br><span>               LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,</span><br><span>                      "CHAN RQD/EMERGENCY-PRIORITY: at least one TCH/F is (now) available!\n");</span><br><span>          return false;</span><br><span>        }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_H, true)) {</span><br><span style="color: hsl(120, 100%, 40%);">+        if (lchan_avail_by_type(rqd->bts, GSM_LCHAN_TCH_H, GSM_LCHAN_NONE, true)) {</span><br><span>               LOG_BTS(rqd->bts, DRSL, LOGL_NOTICE,</span><br><span>                      "CHAN RQD/EMERGENCY-PRIORITY: at least one TCH/H is (now) available!\n");</span><br><span>          return false;</span><br><span>@@ -1881,18 +1881,25 @@</span><br><span> </span><br><span>  /* Emergency calls will be put on a free TCH/H or TCH/F directly in the code below, all other channel requests</span><br><span>        * will get an SDCCH first (if possible). */</span><br><span style="color: hsl(0, 100%, 40%);">-    if (rqd->reason != GSM_CHREQ_REASON_EMERG)</span><br><span style="color: hsl(0, 100%, 40%);">-           lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH);</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rqd->reason != GSM_CHREQ_REASON_EMERG) {</span><br><span style="color: hsl(120, 100%, 40%);">+               if (GSM_CHREQ_REASON_CALL) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH, GSM_LCHAN_TCH_H);</span><br><span style="color: hsl(120, 100%, 40%);">+                  if (!lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+                           lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH, GSM_LCHAN_TCH_F);</span><br><span style="color: hsl(120, 100%, 40%);">+          } else {</span><br><span style="color: hsl(120, 100%, 40%);">+                      lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH, GSM_LCHAN_NONE);</span><br><span style="color: hsl(120, 100%, 40%);">+           }</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span> </span><br><span>        if (!lchan) {</span><br><span>                LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x, retrying with %s\n",</span><br><span>                  gsm_lchant_name(GSM_LCHAN_SDCCH), rqd->ref.ra, gsm_lchant_name(GSM_LCHAN_TCH_H));</span><br><span style="color: hsl(0, 100%, 40%);">-            lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H);</span><br><span style="color: hsl(120, 100%, 40%);">+           lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H, GSM_LCHAN_NONE);</span><br><span>  }</span><br><span>    if (!lchan) {</span><br><span>                LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x, retrying with %s\n",</span><br><span>                  gsm_lchant_name(GSM_LCHAN_SDCCH), rqd->ref.ra, gsm_lchant_name(GSM_LCHAN_TCH_F));</span><br><span style="color: hsl(0, 100%, 40%);">-            lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_F);</span><br><span style="color: hsl(120, 100%, 40%);">+           lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_F, GSM_LCHAN_NONE);</span><br><span>  }</span><br><span>    if (!lchan) {</span><br><span>                LOG_BTS(bts, DRSL, LOGL_NOTICE, "CHAN RQD: no resources for %s 0x%x\n",</span><br><span>diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c</span><br><span>index 2c52d22..8efef52 100644</span><br><span>--- a/src/osmo-bsc/assignment_fsm.c</span><br><span>+++ b/src/osmo-bsc/assignment_fsm.c</span><br><span>@@ -585,19 +585,15 @@</span><br><span>           }</span><br><span>    } else {</span><br><span>             /* Try to allocate a new lchan in order of preference */</span><br><span style="color: hsl(0, 100%, 40%);">-                for (i = 0; i < req->n_ch_mode_rate; i++) {</span><br><span style="color: hsl(0, 100%, 40%);">-                       conn->assignment.new_lchan = lchan_select_by_chan_mode(bts,</span><br><span style="color: hsl(0, 100%, 40%);">-                      req->ch_mode_rate_list[i].chan_mode, req->ch_mode_rate_list[i].chan_rate);</span><br><span style="color: hsl(0, 100%, 40%);">-                    if (!conn->assignment.new_lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                             continue;</span><br><span style="color: hsl(0, 100%, 40%);">-                       LOG_ASSIGNMENT(conn, LOGL_DEBUG, "selected new lchan %s for mode[%d] = %s channel_rate=%d\n",</span><br><span style="color: hsl(120, 100%, 40%);">+               conn->assignment.new_lchan = lchan_select_by_chan_mode_list(bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                       req->ch_mode_rate_list,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                            req->n_ch_mode_rate,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                       &conn->assignment.selected_ch_mode_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (conn->assignment.new_lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+                    LOG_ASSIGNMENT(conn, LOGL_DEBUG, "selected new lchan %s for mode=%s channel_rate=%d\n",</span><br><span>                                   gsm_lchan_name(conn->assignment.new_lchan),</span><br><span style="color: hsl(0, 100%, 40%);">-                                  i, gsm48_chan_mode_name(req->ch_mode_rate_list[i].chan_mode),</span><br><span style="color: hsl(0, 100%, 40%);">-                                req->ch_mode_rate_list[i].chan_rate);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-                 conn->assignment.selected_ch_mode_rate = req->ch_mode_rate_list[i];</span><br><span style="color: hsl(0, 100%, 40%);">-                       break;</span><br><span style="color: hsl(0, 100%, 40%);">-          }</span><br><span style="color: hsl(120, 100%, 40%);">+                                    gsm48_chan_mode_name(conn->assignment.selected_ch_mode_rate.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                                    conn->assignment.selected_ch_mode_rate.chan_rate);</span><br><span>         }</span><br><span> </span><br><span>        /* Check whether the lchan allocation was successful or not and tear</span><br><span>diff --git a/src/osmo-bsc/bsc_vty.c b/src/osmo-bsc/bsc_vty.c</span><br><span>index 070b660..0d73fd2 100644</span><br><span>--- a/src/osmo-bsc/bsc_vty.c</span><br><span>+++ b/src/osmo-bsc/bsc_vty.c</span><br><span>@@ -1937,7 +1937,7 @@</span><br><span> {</span><br><span>       LOG_LCHAN(from_lchan, LOGL_NOTICE, "Manually triggering Assignment from VTY\n");</span><br><span>   if (!to_lchan) {</span><br><span style="color: hsl(0, 100%, 40%);">-                to_lchan = lchan_select_by_type(from_lchan->ts->trx->bts, from_lchan->type);</span><br><span style="color: hsl(120, 100%, 40%);">+              to_lchan = lchan_select_by_type(from_lchan->ts->trx->bts, from_lchan->type, GSM_LCHAN_NONE);</span><br><span>             vty_out(vty, "Error: cannot find free lchan of type %s%s",</span><br><span>                         gsm_lchant_name(from_lchan->type), VTY_NEWLINE);</span><br><span>  }</span><br><span>@@ -2115,7 +2115,7 @@</span><br><span>                    continue;</span><br><span> </span><br><span>                llist_for_each_entry(trx, &bts->trx_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        struct gsm_lchan *lchan = lchan_select_by_type(bts, free_type);</span><br><span style="color: hsl(120, 100%, 40%);">+                       struct gsm_lchan *lchan = lchan_select_by_type(bts, free_type, GSM_LCHAN_NONE);</span><br><span>                      if (!lchan)</span><br><span>                          continue;</span><br><span> </span><br><span>diff --git a/src/osmo-bsc/handover_decision_2.c b/src/osmo-bsc/handover_decision_2.c</span><br><span>index d778876..7699c81 100644</span><br><span>--- a/src/osmo-bsc/handover_decision_2.c</span><br><span>+++ b/src/osmo-bsc/handover_decision_2.c</span><br><span>@@ -1033,7 +1033,7 @@</span><br><span>   c->target.min_free_tchh = ho_get_hodec2_tchh_min_slots(c->target.bts->ho);</span><br><span> </span><br><span>      /* Would the next TCH/F lchan occupy a dynamic timeslot that currently counts for free TCH/H timeslots? */</span><br><span style="color: hsl(0, 100%, 40%);">-      next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_F, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_F, GSM_LCHAN_NONE, false);</span><br><span>  if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN)</span><br><span>                 c->target.next_tchf_reduces_tchh = 2;</span><br><span>     else</span><br><span>@@ -1041,7 +1041,7 @@</span><br><span> </span><br><span>     /* Would the next TCH/H lchan occupy a dynamic timeslot that currently counts for free TCH/F timeslots?</span><br><span>       * Note that a dyn TS already in TCH/H mode (half occupied) would not reduce free TCH/F. */</span><br><span style="color: hsl(0, 100%, 40%);">-     next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_H, false);</span><br><span style="color: hsl(120, 100%, 40%);">+   next_lchan = lchan_avail_by_type(c->target.bts, GSM_LCHAN_TCH_H, GSM_LCHAN_NONE, false);</span><br><span>  if (next_lchan && next_lchan->ts->pchan_on_init == GSM_PCHAN_OSMO_DYN</span><br><span>      && next_lchan->ts->pchan_is != GSM_PCHAN_TCH_H)</span><br><span>            c->target.next_tchh_reduces_tchf = 1;</span><br><span>diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c</span><br><span>index 5f4b892..1d38fff 100644</span><br><span>--- a/src/osmo-bsc/handover_fsm.c</span><br><span>+++ b/src/osmo-bsc/handover_fsm.c</span><br><span>@@ -375,7 +375,7 @@</span><br><span>      ho->async = true;</span><br><span>         gsm_bts_cell_id_list(&ho->target_cell_ids, ho->new_bts);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-  ho->new_lchan = lchan_select_by_type(ho->new_bts, ho->new_lchan_type);</span><br><span style="color: hsl(120, 100%, 40%);">+       ho->new_lchan = lchan_select_by_type(ho->new_bts, ho->new_lchan_type, GSM_LCHAN_NONE);</span><br><span> </span><br><span>  if (ho->scope & HO_INTRA_CELL) {</span><br><span>              ho_count(bts, CTR_INTRA_CELL_HO_ATTEMPTED);</span><br><span>diff --git a/src/osmo-bsc/lchan_select.c b/src/osmo-bsc/lchan_select.c</span><br><span>index efa2ff2..d6c5275 100644</span><br><span>--- a/src/osmo-bsc/lchan_select.c</span><br><span>+++ b/src/osmo-bsc/lchan_select.c</span><br><span>@@ -32,7 +32,7 @@</span><br><span> </span><br><span> static struct gsm_lchan *</span><br><span> _lc_find_trx(struct gsm_bts_trx *trx, enum gsm_phys_chan_config pchan,</span><br><span style="color: hsl(0, 100%, 40%);">-          enum gsm_phys_chan_config as_pchan, bool allow_pchan_switch, bool log)</span><br><span style="color: hsl(120, 100%, 40%);">+        enum gsm_phys_chan_config as_pchan, bool allow_pchan_switch, const struct gsm_bts_trx_ts *exclude_ts, bool log)</span><br><span> {</span><br><span>    struct gsm_lchan *lchan;</span><br><span>     struct gsm_bts_trx_ts *ts;</span><br><span>@@ -69,6 +69,10 @@</span><br><span>              ts = &trx->ts[j];</span><br><span>             if (!ts_is_usable(ts))</span><br><span>                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (ts == exclude_ts) {</span><br><span style="color: hsl(120, 100%, 40%);">+                       LOGPLCHANALLOC("%s is excluded\n", gsm_ts_and_pchan_name(ts));</span><br><span style="color: hsl(120, 100%, 40%);">+                      continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span>            /* The caller first selects what kind of TS to search in, e.g. looking for exact</span><br><span>              * GSM_PCHAN_TCH_F, or maybe among dynamic GSM_PCHAN_OSMO_DYN... */</span><br><span>          if (ts->pchan_on_init != pchan) {</span><br><span>@@ -105,8 +109,8 @@</span><br><span> }</span><br><span> </span><br><span> static struct gsm_lchan *</span><br><span style="color: hsl(0, 100%, 40%);">-_lc_dyn_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,</span><br><span style="color: hsl(0, 100%, 40%);">-           enum gsm_phys_chan_config dyn_as_pchan, bool log)</span><br><span style="color: hsl(120, 100%, 40%);">+_lc_dyn_find_bts_excl(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,</span><br><span style="color: hsl(120, 100%, 40%);">+                enum gsm_phys_chan_config dyn_as_pchan, const struct gsm_bts_trx_ts *exclude_dyn_ts_switch, bool log, bool *ts_switch_required)</span><br><span> {</span><br><span>        struct gsm_bts_trx *trx;</span><br><span>     struct gsm_lchan *lc;</span><br><span>@@ -120,15 +124,18 @@</span><br><span>         * true, because they never switch anyway. */</span><br><span>        try_pchan_switch = (pchan != dyn_as_pchan);</span><br><span>  for (allow_pchan_switch = 0; allow_pchan_switch <= (try_pchan_switch ? 1 : 0); allow_pchan_switch++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             const struct gsm_bts_trx_ts *excl = allow_pchan_switch ? exclude_dyn_ts_switch : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (ts_switch_required)</span><br><span style="color: hsl(120, 100%, 40%);">+                       *ts_switch_required = allow_pchan_switch;</span><br><span>            if (bts->chan_alloc_reverse) {</span><br><span>                    llist_for_each_entry_reverse(trx, &bts->trx_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                lc = _lc_find_trx(trx, pchan, dyn_as_pchan, (bool)allow_pchan_switch, log);</span><br><span style="color: hsl(120, 100%, 40%);">+                           lc = _lc_find_trx(trx, pchan, dyn_as_pchan, (bool)allow_pchan_switch, excl, log);</span><br><span>                            if (lc)</span><br><span>                                      return lc;</span><br><span>                   }</span><br><span>            } else {</span><br><span>                     llist_for_each_entry(trx, &bts->trx_list, list) {</span><br><span style="color: hsl(0, 100%, 40%);">-                                lc = _lc_find_trx(trx, pchan, dyn_as_pchan, (bool)allow_pchan_switch, log);</span><br><span style="color: hsl(120, 100%, 40%);">+                           lc = _lc_find_trx(trx, pchan, dyn_as_pchan, (bool)allow_pchan_switch, excl, log);</span><br><span>                            if (lc)</span><br><span>                                      return lc;</span><br><span>                   }</span><br><span>@@ -139,9 +146,16 @@</span><br><span> }</span><br><span> </span><br><span> static struct gsm_lchan *</span><br><span style="color: hsl(120, 100%, 40%);">+_lc_dyn_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan,</span><br><span style="color: hsl(120, 100%, 40%);">+                 enum gsm_phys_chan_config dyn_as_pchan, bool log, bool *ts_switch_required)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return _lc_dyn_find_bts_excl(bts, pchan, dyn_as_pchan, NULL, log, ts_switch_required);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm_lchan *</span><br><span> _lc_find_bts(struct gsm_bts *bts, enum gsm_phys_chan_config pchan, bool log)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-     return _lc_dyn_find_bts(bts, pchan, pchan, log);</span><br><span style="color: hsl(120, 100%, 40%);">+      return _lc_dyn_find_bts(bts, pchan, pchan, log, NULL);</span><br><span> }</span><br><span> </span><br><span> enum gsm_chan_t chan_mode_to_chan_type(enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate)</span><br><span>@@ -184,16 +198,92 @@</span><br><span>       enum gsm_chan_t type = chan_mode_to_chan_type(chan_mode, chan_rate);</span><br><span>         if (type == GSM_LCHAN_NONE)</span><br><span>          return NULL;</span><br><span style="color: hsl(0, 100%, 40%);">-    return lchan_select_by_type(bts, type);</span><br><span style="color: hsl(120, 100%, 40%);">+       return lchan_select_by_type(bts, type, GSM_LCHAN_NONE);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type, bool log)</span><br><span style="color: hsl(120, 100%, 40%);">+static enum gsm_chan_t _step2_type_get(enum gsm_chan_t type,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      const struct channel_mode_and_rate *chan_mode_rate_list,</span><br><span style="color: hsl(120, 100%, 40%);">+                                      unsigned int chan_mode_rate_list_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        enum gsm_chan_t step2_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (type == GSM_LCHAN_SDCCH) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        for (i = 0; i < chan_mode_rate_list_len; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+                      step2_type = chan_mode_to_chan_type(chan_mode_rate_list[i].chan_mode,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                               chan_mode_rate_list[i].chan_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (step2_type == GSM_LCHAN_TCH_H || step2_type == GSM_LCHAN_TCH_F)</span><br><span style="color: hsl(120, 100%, 40%);">+                           return step2_type;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+     return GSM_LCHAN_NONE;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Try to allocate a new lchan in order of preference */</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_lchan *lchan_select_by_chan_mode_list(struct gsm_bts *bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                           const struct channel_mode_and_rate *chan_mode_rate_list,</span><br><span style="color: hsl(120, 100%, 40%);">+                                              unsigned int chan_mode_rate_list_len,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                 struct channel_mode_and_rate *selected_chan_mode_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct gsm_lchan *new_lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+  /* Try to allocate a new lchan in order of preference */</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < chan_mode_rate_list_len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+            enum gsm_chan_t type = chan_mode_to_chan_type(chan_mode_rate_list[i].chan_mode,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                             chan_mode_rate_list[i].chan_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+              enum gsm_chan_t step2_type;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         if (type == GSM_LCHAN_NONE)</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             step2_type = _step2_type_get(type, (&chan_mode_rate_list[i]) + 1, chan_mode_rate_list_len - i - 1);</span><br><span style="color: hsl(120, 100%, 40%);">+               new_lchan = lchan_select_by_type(bts, type, step2_type);</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!new_lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+                       continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           *selected_chan_mode_rate = chan_mode_rate_list[i];</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm_lchan *_lchan_avail_tch_f(struct gsm_bts *bts, const struct gsm_bts_trx_ts *exclude_dyn_ts_switch, bool log)</span><br><span> {</span><br><span>       struct gsm_lchan *lchan = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F, log);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* If we don't have TCH/F available, try dynamic TCH/F_PDCH */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+           lchan = _lc_dyn_find_bts_excl(bts, GSM_PCHAN_TCH_F_PDCH,</span><br><span style="color: hsl(120, 100%, 40%);">+                                       GSM_PCHAN_TCH_F, exclude_dyn_ts_switch, log, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Try fully dynamic TCH/F_TCH/H_PDCH as TCH/F... */</span><br><span style="color: hsl(120, 100%, 40%);">+  if (!lchan && bts->network->dyn_ts_allow_tch_f)</span><br><span style="color: hsl(120, 100%, 40%);">+         lchan = _lc_dyn_find_bts_excl(bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     GSM_PCHAN_OSMO_DYN,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   GSM_PCHAN_TCH_F, exclude_dyn_ts_switch, log, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  return lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct gsm_lchan *_lchan_avail_tch_h(struct gsm_bts *bts, const struct gsm_bts_trx_ts *exclude_dyn_ts_switch, bool log)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_lchan *lchan = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H, log);</span><br><span style="color: hsl(120, 100%, 40%);">+      /* No dedicated TCH/x available -- try fully dynamic</span><br><span style="color: hsl(120, 100%, 40%);">+   * TCH/F_TCH/H_PDCH */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+           lchan = _lc_dyn_find_bts_excl(bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     GSM_PCHAN_OSMO_DYN,</span><br><span style="color: hsl(120, 100%, 40%);">+                                   GSM_PCHAN_TCH_H, exclude_dyn_ts_switch, log, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+  return lchan;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_lchan *lchan_avail_by_type(struct gsm_bts *bts, enum gsm_chan_t type, enum gsm_chan_t step2_type, bool log)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct gsm_lchan *lchan = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+       bool ts_switch_required;</span><br><span>     enum gsm_phys_chan_config first, first_cbch, second, second_cbch;</span><br><span> </span><br><span>        if (log)</span><br><span style="color: hsl(0, 100%, 40%);">-                LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_avail_by_type(%s)\n", gsm_lchant_name(type));</span><br><span style="color: hsl(120, 100%, 40%);">+         LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_avail_by_type(%s, step2=%s)\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                       gsm_lchant_name(type), gsm_lchant_name(step2_type));</span><br><span> </span><br><span>     switch (type) {</span><br><span>      case GSM_LCHAN_SDCCH:</span><br><span>@@ -218,32 +308,37 @@</span><br><span>                        lchan = _lc_find_bts(bts, second_cbch, log);</span><br><span>                 /* No dedicated SDCCH available -- try fully dynamic</span><br><span>                  * TCH/F_TCH/H_SDCCH8_PDCH if BTS supports it: */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (lchan == NULL && osmo_bts_has_feature(&bts->features, BTS_FEAT_DYN_TS_SDCCH8))</span><br><span style="color: hsl(120, 100%, 40%);">+             if (lchan == NULL && osmo_bts_has_feature(&bts->features, BTS_FEAT_DYN_TS_SDCCH8)) {</span><br><span>                  lchan = _lc_dyn_find_bts(bts,</span><br><span>                                                 GSM_PCHAN_OSMO_DYN,</span><br><span style="color: hsl(0, 100%, 40%);">-                                             GSM_PCHAN_SDCCH8_SACCH8C, log);</span><br><span style="color: hsl(120, 100%, 40%);">+                                               GSM_PCHAN_SDCCH8_SACCH8C, log, &ts_switch_required);</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* If a DYN TS is switched to SDCCH8 as a first step towards</span><br><span style="color: hsl(120, 100%, 40%);">+                     handling a TCH, let's make sure there's still a TCH available</span><br><span style="color: hsl(120, 100%, 40%);">+                         too. Otherwise, let's rather return NOT FOUND now and let</span><br><span style="color: hsl(120, 100%, 40%);">+                         caller subsequently request a TCH, which will take the DYN TS</span><br><span style="color: hsl(120, 100%, 40%);">+                         and be able to success through the entire call channel</span><br><span style="color: hsl(120, 100%, 40%);">+                        establishment */</span><br><span style="color: hsl(120, 100%, 40%);">+                   if (ts_switch_required) {</span><br><span style="color: hsl(120, 100%, 40%);">+                             switch (step2_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+                         case GSM_LCHAN_TCH_F:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 if (!_lchan_avail_tch_f(bts, lchan->ts, log))</span><br><span style="color: hsl(120, 100%, 40%);">+                                              lchan = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                                case GSM_LCHAN_TCH_H:</span><br><span style="color: hsl(120, 100%, 40%);">+                                 if (!_lchan_avail_tch_h(bts, lchan->ts, log))</span><br><span style="color: hsl(120, 100%, 40%);">+                                              lchan = NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+                                 break;</span><br><span style="color: hsl(120, 100%, 40%);">+                                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                                      /* we are fine, go forward */</span><br><span style="color: hsl(120, 100%, 40%);">+                         }</span><br><span style="color: hsl(120, 100%, 40%);">+                     }</span><br><span style="color: hsl(120, 100%, 40%);">+             }</span><br><span>            break;</span><br><span>       case GSM_LCHAN_TCH_F:</span><br><span style="color: hsl(0, 100%, 40%);">-           lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_F, log);</span><br><span style="color: hsl(0, 100%, 40%);">-                /* If we don't have TCH/F available, try dynamic TCH/F_PDCH */</span><br><span style="color: hsl(0, 100%, 40%);">-              if (!lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                     lchan = _lc_dyn_find_bts(bts, GSM_PCHAN_TCH_F_PDCH,</span><br><span style="color: hsl(0, 100%, 40%);">-                                              GSM_PCHAN_TCH_F, log);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-         /* Try fully dynamic TCH/F_TCH/H_PDCH as TCH/F... */</span><br><span style="color: hsl(0, 100%, 40%);">-            if (!lchan && bts->network->dyn_ts_allow_tch_f)</span><br><span style="color: hsl(0, 100%, 40%);">-                   lchan = _lc_dyn_find_bts(bts,</span><br><span style="color: hsl(0, 100%, 40%);">-                                            GSM_PCHAN_OSMO_DYN,</span><br><span style="color: hsl(0, 100%, 40%);">-                                             GSM_PCHAN_TCH_F, log);</span><br><span style="color: hsl(120, 100%, 40%);">+               lchan = _lchan_avail_tch_f(bts, NULL, log);</span><br><span>          break;</span><br><span>       case GSM_LCHAN_TCH_H:</span><br><span style="color: hsl(0, 100%, 40%);">-           lchan = _lc_find_bts(bts, GSM_PCHAN_TCH_H, log);</span><br><span style="color: hsl(0, 100%, 40%);">-                /* No dedicated TCH/x available -- try fully dynamic</span><br><span style="color: hsl(0, 100%, 40%);">-             * TCH/F_TCH/H_PDCH */</span><br><span style="color: hsl(0, 100%, 40%);">-          if (!lchan)</span><br><span style="color: hsl(0, 100%, 40%);">-                     lchan = _lc_dyn_find_bts(bts,</span><br><span style="color: hsl(0, 100%, 40%);">-                                            GSM_PCHAN_OSMO_DYN,</span><br><span style="color: hsl(0, 100%, 40%);">-                                             GSM_PCHAN_TCH_H, log);</span><br><span style="color: hsl(120, 100%, 40%);">+               lchan = _lchan_avail_tch_h(bts, NULL, log);</span><br><span>          break;</span><br><span>       default:</span><br><span>             LOG_BTS(bts, DRLL, LOGL_ERROR, "Unknown gsm_chan_t %u\n", type);</span><br><span>@@ -255,11 +350,11 @@</span><br><span> /* Return a matching lchan from a specific BTS that is currently available. The next logical step is</span><br><span>  * lchan_activate() on it, which would possibly cause dynamic timeslot pchan switching, taken care of by</span><br><span>  * the lchan and timeslot FSMs. */</span><br><span style="color: hsl(0, 100%, 40%);">-struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type)</span><br><span style="color: hsl(120, 100%, 40%);">+struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type, enum gsm_chan_t step2_type)</span><br><span> {</span><br><span>    struct gsm_lchan *lchan = NULL;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-     lchan = lchan_avail_by_type(bts, type, true);</span><br><span style="color: hsl(120, 100%, 40%);">+ lchan = lchan_avail_by_type(bts, type, step2_type, true);</span><br><span> </span><br><span>        LOG_BTS(bts, DRLL, LOGL_DEBUG, "lchan_select_by_type(%s)\n", gsm_lchant_name(type));</span><br><span> </span><br><span>diff --git a/tests/handover/handover_test.c b/tests/handover/handover_test.c</span><br><span>index 2ff9f31..15245eb 100644</span><br><span>--- a/tests/handover/handover_test.c</span><br><span>+++ b/tests/handover/handover_test.c</span><br><span>@@ -434,7 +434,7 @@</span><br><span> {</span><br><span>   struct gsm_lchan *lchan;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-    lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H);</span><br><span style="color: hsl(120, 100%, 40%);">+   lchan = lchan_select_by_type(bts, (full_rate) ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H, GSM_LCHAN_NONE);</span><br><span>  if (!lchan) {</span><br><span>                fprintf(stderr, "No resource for lchan\n");</span><br><span>                exit(EXIT_FAILURE);</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/c/osmo-bsc/+/24876">change 24876</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/c/osmo-bsc/+/24876"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: osmo-bsc </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-Change-Id: I3b32968949a7bdcbebf5a823359295bac51d8e08 </div>
<div style="display:none"> Gerrit-Change-Number: 24876 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: pespin <pespin@sysmocom.de> </div>
<div style="display:none"> Gerrit-MessageType: newchange </div>