From 3713af865503f78ad1a49604dc5d39908b94b2be Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Wed, 27 Feb 2019 16:48:25 +0100 Subject: gsm0808_utils: fix gsm48 multirate configuration generator The function gsm0808_sc_cfg_from_gsm48_mr_cfg() takes an S15 to S0 bitmask and converts that bitmask into an AMR multirate configuration struct. Unfortunately the current implementation implements 3GPP TS 28.062, Table 7.11.3.1.3-2 wrongly in some aspects. Lets fix this. - Fix wrong interpretation of the bitpatterns - 5,15K is invalid and must never be selected - Make sure that no more than 4 rates are selected in the active set - Extend unit-test Change-Id: I6fd7f4073b84093742c322752f2fd878d1071e15 Related: SYS#4470 --- src/gsm/gsm0808_utils.c | 94 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c index dd14d3ca..2552c086 100644 --- a/src/gsm/gsm0808_utils.c +++ b/src/gsm/gsm0808_utils.c @@ -1346,42 +1346,94 @@ uint16_t gsm0808_sc_cfg_from_gsm48_mr_cfg(const struct gsm48_multi_rate_conf *cf /*! Determine a GSM 04.08 AMR configuration struct from a set of speech codec * configuration bits (S0-S15) * \param[out] cfg AMR configuration in GSM 04.08 format. - * \param[in] s15_s0 configuration bits (S0-S15). */ -void gsm48_mr_cfg_from_gsm0808_sc_cfg(struct gsm48_multi_rate_conf *cfg, - uint16_t s15_s0) + * \param[in] s15_s0 configuration bits (S15-S0, non-ambiguous). + * \returns zero when successful; negative on error */ +int gsm48_mr_cfg_from_gsm0808_sc_cfg(struct gsm48_multi_rate_conf *cfg, + uint16_t s15_s0) { + unsigned int count = 0; + + /* Note: See also: 3GPP TS 28.062 + * Table 7.11.3.1.3-2: Preferred Configurations for the Adaptive + * Multi-Rate Codec Types */ + + /* Note: The resulting multirate-configuration must not contain an + * active set of more than four codec rates. The active set also + * must contain at least one rate. */ + memset(cfg, 0, sizeof(*cfg)); + cfg->ver = 1; + cfg->icmi = 1; /* Strip option bits */ s15_s0 &= 0x00ff; - /* Rate 5,15k must always be present */ - cfg->m5_15 = 1; + /* Rate 5,15k can never be selected (see table) */ + cfg->m5_15 = 0; + + if (s15_s0 & GSM0808_SC_CFG_AMR_4_75_5_90_7_40_12_20 & 0xff) { + /* Table Table 7.11.3.1.3-2 lists one mode that selects 4 + * rates at once (Config-NB-Code = 1). The rates selected + * are known to be compatible between GERAN and UTRAN, since + * an active set must not contain more than four rates at + * a time, we ignore all other settings as they are either + * redundaned or excess settings (invalid) */ + cfg->m4_75 = 1; + cfg->m5_90 = 1; + cfg->m7_40 = 1; + cfg->m12_2 = 1; + count += 4; + } - if ((s15_s0 & GSM0808_SC_CFG_DEFAULT_AMR_4_75 & 0xff) == - (GSM0808_SC_CFG_DEFAULT_AMR_4_75 & 0xff)) + /* Check the bits in s15_s0 and set the flags for the + * respective rates. */ + if (s15_s0 & GSM0808_SC_CFG_AMR_4_75 && !cfg->m4_75) { + if (count >= 4) + return -EINVAL; cfg->m4_75 = 1; - if ((s15_s0 & GSM0808_SC_CFG_DEFAULT_AMR_5_90 & 0xff) == - (GSM0808_SC_CFG_DEFAULT_AMR_5_90 & 0xff)) + count++; + } + if (s15_s0 & GSM0808_SC_CFG_AMR_5_90 && !cfg->m5_90) { + if (count >= 4) + return -EINVAL; cfg->m5_90 = 1; - if ((s15_s0 & GSM0808_SC_CFG_DEFAULT_AMR_6_70 & 0xff) == - (GSM0808_SC_CFG_DEFAULT_AMR_6_70 & 0xff)) + count++; + } + if (s15_s0 & GSM0808_SC_CFG_AMR_6_70) { + if (count >= 4) + return -EINVAL; cfg->m6_70 = 1; - if ((s15_s0 & GSM0808_SC_CFG_DEFAULT_AMR_7_40 & 0xff) == - (GSM0808_SC_CFG_DEFAULT_AMR_7_40 & 0xff)) + count++; + } + if (s15_s0 & GSM0808_SC_CFG_AMR_7_40 && !cfg->m7_40) { + if (count >= 4) + return -EINVAL; cfg->m7_40 = 1; - if ((s15_s0 & GSM0808_SC_CFG_DEFAULT_AMR_7_95 & 0xff) == - (GSM0808_SC_CFG_DEFAULT_AMR_7_95 & 0xff)) + count++; + } + if (s15_s0 & GSM0808_SC_CFG_AMR_7_95) { + if (count >= 4) + return -EINVAL; cfg->m7_95 = 1; - if ((s15_s0 & GSM0808_SC_CFG_DEFAULT_AMR_10_2 & 0xff) == - (GSM0808_SC_CFG_DEFAULT_AMR_10_2 & 0xff)) + count++; + } + if (s15_s0 & GSM0808_SC_CFG_AMR_10_2) { + if (count >= 4) + return -EINVAL; cfg->m10_2 = 1; - if ((s15_s0 & GSM0808_SC_CFG_DEFAULT_AMR_12_2 & 0xff) == - (GSM0808_SC_CFG_DEFAULT_AMR_12_2 & 0xff)) + count++; + } + if (s15_s0 & GSM0808_SC_CFG_AMR_12_2 && !cfg->m12_2) { + if (count >= 4) + return -EINVAL; cfg->m12_2 = 1; + count++; + } - cfg->ver = 1; - cfg->icmi = 1; + if (count == 0) + return -EINVAL; + + return 0; } int gsm0808_get_cipher_reject_cause(const struct tlv_parsed *tp) -- cgit v1.2.3