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 <osmith(a)sysmocom.de>
Gerrit-MessageType: newchange