Review at https://gerrit.osmocom.org/2178
gsm0808: Add AoIP specific elements to gsm0808_create_... functions the classic A implementation in libosmocore lacks support for AoIP message elements. This patch adds support for AoIP by adding a set of new gsm0808_create_..., which support the missing AoIP message elements Change-Id: I77f866abec1822d19871052f3c647ad782785b34 --- M include/osmocom/gsm/gsm0808.h M src/gsm/gsm0808.c M src/gsm/libosmogsm.map M tests/gsm0808/gsm0808_test.c M tests/gsm0808/gsm0808_test.ok 5 files changed, 284 insertions(+), 18 deletions(-) git pull ssh://gerrit.osmocom.org:29418/libosmocore refs/changes/78/2178/1 diff --git a/include/osmocom/gsm/gsm0808.h b/include/osmocom/gsm/gsm0808.h index a7e102c..7ef62b2 100644 --- a/include/osmocom/gsm/gsm0808.h +++ b/include/osmocom/gsm/gsm0808.h @@ -20,10 +20,16 @@ #pragma once #include "tlv.h" +#include <osmocom/gsm/protocol/gsm_08_08.h> +#include <sys/socket.h> struct msgb; -struct msgb *gsm0808_create_layer3(struct msgb *msg, uint16_t netcode, uint16_t countrycode, int lac, uint16_t ci); +struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, + uint16_t cc, int lac, uint16_t _ci); +struct msgb *gsm0808_create_layer3_aoip(struct msgb *msg_l3, uint16_t nc, + uint16_t cc, int lac, uint16_t _ci, + struct llist_head *scl); struct msgb *gsm0808_create_reset(void); struct msgb *gsm0808_create_reset_ack(void); struct msgb *gsm0808_create_clear_command(uint8_t reason); @@ -33,9 +39,22 @@ struct msgb *gsm0808_create_classmark_update(const uint8_t *cm2, uint8_t cm2_len, const uint8_t *cm3, uint8_t cm3_len); struct msgb *gsm0808_create_sapi_reject(uint8_t link_id); +struct msgb *gsm0808_create_assignment_completed_aoip(uint8_t rr_cause, + uint8_t chosen_channel, + uint8_t encr_alg_id, + uint8_t speech_mode, + struct sockaddr_storage + *ss, + struct + gsm0808_speech_codec *sc, + struct llist_head *scl); struct msgb *gsm0808_create_assignment_completed(uint8_t rr_cause, - uint8_t chosen_channel, uint8_t encr_alg_id, + uint8_t chosen_channel, + uint8_t encr_alg_id, uint8_t speech_mode); +struct msgb *gsm0808_create_assignment_failure_aoip(uint8_t cause, + uint8_t *rr_cause, + struct llist_head *scl); struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause); struct msgb *gsm0808_create_clear_rqst(uint8_t cause); diff --git a/src/gsm/gsm0808.c b/src/gsm/gsm0808.c index de80006..c37ce3e 100644 --- a/src/gsm/gsm0808.c +++ b/src/gsm/gsm0808.c @@ -19,6 +19,7 @@ */ #include <osmocom/gsm/gsm0808.h> +#include <osmocom/gsm/gsm0808_utils.h> #include <osmocom/gsm/protocol/gsm_08_08.h> #include <osmocom/gsm/gsm48.h> @@ -27,17 +28,20 @@ #define BSSMAP_MSG_SIZE 512 #define BSSMAP_MSG_HEADROOM 128 -struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, uint16_t cc, int lac, uint16_t _ci) +struct msgb *gsm0808_create_layer3_aoip(struct msgb *msg_l3, uint16_t nc, + uint16_t cc, int lac, uint16_t _ci, + struct llist_head *scl) { - struct msgb* msg; + struct msgb *msg; + struct msgb *scl_encoded; struct { uint8_t ident; struct gsm48_loc_area_id lai; uint16_t ci; } __attribute__ ((packed)) lai_ci; - msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap cmpl l3"); + msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap cmpl l3"); if (!msg) return NULL; @@ -49,16 +53,35 @@ gsm48_generate_lai(&lai_ci.lai, cc, nc, lac); lai_ci.ci = htons(_ci); msgb_tlv_put(msg, GSM0808_IE_CELL_IDENTIFIER, sizeof(lai_ci), - (uint8_t *) &lai_ci); + (uint8_t *) & lai_ci); /* copy the layer3 data */ msgb_tlv_put(msg, GSM0808_IE_LAYER_3_INFORMATION, msgb_l3len(msg_l3), msg_l3->l3h); + /* AoIP: add Codec List (BSS Supported) 3.2.2.103 */ + if (scl) { + scl_encoded = gsm0808_enc_speech_codec_list(scl); + if (!scl_encoded) { + msgb_free(msg); + return NULL; + } + msgb_tlv_put(msg, GSM0808_IE_SPEECH_CODEC_LIST, + scl_encoded->len, scl_encoded->data); + msgb_free(scl_encoded); + } + /* push the bssmap header */ - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + msg->l3h = + msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; +} + +struct msgb *gsm0808_create_layer3(struct msgb *msg_l3, uint16_t nc, + uint16_t cc, int lac, uint16_t _ci) +{ + return gsm0808_create_layer3_aoip(msg_l3, nc, cc, lac, _ci, NULL); } struct msgb *gsm0808_create_reset(void) @@ -191,12 +214,22 @@ return msg; } -struct msgb *gsm0808_create_assignment_completed(uint8_t rr_cause, - uint8_t chosen_channel, uint8_t encr_alg_id, - uint8_t speech_mode) +struct msgb *gsm0808_create_assignment_completed_aoip(uint8_t rr_cause, + uint8_t chosen_channel, + uint8_t encr_alg_id, + uint8_t speech_mode, + struct sockaddr_storage + *ss, + struct + gsm0808_speech_codec *sc, + struct llist_head *scl) { - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: ass compl"); + struct msgb *ss_encoded; + struct msgb *sc_encoded; + struct msgb *scl_encoded; + struct msgb *msg = + msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap: ass compl"); if (!msg) return NULL; @@ -218,17 +251,70 @@ if (speech_mode != 0) msgb_tv_put(msg, GSM0808_IE_SPEECH_VERSION, speech_mode); + /* AoIP: AoIP Transport Layer Address (BSS) 3.2.2.102 */ + if (ss) { + ss_encoded = gsm0808_enc_aoip_trasp_addr(ss); + if (!ss_encoded) { + msgb_free(msg); + return NULL; + } + msgb_tlv_put(msg, GSM0808_IE_AOIP_TRASP_ADDR, + ss_encoded->len, ss_encoded->data); + msgb_free(ss_encoded); + } + + /* AoIP: Speech Codec (Chosen) 3.2.2.104 */ + if (sc) { + sc_encoded = gsm0808_enc_speech_codec(sc); + if (!sc_encoded) { + msgb_free(msg); + return NULL; + } + msgb_tlv_put(msg, GSM0808_IE_SPEECH_CODEC, + sc_encoded->len, sc_encoded->data); + msgb_free(sc_encoded); + } + + /* AoIP: add Codec List (BSS Supported) 3.2.2.103 */ + if (scl) { + scl_encoded = gsm0808_enc_speech_codec_list(scl); + if (!scl_encoded) { + msgb_free(msg); + return NULL; + } + msgb_tlv_put(msg, GSM0808_IE_SPEECH_CODEC_LIST, + scl_encoded->len, scl_encoded->data); + msgb_free(scl_encoded); + } + /* write LSA identifier 3.2.2.15 */ - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + msg->l3h = + msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; } -struct msgb *gsm0808_create_assignment_failure(uint8_t cause, uint8_t *rr_cause) +struct msgb *gsm0808_create_assignment_completed(uint8_t rr_cause, + uint8_t chosen_channel, + uint8_t encr_alg_id, + uint8_t speech_mode) { - struct msgb *msg = msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, - "bssmap: ass fail"); + return gsm0808_create_assignment_completed_aoip(rr_cause, + chosen_channel, + encr_alg_id, + speech_mode, + NULL, NULL, NULL); +} + +struct msgb *gsm0808_create_assignment_failure_aoip(uint8_t cause, + uint8_t *rr_cause, + struct llist_head *scl) +{ + struct msgb *scl_encoded; + struct msgb *msg = + msgb_alloc_headroom(BSSMAP_MSG_SIZE, BSSMAP_MSG_HEADROOM, + "bssmap: ass fail"); if (!msg) return NULL; @@ -242,12 +328,31 @@ /* Circuit pool 3.22.45 */ /* Circuit pool list 3.2.2.46 */ + /* AoIP: add Codec List (BSS Supported) 3.2.2.103 */ + if (scl) { + scl_encoded = gsm0808_enc_speech_codec_list(scl); + if (!scl_encoded) { + msgb_free(msg); + return NULL; + } + msgb_tlv_put(msg, GSM0808_IE_SPEECH_CODEC_LIST, + scl_encoded->len, scl_encoded->data); + msgb_free(scl_encoded); + } + /* update the size */ - msg->l3h = msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); + msg->l3h = + msgb_tv_push(msg, BSSAP_MSG_BSS_MANAGEMENT, msgb_length(msg)); return msg; } +struct msgb *gsm0808_create_assignment_failure(uint8_t cause, + uint8_t *rr_cause) +{ + return gsm0808_create_assignment_failure_aoip(cause, rr_cause, NULL); +} + struct msgb *gsm0808_create_clear_rqst(uint8_t cause) { struct msgb *msg; diff --git a/src/gsm/libosmogsm.map b/src/gsm/libosmogsm.map index c89cbe4..3c23ed8 100644 --- a/src/gsm/libosmogsm.map +++ b/src/gsm/libosmogsm.map @@ -125,7 +125,9 @@ gsm0808_bssap_name; gsm0808_bssmap_name; gsm0808_create_assignment_completed; +gsm0808_create_assignment_completed_aoip; gsm0808_create_assignment_failure; +gsm0808_create_assignment_failure_aoip; gsm0808_create_cipher_complete; gsm0808_create_cipher_reject; gsm0808_create_classmark_update; @@ -134,6 +136,7 @@ gsm0808_create_clear_rqst; gsm0808_create_dtap; gsm0808_create_layer3; +gsm0808_create_layer3_aoip; gsm0808_create_reset; gsm0808_create_sapi_reject; gsm0808_prepend_dtap_header; diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c index 7f2cff1..6cfcf34 100644 --- a/tests/gsm0808/gsm0808_test.c +++ b/tests/gsm0808/gsm0808_test.c @@ -41,6 +41,47 @@ abort(); \ } +/* Setup a fake codec list for testing */ +static struct llist_head *setup_codec_list(const void *ctx) +{ + struct gsm0808_speech_codec *enc_sc1; + struct gsm0808_speech_codec *enc_sc2; + struct gsm0808_speech_codec *enc_sc3; + + struct llist_head *sc_list; + + sc_list = talloc_zero(ctx, struct llist_head); + enc_sc1 = talloc_zero(sc_list, struct gsm0808_speech_codec); + enc_sc2 = talloc_zero(sc_list, struct gsm0808_speech_codec); + enc_sc3 = talloc_zero(sc_list, struct gsm0808_speech_codec); + + INIT_LLIST_HEAD(sc_list); + + memset(enc_sc1, 0, sizeof(*enc_sc1)); + enc_sc1->pi = true; + enc_sc1->tf = true; + enc_sc1->type = 0xab; + enc_sc1->type_extended = true; + enc_sc1->cfg_present = true; + enc_sc1->cfg = 0xcdef; + + memset(enc_sc2, 0, sizeof(*enc_sc2)); + enc_sc2->fi = true; + enc_sc2->pt = true; + enc_sc2->type = 0x05; + + memset(enc_sc3, 0, sizeof(*enc_sc3)); + enc_sc3->fi = true; + enc_sc3->tf = true; + enc_sc3->type = 0xf2; + enc_sc3->type_extended = true; + + llist_add(&enc_sc3->list, sc_list); + llist_add(&enc_sc2->list, sc_list); + llist_add(&enc_sc1->list, sc_list); + + return sc_list; +} static void test_create_layer3(void) { @@ -56,6 +97,34 @@ msg = gsm0808_create_layer3(in_msg, 0x1122, 0x2244, 0x3366, 0x4488); VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); + msgb_free(in_msg); +} + +static void test_create_layer3_aoip(const void *ctx) +{ + static const uint8_t res[] = { + 0x00, 0x17, 0x57, 0x05, 0x08, 0x00, 0x77, 0x62, + 0x83, 0x33, 0x66, 0x44, 0x88, 0x17, 0x01, 0x23, + GSM0808_IE_SPEECH_CODEC_LIST, 0x07, 0x5f, 0xab, 0xcd, 0xef, + 0xa5, 0x9f, 0xf2 + }; + + struct msgb *msg, *in_msg; + struct llist_head *sc_list; + printf("Testing creating Layer3 (AoIP)\n"); + + sc_list = setup_codec_list(ctx); + + in_msg = msgb_alloc_headroom(512, 128, "foo"); + in_msg->l3h = in_msg->data; + msgb_v_put(in_msg, 0x23); + + msg = + gsm0808_create_layer3_aoip(in_msg, 0x1122, 0x2244, 0x3366, 0x4488, + sc_list); + VERIFY(msg, res, ARRAY_SIZE(res)); + talloc_free(sc_list); msgb_free(msg); msgb_free(in_msg); } @@ -189,6 +258,44 @@ msgb_free(msg); } +static void test_create_ass_compl_aoip(const void *ctx) +{ + struct sockaddr_storage ss; + struct sockaddr_in sin; + struct gsm0808_speech_codec sc; + struct llist_head *sc_list; + static const uint8_t res[] = + { 0x00, 0x1d, 0x02, 0x15, 0x23, 0x21, 0x42, 0x2c, 0x11, 0x40, 0x22, + GSM0808_IE_AOIP_TRASP_ADDR, 0x06, 0xc0, 0xa8, 0x64, 0x17, 0x04, + 0xd2, GSM0808_IE_SPEECH_CODEC, 0x01, 0x9a, + GSM0808_IE_SPEECH_CODEC_LIST, 0x07, 0x5f, 0xab, 0xcd, 0xef, 0xa5, + 0x9f, 0xf2 }; + struct msgb *msg; + + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_port = htons(1234); + inet_aton("192.168.100.23", &sin.sin_addr); + + memset(&ss, 0, sizeof(ss)); + memcpy(&ss, &sin, sizeof(sin)); + + memset(&sc, 0, sizeof(sc)); + sc.fi = true; + sc.tf = true; + sc.type = 0x0a; + + sc_list = setup_codec_list(ctx); + + printf("Testing creating Assignment Complete (AoIP)\n"); + msg = + gsm0808_create_assignment_completed_aoip(0x23, 0x42, 0x11, 0x22, + &ss, &sc, sc_list); + VERIFY(msg, res, ARRAY_SIZE(res)); + msgb_free(msg); + talloc_free(sc_list); +} + static void test_create_ass_fail() { static const uint8_t res1[] = { 0x00, 0x04, 0x03, 0x04, 0x01, 0x23 }; @@ -205,6 +312,32 @@ msg = gsm0808_create_assignment_failure(0x23, &rr_res); VERIFY(msg, res2, ARRAY_SIZE(res2)); msgb_free(msg); +} + +static void test_create_ass_fail_aoip(const void *ctx) +{ + static const uint8_t res1[] = + { 0x00, 0x0d, 0x03, 0x04, 0x01, 0x23, GSM0808_IE_SPEECH_CODEC_LIST, + 0x07, 0x5f, 0xab, 0xcd, 0xef, 0xa5, 0x9f, 0xf2 }; + static const uint8_t res2[] = + { 0x00, 0x0f, 0x03, 0x04, 0x01, 0x23, 0x15, 0x02, + GSM0808_IE_SPEECH_CODEC_LIST, 0x07, 0x5f, 0xab, + 0xcd, 0xef, 0xa5, 0x9f, 0xf2 }; + uint8_t rr_res = 2; + struct msgb *msg; + struct llist_head *sc_list; + + sc_list = setup_codec_list(ctx); + + printf("Testing creating Assignment Failure (AoIP)\n"); + msg = gsm0808_create_assignment_failure_aoip(0x23, NULL, sc_list); + VERIFY(msg, res1, ARRAY_SIZE(res1)); + msgb_free(msg); + + msg = gsm0808_create_assignment_failure_aoip(0x23, &rr_res, sc_list); + VERIFY(msg, res2, ARRAY_SIZE(res2)); + msgb_free(msg); + talloc_free(sc_list); } static void test_create_clear_rqst() @@ -467,6 +600,7 @@ printf("Testing generation of GSM0808 messages\n"); test_create_layer3(); + test_create_layer3_aoip(ctx); test_create_reset(); test_create_clear_command(); test_create_clear_complete(); @@ -475,7 +609,9 @@ test_create_cm_u(); test_create_sapi_reject(); test_create_ass_compl(); + test_create_ass_compl_aoip(ctx); test_create_ass_fail(); + test_create_ass_fail_aoip(ctx); test_create_clear_rqst(); test_create_dtap(); test_prepend_dtap(); diff --git a/tests/gsm0808/gsm0808_test.ok b/tests/gsm0808/gsm0808_test.ok index eb43126..f406551 100644 --- a/tests/gsm0808/gsm0808_test.ok +++ b/tests/gsm0808/gsm0808_test.ok @@ -1,5 +1,6 @@ Testing generation of GSM0808 messages Testing creating Layer3 +Testing creating Layer3 (AoIP) Testing creating Reset Testing creating Clear Command Testing creating Clear Complete @@ -8,7 +9,9 @@ Testing creating CM U Testing creating SAPI Reject Testing creating Assignment Complete +Testing creating Assignment Complete (AoIP) Testing creating Assignment Failure +Testing creating Assignment Failure (AoIP) Testing creating Clear Request Testing creating DTAP Testing prepend DTAP -- To view, visit https://gerrit.osmocom.org/2178 To unsubscribe, visit https://gerrit.osmocom.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I77f866abec1822d19871052f3c647ad782785b34 Gerrit-PatchSet: 1 Gerrit-Project: libosmocore Gerrit-Branch: master Gerrit-Owner: dexter <pma...@sysmocom.de>