mirror of https://gerrit.osmocom.org/libosmocore
gsm0808_enc/dec_channel_type: support data
Related: OS#4393 Change-Id: Ib7b75c9d86aace329decf20003b68de459021c64
This commit is contained in:
parent
6939169de9
commit
f047a4a04a
|
@ -500,6 +500,42 @@ enum gsm0808_permitted_speech {
|
|||
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 @@ struct gsm0808_speech_codec_list {
|
|||
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 */
|
||||
|
|
|
@ -499,12 +499,6 @@ uint8_t gsm0808_enc_channel_type(struct msgb *msg,
|
|||
|
||||
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 @@ uint8_t gsm0808_enc_channel_type(struct msgb *msg,
|
|||
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 @@ int gsm0808_dec_channel_type(struct gsm0808_channel_type *ct,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -1086,6 +1086,88 @@ static void test_gsm0808_enc_dec_empty_speech_codec_list(void)
|
|||
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 @@ static void test_gsm0808_dec_channel_type_err(void)
|
|||
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 @@ int main(int argc, char **argv)
|
|||
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();
|
||||
|
|
Loading…
Reference in New Issue