diff --git a/include/osmocom/ranap/iu_helpers.h b/include/osmocom/ranap/iu_helpers.h index 9d801be6..d8246468 100644 --- a/include/osmocom/ranap/iu_helpers.h +++ b/include/osmocom/ranap/iu_helpers.h @@ -1,13 +1,20 @@ #pragma once #include +#include #include #include #include +#include + +struct osmo_sockaddr; int ranap_bcd_decode(char *out, size_t out_len, const uint8_t *in, size_t in_len); int ranap_imsi_encode(uint8_t *out, size_t out_len, const char *in); int ranap_transp_assoc_decode(uint16_t *port, const RANAP_IuTransportAssociation_t *transp_assoc); int ranap_transp_layer_addr_decode(char *addr, unsigned int addr_len, const RANAP_TransportLayerAddress_t *trasp_layer_addr); +RANAP_TransportLayerInformation_t *ranap_new_transp_info_rtp(struct osmo_sockaddr *addr, bool use_x213_nsap); +RANAP_TransportLayerInformation_t *ranap_new_transp_info_gtp(struct osmo_sockaddr *addr, uint32_t tei, + bool use_x213_nsap); diff --git a/src/iu_helpers.c b/src/iu_helpers.c index bf82fde3..392622ff 100644 --- a/src/iu_helpers.c +++ b/src/iu_helpers.c @@ -24,8 +24,12 @@ #include #include "asn1helpers.h" #include +#include +#include + #include #include +#include /* decode a BCD-string as used inside ASN.1 encoded Iu interface protocols */ int ranap_bcd_decode(char *out, size_t out_len, const uint8_t *in, size_t in_len) @@ -121,3 +125,102 @@ int ranap_transp_layer_addr_decode(char *addr, unsigned int addr_len, return 0; } + +static int new_transp_layer_addr(BIT_STRING_t *out, struct osmo_sockaddr *addr, bool use_x213_nsap) +{ + uint8_t *buf; + unsigned int len; + size_t ip_len; + uint8_t *ip_addr; + uint16_t icp; + + switch (addr->u.sa.sa_family) { + case AF_INET: + ip_len = sizeof(addr->u.sin.sin_addr.s_addr); + ip_addr = (uint8_t *) &addr->u.sin.sin_addr.s_addr; + icp = 0x0001; /* See X.213, section A.5.2.1.2.7 */ + break; + case AF_INET6: + ip_len = sizeof(addr->u.sin6.sin6_addr.s6_addr); + ip_addr = addr->u.sin6.sin6_addr.s6_addr; + icp = 0x0000; /* See X.213, section A.5.2.1.2.7 */ + break; + default: + return -EINVAL; + } + + if (use_x213_nsap) { + /* 3 bytes IDP (AFI+ICP) + 17 bytes DSP */ + len = 3 + 17; + buf = CALLOC(len, sizeof(uint8_t)); + + /* 1 byte AFI to announce IANA ICP, see also X.213, table A.4 */ + buf[0] = 0x35; + + /* 2 byte IANA ICP IDI, see also X.213, A.5.2.1.2.7 */ + osmo_store16be(icp, &buf[1]); + + /* 17 byte DSP, see also X.213, table A.5 and A.5.2.1.2.7 */ + memcpy(&buf[3], ip_addr, ip_len); + } else { + len = ip_len; + buf = CALLOC(len, sizeof(uint8_t)); + memcpy(buf, ip_addr, ip_len); + } + out->buf = buf; + out->size = len; + out->bits_unused = 0; + + return 0; +} + +RANAP_TransportLayerInformation_t *ranap_new_transp_info_rtp(struct osmo_sockaddr *addr, bool use_x213_nsap) +{ + RANAP_TransportLayerInformation_t *tli; + uint8_t binding_id[4] = { 0 }; + int rc; + + switch (addr->u.sin.sin_family) { + case AF_INET: + osmo_store16be(ntohs(addr->u.sin.sin_port), binding_id); + break; + case AF_INET6: + osmo_store16be(ntohs(addr->u.sin6.sin6_port), binding_id); + break; + default: + return NULL; + } + + tli = CALLOC(1, sizeof(*tli)); + rc = new_transp_layer_addr(&tli->transportLayerAddress, addr, use_x213_nsap); + if (rc < 0) { + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + return NULL; + } + + tli->iuTransportAssociation.present = RANAP_IuTransportAssociation_PR_bindingID; + OCTET_STRING_fromBuf(&tli->iuTransportAssociation.choice.bindingID, + (const char *)binding_id, sizeof(binding_id)); + + return tli; +} + +RANAP_TransportLayerInformation_t *ranap_new_transp_info_gtp(struct osmo_sockaddr *addr, uint32_t tei, + bool use_x213_nsap) +{ + RANAP_TransportLayerInformation_t *tli = CALLOC(1, sizeof(*tli)); + uint32_t binding_buf = htonl(tei); + int rc; + + rc = new_transp_layer_addr(&tli->transportLayerAddress, addr, use_x213_nsap); + if (rc < 0) { + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + return NULL; + } + + tli->iuTransportAssociation.present = RANAP_IuTransportAssociation_PR_gTP_TEI; + OCTET_STRING_fromBuf(&tli->iuTransportAssociation.choice.gTP_TEI, + (const char *)&binding_buf, sizeof(binding_buf)); + + return tli; +} diff --git a/src/ranap_msg_factory.c b/src/ranap_msg_factory.c index f93a2ab8..60dc9e02 100644 --- a/src/ranap_msg_factory.c +++ b/src/ranap_msg_factory.c @@ -20,6 +20,7 @@ #include #include +#include #include "asn1helpers.h" #include @@ -691,61 +692,6 @@ static RANAP_RAB_Parameters_t *new_rab_par_data(uint32_t dl_max_bitrate, uint32_ return rab; } -static void new_transp_layer_addr(BIT_STRING_t *out, uint32_t ip, bool use_x213_nsap) -{ - uint8_t *buf; - unsigned int len; - uint32_t ip_h = ntohl(ip); - - if (use_x213_nsap) { - len = 160/8; - buf = CALLOC(len, sizeof(uint8_t)); - buf[0] = 0x35; /* AFI For IANA ICP */ - buf[1] = 0x00; /* See A.5.2.1.2.7 of X.213 */ - buf[2] = 0x01; - memcpy(&buf[3], &ip_h, sizeof(ip_h)); - } else { - len = sizeof(ip_h); - buf = CALLOC(len, sizeof(uint8_t)); - memcpy(buf, &ip_h, sizeof(ip_h)); - } - out->buf = buf; - out->size = len; - out->bits_unused = 0; -} - -static RANAP_TransportLayerInformation_t *new_transp_info_rtp(uint32_t ip, uint16_t port, - bool use_x213_nsap) -{ - RANAP_TransportLayerInformation_t *tli = CALLOC(1, sizeof(*tli)); - uint8_t binding_id[4]; - - binding_id[0] = port >> 8; - binding_id[1] = port & 0xff; - binding_id[2] = binding_id[3] = 0; - - new_transp_layer_addr(&tli->transportLayerAddress, ip, use_x213_nsap); - tli->iuTransportAssociation.present = RANAP_IuTransportAssociation_PR_bindingID; - OCTET_STRING_fromBuf(&tli->iuTransportAssociation.choice.bindingID, - (const char *) binding_id, sizeof(binding_id)); - - return tli; -} - -static RANAP_TransportLayerInformation_t *new_transp_info_gtp(uint32_t ip, uint32_t tei, - bool use_x213_nsap) -{ - RANAP_TransportLayerInformation_t *tli = CALLOC(1, sizeof(*tli)); - uint32_t binding_buf = htonl(tei); - - new_transp_layer_addr(&tli->transportLayerAddress, ip, use_x213_nsap); - tli->iuTransportAssociation.present = RANAP_IuTransportAssociation_PR_gTP_TEI; - OCTET_STRING_fromBuf(&tli->iuTransportAssociation.choice.gTP_TEI, - (const char *) &binding_buf, sizeof(binding_buf)); - - return tli; -} - static RANAP_UserPlaneInformation_t *new_upi(long mode, uint8_t mode_versions) { RANAP_UserPlaneInformation_t *upi = CALLOC(1, sizeof(*upi)); @@ -786,6 +732,7 @@ struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id, uint32_t rtp_ip, RANAP_RAB_AssignmentRequest_t out; struct msgb *msg; int rc; + struct osmo_sockaddr rtp_addr; memset(&ies, 0, sizeof(ies)); memset(&out, 0, sizeof(out)); @@ -800,8 +747,11 @@ struct msgb *ranap_new_msg_rab_assign_voice(uint8_t rab_id, uint32_t rtp_ip, first.nAS_SynchronisationIndicator = new_rab_nas_sync_ind(60); first.rAB_Parameters = new_rab_par_voice(6700, 12200); first.userPlaneInformation = new_upi(RANAP_UserPlaneMode_support_mode_for_predefined_SDU_sizes, 1); /* 2? */ - first.transportLayerInformation = new_transp_info_rtp(rtp_ip, rtp_port, - use_x213_nsap); + + rtp_addr.u.sin.sin_family = AF_INET; + rtp_addr.u.sin.sin_port = htons(rtp_port); + rtp_addr.u.sin.sin_addr.s_addr = htonl(rtp_ip); + first.transportLayerInformation = ranap_new_transp_info_rtp(&rtp_addr, use_x213_nsap); /* put together the 'Second' part */ RANAP_RAB_SetupOrModifyItemSecond_t second; @@ -855,6 +805,7 @@ struct msgb *ranap_new_msg_rab_assign_data(uint8_t rab_id, uint32_t gtp_ip, RANAP_DataVolumeReportingIndication_t *dat_vol_ind; struct msgb *msg; int rc; + struct osmo_sockaddr gtp_addr; memset(&ies, 0, sizeof(ies)); memset(&out, 0, sizeof(out)); @@ -870,8 +821,10 @@ struct msgb *ranap_new_msg_rab_assign_data(uint8_t rab_id, uint32_t gtp_ip, first.rAB_Parameters = new_rab_par_data(1600000, 800000); first.userPlaneInformation = new_upi(RANAP_UserPlaneMode_transparent_mode, 1); - first.transportLayerInformation = new_transp_info_gtp(gtp_ip, gtp_tei, - use_x213_nsap); + + gtp_addr.u.sin.sin_family = AF_INET; + gtp_addr.u.sin.sin_addr.s_addr = htonl(gtp_ip); + first.transportLayerInformation = ranap_new_transp_info_gtp(>p_addr, gtp_tei, use_x213_nsap); /* put together the 'Second' part */ RANAP_RAB_SetupOrModifyItemSecond_t second; diff --git a/src/tests/test-helpers.c b/src/tests/test-helpers.c index 5c617e52..96540dc0 100644 --- a/src/tests/test-helpers.c +++ b/src/tests/test-helpers.c @@ -28,6 +28,7 @@ #define ASSERT(x) assert(x) #include +#include #include #include @@ -204,6 +205,120 @@ void test_ranap_common(void) OSMO_ASSERT(rc == -1); } +void test_ranap_new_transp_info_rtp(void) +{ + RANAP_TransportLayerInformation_t *tli; + + printf("Testing function ranap_new_transp_info_rtp()\n"); + + struct osmo_sockaddr addr; + + addr.u.sin.sin_family = AF_INET; + addr.u.sin.sin_port = htons(0x1122); + inet_pton(AF_INET, "1.2.3.4", &addr.u.sin.sin_addr); + + printf(" ipv4, x213_nsap\n"); + tli = ranap_new_transp_info_rtp(&addr, true); + printf(" transportLayerAddress = %s\n", + osmo_hexdump_nospc(tli->transportLayerAddress.buf, tli->transportLayerAddress.size)); + printf(" bindingID = %s\n", + osmo_hexdump_nospc(tli->iuTransportAssociation.choice.bindingID.buf, + tli->iuTransportAssociation.choice.bindingID.size)); + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + + printf(" ipv4\n"); + tli = ranap_new_transp_info_rtp(&addr, false); + printf(" transportLayerAddress = %s\n", + osmo_hexdump_nospc(tli->transportLayerAddress.buf, tli->transportLayerAddress.size)); + printf(" bindingID = %s\n", + osmo_hexdump_nospc(tli->iuTransportAssociation.choice.bindingID.buf, + tli->iuTransportAssociation.choice.bindingID.size)); + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + + addr.u.sin.sin_family = AF_INET6; + addr.u.sin.sin_port = htons(0x1122); + inet_pton(AF_INET6, "f11f:f22f:f33f:f44f:f55f:f66f:f77f:f88f", &addr.u.sin6.sin6_addr); + + printf(" ipv6, x213_nsap\n"); + tli = ranap_new_transp_info_rtp(&addr, true); + printf(" transportLayerAddress = %s\n", + osmo_hexdump_nospc(tli->transportLayerAddress.buf, tli->transportLayerAddress.size)); + printf(" bindingID = %s\n", + osmo_hexdump_nospc(tli->iuTransportAssociation.choice.bindingID.buf, + tli->iuTransportAssociation.choice.bindingID.size)); + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + + printf(" ipv6\n"); + tli = ranap_new_transp_info_rtp(&addr, false); + printf(" transportLayerAddress = %s\n", + osmo_hexdump_nospc(tli->transportLayerAddress.buf, tli->transportLayerAddress.size)); + printf(" bindingID = %s\n", + osmo_hexdump_nospc(tli->iuTransportAssociation.choice.bindingID.buf, + tli->iuTransportAssociation.choice.bindingID.size)); + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + + addr.u.sin.sin_family = AF_X25; + printf(" unsupported address family\n"); + tli = ranap_new_transp_info_rtp(&addr, false); + OSMO_ASSERT(tli == NULL); +} + +void test_ranap_new_transp_info_gtp(void) +{ + RANAP_TransportLayerInformation_t *tli; + + printf("Testing function ranap_new_transp_info_gtp()\n"); + + struct osmo_sockaddr addr; + + addr.u.sin.sin_family = AF_INET; + inet_pton(AF_INET, "1.2.3.4", &addr.u.sin.sin_addr); + + printf(" ipv4, x213_nsap\n"); + tli = ranap_new_transp_info_gtp(&addr, 0x11223344, true); + printf(" transportLayerAddress = %s\n", + osmo_hexdump_nospc(tli->transportLayerAddress.buf, tli->transportLayerAddress.size)); + printf(" gTP_TEI = %s\n", + osmo_hexdump_nospc(tli->iuTransportAssociation.choice.gTP_TEI.buf, + tli->iuTransportAssociation.choice.gTP_TEI.size)); + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + + printf(" ipv4\n"); + tli = ranap_new_transp_info_gtp(&addr, 0x11223344, false); + printf(" transportLayerAddress = %s\n", + osmo_hexdump_nospc(tli->transportLayerAddress.buf, tli->transportLayerAddress.size)); + printf(" gTP_TEI = %s\n", + osmo_hexdump_nospc(tli->iuTransportAssociation.choice.gTP_TEI.buf, + tli->iuTransportAssociation.choice.gTP_TEI.size)); + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + + addr.u.sin.sin_family = AF_INET6; + inet_pton(AF_INET6, "f11f:f22f:f33f:f44f:f55f:f66f:f77f:f88f", &addr.u.sin6.sin6_addr); + + printf(" ipv6, x213_nsap\n"); + tli = ranap_new_transp_info_gtp(&addr, 0x11223344, true); + printf(" transportLayerAddress = %s\n", + osmo_hexdump_nospc(tli->transportLayerAddress.buf, tli->transportLayerAddress.size)); + printf(" gTP_TEI = %s\n", + osmo_hexdump_nospc(tli->iuTransportAssociation.choice.gTP_TEI.buf, + tli->iuTransportAssociation.choice.gTP_TEI.size)); + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + + printf(" ipv6\n"); + tli = ranap_new_transp_info_gtp(&addr, 0x11223344, false); + printf(" transportLayerAddress = %s\n", + osmo_hexdump_nospc(tli->transportLayerAddress.buf, tli->transportLayerAddress.size)); + printf(" gTP_TEI = %s\n", + osmo_hexdump_nospc(tli->iuTransportAssociation.choice.gTP_TEI.buf, + tli->iuTransportAssociation.choice.gTP_TEI.size)); + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, tli); + + addr.u.sin.sin_family = AF_X25; + printf(" unsupported address family\n"); + tli = ranap_new_transp_info_gtp(&addr, 0x11223344, false); + OSMO_ASSERT(tli == NULL); +} + int main(int argc, char **argv) { asn1_xer_print = 0; @@ -214,6 +329,8 @@ int main(int argc, char **argv) test_iu_helpers(); test_asn1_helpers(); test_ranap_common(); + test_ranap_new_transp_info_gtp(); + test_ranap_new_transp_info_rtp(); test_common_cleanup(); return 0; diff --git a/src/tests/test-helpers.ok b/src/tests/test-helpers.ok index f2e466f4..049fbb41 100644 --- a/src/tests/test-helpers.ok +++ b/src/tests/test-helpers.ok @@ -23,3 +23,31 @@ PLMN-Id [ 21 43 ], LAC [ ab cd ] rc == -1 PLMN-Id [ 21 43 65 ], LAC [ ab ] rc == -1 +Testing function ranap_new_transp_info_gtp() + ipv4, x213_nsap + transportLayerAddress = 3500010102030400000000000000000000000000 + gTP_TEI = 11223344 + ipv4 + transportLayerAddress = 01020304 + gTP_TEI = 11223344 + ipv6, x213_nsap + transportLayerAddress = 350000f11ff22ff33ff44ff55ff66ff77ff88f00 + gTP_TEI = 11223344 + ipv6 + transportLayerAddress = f11ff22ff33ff44ff55ff66ff77ff88f + gTP_TEI = 11223344 + unsupported address family +Testing function ranap_new_transp_info_rtp() + ipv4, x213_nsap + transportLayerAddress = 3500010102030400000000000000000000000000 + bindingID = 11220000 + ipv4 + transportLayerAddress = 01020304 + bindingID = 11220000 + ipv6, x213_nsap + transportLayerAddress = 350000f11ff22ff33ff44ff55ff66ff77ff88f00 + bindingID = 11220000 + ipv6 + transportLayerAddress = f11ff22ff33ff44ff55ff66ff77ff88f + bindingID = 11220000 + unsupported address family