tnt has submitted this change and it was merged. ( 
https://gerrit.osmocom.org/13172 )

Change subject: assignment_fsm: Properly support assigning signalling mode TCH/x
......................................................................

assignment_fsm: Properly support assigning signalling mode TCH/x

To support the 3 possible preferences, the changes needed were:
 - Replace 'full_rate' bool with a 3 option enum to represent
   the channels types for signalling
 - Switch from _pref/_alt to using an array sorted in preference
   order

Change-Id: I4c7499c8c866ea3ff7b1327edb3615d003d927d3
Signed-off-by: Sylvain Munaut <t...@246tnt.com>
---
M include/osmocom/bsc/gsm_data.h
M include/osmocom/bsc/lchan_select.h
M src/osmo-bsc/assignment_fsm.c
M src/osmo-bsc/codec_pref.c
M src/osmo-bsc/handover_fsm.c
M src/osmo-bsc/lchan_select.c
M src/osmo-bsc/osmo_bsc_bssap.c
M tests/codec_pref/codec_pref_test.c
8 files changed, 168 insertions(+), 133 deletions(-)

Approvals:
  Harald Welte: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/include/osmocom/bsc/gsm_data.h b/include/osmocom/bsc/gsm_data.h
index c4315c0..fb0735a 100644
--- a/include/osmocom/bsc/gsm_data.h
+++ b/include/osmocom/bsc/gsm_data.h
@@ -98,9 +98,15 @@
        SUBSCR_SCCP_ST_CONNECTED
 };

+enum channel_rate {
+       CH_RATE_SDCCH,
+       CH_RATE_HALF,
+       CH_RATE_FULL,
+};
+
 struct channel_mode_and_rate {
        enum gsm48_chan_mode chan_mode;
-       bool full_rate;
+       enum channel_rate chan_rate;
        uint16_t s15_s0;
 };

@@ -115,12 +121,9 @@
        char msc_rtp_addr[INET_ADDRSTRLEN];
        uint16_t msc_rtp_port;

-       /* Prefered rate/codec setting (mandatory) */
-       struct channel_mode_and_rate ch_mode_rate_pref;
-
-       /* Alternate rate/codec setting (optional) */
-       bool ch_mode_rate_alt_present;
-       struct channel_mode_and_rate ch_mode_rate_alt;
+       /* Rate/codec setting in preference order (need at least 1 !) */
+       int n_ch_mode_rate;
+       struct channel_mode_and_rate ch_mode_rate[3];
 };

 /* State of an ongoing Assignment, while the assignment_fsm is still busy. 
This serves as state separation to keep the
diff --git a/include/osmocom/bsc/lchan_select.h 
b/include/osmocom/bsc/lchan_select.h
index 4aecdf6..865181b 100644
--- a/include/osmocom/bsc/lchan_select.h
+++ b/include/osmocom/bsc/lchan_select.h
@@ -3,4 +3,4 @@

 struct gsm_lchan *lchan_select_by_type(struct gsm_bts *bts, enum gsm_chan_t 
type);
 struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
-                                           enum gsm48_chan_mode chan_mode, 
bool full_rate);
+                                           enum gsm48_chan_mode chan_mode, 
enum channel_rate chan_rate);
diff --git a/src/osmo-bsc/assignment_fsm.c b/src/osmo-bsc/assignment_fsm.c
index aa696ac..2180791 100644
--- a/src/osmo-bsc/assignment_fsm.c
+++ b/src/osmo-bsc/assignment_fsm.c
@@ -251,17 +251,15 @@
 static bool lchan_type_compat_with_mode(enum gsm_chan_t type, const struct 
channel_mode_and_rate *ch_mode_rate)
 {
        enum gsm48_chan_mode chan_mode = ch_mode_rate->chan_mode;
-       bool full_rate = ch_mode_rate->full_rate;
+       enum channel_rate chan_rate = ch_mode_rate->chan_rate;

        switch (chan_mode) {
        case GSM48_CMODE_SIGN:
                switch (type) {
-               case GSM_LCHAN_TCH_F:
-               case GSM_LCHAN_TCH_H:
-               case GSM_LCHAN_SDCCH:
-                       return true;
-               default:
-                       return false;
+               case GSM_LCHAN_TCH_F: return chan_rate == CH_RATE_FULL;
+               case GSM_LCHAN_TCH_H: return chan_rate == CH_RATE_HALF;
+               case GSM_LCHAN_SDCCH: return chan_rate == CH_RATE_SDCCH;
+               default: return false;
                }

        case GSM48_CMODE_SPEECH_V1:
@@ -269,12 +267,12 @@
        case GSM48_CMODE_DATA_3k6:
        case GSM48_CMODE_DATA_6k0:
                /* these services can all run on TCH/H, but we may have
-                * an explicit override by the 'full_rate' argument */
+                * an explicit override by the 'chan_rate' argument */
                switch (type) {
                case GSM_LCHAN_TCH_F:
-                       return full_rate;
+                       return chan_rate == CH_RATE_FULL;
                case GSM_LCHAN_TCH_H:
-                       return !full_rate;
+                       return chan_rate == CH_RATE_HALF;
                default:
                        return false;
                }
@@ -320,45 +318,34 @@
  * sure that both are consistent. */
 static int check_requires_voice_stream(struct gsm_subscriber_connection *conn)
 {
-       bool result_requires_voice_alt;
-       bool result_requires_voice_pref;
+       bool requires_voice_pref = false, requires_voice_alt;
        struct assignment_request *req = &conn->assignment.req;
        struct osmo_fsm_inst *fi = conn->fi;
-       int rc;
+       int i, rc;

        /* When the assignment request indicates that there is an alternate
         * rate available (e.g. "Full or Half rate channel, Half rate
         * preferred..."), then both must be either voice or either signalling,
         * a mismatch is not permitted */

-       /* Check the prefered setting */
-       rc = check_requires_voice(&result_requires_voice_pref, 
req->ch_mode_rate_pref.chan_mode);
-       if (rc < 0) {
-               assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
-                               "Prefered channel mode not supported: %s",
-                               
gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode));
-               return -EINVAL;
-       }
-       conn->assignment.requires_voice_stream = result_requires_voice_pref;
+       for (i = 0; i < req->n_ch_mode_rate; i++) {
+               rc = check_requires_voice(&requires_voice_alt, 
req->ch_mode_rate[i].chan_mode);
+               if (rc < 0) {
+                       
assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
+                                       "Channel mode not supported (prev level 
%d): %s", i,
+                                       
gsm48_chan_mode_name(req->ch_mode_rate[i].chan_mode));
+                       return -EINVAL;
+               }

-       /* If there is an alternate setting, check that one as well */
-       if (!req->ch_mode_rate_alt_present)
-               return 0;
-       rc = check_requires_voice(&result_requires_voice_alt, 
req->ch_mode_rate_alt.chan_mode);
-       if (rc < 0) {
-               assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
-                               "Alternate channel mode not supported: %s",
-                               
gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));
-               return -EINVAL;
-       }
-
-       /* Make sure both settings match */
-       if (result_requires_voice_pref != result_requires_voice_alt) {
-               assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
-                               "Inconsistent channel modes: %s != %s",
-                               
gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),
-                               
gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode));
-               return -EINVAL;
+               if (i==0)
+                       requires_voice_pref = requires_voice_alt;
+               else if (requires_voice_alt != requires_voice_pref) {
+                       
assignment_fail(GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP,
+                                       "Inconsistent channel modes: %s != %s",
+                                       
gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode),
+                                       
gsm48_chan_mode_name(req->ch_mode_rate[i].chan_mode));
+                       return -EINVAL;
+               }
        }

        return 0;
@@ -370,18 +357,20 @@
 static bool reuse_existing_lchan(struct gsm_subscriber_connection *conn)
 {
        struct assignment_request *req = &conn->assignment.req;
+       int i;

        if (!conn->lchan)
                return false;

        /* Check if the currently existing lchan is compatible with the
         * preferred rate/codec. */
-       if (lchan_type_compat_with_mode(conn->lchan->type, 
&req->ch_mode_rate_pref))
-               conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;
-       else if (req->ch_mode_rate_alt_present
-                && lchan_type_compat_with_mode(conn->lchan->type, 
&req->ch_mode_rate_alt))
-               conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;
-       else
+       for (i = 0; i < req->n_ch_mode_rate; i++)
+               if (lchan_type_compat_with_mode(conn->lchan->type, 
&req->ch_mode_rate[i])) {
+                       conn->lchan->ch_mode_rate = req->ch_mode_rate[i];
+                       break;
+               }
+
+       if (i == req->n_ch_mode_rate)
                return false;
 
        if (conn->lchan->tch_mode != conn->lchan->ch_mode_rate.chan_mode) {
@@ -399,8 +388,14 @@
 void assignment_fsm_start(struct gsm_subscriber_connection *conn, struct 
gsm_bts *bts,
                          struct assignment_request *req)
 {
+       static const char *rate_names[] = {
+               [CH_RATE_SDCCH] = "SDCCH",
+               [CH_RATE_HALF] = "HR",
+               [CH_RATE_FULL] = "FR",
+       };
        struct osmo_fsm_inst *fi;
        struct lchan_activate_info info;
+       int i;

        OSMO_ASSERT(conn);
        OSMO_ASSERT(conn->fi);
@@ -443,17 +438,13 @@
                return;
        }

-       /* Try to allocate a new lchan with the preferred codec/rate choice */
-       conn->assignment.new_lchan =
-           lchan_select_by_chan_mode(bts, req->ch_mode_rate_pref.chan_mode, 
req->ch_mode_rate_pref.full_rate);
-       conn->lchan->ch_mode_rate = req->ch_mode_rate_pref;
-
-       /* In case the lchan allocation fails, we try with the alternat codec/
-        * rate choice (if possible) */
-       if (!conn->assignment.new_lchan && req->ch_mode_rate_alt_present) {
-               conn->assignment.new_lchan =
-                   lchan_select_by_chan_mode(bts, 
req->ch_mode_rate_alt.chan_mode, req->ch_mode_rate_alt.full_rate);
-               conn->lchan->ch_mode_rate = req->ch_mode_rate_alt;
+       /* Try to allocate a new lchan in order of preference */
+       for (i = 0; i < req->n_ch_mode_rate; i++) {
+               conn->assignment.new_lchan = lchan_select_by_chan_mode(bts,
+                   req->ch_mode_rate[i].chan_mode, 
req->ch_mode_rate[i].chan_rate);
+               conn->lchan->ch_mode_rate = req->ch_mode_rate[i];
+               if (conn->assignment.new_lchan)
+                       break;
        }

        /* Check whether the lchan allocation was successful or not and tear
@@ -462,21 +453,22 @@
                assignment_count_result(BSC_CTR_ASSIGNMENT_NO_CHANNEL);
                assignment_fail(GSM0808_CAUSE_NO_RADIO_RESOURCE_AVAILABLE,
                                "BSSMAP Assignment Command:"
-                               " No lchan available for: preferred=%s%s / 
alternate=%s%s\n",
-                               
gsm48_chan_mode_name(req->ch_mode_rate_pref.chan_mode),
-                               req->ch_mode_rate_pref.full_rate ? ",FR" : 
",HR",
-                               req->ch_mode_rate_alt_present ?
-                                       
gsm48_chan_mode_name(req->ch_mode_rate_alt.chan_mode) : "none",
-                               req->ch_mode_rate_alt_present ?
-                                       (req->ch_mode_rate_alt.full_rate ? 
",FR" : ",HR") : "");
+                               " No lchan available for: pref=%s:%s / 
alt1=%s:%s / alt2=%s:%s\n",
+                               
gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode),
+                               rate_names[req->ch_mode_rate[0].chan_rate],
+                               req->n_ch_mode_rate >= 1 ? 
gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode) : "",
+                               req->n_ch_mode_rate >= 1 ? 
rate_names[req->ch_mode_rate[0].chan_rate] : "",
+                               req->n_ch_mode_rate >= 2 ? 
gsm48_chan_mode_name(req->ch_mode_rate[0].chan_mode) : "",
+                               req->n_ch_mode_rate >= 2 ? 
rate_names[req->ch_mode_rate[0].chan_rate] : ""
+               );
                return;
        }

        assignment_fsm_update_id(conn);
-       LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, 
full_rate=%d,"
+       LOG_ASSIGNMENT(conn, LOGL_INFO, "Starting Assignment: chan_mode=%s, 
chan_type=%s,"
                       " aoip=%s MSC-rtp=%s:%u\n",
                       
gsm48_chan_mode_name(conn->lchan->ch_mode_rate.chan_mode),
-                      conn->lchan->ch_mode_rate.full_rate,
+                      rate_names[conn->lchan->ch_mode_rate.chan_rate],
                       req->aoip ? "yes" : "no", req->msc_rtp_addr, 
req->msc_rtp_port);

        assignment_fsm_state_chg(ASSIGNMENT_ST_WAIT_LCHAN_ACTIVE);
diff --git a/src/osmo-bsc/codec_pref.c b/src/osmo-bsc/codec_pref.c
index a94d6a8..659853c 100644
--- a/src/osmo-bsc/codec_pref.c
+++ b/src/osmo-bsc/codec_pref.c
@@ -281,6 +281,7 @@
 {
        unsigned int i;
        uint8_t perm_spch;
+       bool full_rate;
        bool match = false;
        const struct gsm0808_speech_codec *sc_match = NULL;
        uint16_t amr_s15_s0_supported;
@@ -295,15 +296,16 @@
                perm_spch = audio_support_to_gsm88(msc->audio_support[i]);

                /* Determine if the result is a half or full rate codec */
-               rc = full_rate_from_perm_spch(&ch_mode_rate->full_rate, 
perm_spch);
+               rc = full_rate_from_perm_spch(&full_rate, perm_spch);
                if (rc < 0)
                        return -EINVAL;
+               ch_mode_rate->chan_rate = full_rate ? CH_RATE_FULL : 
CH_RATE_HALF;

                /* If we have a preference for FR or HR in our request, we
                 * discard the potential match */
-               if (rate_pref == RATE_PREF_HR && ch_mode_rate->full_rate)
+               if (rate_pref == RATE_PREF_HR && ch_mode_rate->chan_rate == 
CH_RATE_FULL)
                        continue;
-               if (rate_pref == RATE_PREF_FR && !ch_mode_rate->full_rate)
+               if (rate_pref == RATE_PREF_FR && ch_mode_rate->chan_rate == 
CH_RATE_HALF)
                        continue;

                /* Check this permitted speech value against the BTS specific 
parameters.
@@ -321,8 +323,8 @@

        /* Exit without result, in case no match can be deteched */
        if (!match) {
-               ch_mode_rate->full_rate = false;
                ch_mode_rate->chan_mode = GSM48_CMODE_SIGN;
+               ch_mode_rate->chan_rate = CH_RATE_SDCCH;
                ch_mode_rate->s15_s0 = 0;
                return -1;
        }
diff --git a/src/osmo-bsc/handover_fsm.c b/src/osmo-bsc/handover_fsm.c
index a3d25d6..77f8138 100644
--- a/src/osmo-bsc/handover_fsm.c
+++ b/src/osmo-bsc/handover_fsm.c
@@ -569,10 +569,11 @@
                }

                LOG_HO(conn, LOGL_DEBUG, "BTS %u: Found matching audio type: %s 
%s (for %s)\n",
-                      bts->nr, gsm48_chan_mode_name(ch_mode_rate.chan_mode), 
ch_mode_rate.full_rate? "full-rate" : "half-rate",
+                      bts->nr, gsm48_chan_mode_name(ch_mode_rate.chan_mode),
+                      ch_mode_rate.chan_rate == CH_RATE_FULL ?  "full-rate" : 
"half-rate",
                       gsm0808_channel_type_name(&req->ct));

-               lchan = lchan_select_by_chan_mode(bts, ch_mode_rate.chan_mode, 
ch_mode_rate.full_rate);
+               lchan = lchan_select_by_chan_mode(bts, ch_mode_rate.chan_mode, 
ch_mode_rate.chan_rate);
                if (!lchan) {
                        LOG_HO(conn, LOGL_DEBUG, "BTS %u has no matching free 
channels\n", bts->nr);
                        continue;
diff --git a/src/osmo-bsc/lchan_select.c b/src/osmo-bsc/lchan_select.c
index 0f4dd65..0a9752e 100644
--- a/src/osmo-bsc/lchan_select.c
+++ b/src/osmo-bsc/lchan_select.c
@@ -128,22 +128,31 @@
 }

 struct gsm_lchan *lchan_select_by_chan_mode(struct gsm_bts *bts,
-                                           enum gsm48_chan_mode chan_mode, 
bool full_rate)
+                                           enum gsm48_chan_mode chan_mode, 
enum channel_rate chan_rate)
 {
        enum gsm_chan_t type;

        switch (chan_mode) {
        case GSM48_CMODE_SIGN:
-               type = GSM_LCHAN_SDCCH;
+               switch (chan_rate) {
+               case CH_RATE_SDCCH: type = GSM_LCHAN_SDCCH; break;
+               case CH_RATE_HALF:  type = GSM_LCHAN_TCH_H; break;
+               case CH_RATE_FULL:  type = GSM_LCHAN_TCH_F; break;
+               default: return NULL;
+               }
                break;
        case GSM48_CMODE_SPEECH_EFR:
                /* EFR works over FR channels only */
-               if (!full_rate)
+               if (chan_rate != CH_RATE_FULL)
                        return NULL;
                /* fall through */
        case GSM48_CMODE_SPEECH_V1:
        case GSM48_CMODE_SPEECH_AMR:
-               type = full_rate ? GSM_LCHAN_TCH_F : GSM_LCHAN_TCH_H;
+               switch (chan_rate) {
+               case CH_RATE_HALF:  type = GSM_LCHAN_TCH_H; break;
+               case CH_RATE_FULL:  type = GSM_LCHAN_TCH_F; break;
+               default: return NULL;
+               }
                break;
        default:
                return NULL;
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 85aab22..5c8ce97 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -626,60 +626,48 @@
 static int select_codecs(struct assignment_request *req, struct 
gsm0808_channel_type *ct,
                         struct gsm_subscriber_connection *conn)
 {
-       int rc;
+       int rc, i, nc = 0;
        struct bsc_msc_data *msc;

        msc = conn->sccp.msc;
-       req->ch_mode_rate_alt_present = false;

        switch (ct->ch_rate_type) {
        case GSM0808_SPEECH_FULL_BM:
-               rc = match_codec_pref(&req->ch_mode_rate_pref, ct, 
&conn->codec_list, msc, conn_get_bts(conn),
+               rc = match_codec_pref(&req->ch_mode_rate[nc], ct, 
&conn->codec_list, msc, conn_get_bts(conn),
                                      RATE_PREF_FR);
+               nc += (rc == 0);
                break;
        case GSM0808_SPEECH_HALF_LM:
-               rc = match_codec_pref(&req->ch_mode_rate_pref, ct, 
&conn->codec_list, msc, conn_get_bts(conn),
+               rc = match_codec_pref(&req->ch_mode_rate[nc], ct, 
&conn->codec_list, msc, conn_get_bts(conn),
                                      RATE_PREF_HR);
+               nc += (rc == 0);
                break;
        case GSM0808_SPEECH_PERM:
        case GSM0808_SPEECH_PERM_NO_CHANGE:
        case GSM0808_SPEECH_FULL_PREF_NO_CHANGE:
        case GSM0808_SPEECH_FULL_PREF:
-               rc = match_codec_pref(&req->ch_mode_rate_pref, ct, 
&conn->codec_list, msc, conn_get_bts(conn),
+               rc = match_codec_pref(&req->ch_mode_rate[nc], ct, 
&conn->codec_list, msc, conn_get_bts(conn),
                                      RATE_PREF_FR);
-               if (rc < 0) {
-                       rc = match_codec_pref(&req->ch_mode_rate_pref, ct, 
&conn->codec_list, msc, conn_get_bts(conn),
-                                             RATE_PREF_HR);
-                       break;
-               }
-               rc = match_codec_pref(&req->ch_mode_rate_alt, ct, 
&conn->codec_list, msc, conn_get_bts(conn),
+               nc += (rc == 0);
+               rc = match_codec_pref(&req->ch_mode_rate[nc], ct, 
&conn->codec_list, msc, conn_get_bts(conn),
                                      RATE_PREF_HR);
-               if (rc == 0)
-                       req->ch_mode_rate_alt_present = true;
-               rc = 0;
+               nc += (rc == 0);
                break;
        case GSM0808_SPEECH_HALF_PREF_NO_CHANGE:
        case GSM0808_SPEECH_HALF_PREF:
-               rc = match_codec_pref(&req->ch_mode_rate_pref, ct, 
&conn->codec_list, msc, conn_get_bts(conn),
+               rc = match_codec_pref(&req->ch_mode_rate[nc], ct, 
&conn->codec_list, msc, conn_get_bts(conn),
                                      RATE_PREF_HR);
-
-               if (rc < 0) {
-                       rc = match_codec_pref(&req->ch_mode_rate_pref, ct, 
&conn->codec_list, msc, conn_get_bts(conn),
-                                             RATE_PREF_FR);
-                       break;
-               }
-               rc = match_codec_pref(&req->ch_mode_rate_alt, ct, 
&conn->codec_list, msc, conn_get_bts(conn),
+               nc += (rc == 0);
+               rc = match_codec_pref(&req->ch_mode_rate[nc], ct, 
&conn->codec_list, msc, conn_get_bts(conn),
                                      RATE_PREF_FR);
-               if (rc == 0)
-                       req->ch_mode_rate_alt_present = true;
-               rc = 0;
+               nc += (rc == 0);
                break;
        default:
                rc = -EINVAL;
                break;
        }

-       if (rc < 0) {
+       if (!nc) {
                LOGP(DMSC, LOGL_ERROR, "No supported audio type found for 
channel_type ="
                     " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[%s] }\n",
                     ct->ch_indctr, ct->ch_rate_type, 
osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
@@ -688,29 +676,69 @@
                return -EINVAL;
        }

-       if (req->ch_mode_rate_alt_present) {
-               DEBUGP(DMSC, "Found matching audio type (preferred): %s %s for 
channel_type ="
+       for (i = 0; i < nc; i++ ) {
+               DEBUGP(DMSC, "Found matching audio type (pref=%d): %s %s for 
channel_type ="
                       " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] 
}\n",
-                      req->ch_mode_rate_pref.full_rate ? "full rate" : "half 
rate",
-                      get_value_string(gsm48_chan_mode_names, 
req->ch_mode_rate_pref.chan_mode),
+                      i,
+                      req->ch_mode_rate[i].chan_rate == CH_RATE_FULL ? "full 
rate" : "half rate",
+                      get_value_string(gsm48_chan_mode_names, 
req->ch_mode_rate[i].chan_mode),
                       ct->ch_indctr, ct->ch_rate_type, 
osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
-               DEBUGP(DMSC, "Found matching audio type (alternative): %s %s 
for channel_type ="
-                      " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] 
}\n",
-                      req->ch_mode_rate_alt.full_rate ? "full rate" : "half 
rate",
-                      get_value_string(gsm48_chan_mode_names, 
req->ch_mode_rate_alt.chan_mode),
-                      ct->ch_indctr, ct->ch_rate_type, 
osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
-       } else {
-               DEBUGP(DMSC, "Found matching audio type: %s %s for channel_type 
="
-                      " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] 
}\n",
-                      req->ch_mode_rate_pref.full_rate ? "full rate" : "half 
rate",
-                      get_value_string(gsm48_chan_mode_names, 
req->ch_mode_rate_pref.chan_mode),
-                      ct->ch_indctr, ct->ch_rate_type, 
osmo_hexdump(ct->perm_spch, ct->perm_spch_len));
-
        }

+       req->n_ch_mode_rate = nc;
+
        return 0;
 }

+static int select_sign_chan(struct assignment_request *req, struct 
gsm0808_channel_type *ct)
+{
+       int i, nc = 0;
+
+       switch (ct->ch_rate_type) {
+       case GSM0808_SIGN_ANY:
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
+               break;
+       case GSM0808_SIGN_SDCCH:
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;
+               break;
+       case GSM0808_SIGN_SDCCH_FULL_BM:
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
+               break;
+       case GSM0808_SIGN_SDCCH_HALF_LM:
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_SDCCH;
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
+               break;
+       case GSM0808_SIGN_FULL_BM:
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
+               break;
+       case GSM0808_SIGN_HALF_LM:
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
+               break;
+       case GSM0808_SIGN_FULL_PREF:
+       case GSM0808_SIGN_FULL_PREF_NO_CHANGE:
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
+               break;
+       case GSM0808_SIGN_HALF_PREF:
+       case GSM0808_SIGN_HALF_PREF_NO_CHANGE:
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_HALF;
+               req->ch_mode_rate[nc++].chan_rate = CH_RATE_FULL;
+               break;
+       default:
+               break;
+       }
+
+       for (i = 0; i < nc; i++)
+               req->ch_mode_rate[i].chan_mode = GSM48_CMODE_SIGN;
+
+       req->n_ch_mode_rate = nc;
+
+       return nc > 0 ? 0 : -EINVAL;
+}
+
 /*
  * Handle the assignment request message.
  *
@@ -728,7 +756,6 @@
        uint8_t cause;
        int rc;
        struct assignment_request req = {};
-       struct channel_mode_and_rate ch_mode_rate_pref = {};

        if (!conn) {
                LOGP(DMSC, LOGL_ERROR,
@@ -849,14 +876,15 @@
                }
                break;
        case GSM0808_CHAN_SIGN:
-               ch_mode_rate_pref = (struct channel_mode_and_rate) {
-                       .chan_mode = GSM48_CMODE_SIGN,
-               };
-
                req = (struct assignment_request){
                        .aoip = aoip,
-                       .ch_mode_rate_pref = ch_mode_rate_pref,
                };
+
+               rc = select_sign_chan(&req, &ct);
+               if (rc < 0) {
+                       cause = GSM0808_CAUSE_INCORRECT_VALUE;
+                       goto reject;
+               }
                break;
        default:
                cause = GSM0808_CAUSE_INVALID_MESSAGE_CONTENTS;
diff --git a/tests/codec_pref/codec_pref_test.c 
b/tests/codec_pref/codec_pref_test.c
index bb5468a..ce82f3d 100644
--- a/tests/codec_pref/codec_pref_test.c
+++ b/tests/codec_pref/codec_pref_test.c
@@ -407,7 +407,7 @@

        rc = match_codec_pref(&ch_mode_rate, ct, scl, msc, bts, RATE_PREF_NONE);
        printf(" * result: rc=%i, full_rate=%i, s15_s0=%04x, chan_mode=%s\n",
-              rc, ch_mode_rate.full_rate, ch_mode_rate.s15_s0, 
gsm48_chan_mode_name(ch_mode_rate.chan_mode));
+              rc, ch_mode_rate.chan_rate == CH_RATE_FULL, ch_mode_rate.s15_s0, 
gsm48_chan_mode_name(ch_mode_rate.chan_mode));

        printf("\n");


-- 
To view, visit https://gerrit.osmocom.org/13172
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-MessageType: merged
Gerrit-Change-Id: I4c7499c8c866ea3ff7b1327edb3615d003d927d3
Gerrit-Change-Number: 13172
Gerrit-PatchSet: 5
Gerrit-Owner: tnt <t...@246tnt.com>
Gerrit-Reviewer: Harald Welte <lafo...@gnumonks.org>
Gerrit-Reviewer: Jenkins Builder (1000002)
Gerrit-Reviewer: Vadim Yanitskiy <axilira...@gmail.com>
Gerrit-Reviewer: tnt <t...@246tnt.com>
Gerrit-CC: Max <msur...@sysmocom.de>

Reply via email to