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;