gsm0808: add encoder for cause codes and use it

At the moment the all gsm0808 cause codes are encoded directly using the
tlv API directly to put a one byte TLV field. This works ok for most
situations where the cause code consists of a single byte. However,
gsm0808 specifies a two byte cause code model where cause codes may be
extended up to two bytes. Instead of implementing the encoding over and
over and again, let's rather have an encoder function we can call.

- Add an encoder function that can generate single byte and extended
  cause codeds and makes the length decision automatically.

- Use only this function to append cause codes

Change-Id: I71d58fad89502a43532f60717ca022c15c73f8bb
This commit is contained in:
Philipp Maier 2018-11-30 13:36:12 +01:00 committed by Harald Welte
parent e190e032d9
commit 4f4905fac5
6 changed files with 75 additions and 19 deletions

View File

@ -77,6 +77,7 @@ int gsm0808_cell_id_list_name_buf(char *buf, size_t buflen, const struct gsm0808
int gsm0808_cell_id_u_name(char *buf, size_t buflen,
enum CELL_IDENT id_discr, const union gsm0808_cell_id_u *u);
uint8_t gsm0808_enc_cause(struct msgb *msg, uint16_t cause);
uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
const struct sockaddr_storage *ss);
int gsm0808_dec_aoip_trasp_addr(struct sockaddr_storage *ss,

View File

@ -141,7 +141,7 @@ struct msgb *gsm0808_create_reset(void)
return NULL;
msgb_v_put(msg, BSS_MAP_MSG_RESET);
msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause);
gsm0808_enc_cause(msg, cause);
msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg));
return msg;
@ -190,7 +190,7 @@ struct msgb *gsm0808_create_clear_command(uint8_t cause)
msg->l3h = msgb_tv_put(msg, BSSAP_MSG_BSS_MANAGEMENT, 4);
msgb_v_put(msg, BSS_MAP_MSG_CLEAR_CMD);
msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause);
gsm0808_enc_cause(msg, cause);
return msg;
}
@ -273,7 +273,7 @@ struct msgb *gsm0808_create_cipher_reject(enum gsm0808_cause cause)
msgb_v_put(msg, BSS_MAP_MSG_CIPHER_MODE_REJECT);
msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, (const uint8_t *)&cause);
gsm0808_enc_cause(msg, cause);
msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg));
@ -286,18 +286,22 @@ struct msgb *gsm0808_create_cipher_reject(enum gsm0808_cause cause)
* \returns callee-allocated msgb with BSSMAP Cipher Mode Reject message */
struct msgb *gsm0808_create_cipher_reject_ext(enum gsm0808_cause_class class, uint8_t ext)
{
uint8_t c[2];
uint16_t cause;
struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM,
"bssmap: cipher mode reject");
if (!msg)
return NULL;
c[0] = 0x80 | (class << 4); /* set the high bit to indicate extended cause */
c[1] = ext;
/* Set cause code class in the upper byte */
cause = 0x80 | (class << 4);
cause = cause << 8;
/* Set cause code extension in the lower byte */
cause |= ext;
msgb_v_put(msg, BSS_MAP_MSG_CIPHER_MODE_REJECT);
msgb_tlv_put(msg, GSM0808_IE_CAUSE, 2, c);
gsm0808_enc_cause(msg, cause);
msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg));
@ -572,7 +576,7 @@ struct msgb *gsm0808_create_ass_fail(uint8_t cause, const uint8_t *rr_cause,
return NULL;
msgb_v_put(msg, BSS_MAP_MSG_ASSIGMENT_FAILURE);
msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause);
gsm0808_enc_cause(msg, cause);
/* RR cause 3.2.2.22 */
if (rr_cause)
@ -614,7 +618,7 @@ struct msgb *gsm0808_create_clear_rqst(uint8_t cause)
return NULL;
msgb_v_put(msg, BSS_MAP_MSG_CLEAR_RQST);
msgb_tlv_put(msg, GSM0808_IE_CAUSE, 1, &cause);
gsm0808_enc_cause(msg, cause);
msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg));
return msg;
@ -751,7 +755,7 @@ struct msgb *gsm0808_create_handover_required(const struct gsm0808_handover_requ
msgb_v_put(msg, BSS_MAP_MSG_HANDOVER_REQUIRED);
/* Cause, 3.2.2.5 */
msgb_tlv_put(msg, GSM0808_IE_CAUSE, params->cause & 0x80? 2 : 1, (const uint8_t*)&params->cause);
gsm0808_enc_cause(msg, params->cause);
/* Cell Identifier List, 3.2.2.27 */
gsm0808_enc_cell_id_list2(msg, &params->cil);
@ -876,7 +880,7 @@ struct msgb *gsm0808_create_handover_failure(const struct gsm0808_handover_failu
msgb_v_put(msg, BSS_MAP_MSG_HANDOVER_FAILURE);
/* Cause, 3.2.2.5 */
msgb_tlv_put(msg, GSM0808_IE_CAUSE, params->cause & 0x80? 2 : 1, (const uint8_t*)&params->cause);
gsm0808_enc_cause(msg, params->cause);
/* RR Cause, 3.2.2.22 */
if (params->rr_cause_present)
@ -907,7 +911,7 @@ struct msgb *gsm0808_create_handover_performed(const struct gsm0808_handover_per
msgb_v_put(msg, BSS_MAP_MSG_HANDOVER_PERFORMED);
/* Cause, 3.2.2.5 */
msgb_tlv_put(msg, GSM0808_IE_CAUSE, gsm0808_cause_ext(params->cause) ? 2 : 1, (const uint8_t *)&params->cause);
gsm0808_enc_cause(msg, params->cause);
/* Cell Identifier, 3.2.2.17 */
gsm0808_enc_cell_id(msg, &params->cell_id);

View File

@ -48,6 +48,32 @@
* \file gsm0808_utils.c
*/
/*! Encode TS 08.08 AoIP Cause IE
* \param[out] msg Message Buffer to which to append IE
* \param[in] cause Cause code to be used in IE
* \returns number of bytes added to \a msg */
uint8_t gsm0808_enc_cause(struct msgb *msg, uint16_t cause)
{
/* See also 3GPP TS 48.008 3.2.2.5 Cause */
uint8_t *old_tail;
bool extended;
old_tail = msg->tail;
extended = gsm0808_cause_ext(cause >> 8);
msgb_put_u8(msg, GSM0808_IE_CAUSE);
if (extended) {
msgb_put_u8(msg, 2);
msgb_put_u16(msg, cause);
} else {
msgb_put_u8(msg, 1);
msgb_put_u8(msg, (uint8_t) (cause & 0xFF));
}
return (uint8_t) (msg->tail - old_tail);
}
/*! Encode TS 08.08 AoIP transport address IE
* \param[out] msg Message Buffer to which to append IE
* \param[in] ss Socket Address to be used in IE

View File

@ -183,6 +183,7 @@ gsm0808_create_handover_complete;
gsm0808_create_handover_failure;
gsm0808_create_handover_performed;
gsm0808_prepend_dtap_header;
gsm0808_enc_cause;
gsm0808_enc_aoip_trasp_addr;
gsm0808_dec_aoip_trasp_addr;
gsm0808_enc_speech_codec;

View File

@ -30,6 +30,13 @@
#include <arpa/inet.h>
#include <errno.h>
#define EXPECT_ENCODED(hexstr) do { \
const char *enc_str = msgb_hexdump(msg); \
printf("%s: encoded: %s(rc = %u)\n", __func__, enc_str, rc_enc); \
OSMO_ASSERT(strcmp(enc_str, hexstr " ") == 0); \
OSMO_ASSERT(rc_enc == msg->len); \
} while(0)
#define VERIFY(msg, data, len) \
if (msgb_l3len(msg) != len) { \
printf("%s:%d Length don't match: %d vs. %d. %s\n", \
@ -65,6 +72,27 @@ static void setup_codec_list(struct gsm0808_speech_codec_list *scl)
scl->len = 3;
}
void test_gsm0808_enc_cause(void)
{
/* NOTE: This must be tested early because many of the following tests
* rely on the generation of a proper cause code. */
uint8_t rc_enc;
struct msgb *msg;
/* Test with a single byte cause code */
msg = msgb_alloc(1024, "output buffer");
rc_enc = gsm0808_enc_cause(msg, 0x41);
EXPECT_ENCODED("04 01 41");
msgb_free(msg);
/* Test with an extended (two byte) cause code */
msg = msgb_alloc(1024, "output buffer");
rc_enc = gsm0808_enc_cause(msg, 0x8041);
EXPECT_ENCODED("04 02 80 41");
msgb_free(msg);
}
static void test_create_layer3(void)
{
static const uint8_t res[] = {
@ -824,13 +852,6 @@ static void test_gsm0808_enc_dec_encrypt_info()
msgb_free(msg);
}
#define EXPECT_ENCODED(hexstr) do { \
const char *enc_str = msgb_hexdump(msg); \
printf("%s: encoded: %s(rc = %u)\n", __func__, enc_str, rc_enc); \
OSMO_ASSERT(strcmp(enc_str, hexstr " ") == 0); \
OSMO_ASSERT(rc_enc == msg->len); \
} while(0)
static void test_gsm0808_enc_dec_cell_id_list_lac()
{
struct gsm0808_cell_id_list2 enc_cil;
@ -1770,6 +1791,7 @@ void test_gsm48_mr_cfg_from_gsm0808_sc_cfg()
int main(int argc, char **argv)
{
printf("Testing generation of GSM0808 messages\n");
test_gsm0808_enc_cause();
test_create_layer3();
test_create_layer3_aoip();
test_create_reset();

View File

@ -1,4 +1,6 @@
Testing generation of GSM0808 messages
test_gsm0808_enc_cause: encoded: 04 01 41 (rc = 3)
test_gsm0808_enc_cause: encoded: 04 02 80 41 (rc = 4)
Testing creating Layer3
Testing creating Layer3 (AoIP)
Testing creating Reset