osmith has submitted this change. ( 
https://gerrit.osmocom.org/c/libosmocore/+/31265 )

Change subject: gsm0808_enc/dec_channel_type: support data
......................................................................

gsm0808_enc/dec_channel_type: support data

Related: OS#4393
Change-Id: Ib7b75c9d86aace329decf20003b68de459021c64
---
M include/osmocom/gsm/protocol/gsm_08_08.h
M src/gsm/gsm0808_utils.c
M tests/gsm0808/gsm0808_test.c
3 files changed, 245 insertions(+), 20 deletions(-)

Approvals:
  laforge: Looks good to me, but someone else must approve
  osmith: Looks good to me, approved
  Jenkins Builder: Verified



diff --git a/include/osmocom/gsm/protocol/gsm_08_08.h 
b/include/osmocom/gsm/protocol/gsm_08_08.h
index a33b01a..eacb954 100644
--- a/include/osmocom/gsm/protocol/gsm_08_08.h
+++ b/include/osmocom/gsm/protocol/gsm_08_08.h
@@ -500,6 +500,42 @@
        GSM0808_PERM_HR6        = 0x45, /*!< OHR AMR */
 };

+/* 3GPP TS 48.008 3.2.2.11 Channel Type
+ * Transparent: Data Rate */
+enum gsm0808_data_rate_transp {
+       GSM0808_DATA_RATE_TRANSP_32000    = 0x3a,
+       GSM0808_DATA_RATE_TRANSP_28800    = 0x39,
+       GSM0808_DATA_RATE_TRANSP_14400    = 0x18,
+       GSM0808_DATA_RATE_TRANSP_09600    = 0x10,
+       GSM0808_DATA_RATE_TRANSP_04800    = 0x11,
+       GSM0808_DATA_RATE_TRANSP_02400    = 0x12,
+       GSM0808_DATA_RATE_TRANSP_01200    = 0x13,
+       GSM0808_DATA_RATE_TRANSP_00600    = 0x14,
+       GSM0808_DATA_RATE_TRANSP_01200_75 = 0x15,
+};
+
+/* 3GPP TS 48.008 3.2.2.11 Channel Type
+ * Non-Transparent: Radio Interface Data Rate (preferred) */
+enum gsm0808_data_rate_non_transp {
+       GSM0808_DATA_RATE_NON_TRANSP_12000_6000 = 0x00,
+       GSM0808_DATA_RATE_NON_TRANSP_43500      = 0x34,
+       GSM0808_DATA_RATE_NON_TRANSP_29000      = 0x31,
+       GSM0808_DATA_RATE_NON_TRANSP_14500      = 0x14,
+       GSM0808_DATA_RATE_NON_TRANSP_12000      = 0x10,
+       GSM0808_DATA_RATE_NON_TRANSP_06000      = 0x11,
+};
+
+/* 3GPP TS 48.008 3.2.2.11 Channel Type
+ * Non-Transparent: Allowed Radio Interface Data Rate (all possible allowed) */
+enum gsm0808_data_rate_allowed_r_if {
+       GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_43500 = 0x40,
+       GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_32000 = 0x20,
+       GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_29000 = 0x10,
+       GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_14500 = 0x08,
+       GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_12000 = 0x02,
+       GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_06000 = 0x01,
+};
+
 extern const struct value_string gsm0808_permitted_speech_names[];
 static inline const char *gsm0808_permitted_speech_name(enum 
gsm0808_permitted_speech val)
 { return get_value_string(gsm0808_permitted_speech_names, val); }
@@ -658,13 +694,32 @@
        uint8_t len;
 };

+/* 3GPP TS 48.008 3.2.2.11 Channel Type
+ * Asymmetry Preference (used for data, non-transparent service) */
+enum gsm0808_channel_type_asym_pref {
+       GSM0808_CT_ASYM_PREF_NOT_APPLICABLE = 0,
+       GSM0808_CT_ASYM_PREF_UL             = 1,
+       GSM0808_CT_ASYM_PREF_DL             = 2,
+       GSM0808_CT_ASYM_PREF_SPARE          = 3,
+};
+
 /* 3GPP TS 48.008 3.2.2.11 Channel Type */
 #define CH_TYPE_PERM_SPCH_MAXLEN 9
 struct gsm0808_channel_type {
        uint8_t ch_indctr;
        uint8_t ch_rate_type;
+
+       /* Speech only */
        uint8_t perm_spch[CH_TYPE_PERM_SPCH_MAXLEN];
        unsigned int perm_spch_len;
+
+       /* Data only */
+       bool data_transparent;
+       uint8_t data_rate;
+       bool data_rate_allowed_is_set;
+       uint8_t data_rate_allowed;
+       bool data_asym_pref_is_set;
+       enum gsm0808_channel_type_asym_pref data_asym_pref;
 };

 /* 3GPP TS 48.008 3.2.2.10 Encryption Information */
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index 83d2ce7..4993539 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -499,12 +499,6 @@

        OSMO_ASSERT(ct->perm_spch_len <= CHANNEL_TYPE_ELEMENT_MAXLEN - 2);

-       /* FIXME: Implement encoding support for Data
-        * and Speech + CTM Text Telephony */
-       if ((ct->ch_indctr & 0x0f) != GSM0808_CHAN_SPEECH
-           && (ct->ch_indctr & 0x0f) != GSM0808_CHAN_SIGN)
-               OSMO_ASSERT(false);
-
        msgb_put_u8(msg, GSM0808_IE_CHANNEL_TYPE);
        tlv_len = msgb_put(msg, 1);
        old_tail = msg->tail;
@@ -512,12 +506,44 @@
        msgb_put_u8(msg, ct->ch_indctr & 0x0f);
        msgb_put_u8(msg, ct->ch_rate_type);

-       for (i = 0; i < ct->perm_spch_len; i++) {
-               byte = ct->perm_spch[i];
+       switch (ct->ch_indctr) {
+       case GSM0808_CHAN_DATA:
+               byte = ct->data_rate;

-               if (i < ct->perm_spch_len - 1)
-                       byte |= 0x80;
+               if (ct->data_transparent)
+                       byte |= 0x40; /* Set T/NT */
+
+               if (ct->data_rate_allowed_is_set) {
+                       OSMO_ASSERT(!ct->data_transparent);
+                       byte |= 0x80; /* Set ext */
+                       msgb_put_u8(msg, byte);
+
+                       byte = ct->data_rate_allowed;
+                       if (ct->data_asym_pref_is_set) {
+                               byte |= 0x80; /* Set ext */
+                               msgb_put_u8(msg, byte);
+
+                               /* Set asymmetry indication, rest is spare */
+                               byte = ct->data_asym_pref << 5;
+                       }
+               }
                msgb_put_u8(msg, byte);
+               break;
+       case GSM0808_CHAN_SPEECH:
+       case GSM0808_CHAN_SPEECH_CTM_TEXT_TELEPHONY:
+               for (i = 0; i < ct->perm_spch_len; i++) {
+                       byte = ct->perm_spch[i];
+
+                       if (i < ct->perm_spch_len - 1)
+                               byte |= 0x80;
+                       msgb_put_u8(msg, byte);
+               }
+               break;
+       case GSM0808_CHAN_SIGN:
+               /* Octet 5 is spare */
+               break;
+       default:
+               OSMO_ASSERT(false);
        }

        *tlv_len = (uint8_t) (msg->tail - old_tail);
@@ -549,17 +575,57 @@
        ct->ch_rate_type = (*elem) & 0x0f;
        elem++;

-       for (i = 0; i < ARRAY_SIZE(ct->perm_spch); i++) {
-               if (elem - old_elem >= len)
-                       return -EOVERFLOW;
-
+       switch (ct->ch_indctr) {
+       case GSM0808_CHAN_DATA:
                byte = *elem;
                elem++;
-               ct->perm_spch[i] = byte & 0x7f;
-               if ((byte & 0x80) == 0x00)
-                       break;
+               ct->data_transparent = byte & 0x40; /* T/NT */
+               ct->data_rate = byte & 0x3f;
+
+               /* Optional extension for non-transparent service */
+               if (byte & 0x80) {
+                       if (ct->data_transparent)
+                               return -EINVAL;
+                       if (elem - old_elem >= len)
+                               return -EOVERFLOW;
+                       byte = *elem;
+                       elem++;
+
+                       ct->data_rate_allowed_is_set = true;
+                       ct->data_rate_allowed = byte & 0x7f;
+
+                       /* Optional extension */
+                       if (byte & 0x80) {
+                               if (elem - old_elem >= len)
+                                       return -EOVERFLOW;
+                               byte = *elem;
+                               elem++;
+
+                               ct->data_asym_pref_is_set = true;
+                               ct->data_asym_pref = byte & 0x60 >> 5;
+                       }
+               }
+               break;
+       case GSM0808_CHAN_SPEECH:
+       case GSM0808_CHAN_SPEECH_CTM_TEXT_TELEPHONY:
+               for (i = 0; i < ARRAY_SIZE(ct->perm_spch); i++) {
+                       if (elem - old_elem >= len)
+                               return -EOVERFLOW;
+
+                       byte = *elem;
+                       elem++;
+                       ct->perm_spch[i] = byte & 0x7f;
+                       if ((byte & 0x80) == 0x00)
+                               break;
+               }
+               ct->perm_spch_len = i + 1;
+               break;
+       case GSM0808_CHAN_SIGN:
+               /* Octet 5 is spare */
+               break;
+       default:
+               return -ENOTSUP;
        }
-       ct->perm_spch_len = i + 1;

        return (int)(elem - old_elem);
 }
diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c
index a9f1311..a03f276 100644
--- a/tests/gsm0808/gsm0808_test.c
+++ b/tests/gsm0808/gsm0808_test.c
@@ -1086,6 +1086,88 @@
        msgb_free(msg);
 }

+static void test_gsm0808_enc_dec_channel_type_data(void)
+{
+       struct gsm0808_channel_type enc_ct = {
+               .ch_indctr = GSM0808_CHAN_DATA,
+               .ch_rate_type = GSM0808_DATA_HALF_PREF,
+
+               .data_transparent = true,
+               .data_rate = GSM0808_DATA_RATE_TRANSP_04800,
+       };
+       struct gsm0808_channel_type dec_ct = {};
+       struct msgb *msg;
+       uint8_t ct_enc_expected[] = { GSM0808_IE_CHANNEL_TYPE,
+               0x03, 0x02, 0x0b, 0x51,
+       };
+       uint8_t rc_enc;
+       int rc_dec;
+
+       msg = msgb_alloc(1024, "output buffer");
+       rc_enc = gsm0808_enc_channel_type(msg, &enc_ct);
+       OSMO_ASSERT(rc_enc == 5);
+       if (memcmp(ct_enc_expected, msg->data, msg->len)) {
+               printf("   got: %s\n", osmo_hexdump(msg->data, msg->len));
+               printf("expect: %s\n", osmo_hexdump(ct_enc_expected, 
sizeof(ct_enc_expected)));
+               OSMO_ASSERT(false);
+       }
+
+       rc_dec = gsm0808_dec_channel_type(&dec_ct, msg->data + 2, msg->len - 2);
+       OSMO_ASSERT(rc_dec == 3);
+       OSMO_ASSERT(dec_ct.ch_indctr == enc_ct.ch_indctr);
+       OSMO_ASSERT(dec_ct.ch_rate_type == enc_ct.ch_rate_type);
+       OSMO_ASSERT(dec_ct.data_transparent == enc_ct.data_transparent);
+       OSMO_ASSERT(dec_ct.data_rate == enc_ct.data_rate);
+       OSMO_ASSERT(dec_ct.data_rate_allowed_is_set == 
enc_ct.data_rate_allowed_is_set);
+       OSMO_ASSERT(dec_ct.data_asym_pref_is_set == 
enc_ct.data_asym_pref_is_set);
+
+       msgb_free(msg);
+}
+
+static void test_gsm0808_enc_dec_channel_type_data_asym_pref(void)
+{
+       struct gsm0808_channel_type enc_ct = {
+               .ch_indctr = GSM0808_CHAN_DATA,
+               .ch_rate_type = GSM0808_DATA_HALF_PREF,
+
+               .data_transparent = false,
+               .data_rate = GSM0808_DATA_RATE_NON_TRANSP_06000,
+               .data_rate_allowed_is_set = true,
+               .data_rate_allowed = GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_06000
+                                    | 
GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_12000
+                                    | 
GSM0808_DATA_RATE_NON_TRANSP_ALLOWED_14500,
+               .data_asym_pref_is_set = true,
+               .data_asym_pref = GSM0808_CT_ASYM_PREF_UL,
+       };
+       struct gsm0808_channel_type dec_ct = {};
+       struct msgb *msg;
+       uint8_t ct_enc_expected[] = { GSM0808_IE_CHANNEL_TYPE,
+               0x05, 0x02, 0x0b, 0x91, 0x8b, 0x20,
+       };
+       uint8_t rc_enc;
+       int rc_dec;
+
+       msg = msgb_alloc(1024, "output buffer");
+       rc_enc = gsm0808_enc_channel_type(msg, &enc_ct);
+       OSMO_ASSERT(rc_enc == 7);
+       if (memcmp(ct_enc_expected, msg->data, msg->len)) {
+               printf("   got: %s\n", osmo_hexdump(msg->data, msg->len));
+               printf("expect: %s\n", osmo_hexdump(ct_enc_expected, 
sizeof(ct_enc_expected)));
+               OSMO_ASSERT(false);
+       }
+
+       rc_dec = gsm0808_dec_channel_type(&dec_ct, msg->data + 2, msg->len - 2);
+       OSMO_ASSERT(rc_dec == 5);
+       OSMO_ASSERT(dec_ct.ch_indctr == enc_ct.ch_indctr);
+       OSMO_ASSERT(dec_ct.ch_rate_type == enc_ct.ch_rate_type);
+       OSMO_ASSERT(dec_ct.data_transparent == enc_ct.data_transparent);
+       OSMO_ASSERT(dec_ct.data_rate == enc_ct.data_rate);
+       OSMO_ASSERT(dec_ct.data_rate_allowed_is_set == 
enc_ct.data_rate_allowed_is_set);
+       OSMO_ASSERT(dec_ct.data_asym_pref_is_set == 
enc_ct.data_asym_pref_is_set);
+
+       msgb_free(msg);
+}
+
 static void test_gsm0808_enc_dec_channel_type_speech(void)
 {
        struct gsm0808_channel_type enc_ct = {
@@ -1122,9 +1204,29 @@
        struct gsm0808_channel_type ct;
        int rc;

+       /* Unknown channel indicator */
+       const uint8_t hex1[] = { 0x05, 0x0b, 0xa1, 0x25 };
+       rc = gsm0808_dec_channel_type(&ct, hex1, sizeof(hex1));
+       OSMO_ASSERT(rc == -ENOTSUP);
+
+       /* Data: ext in Octet 5 with transparent service */
+       const uint8_t hex2[] = { 0x02, 0x0b, 0xc0, 0x00 };
+       rc = gsm0808_dec_channel_type(&ct, hex2, sizeof(hex2));
+       OSMO_ASSERT(rc == -EINVAL);
+
+       /* Data: ext in Octet 5, but too short */
+       const uint8_t hex3[] = { 0x02, 0x0b, 0x80 };
+       rc = gsm0808_dec_channel_type(&ct, hex3, sizeof(hex3));
+       OSMO_ASSERT(rc == -EOVERFLOW);
+
+       /* Data: ext in Octet 5a, but too short */
+       const uint8_t hex4[] = { 0x02, 0x0b, 0x80, 0x80 };
+       rc = gsm0808_dec_channel_type(&ct, hex4, sizeof(hex4));
+       OSMO_ASSERT(rc == -EOVERFLOW);
+
        /* Speech: extension bit is set in last byte */
-       const uint8_t hex[] = { 0x01, 0x0b, 0xa1, 0xa5 };
-       rc = gsm0808_dec_channel_type(&ct, hex, sizeof(hex));
+       const uint8_t hex5[] = { 0x01, 0x0b, 0xa1, 0xa5 };
+       rc = gsm0808_dec_channel_type(&ct, hex5, sizeof(hex5));
        OSMO_ASSERT(rc == -EOVERFLOW);
 }

@@ -2579,6 +2681,8 @@
        test_gsm0808_enc_dec_speech_codec_with_cfg();
        test_gsm0808_enc_dec_speech_codec_list();
        test_gsm0808_enc_dec_empty_speech_codec_list();
+       test_gsm0808_enc_dec_channel_type_data();
+       test_gsm0808_enc_dec_channel_type_data_asym_pref();
        test_gsm0808_enc_dec_channel_type_speech();
        test_gsm0808_dec_channel_type_err();
        test_gsm0808_enc_dec_encrypt_info();

--
To view, visit https://gerrit.osmocom.org/c/libosmocore/+/31265
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings

Gerrit-Project: libosmocore
Gerrit-Branch: master
Gerrit-Change-Id: Ib7b75c9d86aace329decf20003b68de459021c64
Gerrit-Change-Number: 31265
Gerrit-PatchSet: 4
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