<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/13818">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved
  tnt: Looks good to me, but someone else must approve

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">assignment_fsm: Properly support assigning signalling mode TCH/x<br><br>To support the 3 possible preferences, the changes needed were:<br> - Replace 'full_rate' bool with a 3 option enum to represent<br>   the channels types for signalling<br> - Switch from _pref/_alt to using an array sorted in preference<br>   order<br><br>Originally merged as Change-Id I4c7499c8c866ea3ff7b1327edb3615d003d927d3,<br>reverted because the change broke voice calls. Re-submitting with the fix:<br>don't forget to set conn->assignment.requires_voice_stream.<br><br>Signed-off-by: Sylvain Munaut <tnt@246tNt.com><br>Change-Id: I7513d2cbe8b695ba6f031ad11560c63a6535cf2d<br>---<br>M include/osmocom/bsc/gsm_data.h<br>M include/osmocom/bsc/lchan_select.h<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/lchan_select.c<br>M src/osmo-bsc/osmo_bsc_bssap.c<br>M tests/codec_pref/codec_pref_test.c<br>8 files changed, 169 insertions(+), 133 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h</span><br><span>index dacc63b..dc686c3 100644</span><br><span>--- a/include/osmocom/bsc/gsm_data.h</span><br><span>+++ b/include/osmocom/bsc/gsm_data.h</span><br><span>@@ -98,9 +98,15 @@</span><br><span>     SUBSCR_SCCP_ST_CONNECTED</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+enum channel_rate {</span><br><span style="color: hsl(120, 100%, 40%);">+       CH_RATE_SDCCH,</span><br><span style="color: hsl(120, 100%, 40%);">+        CH_RATE_HALF,</span><br><span style="color: hsl(120, 100%, 40%);">+ CH_RATE_FULL,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct channel_mode_and_rate {</span><br><span>        enum gsm48_chan_mode chan_mode;</span><br><span style="color: hsl(0, 100%, 40%);">- bool full_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+       enum channel_rate chan_rate;</span><br><span>         uint16_t s15_s0;</span><br><span> };</span><br><span> </span><br><span>@@ -115,12 +121,9 @@</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%);">-      /* Prefered rate/codec setting (mandatory) */</span><br><span style="color: hsl(0, 100%, 40%);">-   struct channel_mode_and_rate ch_mode_rate_pref;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">- /* Alternate rate/codec setting (optional) */</span><br><span style="color: hsl(0, 100%, 40%);">-   bool ch_mode_rate_alt_present;</span><br><span style="color: hsl(0, 100%, 40%);">-  struct channel_mode_and_rate ch_mode_rate_alt;</span><br><span style="color: hsl(120, 100%, 40%);">+        /* Rate/codec setting in preference order (need at least 1 !) */</span><br><span style="color: hsl(120, 100%, 40%);">+      int n_ch_mode_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+   struct channel_mode_and_rate ch_mode_rate[3];</span><br><span> };</span><br><span> </span><br><span> /* State of an ongoing Assignment, while the assignment_fsm is still busy. This serves as state separation to keep the</span><br><span>diff --git a/include/osmocom/bsc/lchan_select.h b/include/osmocom/bsc/lchan_select.h</span><br><span>index 4aecdf6..865181b 100644</span><br><span>--- a/include/osmocom/bsc/lchan_select.h</span><br><span>+++ b/include/osmocom/bsc/lchan_select.h</span><br><span>@@ -3,4 +3,4 @@</span><br><span> </span><br><span> struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t type);</span><br><span> struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,</span><br><span style="color: hsl(0, 100%, 40%);">-                                      enum gsm48_chan_mode chan_mode, bool full_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+                                      enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate);</span><br><span>diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c</span><br><span>index fdfc080..834b58b 100644</span><br><span>--- a/src/osmo-bsc/assignment_fsm.c</span><br><span>+++ b/src/osmo-bsc/assignment_fsm.c</span><br><span>@@ -250,17 +250,15 @@</span><br><span> static bool lchan_type_compat_with_mode(enum gsm_chan_t type, const struct channel_mode_and_rate *ch_mode_rate)</span><br><span> {</span><br><span>   enum gsm48_chan_mode chan_mode = ch_mode_rate->chan_mode;</span><br><span style="color: hsl(0, 100%, 40%);">-    bool full_rate = ch_mode_rate->full_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+  enum channel_rate chan_rate = ch_mode_rate->chan_rate;</span><br><span> </span><br><span>        switch (chan_mode) {</span><br><span>         case GSM48_CMODE_SIGN:</span><br><span>               switch (type) {</span><br><span style="color: hsl(0, 100%, 40%);">-         case GSM_LCHAN_TCH_F:</span><br><span style="color: hsl(0, 100%, 40%);">-           case GSM_LCHAN_TCH_H:</span><br><span style="color: hsl(0, 100%, 40%);">-           case GSM_LCHAN_SDCCH:</span><br><span style="color: hsl(0, 100%, 40%);">-                   return true;</span><br><span style="color: hsl(0, 100%, 40%);">-            default:</span><br><span style="color: hsl(0, 100%, 40%);">-                        return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         case GSM_LCHAN_TCH_F: return chan_rate == CH_RATE_FULL;</span><br><span style="color: hsl(120, 100%, 40%);">+               case GSM_LCHAN_TCH_H: return chan_rate == CH_RATE_HALF;</span><br><span style="color: hsl(120, 100%, 40%);">+               case GSM_LCHAN_SDCCH: return chan_rate == CH_RATE_SDCCH;</span><br><span style="color: hsl(120, 100%, 40%);">+              default: return false;</span><br><span>               }</span><br><span> </span><br><span>        case GSM48_CMODE_SPEECH_V1:</span><br><span>@@ -268,12 +266,12 @@</span><br><span>  case GSM48_CMODE_DATA_3k6:</span><br><span>   case GSM48_CMODE_DATA_6k0:</span><br><span>           /* these services can all run on TCH/H, but we may have</span><br><span style="color: hsl(0, 100%, 40%);">-          * an explicit override by the 'full_rate' argument */</span><br><span style="color: hsl(120, 100%, 40%);">+                 * an explicit override by the 'chan_rate' argument */</span><br><span>               switch (type) {</span><br><span>              case GSM_LCHAN_TCH_F:</span><br><span style="color: hsl(0, 100%, 40%);">-                   return full_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+                     return chan_rate == CH_RATE_FULL;</span><br><span>            case GSM_LCHAN_TCH_H:</span><br><span style="color: hsl(0, 100%, 40%);">-                   return !full_rate;</span><br><span style="color: hsl(120, 100%, 40%);">+                    return chan_rate == CH_RATE_HALF;</span><br><span>            default:</span><br><span>                     return false;</span><br><span>                }</span><br><span>@@ -319,47 +317,37 @@</span><br><span>  * sure that both are consistent. */</span><br><span> static int check_requires_voice_stream(struct gsm_subscriber_connection *conn)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-        bool result_requires_voice_alt;</span><br><span style="color: hsl(0, 100%, 40%);">- bool result_requires_voice_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+      bool requires_voice_pref = false, requires_voice_alt;</span><br><span>        struct assignment_request *req = &conn->assignment.req;</span><br><span>       struct osmo_fsm_inst *fi = conn->fi;</span><br><span style="color: hsl(0, 100%, 40%);">- int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       int i, rc;</span><br><span> </span><br><span>       /* When the assignment request indicates that there is an alternate</span><br><span>   * rate available (e.g. "Full or Half rate channel, Half rate</span><br><span>    * preferred..."), then both must be either voice or either signalling,</span><br><span>          * a mismatch is not permitted */</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Check the prefered setting */</span><br><span style="color: hsl(0, 100%, 40%);">-        rc = check_requires_voice(&result_requires_voice_pref, req->ch_mode_rate_pref.chan_mode);</span><br><span style="color: hsl(0, 100%, 40%);">-        if (rc < 0) {</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%);">-                                "Prefered channel mode not supported: %s",</span><br><span style="color: hsl(0, 100%, 40%);">-                            gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode));</span><br><span style="color: hsl(0, 100%, 40%);">-             return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-       conn->assignment.requires_voice_stream = result_requires_voice_pref;</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < req->n_ch_mode_rate; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             rc = check_requires_voice(&requires_voice_alt, req->ch_mode_rate[i].chan_mode);</span><br><span style="color: hsl(120, 100%, 40%);">+                if (rc < 0) {</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%);">+                                      "Channel mode not supported (prev level %d): %s", i,</span><br><span style="color: hsl(120, 100%, 40%);">+                                        gsm48_chan_mode_name(req->ch_mode_rate[i].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> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* If there is an alternate setting, check that one as well */</span><br><span style="color: hsl(0, 100%, 40%);">-  if (!req->ch_mode_rate_alt_present)</span><br><span style="color: hsl(0, 100%, 40%);">-          return 0;</span><br><span style="color: hsl(0, 100%, 40%);">-       rc = check_requires_voice(&result_requires_voice_alt, req->ch_mode_rate_alt.chan_mode);</span><br><span style="color: hsl(0, 100%, 40%);">-  if (rc < 0) {</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%);">-                                "Alternate channel mode not supported: %s",</span><br><span style="color: hsl(0, 100%, 40%);">-                           gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));</span><br><span style="color: hsl(0, 100%, 40%);">-              return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               if (i==0)</span><br><span style="color: hsl(120, 100%, 40%);">+                     requires_voice_pref = requires_voice_alt;</span><br><span style="color: hsl(120, 100%, 40%);">+             else if (requires_voice_alt != requires_voice_pref) {</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[0].chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                                      gsm48_chan_mode_name(req->ch_mode_rate[i].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>    }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Make sure both settings match */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (result_requires_voice_pref != result_requires_voice_alt) {</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%);">-                                "Inconsistent channel modes: %s != %s",</span><br><span style="color: hsl(0, 100%, 40%);">-                               gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(0, 100%, 40%);">-                              gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));</span><br><span style="color: hsl(0, 100%, 40%);">-              return -EINVAL;</span><br><span style="color: hsl(0, 100%, 40%);">- }</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(120, 100%, 40%);">+     conn->assignment.requires_voice_stream = requires_voice_pref;</span><br><span>     return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -369,18 +357,20 @@</span><br><span> static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn)</span><br><span> {</span><br><span>  struct assignment_request *req = &conn->assignment.req;</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span> </span><br><span>   if (!conn->lchan)</span><br><span>                 return false;</span><br><span> </span><br><span>    /* Check if the currently existing lchan is compatible with the</span><br><span>       * preferred rate/codec. */</span><br><span style="color: hsl(0, 100%, 40%);">-     if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_pref))</span><br><span style="color: hsl(0, 100%, 40%);">-               conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;</span><br><span style="color: hsl(0, 100%, 40%);">-    else if (req->ch_mode_rate_alt_present</span><br><span style="color: hsl(0, 100%, 40%);">-                && lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate_alt))</span><br><span style="color: hsl(0, 100%, 40%);">-                conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;</span><br><span style="color: hsl(0, 100%, 40%);">-     else</span><br><span style="color: hsl(120, 100%, 40%);">+  for (i = 0; i < req->n_ch_mode_rate; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+               if (lchan_type_compat_with_mode(conn->lchan->type, &req->ch_mode_rate[i])) {</span><br><span style="color: hsl(120, 100%, 40%);">+                     conn->lchan->ch_mode_rate = req->ch_mode_rate[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%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   if (i == req->n_ch_mode_rate)</span><br><span>             return false;</span><br><span> </span><br><span>    if (conn->lchan->tch_mode != conn->lchan->ch_mode_rate.chan_mode) {</span><br><span>@@ -398,8 +388,14 @@</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 style="color: hsl(120, 100%, 40%);">+        static const char *rate_names[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+           [CH_RATE_SDCCH] = "SDCCH",</span><br><span style="color: hsl(120, 100%, 40%);">+          [CH_RATE_HALF] = "HR",</span><br><span style="color: hsl(120, 100%, 40%);">+              [CH_RATE_FULL] = "FR",</span><br><span style="color: hsl(120, 100%, 40%);">+      };</span><br><span>   struct osmo_fsm_inst *fi;</span><br><span>    struct lchan_activate_info info;</span><br><span style="color: hsl(120, 100%, 40%);">+      int i;</span><br><span> </span><br><span>   OSMO_ASSERT(conn);</span><br><span>   OSMO_ASSERT(conn->fi);</span><br><span>@@ -442,17 +438,13 @@</span><br><span>            return;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   /* Try to allocate a new lchan with the preferred codec/rate choice */</span><br><span style="color: hsl(0, 100%, 40%);">-  conn->assignment.new_lchan =</span><br><span style="color: hsl(0, 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(0, 100%, 40%);">-   conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-    /* In case the lchan allocation fails, we try with the alternat codec/</span><br><span style="color: hsl(0, 100%, 40%);">-   * rate choice (if possible) */</span><br><span style="color: hsl(0, 100%, 40%);">- if (!conn->assignment.new_lchan && req->ch_mode_rate_alt_present) {</span><br><span style="color: hsl(0, 100%, 40%);">-               conn->assignment.new_lchan =</span><br><span style="color: hsl(0, 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(0, 100%, 40%);">-             conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;</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 < req->n_ch_mode_rate; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+             conn->assignment.new_lchan = lchan_select_by_chan_mode(bts,</span><br><span style="color: hsl(120, 100%, 40%);">+                    req->ch_mode_rate[i].chan_mode, req->ch_mode_rate[i].chan_rate);</span><br><span style="color: hsl(120, 100%, 40%);">+            conn->lchan->ch_mode_rate = req->ch_mode_rate[i];</span><br><span style="color: hsl(120, 100%, 40%);">+            if (conn->assignment.new_lchan)</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span>       }</span><br><span> </span><br><span>        /* Check whether the lchan allocation was successful or not and tear</span><br><span>@@ -461,21 +453,22 @@</span><br><span>                 assignment_count_result(BSC_CTR_ASSIGNMENT_NO_CHANNEL);</span><br><span>              assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,</span><br><span>                           "BSSMAP Assignment Command:"</span><br><span style="color: hsl(0, 100%, 40%);">-                          " No lchan available for: preferred=%s%s / alternate=%s%s\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                         gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),</span><br><span style="color: hsl(0, 100%, 40%);">-                              req->ch_mode_rate_pref.full_rate ? ",FR" : ",HR",</span><br><span style="color: hsl(0, 100%, 40%);">-                                req->ch_mode_rate_alt_present ?</span><br><span style="color: hsl(0, 100%, 40%);">-                                      gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode) : "none",</span><br><span style="color: hsl(0, 100%, 40%);">-                            req->ch_mode_rate_alt_present ?</span><br><span style="color: hsl(0, 100%, 40%);">-                                      (req->ch_mode_rate_alt.full_rate ? ",FR" : ",HR") : "");</span><br><span style="color: hsl(120, 100%, 40%);">+                             " No lchan available for: pref=%s:%s / alt1=%s:%s / alt2=%s:%s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+                          gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode),</span><br><span style="color: hsl(120, 100%, 40%);">+                              rate_names[req->ch_mode_rate[0].chan_rate],</span><br><span style="color: hsl(120, 100%, 40%);">+                                req->n_ch_mode_rate >= 1 ? gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                              req->n_ch_mode_rate >= 1 ? rate_names[req->ch_mode_rate[0].chan_rate] : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                                req->n_ch_mode_rate >= 2 ? gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode) : "",</span><br><span style="color: hsl(120, 100%, 40%);">+                              req->n_ch_mode_rate >= 2 ? rate_names[req->ch_mode_rate[0].chan_rate] : ""</span><br><span style="color: hsl(120, 100%, 40%);">+         );</span><br><span>           return;</span><br><span>      }</span><br><span> </span><br><span>        assignment_fsm_update_id(conn);</span><br><span style="color: hsl(0, 100%, 40%);">- LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, full_rate=%d,"</span><br><span style="color: hsl(120, 100%, 40%);">+  LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, chan_type=%s,"</span><br><span>                        " aoip=%s MSC-rtp=%s:%u\n",</span><br><span>                        gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),</span><br><span style="color: hsl(0, 100%, 40%);">-                conn->lchan->ch_mode_rate.full_rate,</span><br><span style="color: hsl(120, 100%, 40%);">+                    rate_names[conn->lchan->ch_mode_rate.chan_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>diff --git a/src/osmo-bsc/codec_pref.c b/src/osmo-bsc/codec_pref.c</span><br><span>index 3e06114..b27defc 100644</span><br><span>--- a/src/osmo-bsc/codec_pref.c</span><br><span>+++ b/src/osmo-bsc/codec_pref.c</span><br><span>@@ -324,6 +324,7 @@</span><br><span> {</span><br><span>       unsigned int i;</span><br><span>      uint8_t perm_spch;</span><br><span style="color: hsl(120, 100%, 40%);">+    bool full_rate;</span><br><span>      bool match = false;</span><br><span>  const struct gsm0808_speech_codec *sc_match = NULL;</span><br><span>  int rc;</span><br><span>@@ -337,15 +338,16 @@</span><br><span>              perm_spch = audio_support_to_gsm88(msc->audio_support[i]);</span><br><span> </span><br><span>            /* 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(&ch_mode_rate->full_rate, perm_spch);</span><br><span style="color: hsl(120, 100%, 40%);">+            rc = full_rate_from_perm_spch(&full_rate, perm_spch);</span><br><span>            if (rc < 0)</span><br><span>                       return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+               ch_mode_rate->chan_rate = full_rate ? CH_RATE_FULL : CH_RATE_HALF;</span><br><span> </span><br><span>            /* If we have a preference for FR or HR in our request, we</span><br><span>            * discard the potential match */</span><br><span style="color: hsl(0, 100%, 40%);">-               if (rate_pref == RATE_PREF_HR && ch_mode_rate->full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+          if (rate_pref == RATE_PREF_HR && ch_mode_rate->chan_rate == CH_RATE_FULL)</span><br><span>                         continue;</span><br><span style="color: hsl(0, 100%, 40%);">-               if (rate_pref == RATE_PREF_FR && !ch_mode_rate->full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+         if (rate_pref == RATE_PREF_FR && ch_mode_rate->chan_rate == CH_RATE_HALF)</span><br><span>                         continue;</span><br><span> </span><br><span>                /* Check this permitted speech value against the BTS specific parameters.</span><br><span>@@ -375,8 +377,8 @@</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%);">-           ch_mode_rate->full_rate = false;</span><br><span>          ch_mode_rate->chan_mode = GSM48_CMODE_SIGN;</span><br><span style="color: hsl(120, 100%, 40%);">+                ch_mode_rate->chan_rate = CH_RATE_SDCCH;</span><br><span>          ch_mode_rate->s15_s0 = 0;</span><br><span>                 return -1;</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 0d1449f..c044407 100644</span><br><span>--- a/src/osmo-bsc/handover_fsm.c</span><br><span>+++ b/src/osmo-bsc/handover_fsm.c</span><br><span>@@ -582,10 +582,11 @@</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(ch_mode_rate.chan_mode), ch_mode_rate.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),</span><br><span style="color: hsl(120, 100%, 40%);">+                     ch_mode_rate.chan_rate == CH_RATE_FULL ?  "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, ch_mode_rate.chan_mode, ch_mode_rate.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.chan_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>diff --git a/src/osmo-bsc/lchan_select.c b/src/osmo-bsc/lchan_select.c</span><br><span>index 0f4dd65..0a9752e 100644</span><br><span>--- a/src/osmo-bsc/lchan_select.c</span><br><span>+++ b/src/osmo-bsc/lchan_select.c</span><br><span>@@ -128,22 +128,31 @@</span><br><span> }</span><br><span> </span><br><span> struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,</span><br><span style="color: hsl(0, 100%, 40%);">-                                     enum gsm48_chan_mode chan_mode, bool full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+                                       enum gsm48_chan_mode chan_mode, enum channel_rate chan_rate)</span><br><span> {</span><br><span>        enum gsm_chan_t type;</span><br><span> </span><br><span>    switch (chan_mode) {</span><br><span>         case GSM48_CMODE_SIGN:</span><br><span style="color: hsl(0, 100%, 40%);">-          type = GSM_LCHAN_SDCCH;</span><br><span style="color: hsl(120, 100%, 40%);">+               switch (chan_rate) {</span><br><span style="color: hsl(120, 100%, 40%);">+          case CH_RATE_SDCCH: type = GSM_LCHAN_SDCCH; break;</span><br><span style="color: hsl(120, 100%, 40%);">+            case CH_RATE_HALF:  type = GSM_LCHAN_TCH_H; break;</span><br><span style="color: hsl(120, 100%, 40%);">+            case CH_RATE_FULL:  type = GSM_LCHAN_TCH_F; break;</span><br><span style="color: hsl(120, 100%, 40%);">+            default: return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span>            break;</span><br><span>       case GSM48_CMODE_SPEECH_EFR:</span><br><span>                 /* EFR works over FR channels only */</span><br><span style="color: hsl(0, 100%, 40%);">-           if (!full_rate)</span><br><span style="color: hsl(120, 100%, 40%);">+               if (chan_rate != CH_RATE_FULL)</span><br><span>                       return NULL;</span><br><span>                 /* fall through */</span><br><span>   case GSM48_CMODE_SPEECH_V1:</span><br><span>  case GSM48_CMODE_SPEECH_AMR:</span><br><span style="color: hsl(0, 100%, 40%);">-            type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H;</span><br><span style="color: hsl(120, 100%, 40%);">+         switch (chan_rate) {</span><br><span style="color: hsl(120, 100%, 40%);">+          case CH_RATE_HALF:  type = GSM_LCHAN_TCH_H; break;</span><br><span style="color: hsl(120, 100%, 40%);">+            case CH_RATE_FULL:  type = GSM_LCHAN_TCH_F; break;</span><br><span style="color: hsl(120, 100%, 40%);">+            default: return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span>            break;</span><br><span>       default:</span><br><span>             return NULL;</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 2d5d4ae..470ae42 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>@@ -627,60 +627,48 @@</span><br><span> static int select_codecs(struct assignment_request *req, struct gsm0808_channel_type *ct,</span><br><span>                    struct gsm_subscriber_connection *conn)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">-   int rc;</span><br><span style="color: hsl(120, 100%, 40%);">+       int rc, i, nc = 0;</span><br><span>   struct bsc_msc_data *msc;</span><br><span> </span><br><span>        msc = conn->sccp.msc;</span><br><span style="color: hsl(0, 100%, 40%);">-        req->ch_mode_rate_alt_present = false;</span><br><span> </span><br><span>        switch (ct->ch_rate_type) {</span><br><span>       case GSM0808_SPEECH_FULL_BM:</span><br><span style="color: hsl(0, 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%);">+          rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span>                                RATE_PREF_FR);</span><br><span style="color: hsl(120, 100%, 40%);">+          nc += (rc == 0);</span><br><span>             break;</span><br><span>       case GSM0808_SPEECH_HALF_LM:</span><br><span style="color: hsl(0, 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%);">+          rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span>                                RATE_PREF_HR);</span><br><span style="color: hsl(120, 100%, 40%);">+          nc += (rc == 0);</span><br><span>             break;</span><br><span>       case GSM0808_SPEECH_PERM:</span><br><span>    case GSM0808_SPEECH_PERM_NO_CHANGE:</span><br><span>  case GSM0808_SPEECH_FULL_PREF_NO_CHANGE:</span><br><span>     case GSM0808_SPEECH_FULL_PREF:</span><br><span style="color: hsl(0, 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%);">+          rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span>                                RATE_PREF_FR);</span><br><span style="color: hsl(0, 100%, 40%);">-            if (rc < 0) {</span><br><span style="color: hsl(0, 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(0, 100%, 40%);">-                                          RATE_PREF_HR);</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%);">-               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%);">+           nc += (rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span>                                RATE_PREF_HR);</span><br><span style="color: hsl(0, 100%, 40%);">-            if (rc == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                    req->ch_mode_rate_alt_present = true;</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               nc += (rc == 0);</span><br><span>             break;</span><br><span>       case GSM0808_SPEECH_HALF_PREF_NO_CHANGE:</span><br><span>     case GSM0808_SPEECH_HALF_PREF:</span><br><span style="color: hsl(0, 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%);">+          rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span>                                RATE_PREF_HR);</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span style="color: hsl(0, 100%, 40%);">-            if (rc < 0) {</span><br><span style="color: hsl(0, 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(0, 100%, 40%);">-                                          RATE_PREF_FR);</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%);">-               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%);">+           nc += (rc == 0);</span><br><span style="color: hsl(120, 100%, 40%);">+              rc = match_codec_pref(&req->ch_mode_rate[nc], ct, &conn->codec_list, msc, conn_get_bts(conn),</span><br><span>                                RATE_PREF_FR);</span><br><span style="color: hsl(0, 100%, 40%);">-            if (rc == 0)</span><br><span style="color: hsl(0, 100%, 40%);">-                    req->ch_mode_rate_alt_present = true;</span><br><span style="color: hsl(0, 100%, 40%);">-                rc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+               nc += (rc == 0);</span><br><span>             break;</span><br><span>       default:</span><br><span>             rc = -EINVAL;</span><br><span>                break;</span><br><span>       }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+      if (!nc) {</span><br><span>           LOGP(DMSC, LOGL_ERROR, "No supported audio type found for channel_type ="</span><br><span>               " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[%s] }\n",</span><br><span>                ct->ch_indctr, ct->ch_rate_type, osmo_hexdump(ct->perm_spch, ct->perm_spch_len));</span><br><span>@@ -689,29 +677,69 @@</span><br><span>           return -EINVAL;</span><br><span>      }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-   if (req->ch_mode_rate_alt_present) {</span><br><span style="color: hsl(0, 100%, 40%);">-         DEBUGP(DMSC, "Found matching audio type (preferred): %s %s for channel_type ="</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0; i < nc; i++ ) {</span><br><span style="color: hsl(120, 100%, 40%);">+                DEBUGP(DMSC, "Found matching audio type (pref=%d): %s %s for channel_type ="</span><br><span>                      " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] }\n",</span><br><span style="color: hsl(0, 100%, 40%);">-                  req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(0, 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%);">+                 i,</span><br><span style="color: hsl(120, 100%, 40%);">+                    req->ch_mode_rate[i].chan_rate == CH_RATE_FULL ? "full rate" : "half rate",</span><br><span style="color: hsl(120, 100%, 40%);">+                    get_value_string(gsm48_chan_mode_names, req->ch_mode_rate[i].chan_mode),</span><br><span>                  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%);">-            DEBUGP(DMSC, "Found matching audio type (alternative): %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%);">-                  req->ch_mode_rate_alt.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(0, 100%, 40%);">-                     get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_alt.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%);">-    } else {</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%);">-                  req->ch_mode_rate_pref.full_rate ? "full rate" : "half rate",</span><br><span style="color: hsl(0, 100%, 40%);">-                    get_value_string(gsm48_chan_mode_names, req->ch_mode_rate_pref.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>         }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ req->n_ch_mode_rate = nc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span>       return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static int select_sign_chan(struct assignment_request *req, struct gsm0808_channel_type *ct)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int i, nc = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      switch (ct->ch_rate_type) {</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_SIGN_ANY:</span><br><span style="color: hsl(120, 100%, 40%);">+                req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;</span><br><span style="color: hsl(120, 100%, 40%);">+         req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;</span><br><span style="color: hsl(120, 100%, 40%);">+          req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_SIGN_SDCCH:</span><br><span style="color: hsl(120, 100%, 40%);">+              req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;</span><br><span style="color: hsl(120, 100%, 40%);">+         break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_SIGN_SDCCH_FULL_BM:</span><br><span style="color: hsl(120, 100%, 40%);">+              req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;</span><br><span style="color: hsl(120, 100%, 40%);">+         req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_SIGN_SDCCH_HALF_LM:</span><br><span style="color: hsl(120, 100%, 40%);">+              req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;</span><br><span style="color: hsl(120, 100%, 40%);">+         req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_SIGN_FULL_BM:</span><br><span style="color: hsl(120, 100%, 40%);">+            req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_SIGN_HALF_LM:</span><br><span style="color: hsl(120, 100%, 40%);">+            req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_SIGN_FULL_PREF:</span><br><span style="color: hsl(120, 100%, 40%);">+  case GSM0808_SIGN_FULL_PREF_NO_CHANGE:</span><br><span style="color: hsl(120, 100%, 40%);">+                req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;</span><br><span style="color: hsl(120, 100%, 40%);">+          req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;</span><br><span style="color: hsl(120, 100%, 40%);">+          break;</span><br><span style="color: hsl(120, 100%, 40%);">+        case GSM0808_SIGN_HALF_PREF:</span><br><span style="color: hsl(120, 100%, 40%);">+  case GSM0808_SIGN_HALF_PREF_NO_CHANGE:</span><br><span style="color: hsl(120, 100%, 40%);">+                req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;</span><br><span style="color: hsl(120, 100%, 40%);">+          req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;</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%);">+              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%);">+   for (i = 0; i < nc; i++)</span><br><span style="color: hsl(120, 100%, 40%);">+           req->ch_mode_rate[i].chan_mode = GSM48_CMODE_SIGN;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       req->n_ch_mode_rate = nc;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+        return nc > 0 ? 0 : -EINVAL;</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>@@ -729,7 +757,6 @@</span><br><span>  uint8_t cause;</span><br><span>       int rc;</span><br><span>      struct assignment_request req = {};</span><br><span style="color: hsl(0, 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>@@ -850,14 +877,15 @@</span><br><span>               }</span><br><span>            break;</span><br><span>       case GSM0808_CHAN_SIGN:</span><br><span style="color: hsl(0, 100%, 40%);">-         ch_mode_rate_pref = (struct channel_mode_and_rate) {</span><br><span style="color: hsl(0, 100%, 40%);">-                    .chan_mode = GSM48_CMODE_SIGN,</span><br><span style="color: hsl(0, 100%, 40%);">-          };</span><br><span style="color: hsl(0, 100%, 40%);">-</span><br><span>           req = (struct assignment_request){</span><br><span>                   .aoip = aoip,</span><br><span style="color: hsl(0, 100%, 40%);">-                   .ch_mode_rate_pref = ch_mode_rate_pref,</span><br><span>              };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          rc = select_sign_chan(&req, &ct);</span><br><span style="color: hsl(120, 100%, 40%);">+             if (rc < 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+                      cause = GSM0808_CAUSE_INCORRECT_VALUE;</span><br><span style="color: hsl(120, 100%, 40%);">+                        goto reject;</span><br><span style="color: hsl(120, 100%, 40%);">+          }</span><br><span>            break;</span><br><span>       default:</span><br><span>             cause = GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS;</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 bb5468a..ce82f3d 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>@@ -407,7 +407,7 @@</span><br><span> </span><br><span>       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, ch_mode_rate.full_rate, ch_mode_rate.s15_s0, gsm48_chan_mode_name(ch_mode_rate.chan_mode));</span><br><span style="color: hsl(120, 100%, 40%);">+               rc, ch_mode_rate.chan_rate == CH_RATE_FULL, 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/13818">change 13818</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/13818"/><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: merged </div>
<div style="display:none"> Gerrit-Change-Id: I7513d2cbe8b695ba6f031ad11560c63a6535cf2d </div>
<div style="display:none"> Gerrit-Change-Number: 13818 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder (1000002) </div>
<div style="display:none"> Gerrit-Reviewer: Neels Hofmeyr <nhofmeyr@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: tnt <tnt@246tNt.com> </div>