summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPhilipp Maier <pmaier@sysmocom.de>2019-02-27 16:48:25 +0100
committerPhilipp Maier <pmaier@sysmocom.de>2019-03-11 09:08:31 +0100
commit3713af865503f78ad1a49604dc5d39908b94b2be (patch)
tree9a2728d3d95832fa973ec341d874124c8ae30f15 /src
parent3a5045302f51faf104e64783977f710d36e06e3f (diff)
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
Diffstat (limited to 'src')
-rw-r--r--src/gsm/gsm0808_utils.c94
1 files changed, 73 insertions, 21 deletions
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)