osmith has uploaded this change for review. ( 
https://gerrit.osmocom.org/c/osmo-bsc/+/31547 )


Change subject: bssmap_handle_ass_req_ct_data: implement
......................................................................

bssmap_handle_ass_req_ct_data: implement

Handle assignment requests for CSD. In this initial version, the code
for non-transparent data mode is a stub.

Related: OS#5763
Change-Id: I350bea15fd2158eb6edc9bc92f2dca48930736e9
---
M TODO-RELEASE
M include/osmocom/bsc/codec_pref.h
M src/osmo-bsc/codec_pref.c
M src/osmo-bsc/osmo_bsc_bssap.c
4 files changed, 235 insertions(+), 4 deletions(-)



  git pull ssh://gerrit.osmocom.org:29418/osmo-bsc refs/changes/47/31547/1

diff --git a/TODO-RELEASE b/TODO-RELEASE
index d0852fc..d38d67e 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -7,3 +7,4 @@
 # If any interfaces have been added since the last public release: c:r:a + 1.
 # If any interfaces have been removed or changed since the last public 
release: c:r:0.
 #library       what            description / commit summary line
+libosmogsm     >1.8.0          circuit switched data stuff 
(gsm0808_enc/dec_channel_type etc.)
diff --git a/include/osmocom/bsc/codec_pref.h b/include/osmocom/bsc/codec_pref.h
index adefe04..5944a4a 100644
--- a/include/osmocom/bsc/codec_pref.h
+++ b/include/osmocom/bsc/codec_pref.h
@@ -17,6 +17,10 @@
        RATE_PREF_FR,
 };

+int match_codec_pref_data(struct channel_mode_and_rate *ch_mode_rate,
+                         const struct gsm0808_channel_type *ct,
+                         const bool full_rate);
+
 int match_codec_pref(struct channel_mode_and_rate *ch_mode_rate,
                     const struct gsm0808_channel_type *ct,
                     const struct gsm0808_speech_codec_list *scl,
diff --git a/src/osmo-bsc/codec_pref.c b/src/osmo-bsc/codec_pref.c
index 0cf98c6..fd369b2 100644
--- a/src/osmo-bsc/codec_pref.c
+++ b/src/osmo-bsc/codec_pref.c
@@ -87,6 +87,82 @@
        }
 }

+static int gsm0808_data_rate_transp_to_gsm0858(enum gsm0808_data_rate_transp 
rate)
+{
+       switch (rate) {
+       case GSM0808_DATA_RATE_TRANSP_32000:
+               return RSL_CMOD_CSD_T_32000;
+       case GSM0808_DATA_RATE_TRANSP_28800:
+               return RSL_CMOD_CSD_T_29000;
+       case GSM0808_DATA_RATE_TRANSP_14400:
+               return RSL_CMOD_CSD_T_14400;
+       case GSM0808_DATA_RATE_TRANSP_09600:
+               return RSL_CMOD_CSD_T_9600;
+       case GSM0808_DATA_RATE_TRANSP_04800:
+               return RSL_CMOD_CSD_T_4800;
+       case GSM0808_DATA_RATE_TRANSP_02400:
+               return RSL_CMOD_CSD_T_2400;
+       case GSM0808_DATA_RATE_TRANSP_01200:
+               return RSL_CMOD_CSD_T_1200;
+       case GSM0808_DATA_RATE_TRANSP_00600:
+               return RSL_CMOD_CSD_T_600;
+       case GSM0808_DATA_RATE_TRANSP_01200_75:
+               return RSL_CMOD_CSD_T_1200_75;
+       default:
+               LOGP(DMSC, LOGL_ERROR, "Unsupported transparent data rate 
0x%x\n", rate);
+               return -1;
+       }
+}
+
+static int gsm0808_data_rate_transp_to_gsm0804(enum gsm0808_data_rate_transp 
rate)
+{
+       switch (rate) {
+       case GSM0808_DATA_RATE_TRANSP_14400:
+               return GSM48_CMODE_DATA_14k5;
+       case GSM0808_DATA_RATE_TRANSP_09600:
+               return GSM48_CMODE_DATA_12k0;
+       case GSM0808_DATA_RATE_TRANSP_04800:
+               return GSM48_CMODE_DATA_6k0;
+       case GSM0808_DATA_RATE_TRANSP_02400:
+       case GSM0808_DATA_RATE_TRANSP_01200:
+       case GSM0808_DATA_RATE_TRANSP_00600:
+       case GSM0808_DATA_RATE_TRANSP_01200_75:
+               return GSM48_CMODE_DATA_3k6;
+       default:
+               LOGP(DMSC, LOGL_ERROR, "Unsupported transparent data rate 
0x%x\n", rate);
+               return -1;
+       }
+}
+
+static int gsm0808_data_rate_non_transp_to_gsm0804(enum 
gsm0808_data_rate_non_transp rate)
+{
+       LOGP(DMSC, LOGL_ERROR, "%s is not implemented\n", __func__); /* FIXME */
+       return -1;
+}
+
+static int gsm0808_data_rate_non_transp_to_gsm0858(enum 
gsm0808_data_rate_non_transp rate, bool full_rate)
+{
+       switch (rate) {
+       case GSM0808_DATA_RATE_NON_TRANSP_12000_6000:
+               if (full_rate)
+                       return RSL_CMOD_CSD_NT_12k0;
+               return RSL_CMOD_CSD_NT_6k0;
+       case GSM0808_DATA_RATE_NON_TRANSP_14500:
+               return RSL_CMOD_CSD_NT_14k5;
+       case GSM0808_DATA_RATE_NON_TRANSP_12000:
+               return RSL_CMOD_CSD_NT_12k0;
+       case GSM0808_DATA_RATE_NON_TRANSP_06000:
+               return RSL_CMOD_CSD_NT_6k0;
+       case GSM0808_DATA_RATE_NON_TRANSP_43500:
+               return RSL_CMOD_CSD_NT_43k5;
+       case GSM0808_DATA_RATE_NON_TRANSP_29000:
+               return RSL_CMOD_CSD_NT_28k8;
+       default:
+               LOGP(DMSC, LOGL_ERROR, "Unsupported non-transparent data rate 
0x%x\n", rate);
+               return -1;
+       }
+}
+
 /* Look up a matching permitted speech value for a given msc audio codec pref 
*/
 static enum gsm0808_permitted_speech audio_support_to_gsm88(const struct 
gsm_audio_support *audio)
 {
@@ -309,6 +385,50 @@
        return 0;
 }

+static enum gsm48_chan_mode match_non_transp_data_rate(const struct 
gsm0808_channel_type *ct, bool full_rate)
+{
+       /* FIXME: Handle ct->data_rate_allowed too if it is set. Find the best
+        * match by comparing the preferred ct->data_rate + all allowed
+        * ct->data_rate_allowed against what's most suitable for the BTS. */
+
+       return gsm0808_data_rate_non_transp_to_gsm0858(ct->data_rate, 
full_rate);
+}
+
+/*! Match the codec preferences from local config with codec preference IEs
+ * received from the MSC and the BTS' codec configuration.
+ *  \param[out] ch_mode_rate resulting codec and rate information
+ *  \param[in] ct GSM 08.08 channel type received from MSC.
+ *  \param[in] full_rate true means FR is preferred, false means HR
+ *  \returns 0 on success, -1 in case no match was found */
+int match_codec_pref_data(struct channel_mode_and_rate *ch_mode_rate,
+                         const struct gsm0808_channel_type *ct,
+                         const bool full_rate)
+{
+       *ch_mode_rate = (struct channel_mode_and_rate){};
+       ch_mode_rate->chan_rate = full_rate ? CH_RATE_FULL : CH_RATE_HALF;
+       ch_mode_rate->data_transparent = ct->data_transparent;
+
+       if (ct->data_transparent) {
+               ch_mode_rate->data_rate = 
gsm0808_data_rate_transp_to_gsm0858(ct->data_rate);
+               if (ch_mode_rate->data_rate == -1)
+                       return -1;
+
+               ch_mode_rate->chan_mode = 
gsm0808_data_rate_transp_to_gsm0804(ct->data_rate);
+               if (ch_mode_rate->chan_mode == -1)
+                       return -1;
+       } else {
+               ch_mode_rate->data_rate = match_non_transp_data_rate(ct, 
full_rate);
+               if (ch_mode_rate->data_rate == -1)
+                       return -1;
+
+               ch_mode_rate->chan_mode = 
gsm0808_data_rate_non_transp_to_gsm0804(ct->data_rate);
+               if (ch_mode_rate->chan_mode == -1)
+                       return -1;
+       }
+
+       return 0;
+}
+
 /*! Match the codec preferences from local config with codec preference IEs
  * received from the MSC and the BTS' codec configuration.
  *  \param[out] ch_mode_rate resulting codec and rate information
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index c8083e1..59195ca 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -674,6 +674,67 @@
  * lchan is requested. The preferred lchan will be requested first. If we
  * find an alternate setting here, this one will be tried secondly if our
  * primary choice fails. */
+static int select_codecs_data(struct assignment_request *req, struct 
gsm0808_channel_type *ct,
+                        struct gsm_subscriber_connection *conn)
+{
+       int rc, i, nc = 0;
+
+       switch (ct->ch_rate_type) {
+       case GSM0808_DATA_FULL_BM:
+               rc = match_codec_pref_data(&req->ch_mode_rate_list[nc], ct, 
true);
+               nc += (rc == 0) ? 1 : 0;
+               break;
+       case GSM0808_DATA_HALF_LM:
+               rc = match_codec_pref_data(&req->ch_mode_rate_list[nc], ct, 
false);
+               nc += (rc == 0) ? 1 : 0;
+               break;
+       case GSM0808_DATA_FULL_PREF_NO_CHANGE:
+       case GSM0808_DATA_FULL_PREF:
+               rc = match_codec_pref_data(&req->ch_mode_rate_list[nc], ct, 
true);
+               nc += (rc == 0) ? 1 : 0;
+               rc = match_codec_pref_data(&req->ch_mode_rate_list[nc], ct, 
false);
+               nc += (rc == 0) ? 1 : 0;
+               break;
+       case GSM0808_DATA_HALF_PREF_NO_CHANGE:
+       case GSM0808_DATA_HALF_PREF:
+               rc = match_codec_pref_data(&req->ch_mode_rate_list[nc], ct, 
false);
+               nc += (rc == 0) ? 1 : 0;
+               rc = match_codec_pref_data(&req->ch_mode_rate_list[nc], ct, 
true);
+               nc += (rc == 0) ? 1 : 0;
+               break;
+       default:
+               rc = -EINVAL;
+               break;
+       }
+
+       if (!nc) {
+               LOGP(DMSC, LOGL_ERROR, "No supported data codec 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));
+               return -EINVAL;
+       }
+
+       for (i = 0; i < nc; i++) {
+               DEBUGP(DMSC, "Found matching data codec (pref=%d): %s %s for 
channel_type ="
+                      " { ch_indctr=0x%x, ch_rate_type=0x%x, perm_spch=[ %s] 
}\n",
+                      i,
+                      req->ch_mode_rate_list[i].chan_rate == CH_RATE_FULL ? 
"full rate" : "half rate",
+                      get_value_string(gsm48_chan_mode_names, 
req->ch_mode_rate_list[i].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;
+}
+
+/* Select a preferred and an alternative codec rate depending on the available
+ * capabilities. This decision does not include the actual channel load yet,
+ * this is also the reason why the result is a preferred and an alternate
+ * setting. The final decision is made in assignment_fsm.c when the actual
+ * lchan is requested. The preferred lchan will be requested first. If we
+ * find an alternate setting here, this one will be tried secondly if our
+ * primary choice fails. */
 static int select_codecs(struct assignment_request *req, struct 
gsm0808_channel_type *ct,
                         struct gsm_subscriber_connection *conn)
 {
@@ -924,6 +985,38 @@
        return 0;
 }

+static int bssmap_handle_ass_req_ct_data(struct gsm_subscriber_connection 
*conn, struct tlv_parsed *tp,
+                                        struct gsm0808_channel_type *ct, 
struct assignment_request *req,
+                                        uint8_t *cause)
+{
+       bool aoip = gscon_is_aoip(conn);
+       int rc;
+
+       *req = (struct assignment_request){
+               .assign_for = ASSIGN_FOR_BSSMAP_REQ,
+               .aoip = aoip,
+       };
+
+       if (bssmap_handle_ass_req_tp_cic(tp, aoip, &req->msc_assigned_cic, 
cause) < 0)
+               return -1;
+
+       if (bssmap_handle_ass_req_tp_rtp_addr(tp, aoip, req->msc_rtp_addr, 
sizeof(req->msc_rtp_addr), &req->msc_rtp_port, cause) < 0)
+               return -1;
+
+       /* According to 3GPP TS 48.008 ยง 3.2.1.1 note 13, the codec list IE
+        * shall be included for aoip unless channel type is signalling. */
+       if (bssmap_handle_ass_req_tp_codec_list(conn, tp, aoip, cause) < 0)
+               return -1;
+
+       rc = select_codecs_data(req, ct, conn);
+       if (rc < 0) {
+               *cause = GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_UNAVAIL;
+               return -1;
+       }
+
+       return 0;
+}
+
 static int bssmap_handle_ass_req_ct_speech(struct gsm_subscriber_connection 
*conn, struct tlv_parsed *tp,
                                           struct gsm0808_channel_type *ct, 
struct assignment_request *req,
                                           uint8_t *cause)
@@ -1023,12 +1116,12 @@
        bssmap_handle_ass_req_lcls(conn, &tp);

        /* Currently we only support a limited subset of all
-        * possible channel types, such as multi-slot or CSD */
+        * possible channel types, such as multi-slot */
        switch (ct.ch_indctr) {
        case GSM0808_CHAN_DATA:
-               LOGP(DMSC, LOGL_ERROR, "Unsupported channel type, currently 
only speech is supported!\n");
-               cause = GSM0808_CAUSE_REQ_CODEC_TYPE_OR_CONFIG_NOT_SUPP;
-               goto reject;
+               if (bssmap_handle_ass_req_ct_data(conn, &tp, &ct, &req, &cause) 
< 0)
+                       goto reject;
+               break;
        case GSM0808_CHAN_SPEECH:
                if (bssmap_handle_ass_req_ct_speech(conn, &tp, &ct, &req, 
&cause) < 0)
                        goto reject;

--
To view, visit https://gerrit.osmocom.org/c/osmo-bsc/+/31547
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: osmo-bsc
Gerrit-Branch: master
Gerrit-Change-Id: I350bea15fd2158eb6edc9bc92f2dca48930736e9
Gerrit-Change-Number: 31547
Gerrit-PatchSet: 1
Gerrit-Owner: osmith <[email protected]>
Gerrit-MessageType: newchange

Reply via email to