osmith has submitted this change. ( 
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
Depends: libosmocore Ia965cdd9f53af756e5ffaff9b8f389b5ad629969
Change-Id: I350bea15fd2158eb6edc9bc92f2dca48930736e9
---
M TODO-RELEASE
M include/osmocom/bsc/Makefile.am
M include/osmocom/bsc/codec_pref.h
A include/osmocom/bsc/data_rate_pref.h
M src/osmo-bsc/Makefile.am
A src/osmo-bsc/data_rate_pref.c
M src/osmo-bsc/osmo_bsc_bssap.c
7 files changed, 282 insertions(+), 4 deletions(-)

Approvals:
  Jenkins Builder: Verified
  osmith: Looks good to me, approved




diff --git a/TODO-RELEASE b/TODO-RELEASE
index 78fcea3..551cc18 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -10,3 +10,4 @@
                osmo-bsc VTY    Timeslot phys_chan_config will now write back 
with new dynamic timeslot names: 'DYNAMIC/OSMOCOM' instead of 
'TCH/F_TCH/H_SDCCH8_PDCH' and 'DYNAMIC/IPACCESS' instead of 'TCH/F_PDCH'
                osmo-bsc CTRL   CTRL commands like 'bts.N.channel-load' will 
now respond with new dynamic timeslot names: 'DYNAMIC/OSMOCOM' instead of 
'TCH/F_TCH/H_SDCCH8_PDCH' and 'DYNAMIC/IPACCESS' instead of 'TCH/F_PDCH'
                osmo-bsc CTRL,VTY       osmo_fsm instance IDs now use new 
dynamic timeslot names 'DYNAMIC_OSMOCOM' and 'DYNAMIC_IPACCESS'
+libosmogsm     >1.8.0          circuit switched data stuff 
(gsm0808_enc/dec_channel_type etc.)
diff --git a/include/osmocom/bsc/Makefile.am b/include/osmocom/bsc/Makefile.am
index 53d45ad..8baff9c 100644
--- a/include/osmocom/bsc/Makefile.am
+++ b/include/osmocom/bsc/Makefile.am
@@ -19,6 +19,7 @@
        chan_alloc.h \
        chan_counts.h \
        codec_pref.h \
+       data_rate_pref.h \
        ctrl.h \
        debug.h \
        e1_config.h \
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/include/osmocom/bsc/data_rate_pref.h 
b/include/osmocom/bsc/data_rate_pref.h
new file mode 100644
index 0000000..da3f1fd
--- /dev/null
+++ b/include/osmocom/bsc/data_rate_pref.h
@@ -0,0 +1,11 @@
+#pragma once
+
+#include <stdbool.h>
+#include <osmocom/gsm/protocol/gsm_04_08.h>
+
+struct gsm0808_channel_type;
+struct channel_mode_and_rate;
+
+int match_data_rate_pref(struct channel_mode_and_rate *ch_mode_rate,
+                        const struct gsm0808_channel_type *ct,
+                        const bool full_rate);
diff --git a/src/osmo-bsc/Makefile.am b/src/osmo-bsc/Makefile.am
index 60a76fa..53c0912 100644
--- a/src/osmo-bsc/Makefile.am
+++ b/src/osmo-bsc/Makefile.am
@@ -62,6 +62,7 @@
        chan_alloc.c \
        chan_counts.c \
        codec_pref.c \
+       data_rate_pref.c \
        e1_config.c \
        gsm_04_08_rr.c \
        gsm_data.c \
diff --git a/src/osmo-bsc/data_rate_pref.c b/src/osmo-bsc/data_rate_pref.c
new file mode 100644
index 0000000..443fea7
--- /dev/null
+++ b/src/osmo-bsc/data_rate_pref.c
@@ -0,0 +1,152 @@
+/*
+ * (C) 2023 by sysmocom s.f.m.c. GmbH <[email protected]>
+ * All Rights Reserved
+ *
+ * Author: Oliver Smith
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <osmocom/gsm/protocol/gsm_08_08.h>
+#include <osmocom/gsm/protocol/gsm_08_58.h>
+#include <osmocom/bsc/data_rate_pref.h>
+#include <osmocom/bsc/debug.h>
+#include <osmocom/bsc/lchan.h>
+
+static int gsm0808_data_rate_transp_to_gsm0858(enum gsm0808_data_rate_transp 
rate)
+{
+       switch (rate) {
+       case GSM0808_DATA_RATE_TRANSP_32k0:
+               return RSL_CMOD_CSD_T_32k0;
+       case GSM0808_DATA_RATE_TRANSP_28k8:
+               return RSL_CMOD_CSD_T_29k0;
+       case GSM0808_DATA_RATE_TRANSP_14k4:
+               return RSL_CMOD_CSD_T_14k4;
+       case GSM0808_DATA_RATE_TRANSP_9k6:
+               return RSL_CMOD_CSD_T_9k6;
+       case GSM0808_DATA_RATE_TRANSP_4k8:
+               return RSL_CMOD_CSD_T_4k8;
+       case GSM0808_DATA_RATE_TRANSP_2k4:
+               return RSL_CMOD_CSD_T_2k4;
+       case GSM0808_DATA_RATE_TRANSP_1k2:
+               return RSL_CMOD_CSD_T_1k2;
+       case GSM0808_DATA_RATE_TRANSP_600:
+               return RSL_CMOD_CSD_T_600;
+       case GSM0808_DATA_RATE_TRANSP_1200_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_gsm0408(enum gsm0808_data_rate_transp 
rate)
+{
+       switch (rate) {
+       case GSM0808_DATA_RATE_TRANSP_14k4:
+               return GSM48_CMODE_DATA_14k5;
+       case GSM0808_DATA_RATE_TRANSP_9k6:
+               return GSM48_CMODE_DATA_12k0;
+       case GSM0808_DATA_RATE_TRANSP_4k8:
+               return GSM48_CMODE_DATA_6k0;
+       case GSM0808_DATA_RATE_TRANSP_2k4:
+       case GSM0808_DATA_RATE_TRANSP_1k2:
+       case GSM0808_DATA_RATE_TRANSP_600:
+       case GSM0808_DATA_RATE_TRANSP_1200_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_gsm0408(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_14k5:
+               return RSL_CMOD_CSD_NT_14k5;
+       case GSM0808_DATA_RATE_NON_TRANSP_12k0:
+               return RSL_CMOD_CSD_NT_12k0;
+       case GSM0808_DATA_RATE_NON_TRANSP_6k0:
+               return RSL_CMOD_CSD_NT_6k0;
+       case GSM0808_DATA_RATE_NON_TRANSP_43k5:
+               return RSL_CMOD_CSD_NT_43k5;
+       case GSM0808_DATA_RATE_NON_TRANSP_29k0:
+               return RSL_CMOD_CSD_NT_28k8;
+       default:
+               LOGP(DMSC, LOGL_ERROR, "Unsupported non-transparent data rate 
0x%x\n", rate);
+               return -1;
+       }
+}
+
+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 GSM 08.08 channel type received from the MSC to suitable data for
+ * the BTS, the GSM 04.08 channel mode, channel rate (FR/HR) and GSM 08.58
+ * data rate.
+ *  \param[out] ch_mode_rate resulting channel rate, channel mode and data rate
+ *  \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_data_rate_pref(struct channel_mode_and_rate *ch_mode_rate,
+                        const struct gsm0808_channel_type *ct,
+                        const bool full_rate)
+{
+       int rc;
+       *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) {
+               rc = gsm0808_data_rate_transp_to_gsm0858(ct->data_rate);
+               if (rc == -1)
+                       return -1;
+               ch_mode_rate->data_rate.t = rc;
+
+               rc = gsm0808_data_rate_transp_to_gsm0408(ct->data_rate);
+               if (rc == -1)
+                       return -1;
+               ch_mode_rate->chan_mode = rc;
+       } else {
+               rc = match_non_transp_data_rate(ct, full_rate);
+               if (rc == -1)
+                       return -1;
+               ch_mode_rate->data_rate.nt = rc;
+
+               rc = gsm0808_data_rate_non_transp_to_gsm0408(ct->data_rate);
+               if (rc == -1)
+                       return -1;
+               ch_mode_rate->chan_mode = rc;
+       }
+
+       return 0;
+}
diff --git a/src/osmo-bsc/osmo_bsc_bssap.c b/src/osmo-bsc/osmo_bsc_bssap.c
index 221e477..59d5aa5 100644
--- a/src/osmo-bsc/osmo_bsc_bssap.c
+++ b/src/osmo-bsc/osmo_bsc_bssap.c
@@ -31,6 +31,7 @@
 #include <osmocom/bsc/gsm_04_08_rr.h>
 #include <osmocom/bsc/bsc_subscr_conn_fsm.h>
 #include <osmocom/bsc/codec_pref.h>
+#include <osmocom/bsc/data_rate_pref.h>
 #include <osmocom/bsc/abis_rsl.h>
 #include <osmocom/bsc/handover_fsm.h>
 #include <osmocom/bsc/bts.h>
@@ -667,6 +668,67 @@
        return 0;
 }

+/* Select a preferred and an alternative data 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_data_rates(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_data_rate_pref(&req->ch_mode_rate_list[nc], ct, 
true);
+               nc += (rc == 0) ? 1 : 0;
+               break;
+       case GSM0808_DATA_HALF_LM:
+               rc = match_data_rate_pref(&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_data_rate_pref(&req->ch_mode_rate_list[nc], ct, 
true);
+               nc += (rc == 0) ? 1 : 0;
+               rc = match_data_rate_pref(&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_data_rate_pref(&req->ch_mode_rate_list[nc], ct, 
false);
+               nc += (rc == 0) ? 1 : 0;
+               rc = match_data_rate_pref(&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 rate 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 rate (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 lchan availability 
yet,
  * this is also the reason why the result is a preferred and an alternate
@@ -924,6 +986,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_data_rates(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 +1117,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: 5
Gerrit-Owner: osmith <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: osmith <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>
Gerrit-MessageType: merged

Reply via email to