diff --git a/include/osmocom/gsm/gsm0808_utils.h b/include/osmocom/gsm/gsm0808_utils.h index 097bd76bb..90ff6771a 100644 --- a/include/osmocom/gsm/gsm0808_utils.h +++ b/include/osmocom/gsm/gsm0808_utils.h @@ -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, diff --git a/src/gsm/gsm0808.c b/src/gsm/gsm0808.c index c0d5f39d0..e951ab1fe 100644 --- a/src/gsm/gsm0808.c +++ b/src/gsm/gsm0808.c @@ -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*)¶ms->cause); + gsm0808_enc_cause(msg, params->cause); /* Cell Identifier List, 3.2.2.27 */ gsm0808_enc_cell_id_list2(msg, ¶ms->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*)¶ms->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 *)¶ms->cause); + gsm0808_enc_cause(msg, params->cause); /* Cell Identifier, 3.2.2.17 */ gsm0808_enc_cell_id(msg, ¶ms->cell_id); diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c index c58d8284f..38a8664cb 100644 --- a/src/gsm/gsm0808_utils.c +++ b/src/gsm/gsm0808_utils.c @@ -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 diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index e9a9e4f29..dc4e0a69d 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -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; diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c index 197ec06da..63b87200d 100644 --- a/tests/gsm0808/gsm0808_test.c +++ b/tests/gsm0808/gsm0808_test.c @@ -30,6 +30,13 @@ #include #include +#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(); diff --git a/tests/gsm0808/gsm0808_test.ok b/tests/gsm0808/gsm0808_test.ok index a48cf1d57..e5833d011 100644 --- a/tests/gsm0808/gsm0808_test.ok +++ b/tests/gsm0808/gsm0808_test.ok @@ -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