<p>dexter has uploaded this change for <strong>review</strong>.</p><p><a href="https://gerrit.osmocom.org/12625">View Change</a></p><pre style="font-family: monospace,monospace; white-space: pre-wrap;">assignment_fsm: fix channel allocator preferences<br><br>When the MSC allocates a channel through the ASSIGNMENT REQUEST, it may<br>ask for a TCH/H and a TCH/F at the same time and tell which of the two<br>types it prefers.<br><br>The process of channel allocation currently selects, based on the BTS,<br>MSC and MS capabilites exactly one apropriate codec/rate (e.g. TCH/H)<br>and then trys to allocate it. If that allocation fails, there is no way<br>to try the second choice and the assignment fails.<br><br>For example: The MSC asks for TCH/F and TCH/H, prefering TCH/F, then the<br>channel allocator will try TCH/F and if it fails (all TCH/F are<br>currently in use), then TCH/H is never tried.<br><br>Since the BSC currently only trys the first best codec/rate that is<br>supported it also ignores the preference.<br><br>Lets fix those problems by including the preference information and both<br>possible codec/rate settings into the channel allocation decision.<br><br>Change-Id: I5239e05c1cfbcb8af28f43373a58fa6c2d216c51<br>Related: OS#3503<br>---<br>M include/osmocom/bsc/codec_pref.h<br>M include/osmocom/bsc/gsm_data.h<br>M src/osmo-bsc/abis_rsl.c<br>M src/osmo-bsc/assignment_fsm.c<br>M src/osmo-bsc/codec_pref.c<br>M src/osmo-bsc/handover_fsm.c<br>M src/osmo-bsc/osmo_bsc_bssap.c<br>M tests/codec_pref/codec_pref_test.c<br>8 files changed, 366 insertions(+), 136 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/25/12625/1</pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/codec_pref.h b/include/osmocom/bsc/codec_pref.h</span><br><span>index 51340c1..adefe04 100644</span><br><span>--- a/include/osmocom/bsc/codec_pref.h</span><br><span>+++ b/include/osmocom/bsc/codec_pref.h</span><br><span>@@ -9,14 +9,19 @@</span><br><span> struct bts_codec_conf;</span><br><span> struct bsc_msc_data;</span><br><span> struct gsm_bts;</span><br><span style="color: hsl(120, 100%, 40%);">+struct channel_mode_and_rate;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-int match_codec_pref(enum gsm48_chan_mode *chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">-                     bool *full_rate,</span><br><span style="color: hsl(0, 100%, 40%);">-                uint16_t *s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+enum rate_pref {</span><br><span style="color: hsl(120, 100%, 40%);">+      RATE_PREF_NONE,</span><br><span style="color: hsl(120, 100%, 40%);">+       RATE_PREF_HR,</span><br><span style="color: hsl(120, 100%, 40%);">+ RATE_PREF_FR,</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%);">+int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,</span><br><span>                     const struct gsm0808_channel_type *ct,</span><br><span>               const struct gsm0808_speech_codec_list *scl,</span><br><span>                 const struct bsc_msc_data *msc,</span><br><span style="color: hsl(0, 100%, 40%);">-                 const struct gsm_bts *bts);</span><br><span style="color: hsl(120, 100%, 40%);">+                   const struct gsm_bts *bts, enum rate_pref rate_pref);</span><br><span> </span><br><span> void gen_bss_supported_codec_list(struct gsm0808_speech_codec_list *scl,</span><br><span>                             const struct bsc_msc_data *msc,</span><br><span>diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h</span><br><span>index 22d80df..a161051 100644</span><br><span>--- a/include/osmocom/bsc/gsm_data.h</span><br><span>+++ b/include/osmocom/bsc/gsm_data.h</span><br><span>@@ -99,6 +99,12 @@</span><br><span>  SUBSCR_SCCP_ST_CONNECTED</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct channel_mode_and_rate {</span><br><span style="color: hsl(120, 100%, 40%);">+    enum gsm48_chan_mode chan_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+       bool full_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint16_t s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct assignment_request {</span><br><span>        bool aoip;</span><br><span> </span><br><span>@@ -107,9 +113,12 @@</span><br><span>        char msc_rtp_addr[INET_ADDRSTRLEN];</span><br><span>  uint16_t msc_rtp_port;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-      enum gsm48_chan_mode chan_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- bool full_rate;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Prefered rate/codec setting (mandatory) */</span><br><span style="color: hsl(120, 100%, 40%);">+ struct channel_mode_and_rate ch_mode_rate_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Alternate rate/codec setting (optional) */</span><br><span style="color: hsl(120, 100%, 40%);">+ bool ch_mode_rate_alt_present;</span><br><span style="color: hsl(120, 100%, 40%);">+        struct channel_mode_and_rate ch_mode_rate_alt;</span><br><span> };</span><br><span> </span><br><span> struct assignment_fsm_data {</span><br><span>@@ -282,6 +291,13 @@</span><br><span>              /* pointer to "other" connection, if Call Leg Relocation was successful */</span><br><span>                 struct gsm_subscriber_connection *other;</span><br><span>     } lcls;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Depending on the preferences that where submitted together with</span><br><span style="color: hsl(120, 100%, 40%);">+     * the assignment and the current channel load, the BSC has to select</span><br><span style="color: hsl(120, 100%, 40%);">+  * one of the offered codec/rates. The final selection by the BSC is</span><br><span style="color: hsl(120, 100%, 40%);">+   * stored here and is used when sending the assignment complete or</span><br><span style="color: hsl(120, 100%, 40%);">+     * when performing a handover procedure. */</span><br><span style="color: hsl(120, 100%, 40%);">+   struct channel_mode_and_rate ch_mode_rate;</span><br><span> };</span><br><span> </span><br><span> </span><br><span>diff --git a/src/osmo-bsc/abis_rsl.c b/src/osmo-bsc/abis_rsl.c</span><br><span>index d67573f..c1e6bf0 100644</span><br><span>--- a/src/osmo-bsc/abis_rsl.c</span><br><span>+++ b/src/osmo-bsc/abis_rsl.c</span><br><span>@@ -1375,22 +1375,12 @@</span><br><span>  /* check availability / allocate channel</span><br><span>      *</span><br><span>    * - First try to allocate SDCCH.</span><br><span style="color: hsl(0, 100%, 40%);">-        * - If SDCCH is not available, try whatever MS requested, if not SDCCH.</span><br><span style="color: hsl(0, 100%, 40%);">-         * - If there is still no channel available, reject channel request.</span><br><span style="color: hsl(120, 100%, 40%);">+   * - If SDCCH is not available, try to a TCH/H (less bandwith).</span><br><span style="color: hsl(120, 100%, 40%);">+        * - If there is still no channel available, try a TCH/F.</span><br><span>     *</span><br><span style="color: hsl(0, 100%, 40%);">-       * Note: If the MS requests not TCH/H, we don't know if the phone</span><br><span style="color: hsl(0, 100%, 40%);">-    *       supports TCH/H, so we must assign TCH/F or SDCCH.</span><br><span>    */</span><br><span>  lchan = lchan_select_by_type(bts, GSM_LCHAN_SDCCH);</span><br><span style="color: hsl(0, 100%, 40%);">-     if (!lchan && lctype != GSM_LCHAN_SDCCH) {</span><br><span style="color: hsl(0, 100%, 40%);">-              LOGP(DRSL, LOGL_NOTICE, "(bts=%d) CHAN RQD: no resources for %s "</span><br><span style="color: hsl(0, 100%, 40%);">-                     "0x%x, retrying with %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                   msg->lchan->ts->trx->bts->nr,</span><br><span style="color: hsl(0, 100%, 40%);">-                    gsm_lchant_name(GSM_LCHAN_SDCCH), rqd_ref->ra,</span><br><span style="color: hsl(0, 100%, 40%);">-                       gsm_lchant_name(lctype));</span><br><span style="color: hsl(0, 100%, 40%);">-               lchan = lchan_select_by_type(bts, lctype);</span><br><span style="color: hsl(0, 100%, 40%);">-      }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!lchan && lctype == GSM_LCHAN_SDCCH) {</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!lchan) {</span><br><span>                LOGP(DRSL, LOGL_NOTICE, "(bts=%d) CHAN RQD: no resources for %s "</span><br><span>                  "0x%x, retrying with %s\n",</span><br><span>                        msg->lchan->ts->trx->bts->nr,</span><br><span>@@ -1398,7 +1388,7 @@</span><br><span>                         gsm_lchant_name(GSM_LCHAN_TCH_H));</span><br><span>           lchan = lchan_select_by_type(bts, GSM_LCHAN_TCH_H);</span><br><span>  }</span><br><span style="color: hsl(0, 100%, 40%);">-       if (!lchan && lctype == GSM_LCHAN_SDCCH) {</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!lchan) {</span><br><span>                LOGP(DRSL, LOGL_NOTICE, "(bts=%d) CHAN RQD: no resources for %s "</span><br><span>                  "0x%x, retrying with %s\n",</span><br><span>                        msg->lchan->ts->trx->bts->nr,</span><br><span>diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c</span><br><span>index a24f7f9..d61b4bb 100644</span><br><span>--- a/src/osmo-bsc/assignment_fsm.c</span><br><span>+++ b/src/osmo-bsc/assignment_fsm.c</span><br><span>@@ -170,7 +170,7 @@</span><br><span>          if (gscon_is_aoip(conn)) {</span><br><span>                   /* Extrapolate speech codec from speech mode */</span><br><span>                      gsm0808_speech_codec_from_chan_type(&sc, perm_spch);</span><br><span style="color: hsl(0, 100%, 40%);">-                        sc.cfg = conn->assignment.req.s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+                      sc.cfg = conn->ch_mode_rate.s15_s0;</span><br><span>                       sc_ptr = &sc;</span><br><span>            }</span><br><span>    }</span><br><span>@@ -252,8 +252,11 @@</span><br><span> }</span><br><span> </span><br><span> static bool lchan_type_compat_with_mode(enum gsm_chan_t type,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      enum gsm48_chan_mode chan_mode, int full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+                                        struct channel_mode_and_rate *ch_mode_rate)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+      enum gsm48_chan_mode chan_mode = ch_mode_rate->chan_mode;</span><br><span style="color: hsl(120, 100%, 40%);">+  int full_rate = ch_mode_rate->full_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>        switch (chan_mode) {</span><br><span>         case GSM48_CMODE_SIGN:</span><br><span>               switch (type) {</span><br><span>@@ -296,6 +299,170 @@</span><br><span>      OSMO_ASSERT(osmo_fsm_register(&assignment_fsm) == 0);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Check if the incoming assignment requests requires a voice stream or not,</span><br><span style="color: hsl(120, 100%, 40%);">+ * we will look at the preferred and the alternate channel mode and also make</span><br><span style="color: hsl(120, 100%, 40%);">+ * sure that both are consistent. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int check_voice_stream_needed(struct gsm_subscriber_connection *conn, struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      bool result_alt = false;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool result_pref = false;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct assignment_request *req = &conn->assignment.req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      /* When the assignment request indicates that there is an alternate</span><br><span style="color: hsl(120, 100%, 40%);">+    * rate available (e.g. "Full or Half rate channel, Half rate</span><br><span style="color: hsl(120, 100%, 40%);">+     * preferred..."), then both must be either voice or either signalling,</span><br><span style="color: hsl(120, 100%, 40%);">+   * a mismatch is not permitted */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Check the prefered setting */</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (req->ch_mode_rate_pref.chan_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_CMODE_SPEECH_V1:</span><br><span style="color: hsl(120, 100%, 40%);">+   case GSM48_CMODE_SPEECH_EFR:</span><br><span style="color: hsl(120, 100%, 40%);">+  case GSM48_CMODE_SPEECH_AMR:</span><br><span style="color: hsl(120, 100%, 40%);">+          result_pref = true;</span><br><span style="color: hsl(120, 100%, 40%);">+           break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_CMODE_SIGN:</span><br><span style="color: hsl(120, 100%, 40%);">+                result_pref = false;</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%);">+              assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Prefered channel mode not supported: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                          gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+           return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+       }</span><br><span style="color: hsl(120, 100%, 40%);">+     conn->assignment.requires_voice_stream = result_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* If there is an alternate setting, check that one as well */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!req->ch_mode_rate_alt_present)</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     switch (req->ch_mode_rate_alt.chan_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case GSM48_CMODE_SPEECH_V1:</span><br><span style="color: hsl(120, 100%, 40%);">+   case GSM48_CMODE_SPEECH_EFR:</span><br><span style="color: hsl(120, 100%, 40%);">+  case GSM48_CMODE_SPEECH_AMR:</span><br><span style="color: hsl(120, 100%, 40%);">+          result_alt = true;</span><br><span style="color: hsl(120, 100%, 40%);">+            break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM48_CMODE_SIGN:</span><br><span style="color: hsl(120, 100%, 40%);">+                result_alt = false;</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%);">+              assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Alternate channel mode not supported: %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                         gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</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%);">+   /* Make sure both settings match */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (result_pref != result_alt) {</span><br><span style="color: hsl(120, 100%, 40%);">+              assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,</span><br><span style="color: hsl(120, 100%, 40%);">+                              "Inconsistent channel modes: %s != %s",</span><br><span style="color: hsl(120, 100%, 40%);">+                             gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                            gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+            return -EINVAL;</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%);">+   return 0;</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%);">+/* Check if the conn is already associated with an lchan. If yes, we will check</span><br><span style="color: hsl(120, 100%, 40%);">+ * if that lchan is compatible with the preferred rate/codec. If the lchan</span><br><span style="color: hsl(120, 100%, 40%);">+ * turns out to be incompatible we try with the alternate rate/codec. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int check_for_existing_lchan(struct gsm_subscriber_connection *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct assignment_request *req = &conn->assignment.req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!conn->lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* Check if the currently existing lchan is compatible with the</span><br><span style="color: hsl(120, 100%, 40%);">+        * preferred rate/codec. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_pref)) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (conn->lchan->tch_mode == req->ch_mode_rate_pref.chan_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     /* current lchan suffices and already is in the right mode. We're done. */</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOG_ASSIGNMENT(conn, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "Current lchan is compatible with requested chan_mode,"</span><br><span style="color: hsl(120, 100%, 40%);">+                                     " sending BSSMAP Assignment Complete directly."</span><br><span style="color: hsl(120, 100%, 40%);">+                                     " requested chan_mode=%s; current lchan is %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                   gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                                    gsm_lchan_name(conn->lchan));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     conn->ch_mode_rate = req->ch_mode_rate_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                  send_assignment_complete(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 1;</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%);">+           if (!req->ch_mode_rate_alt_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* FIXME: send Channel Mode Modify to put the current lchan in the right mode, and kick</span><br><span style="color: hsl(120, 100%, 40%);">+                        * off its RTP stream setup code path. See gsm48_lchan_modify() and</span><br><span style="color: hsl(120, 100%, 40%);">+                    * gsm48_rx_rr_modif_ack(), and see lchan_fsm.h LCHAN_EV_CHAN_MODE_MODIF_* */</span><br><span style="color: hsl(120, 100%, 40%);">+                 LOG_ASSIGNMENT(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "NOT IMPLEMENTED:"</span><br><span style="color: hsl(120, 100%, 40%);">+                                  " Current lchan would be compatible, we should send Channel Mode Modify\n");</span><br><span style="color: hsl(120, 100%, 40%);">+                 return 0;</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 style="color: hsl(120, 100%, 40%);">+   /* Exit early when no alternate choice for a rate/codec exists. */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!req->ch_mode_rate_alt_present)</span><br><span style="color: hsl(120, 100%, 40%);">+                return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* In cases where the prefered rate/codec does is not compatible,</span><br><span style="color: hsl(120, 100%, 40%);">+      * try the alternate rate/codec. */</span><br><span style="color: hsl(120, 100%, 40%);">+   if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_alt)) {</span><br><span style="color: hsl(120, 100%, 40%);">+            if (conn->lchan->tch_mode == req->ch_mode_rate_alt.chan_mode) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      /* current lchan suffices and already is in the right mode. We're done. */</span><br><span style="color: hsl(120, 100%, 40%);">+                        LOG_ASSIGNMENT(conn, LOGL_DEBUG,</span><br><span style="color: hsl(120, 100%, 40%);">+                                     "Current lchan is compatible with requested chan_mode,"</span><br><span style="color: hsl(120, 100%, 40%);">+                                     " sending BSSMAP Assignment Complete directly."</span><br><span style="color: hsl(120, 100%, 40%);">+                                     " requested chan_mode=%s; current lchan is %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                                   gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                                     gsm_lchan_name(conn->lchan));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                     conn->ch_mode_rate = req->ch_mode_rate_alt;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                   send_assignment_complete(conn);</span><br><span style="color: hsl(120, 100%, 40%);">+                       return 1;</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%);">+           /* FIXME: send Channel Mode Modify to put the current lchan in the right mode, and kick</span><br><span style="color: hsl(120, 100%, 40%);">+                * off its RTP stream setup code path. See gsm48_lchan_modify() and</span><br><span style="color: hsl(120, 100%, 40%);">+            * gsm48_rx_rr_modif_ack(), and see lchan_fsm.h LCHAN_EV_CHAN_MODE_MODIF_* */</span><br><span style="color: hsl(120, 100%, 40%);">+         LOG_ASSIGNMENT(conn, LOGL_ERROR,</span><br><span style="color: hsl(120, 100%, 40%);">+                             "NOT IMPLEMENTED:"</span><br><span style="color: hsl(120, 100%, 40%);">+                          " Current lchan would be compatible, we should send Channel Mode Modify\n");</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%);">+   return 0;</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%);">+/* Check if a new lchan finally exists, if not log the problem and inform the</span><br><span style="color: hsl(120, 100%, 40%);">+ * MSC by sending an BSSMAP assignment failure */</span><br><span style="color: hsl(120, 100%, 40%);">+static int check_new_lchan(struct gsm_subscriber_connection *conn, struct osmo_fsm_inst *fi)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     struct assignment_request *req = &conn->assignment.req;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!conn->assignment.new_lchan && req->ch_mode_rate_alt_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+             assignment_count_result(BSC_CTR_ASSIGNMENT_NO_CHANNEL);</span><br><span style="color: hsl(120, 100%, 40%);">+               assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "BSSMAP Assignment Command:"</span><br><span style="color: hsl(120, 100%, 40%);">+                                " No lchan available for: chan_mode_pref=%s, full_rate_pref=%i / chan_mode_alt=%s, full_rate_alt=%i\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                             get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                         req->ch_mode_rate_pref.full_rate, get_value_string(gsm48_chan_mode_names,</span><br><span style="color: hsl(120, 100%, 40%);">+                                                                             req->ch_mode_rate_alt.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                               req->ch_mode_rate_alt.full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+          return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+    } else if (!conn->assignment.new_lchan) {</span><br><span style="color: hsl(120, 100%, 40%);">+          assignment_count_result(BSC_CTR_ASSIGNMENT_NO_CHANNEL);</span><br><span style="color: hsl(120, 100%, 40%);">+               assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,</span><br><span style="color: hsl(120, 100%, 40%);">+                            "BSSMAP Assignment Command:"</span><br><span style="color: hsl(120, 100%, 40%);">+                                " No lchan available for: chan_mode=%s, full_rate=%i\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                            get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                         req->ch_mode_rate_pref.full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+         return -1;</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%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct gsm_bts *bts,</span><br><span>                       struct assignment_request *req)</span><br><span> {</span><br><span>@@ -314,75 +481,50 @@</span><br><span>       conn->assignment.fi = fi;</span><br><span>         fi->priv = conn;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+       /* Create a copy of the request data and use that copy from now on. */</span><br><span>       conn->assignment.req = *req;</span><br><span style="color: hsl(120, 100%, 40%);">+       req = &conn->assignment.req;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- switch (req->chan_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    case GSM48_CMODE_SPEECH_V1:</span><br><span style="color: hsl(0, 100%, 40%);">-     case GSM48_CMODE_SPEECH_EFR:</span><br><span style="color: hsl(0, 100%, 40%);">-    case GSM48_CMODE_SPEECH_AMR:</span><br><span style="color: hsl(0, 100%, 40%);">-            conn->assignment.requires_voice_stream = true;</span><br><span style="color: hsl(0, 100%, 40%);">-               /* Select an lchan below. */</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(0, 100%, 40%);">-  case GSM48_CMODE_SIGN:</span><br><span style="color: hsl(0, 100%, 40%);">-          conn->assignment.requires_voice_stream = false;</span><br><span style="color: hsl(0, 100%, 40%);">-              /* Select an lchan below. */</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(0, 100%, 40%);">-  default:</span><br><span style="color: hsl(0, 100%, 40%);">-                assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,</span><br><span style="color: hsl(0, 100%, 40%);">-                                "Channel mode not supported: %s",</span><br><span style="color: hsl(0, 100%, 40%);">-                             gsm48_chan_mode_name(req->chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Check if we need a voice stream. If yes, set the approriate struct</span><br><span style="color: hsl(120, 100%, 40%);">+  * members in conn */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (check_voice_stream_needed(conn, fi) < 0)</span><br><span>              return;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (conn->lchan</span><br><span style="color: hsl(0, 100%, 40%);">-          && lchan_type_compat_with_mode(conn->lchan->type, req->chan_mode, req->full_rate)) {</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            if (conn->lchan->tch_mode == req->chan_mode) {</span><br><span style="color: hsl(0, 100%, 40%);">-                 /* current lchan suffices and already is in the right mode. We're done. */</span><br><span style="color: hsl(0, 100%, 40%);">-                  LOG_ASSIGNMENT(conn, LOGL_DEBUG,</span><br><span style="color: hsl(0, 100%, 40%);">-                                       "Current lchan is compatible with requested chan_mode,"</span><br><span style="color: hsl(0, 100%, 40%);">-                                       " sending BSSMAP Assignment Complete directly."</span><br><span style="color: hsl(0, 100%, 40%);">-                                       " requested chan_mode=%s; current lchan is %s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                                     gsm48_chan_mode_name(req->chan_mode),</span><br><span style="color: hsl(0, 100%, 40%);">-                                gsm_lchan_name(conn->lchan));</span><br><span style="color: hsl(0, 100%, 40%);">-                 send_assignment_complete(conn);</span><br><span style="color: hsl(0, 100%, 40%);">-                 return;</span><br><span style="color: hsl(0, 100%, 40%);">-         }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-               /* FIXME: send Channel Mode Modify to put the current lchan in the right mode, and kick</span><br><span style="color: hsl(0, 100%, 40%);">-          * off its RTP stream setup code path. See gsm48_lchan_modify() and</span><br><span style="color: hsl(0, 100%, 40%);">-              * gsm48_rx_rr_modif_ack(), and see lchan_fsm.h LCHAN_EV_CHAN_MODE_MODIF_* */</span><br><span style="color: hsl(0, 100%, 40%);">-           LOG_ASSIGNMENT(conn, LOGL_ERROR,</span><br><span style="color: hsl(0, 100%, 40%);">-                               "NOT IMPLEMENTED:"</span><br><span style="color: hsl(0, 100%, 40%);">-                            " Current lchan would be compatible, we should send Channel Mode Modify\n");</span><br><span style="color: hsl(0, 100%, 40%);">-   }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-       conn->assignment.new_lchan = lchan_select_by_chan_mode(bts, req->chan_mode, req->full_rate);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-   if (!conn->assignment.new_lchan) {</span><br><span style="color: hsl(0, 100%, 40%);">-           assignment_count_result(BSC_CTR_ASSIGNMENT_NO_CHANNEL);</span><br><span style="color: hsl(0, 100%, 40%);">-         assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,</span><br><span style="color: hsl(0, 100%, 40%);">-                              "BSSMAP Assignment Command:"</span><br><span style="color: hsl(0, 100%, 40%);">-                          " No lchan available for: chan_mode=%s, full_rate=%i\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                              get_value_string(gsm48_chan_mode_names, req->chan_mode), req->full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+       /* There may be an already existing lchan, if yes, try to work with</span><br><span style="color: hsl(120, 100%, 40%);">+    * the existing lchan */</span><br><span style="color: hsl(120, 100%, 40%);">+      if (check_for_existing_lchan(conn))</span><br><span>          return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     /* Try to allocate a new lchan with the preferred codec/rate choice */</span><br><span style="color: hsl(120, 100%, 40%);">+        conn->assignment.new_lchan =</span><br><span style="color: hsl(120, 100%, 40%);">+           lchan_select_by_chan_mode(bts, req->ch_mode_rate_pref.chan_mode, req->ch_mode_rate_pref.full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+ conn->ch_mode_rate = req->ch_mode_rate_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  /* In case the lchan allocation fails, we try with the alternat</span><br><span style="color: hsl(120, 100%, 40%);">+        * codec/rate choice (if possible) */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!conn->assignment.new_lchan && req->ch_mode_rate_alt_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+             conn->assignment.new_lchan =</span><br><span style="color: hsl(120, 100%, 40%);">+                   lchan_select_by_chan_mode(bts, req->ch_mode_rate_alt.chan_mode, req->ch_mode_rate_alt.full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+           conn->ch_mode_rate = req->ch_mode_rate_alt;</span><br><span>    }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ /* Check whether the lchan allocation was successful or not and tear</span><br><span style="color: hsl(120, 100%, 40%);">+   * down the assignment in case of failure. */</span><br><span style="color: hsl(120, 100%, 40%);">+ if (check_new_lchan(conn, fi) < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+         return;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>    assignment_fsm_update_id(conn);</span><br><span>      LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, full_rate=%d,"</span><br><span>                        " aoip=%s MSC-rtp=%s:%u\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                   gsm48_chan_mode_name(req->chan_mode), req->full_rate,</span><br><span style="color: hsl(120, 100%, 40%);">+                   gsm48_chan_mode_name(conn->ch_mode_rate.chan_mode), conn->ch_mode_rate.full_rate,</span><br><span>                      req->aoip ? "yes" : "no", req->msc_rtp_addr, req->msc_rtp_port);</span><br><span> </span><br><span>     assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE);</span><br><span>   info = (struct lchan_activate_info){</span><br><span>                 .activ_for = FOR_ASSIGNMENT,</span><br><span>                 .for_conn = conn,</span><br><span style="color: hsl(0, 100%, 40%);">-               .chan_mode = req->chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">-         .s15_s0 = req->s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+             .chan_mode = conn->ch_mode_rate.chan_mode,</span><br><span style="color: hsl(120, 100%, 40%);">+         .s15_s0 = conn->ch_mode_rate.s15_s0,</span><br><span>              .requires_voice_stream = conn->assignment.requires_voice_stream,</span><br><span>          .msc_assigned_cic = req->msc_assigned_cic,</span><br><span>                .re_use_mgw_endpoint_from_lchan = conn->lchan,</span><br><span>diff --git a/src/osmo-bsc/codec_pref.c b/src/osmo-bsc/codec_pref.c</span><br><span>index c99c383..a94d6a8 100644</span><br><span>--- a/src/osmo-bsc/codec_pref.c</span><br><span>+++ b/src/osmo-bsc/codec_pref.c</span><br><span>@@ -266,21 +266,18 @@</span><br><span> </span><br><span> /*! Match the codec preferences from local config with a received codec preferences IEs received from the</span><br><span>  * MSC and the BTS' codec configuration.</span><br><span style="color: hsl(0, 100%, 40%);">- *  \param[out] chan_mode GSM 04.08 channel mode.</span><br><span style="color: hsl(0, 100%, 40%);">- *  \param[out] full_rate true if full-rate.</span><br><span style="color: hsl(0, 100%, 40%);">- *  \param[out] s15_s0 codec configuration bits S15-S0 (AMR)</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] ch_mode_rate resulting codec and rate information</span><br><span>  *  \param[in] ct GSM 08.08 channel type received from MSC.</span><br><span>  *  \param[in] scl GSM 08.08 speech codec list received from MSC (optional).</span><br><span>  *  \param[in] msc associated msc (current codec settings).</span><br><span>  *  \param[in] bts associated bts (current codec settings).</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] pref selected rate preference (full, half or none).</span><br><span>  *  \returns 0 on success, -1 in case no match was found */</span><br><span style="color: hsl(0, 100%, 40%);">-int match_codec_pref(enum gsm48_chan_mode *chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">-                 bool *full_rate,</span><br><span style="color: hsl(0, 100%, 40%);">-                uint16_t *s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,</span><br><span>                  const struct gsm0808_channel_type *ct,</span><br><span>               const struct gsm0808_speech_codec_list *scl,</span><br><span>                 const struct bsc_msc_data *msc,</span><br><span style="color: hsl(0, 100%, 40%);">-                 const struct gsm_bts *bts)</span><br><span style="color: hsl(120, 100%, 40%);">+                    const struct gsm_bts *bts, enum rate_pref rate_pref)</span><br><span> {</span><br><span>       unsigned int i;</span><br><span>      uint8_t perm_spch;</span><br><span>@@ -297,6 +294,18 @@</span><br><span>            /* Pick a permitted speech value from the global codec configuration list */</span><br><span>                 perm_spch = audio_support_to_gsm88(msc->audio_support[i]);</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+             /* Determine if the result is a half or full rate codec */</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = full_rate_from_perm_spch(&ch_mode_rate->full_rate, perm_spch);</span><br><span style="color: hsl(120, 100%, 40%);">+            if (rc < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             /* If we have a preference for FR or HR in our request, we</span><br><span style="color: hsl(120, 100%, 40%);">+             * discard the potential match */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rate_pref == RATE_PREF_HR && ch_mode_rate->full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+                  continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rate_pref == RATE_PREF_FR && !ch_mode_rate->full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+                 continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>          /* Check this permitted speech value against the BTS specific parameters.</span><br><span>             * if the BTS does not support the codec, try the next one */</span><br><span>                if (!test_codec_support_bts(bts, perm_spch))</span><br><span>@@ -312,19 +321,14 @@</span><br><span> </span><br><span>     /* Exit without result, in case no match can be deteched */</span><br><span>  if (!match) {</span><br><span style="color: hsl(0, 100%, 40%);">-           *full_rate = false;</span><br><span style="color: hsl(0, 100%, 40%);">-             *chan_mode = GSM48_CMODE_SIGN;</span><br><span style="color: hsl(0, 100%, 40%);">-          *s15_s0 = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+          ch_mode_rate->full_rate = false;</span><br><span style="color: hsl(120, 100%, 40%);">+           ch_mode_rate->chan_mode = GSM48_CMODE_SIGN;</span><br><span style="color: hsl(120, 100%, 40%);">+                ch_mode_rate->s15_s0 = 0;</span><br><span>                 return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Determine if the result is a half or full rate codec */</span><br><span style="color: hsl(0, 100%, 40%);">-      rc = full_rate_from_perm_spch(full_rate, perm_spch);</span><br><span style="color: hsl(0, 100%, 40%);">-    if (rc < 0)</span><br><span style="color: hsl(0, 100%, 40%);">-          return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>      /* Lookup a channel mode for the selected codec */</span><br><span style="color: hsl(0, 100%, 40%);">-      *chan_mode = gsm88_to_chan_mode(perm_spch);</span><br><span style="color: hsl(120, 100%, 40%);">+   ch_mode_rate->chan_mode = gsm88_to_chan_mode(perm_spch);</span><br><span> </span><br><span>      /* Special handling for AMR */</span><br><span>       if (perm_spch == GSM0808_PERM_HR3 || perm_spch == GSM0808_PERM_FR3) {</span><br><span>@@ -337,9 +341,9 @@</span><br><span>           * result */</span><br><span>                 amr_s15_s0_supported = gen_bss_supported_amr_s15_s0(msc, bts, (perm_spch == GSM0808_PERM_HR3));</span><br><span>              if (sc_match)</span><br><span style="color: hsl(0, 100%, 40%);">-                   *s15_s0 = sc_match->cfg & amr_s15_s0_supported;</span><br><span style="color: hsl(120, 100%, 40%);">+                        ch_mode_rate->s15_s0 = sc_match->cfg & amr_s15_s0_supported;</span><br><span>               else</span><br><span style="color: hsl(0, 100%, 40%);">-                    *s15_s0 = amr_s15_s0_supported;</span><br><span style="color: hsl(120, 100%, 40%);">+                       ch_mode_rate->s15_s0 = amr_s15_s0_supported;</span><br><span> </span><br><span>          /* NOTE: The function test_codec_pref() will populate the</span><br><span>             * sc_match pointer from the searched speech codec list. For</span><br><span>@@ -349,7 +353,7 @@</span><br><span>            * However s15_s0 is always populated with a meaningful value,</span><br><span>                * regardless if AoIP is in use or not. */</span><br><span>   } else</span><br><span style="color: hsl(0, 100%, 40%);">-          *s15_s0 = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+          ch_mode_rate->s15_s0 = 0;</span><br><span> </span><br><span>     return 0;</span><br><span> }</span><br><span>diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c</span><br><span>index 35f2e55..dc89ca4 100644</span><br><span>--- a/src/osmo-bsc/handover_fsm.c</span><br><span>+++ b/src/osmo-bsc/handover_fsm.c</span><br><span>@@ -521,10 +521,8 @@</span><br><span>       struct bsc_msc_data *msc = conn->sccp.msc;</span><br><span>        struct handover_in_req *req = &ho->inter_bsc_in;</span><br><span>      int match_idx;</span><br><span style="color: hsl(0, 100%, 40%);">-  enum gsm48_chan_mode mode;</span><br><span style="color: hsl(0, 100%, 40%);">-      bool full_rate = false;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t s15_s0;</span><br><span>     struct osmo_fsm_inst *fi;</span><br><span style="color: hsl(120, 100%, 40%);">+     struct channel_mode_and_rate ch_mode_rate = {};</span><br><span> </span><br><span>  handover_fsm_alloc(conn);</span><br><span> </span><br><span>@@ -562,7 +560,7 @@</span><br><span>                 bts->nr, req->cell_id_target_name);</span><br><span> </span><br><span>                 /* Figure out channel type */</span><br><span style="color: hsl(0, 100%, 40%);">-           if (match_codec_pref(&mode, &full_rate, &s15_s0, &req->ct, &req->scl, msc, bts)) {</span><br><span style="color: hsl(120, 100%, 40%);">+          if (match_codec_pref(&ch_mode_rate, &req->ct, &req->scl, msc, bts, RATE_PREF_NONE)) {</span><br><span>                      LOG_HO(conn, LOGL_DEBUG,</span><br><span>                            "BTS %u has no matching channel codec (%s, speech codec list len = %u)\n",</span><br><span>                         bts->nr, gsm0808_channel_type_name(&req->ct), req->scl.len);</span><br><span>@@ -570,10 +568,10 @@</span><br><span>             }</span><br><span> </span><br><span>                LOG_HO(conn, LOGL_DEBUG, "BTS %u: Found matching audio type: %s %s (for %s)\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                      bts->nr, gsm48_chan_mode_name(mode), full_rate? "full-rate" : "half-rate",</span><br><span style="color: hsl(120, 100%, 40%);">+                     bts->nr, gsm48_chan_mode_name(ch_mode_rate.chan_mode), ch_mode_rate.full_rate? "full-rate" : "half-rate",</span><br><span>                     gsm0808_channel_type_name(&req->ct));</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-         lchan = lchan_select_by_chan_mode(bts, mode, full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+              lchan = lchan_select_by_chan_mode(bts, ch_mode_rate.chan_mode, ch_mode_rate.full_rate);</span><br><span>              if (!lchan) {</span><br><span>                        LOG_HO(conn, LOGL_DEBUG, "BTS %u has no matching free channels\n", bts->nr);</span><br><span>                    continue;</span><br><span>@@ -605,9 +603,9 @@</span><br><span>      info = (struct lchan_activate_info){</span><br><span>                 .activ_for = FOR_HANDOVER,</span><br><span>           .for_conn = conn,</span><br><span style="color: hsl(0, 100%, 40%);">-               .chan_mode = mode,</span><br><span style="color: hsl(0, 100%, 40%);">-              .s15_s0 = s15_s0,</span><br><span style="color: hsl(0, 100%, 40%);">-               .requires_voice_stream = chan_mode_is_tch(mode),</span><br><span style="color: hsl(120, 100%, 40%);">+              .chan_mode = ch_mode_rate.chan_mode,</span><br><span style="color: hsl(120, 100%, 40%);">+          .s15_s0 = ch_mode_rate.s15_s0,</span><br><span style="color: hsl(120, 100%, 40%);">+                .requires_voice_stream = chan_mode_is_tch(ch_mode_rate.chan_mode),</span><br><span>           .msc_assigned_cic = req->msc_assigned_cic,</span><br><span>        };</span><br><span> </span><br><span>@@ -715,7 +713,7 @@</span><br><span>                 if (gscon_is_aoip(conn)) {</span><br><span>                   /* Extrapolate speech codec from speech mode */</span><br><span>                      gsm0808_speech_codec_from_chan_type(&sc, ho_perf_params.speech_version_chosen);</span><br><span style="color: hsl(0, 100%, 40%);">-                     sc.cfg = conn->assignment.req.s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+                      sc.cfg = conn->ch_mode_rate.s15_s0;</span><br><span>                       memcpy(&ho_perf_params.speech_codec_chosen, &sc, sizeof(sc));</span><br><span>                        ho_perf_params.speech_codec_chosen_present = true;</span><br><span>           }</span><br><span>diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>index f2ccf2c..7b3cd25 100644</span><br><span>--- a/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>+++ b/src/osmo-bsc/osmo_bsc_bssap.c</span><br><span>@@ -599,6 +599,97 @@</span><br><span>    return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+/* Select a prefered and an alternative codec rate depending on the available</span><br><span style="color: hsl(120, 100%, 40%);">+ * capabilities. This decision does not include the actual channel load yet,</span><br><span style="color: hsl(120, 100%, 40%);">+ * this is also the reason why the result is a prefered and an alternate</span><br><span style="color: hsl(120, 100%, 40%);">+ * setting. The final decision is made in assignment_fsm.c when the actual</span><br><span style="color: hsl(120, 100%, 40%);">+ * lchan is requested. The preferred lchan will be requested first. If we</span><br><span style="color: hsl(120, 100%, 40%);">+ * find an alternate setting here, this one will be tried secondly if our</span><br><span style="color: hsl(120, 100%, 40%);">+ * primary coice fails. */</span><br><span style="color: hsl(120, 100%, 40%);">+static int select_codec(struct assignment_request *req, struct gsm0808_channel_type *ct,</span><br><span style="color: hsl(120, 100%, 40%);">+                     struct gsm_subscriber_connection *conn)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       struct bsc_msc_data *msc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   msc = conn->sccp.msc;</span><br><span style="color: hsl(120, 100%, 40%);">+      req->ch_mode_rate_alt_present = false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   switch (ct->ch_rate_type & GSM0808_SPEECH_PERM) {</span><br><span style="color: hsl(120, 100%, 40%);">+      case GSM0808_DATA_FULL_BM:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                RATE_PREF_FR);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_DATA_HALF_LM:</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                RATE_PREF_HR);</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_DATA_FULL_RPREF:</span><br><span style="color: hsl(120, 100%, 40%);">+         rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                RATE_PREF_FR);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                        RATE_PREF_NONE);</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%);">+             rc = match_codec_pref(&req->ch_mode_rate_alt, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                 RATE_PREF_HR);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  req->ch_mode_rate_alt_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_DATA_HALF_PREF:</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                RATE_PREF_HR);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      rc = match_codec_pref(&req->ch_mode_rate_pref, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                        RATE_PREF_NONE);</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%);">+             rc = match_codec_pref(&req->ch_mode_rate_alt, ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span style="color: hsl(120, 100%, 40%);">+                                 RATE_PREF_FR);</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rc == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                  req->ch_mode_rate_alt_present = true;</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = 0;</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%);">+              rc = -EINVAL;</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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+              LOGP(DMSC, LOGL_ERROR, "No supported audio type found for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+                " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[%s] }\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                 ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span style="color: hsl(120, 100%, 40%);">+            /* TODO: actually output codec names, e.g. implement</span><br><span style="color: hsl(120, 100%, 40%);">+           * gsm0808_permitted_speech_names[] and iterate perm_spch. */</span><br><span style="color: hsl(120, 100%, 40%);">+         return -EINVAL;</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%);">+   if (req->ch_mode_rate_alt_present) {</span><br><span style="color: hsl(120, 100%, 40%);">+               DEBUGP(DMSC, "Found matching audio type (preferred): %s %s for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+                     " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(120, 100%, 40%);">+                  get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                 ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span style="color: hsl(120, 100%, 40%);">+          DEBUGP(DMSC, "Found matching audio type (alternative): %s %s for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+                   " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                req->ch_mode_rate_alt.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(120, 100%, 40%);">+                   get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_alt.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                  ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span style="color: hsl(120, 100%, 40%);">+  } else {</span><br><span style="color: hsl(120, 100%, 40%);">+              DEBUGP(DMSC, "Found matching audio type: %s %s for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+                 " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(120, 100%, 40%);">+                  get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                 ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</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 style="color: hsl(120, 100%, 40%);">+   return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*</span><br><span>  * Handle the assignment request message.</span><br><span>  *</span><br><span>@@ -608,18 +699,15 @@</span><br><span>                                   struct msgb *msg, unsigned int length)</span><br><span> {</span><br><span>     struct msgb *resp;</span><br><span style="color: hsl(0, 100%, 40%);">-      struct bsc_msc_data *msc;</span><br><span>    struct tlv_parsed tp;</span><br><span>        uint16_t cic = 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       enum gsm48_chan_mode chan_mode = GSM48_CMODE_SIGN;</span><br><span style="color: hsl(0, 100%, 40%);">-      bool full_rate = false;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t s15_s0 = 0;</span><br><span>         bool aoip = false;</span><br><span>   struct sockaddr_storage rtp_addr;</span><br><span>    struct gsm0808_channel_type ct;</span><br><span>      uint8_t cause;</span><br><span>       int rc;</span><br><span>      struct assignment_request req = {};</span><br><span style="color: hsl(120, 100%, 40%);">+   struct channel_mode_and_rate ch_mode_rate_pref = {};</span><br><span> </span><br><span>     if (!conn) {</span><br><span>                 LOGP(DMSC, LOGL_ERROR,</span><br><span>@@ -627,7 +715,6 @@</span><br><span>                 return -1;</span><br><span>   }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   msc = conn->sccp.msc;</span><br><span>     aoip = gscon_is_aoip(conn);</span><br><span> </span><br><span>      tlv_parse(&tp, gsm0808_att_tlvdef(), msg->l4h + 1, length - 1, 0, 0);</span><br><span>@@ -715,33 +802,19 @@</span><br><span>                         goto reject;</span><br><span>                 }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+         req = (struct assignment_request){</span><br><span style="color: hsl(120, 100%, 40%);">+                    .aoip = aoip,</span><br><span style="color: hsl(120, 100%, 40%);">+                 .msc_assigned_cic = cic,</span><br><span style="color: hsl(120, 100%, 40%);">+              };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                 /* Match codec information from the assignment command against the</span><br><span>            * local preferences of the BSC and BTS */</span><br><span style="color: hsl(0, 100%, 40%);">-              rc = match_codec_pref(&chan_mode, &full_rate, &s15_s0, &ct, &conn->codec_list,</span><br><span style="color: hsl(0, 100%, 40%);">-                                 msc, conn_get_bts(conn));</span><br><span style="color: hsl(120, 100%, 40%);">+               rc = select_codec(&req, &ct, conn);</span><br><span>          if (rc < 0) {</span><br><span style="color: hsl(0, 100%, 40%);">-                        LOGP(DMSC, LOGL_ERROR, "No supported audio type found for channel_type ="</span><br><span style="color: hsl(0, 100%, 40%);">-                          " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                          ct.ch_indctr, ct.ch_rate_type, osmo_hexdump(ct.perm_spch, ct.perm_spch_len));</span><br><span style="color: hsl(0, 100%, 40%);">-                      /* TODO: actually output codec names, e.g. implement</span><br><span style="color: hsl(0, 100%, 40%);">-                     * gsm0808_permitted_speech_names[] and iterate perm_spch. */</span><br><span>                        cause = GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_UNAVAIL;</span><br><span>                      goto reject;</span><br><span>                 }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-           DEBUGP(DMSC, "Found matching audio type: %s %s for channel_type ="</span><br><span style="color: hsl(0, 100%, 40%);">-                   " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  full_rate? "full rate" : "half rate",</span><br><span style="color: hsl(0, 100%, 40%);">-                       get_value_string(gsm48_chan_mode_names, chan_mode),</span><br><span style="color: hsl(0, 100%, 40%);">-                     ct.ch_indctr, ct.ch_rate_type, osmo_hexdump(ct.perm_spch, ct.perm_spch_len));</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            req = (struct assignment_request){</span><br><span style="color: hsl(0, 100%, 40%);">-                      .aoip = aoip,</span><br><span style="color: hsl(0, 100%, 40%);">-                   .msc_assigned_cic = cic,</span><br><span style="color: hsl(0, 100%, 40%);">-                        .chan_mode = chan_mode,</span><br><span style="color: hsl(0, 100%, 40%);">-                 .full_rate = full_rate,</span><br><span style="color: hsl(0, 100%, 40%);">-                 .s15_s0 = s15_s0</span><br><span style="color: hsl(0, 100%, 40%);">-                };</span><br><span>           if (aoip) {</span><br><span>                  unsigned int rc = osmo_sockaddr_to_str_and_uint(req.msc_rtp_addr,</span><br><span>                                                                    sizeof(req.msc_rtp_addr),</span><br><span>@@ -755,9 +828,13 @@</span><br><span>             }</span><br><span>            break;</span><br><span>       case GSM0808_CHAN_SIGN:</span><br><span style="color: hsl(120, 100%, 40%);">+               ch_mode_rate_pref = (struct channel_mode_and_rate) {</span><br><span style="color: hsl(120, 100%, 40%);">+                  .chan_mode = GSM48_CMODE_SIGN,</span><br><span style="color: hsl(120, 100%, 40%);">+                };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>                 req = (struct assignment_request){</span><br><span>                   .aoip = aoip,</span><br><span style="color: hsl(0, 100%, 40%);">-                   .chan_mode = chan_mode,</span><br><span style="color: hsl(120, 100%, 40%);">+                       .ch_mode_rate_pref = ch_mode_rate_pref,</span><br><span>              };</span><br><span>           break;</span><br><span>       default:</span><br><span>diff --git a/tests/codec_pref/codec_pref_test.c b/tests/codec_pref/codec_pref_test.c</span><br><span>index 534b99e..bb5468a 100644</span><br><span>--- a/tests/codec_pref/codec_pref_test.c</span><br><span>+++ b/tests/codec_pref/codec_pref_test.c</span><br><span>@@ -380,9 +380,7 @@</span><br><span> {</span><br><span>     int rc;</span><br><span>      unsigned int i;</span><br><span style="color: hsl(0, 100%, 40%);">- bool full_rate;</span><br><span style="color: hsl(0, 100%, 40%);">- enum gsm48_chan_mode chan_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- uint16_t s15_s0;</span><br><span style="color: hsl(120, 100%, 40%);">+      struct channel_mode_and_rate ch_mode_rate = { };</span><br><span> </span><br><span>         printf("Determining channel mode and rate:\n");</span><br><span> </span><br><span>@@ -407,9 +405,9 @@</span><br><span>  printf("   codec->efr=%u\n", bts->codec.efr);</span><br><span>        printf("   codec->amr=%u\n", bts->codec.amr);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-       rc = match_codec_pref(&chan_mode, &full_rate, &s15_s0, ct, scl, msc, bts);</span><br><span style="color: hsl(120, 100%, 40%);">+        rc = match_codec_pref(&ch_mode_rate, ct, scl, msc, bts, RATE_PREF_NONE);</span><br><span>         printf(" * result: rc=%i, full_rate=%i, s15_s0=%04x, chan_mode=%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-        rc, full_rate, s15_s0, gsm48_chan_mode_name(chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+              rc, ch_mode_rate.full_rate, ch_mode_rate.s15_s0, gsm48_chan_mode_name(ch_mode_rate.chan_mode));</span><br><span> </span><br><span>   printf("\n");</span><br><span> </span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/12625">change 12625</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/12625"/><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-MessageType: newchange </div>
<div style="display:none"> Gerrit-Change-Id: I5239e05c1cfbcb8af28f43373a58fa6c2d216c51 </div>
<div style="display:none"> Gerrit-Change-Number: 12625 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: dexter <pmaier@sysmocom.de> </div>