From 7daa502a2dd208835ed9e7fabe7658102e77ca9e Mon Sep 17 00:00:00 2001 From: Philipp Maier Date: Thu, 6 Jan 2022 15:45:35 +0100 Subject: [PATCH] ranap_rab_ass: add decoder and rewrite functions for RAB-AssignmentRequest/Response The RANAP RAB AssignmentRequest and AssignmentResponse contains the IP-Address and the IP-Port for the RTP voice stream. In the comming MGCP implementation we will have to extract and replace this information. Lets add functions that do that in a convinient way. Change-Id: I58b542bf23ff5e1db2ccf6833fec91d9ba332837 Related: OS#5152 --- configure.ac | 1 + include/osmocom/hnbgw/Makefile.am | 3 +- include/osmocom/hnbgw/ranap_rab_ass.h | 13 + src/osmo-hnbgw/Makefile.am | 1 + src/osmo-hnbgw/ranap_rab_ass.c | 425 ++++++++++++++++++++++ tests/Makefile.am | 1 + tests/ranap_rab_ass/Makefile.am | 37 ++ tests/ranap_rab_ass/ranap_rab_ass_test.c | 340 +++++++++++++++++ tests/ranap_rab_ass/ranap_rab_ass_test.ok | 16 + tests/testsuite.at | 10 +- 10 files changed, 841 insertions(+), 6 deletions(-) create mode 100644 include/osmocom/hnbgw/ranap_rab_ass.h create mode 100644 src/osmo-hnbgw/ranap_rab_ass.c create mode 100644 tests/ranap_rab_ass/Makefile.am create mode 100644 tests/ranap_rab_ass/ranap_rab_ass_test.c create mode 100644 tests/ranap_rab_ass/ranap_rab_ass_test.ok diff --git a/configure.ac b/configure.ac index a88ff42..520cd68 100644 --- a/configure.ac +++ b/configure.ac @@ -221,6 +221,7 @@ AC_OUTPUT( src/osmo-hnbgw/Makefile tests/Makefile tests/atlocal + tests/ranap_rab_ass/Makefile doc/Makefile doc/examples/Makefile doc/manuals/Makefile diff --git a/include/osmocom/hnbgw/Makefile.am b/include/osmocom/hnbgw/Makefile.am index b2a667d..0ddd42e 100644 --- a/include/osmocom/hnbgw/Makefile.am +++ b/include/osmocom/hnbgw/Makefile.am @@ -1,4 +1,5 @@ noinst_HEADERS = \ vty.h \ context_map.h hnbgw.h hnbgw_cn.h \ - hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h + hnbgw_hnbap.h hnbgw_rua.h hnbgw_ranap.h \ + ranap_rab_ass.h diff --git a/include/osmocom/hnbgw/ranap_rab_ass.h b/include/osmocom/hnbgw/ranap_rab_ass.h new file mode 100644 index 0000000..4cb8e37 --- /dev/null +++ b/include/osmocom/hnbgw/ranap_rab_ass.h @@ -0,0 +1,13 @@ +#pragma once + +int ranap_rab_ass_req_encode(uint8_t *data, unsigned int len, + RANAP_RAB_AssignmentRequestIEs_t *rab_assignment_request_ies); +int ranap_rab_ass_resp_encode(uint8_t *data, unsigned int len, + RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies); + +int ranap_rab_ass_req_ies_extract_inet_addr(struct osmo_sockaddr *addr, uint8_t *rab_id, + RANAP_RAB_AssignmentRequestIEs_t *ies); +int ranap_rab_ass_resp_ies_extract_inet_addr(struct osmo_sockaddr *addr, RANAP_RAB_AssignmentResponseIEs_t *ies); + +int ranap_rab_ass_req_ies_replace_inet_addr(RANAP_RAB_AssignmentRequestIEs_t *ies, struct osmo_sockaddr *addr); +int ranap_rab_ass_resp_ies_replace_inet_addr(RANAP_RAB_AssignmentResponseIEs_t *ies, struct osmo_sockaddr *addr); diff --git a/src/osmo-hnbgw/Makefile.am b/src/osmo-hnbgw/Makefile.am index bda8633..0948170 100644 --- a/src/osmo-hnbgw/Makefile.am +++ b/src/osmo-hnbgw/Makefile.am @@ -37,6 +37,7 @@ osmo_hnbgw_SOURCES = \ hnbgw_vty.c \ context_map.c \ hnbgw_cn.c \ + ranap_rab_ass.c \ $(NULL) osmo_hnbgw_LDADD = \ diff --git a/src/osmo-hnbgw/ranap_rab_ass.c b/src/osmo-hnbgw/ranap_rab_ass.c new file mode 100644 index 0000000..f5d86a1 --- /dev/null +++ b/src/osmo-hnbgw/ranap_rab_ass.c @@ -0,0 +1,425 @@ +/* (C) 2021 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +/* Note: This files contains tools to decode and re-encode the RAB-AssignmentRequest. This set of tools is used by + * mgcp_fsm.c to extract and manipulate the transportLayerAddress. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*! Encode RABAP RAB AssignmentRequest from RANAP_RAB_AssignmentRequestIEs. + * \ptmap[out] data user provided memory to store resulting ASN.1 encoded message. + * \ptmap[in] len length of user provided memory to store resulting ASN.1 encoded message. + * \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentRequestIEs. + * \returns resulting message length on success; negative on error. */ +int ranap_rab_ass_req_encode(uint8_t *data, unsigned int len, + RANAP_RAB_AssignmentRequestIEs_t *rab_assignment_request_ies) +{ + int rc; + struct msgb *msg; + RANAP_RAB_AssignmentRequest_t _rab_assignment_request; + RANAP_RAB_AssignmentRequest_t *rab_assignment_request = &_rab_assignment_request; + + memset(data, 0, len); + memset(rab_assignment_request, 0, sizeof(*rab_assignment_request)); + + rc = ranap_encode_rab_assignmentrequesties(rab_assignment_request, rab_assignment_request_ies); + if (rc < 0) + return -EINVAL; + + /* generate an Initiating Mesasage */ + msg = ranap_generate_initiating_message(RANAP_ProcedureCode_id_RAB_Assignment, + RANAP_Criticality_reject, + &asn_DEF_RANAP_RAB_AssignmentRequest, rab_assignment_request); + + /* 'msg' has been generated, we cann now release the input 'out' */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_AssignmentRequest, rab_assignment_request); + + if (!msg) + return -EINVAL; + if (msg->len > len) + return -EINVAL; + + memcpy(data, msg->data, msg->len); + rc = msg->len; + msgb_free(msg); + return rc; +} + +/*! Encode RABAP RAB AssignmentRequest from RANAP_RAB_AssignmentResponseIEs. + * \ptmap[out] data user provided memory to store resulting ASN.1 encoded message. + * \ptmap[in] len length of user provided memory to store resulting ASN.1 encoded message. + * \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentResponseIEs. + * \returns resulting message length on success; negative on error. */ +int ranap_rab_ass_resp_encode(uint8_t *data, unsigned int len, + RANAP_RAB_AssignmentResponseIEs_t *rab_assignment_response_ies) +{ + int rc; + struct msgb *msg; + + RANAP_RAB_AssignmentResponse_t _rab_assignment_response; + RANAP_RAB_AssignmentResponse_t *rab_assignment_response = &_rab_assignment_response; + + memset(data, 0, len); + memset(rab_assignment_response, 0, sizeof(*rab_assignment_response)); + + rc = ranap_encode_rab_assignmentresponseies(rab_assignment_response, rab_assignment_response_ies); + if (rc < 0) + return -EINVAL; + + /* generate an outcome mesasage */ + msg = ranap_generate_outcome(RANAP_ProcedureCode_id_RAB_Assignment, + RANAP_Criticality_reject, + &asn_DEF_RANAP_RAB_AssignmentResponse, rab_assignment_response); + + /* 'msg' has been generated, we cann now release the input 'out' */ + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_AssignmentResponse, rab_assignment_response); + + if (!msg) + return -EINVAL; + if (msg->len > len) + return -EINVAL; + + memcpy(data, msg->data, msg->len); + rc = msg->len; + msgb_free(msg); + return rc; +} + +/* Pick the first item from the RAB setup-or-modify list and return the first protocol-ie-field-pair. This is based on + * the assumption that a PS call will only assign a signle RAB. This could be different for video calls and IMS but + * those are in practice a corner case, so we go for this simplified assumption for now. */ +static RANAP_ProtocolIE_FieldPair_t *prot_ie_field_pair_from_ass_req_ies(const RANAP_RAB_AssignmentRequestIEs_t *ies) +{ + RANAP_ProtocolIE_ContainerPair_t *protocol_ie_container_pair; + RANAP_ProtocolIE_FieldPair_t *protocol_ie_field_pair; + + /* Make sure we indeed deal with a setup-or-modify list */ + if (!(ies->presenceMask & RAB_ASSIGNMENTREQUESTIES_RANAP_RAB_SETUPORMODIFYLIST_PRESENT)) { + RANAP_DEBUG + ("Decoding failed, the RANAP RAB AssignmentRequest did not contain a setup-or-modify list!\n"); + return NULL; + } + + protocol_ie_container_pair = ies->raB_SetupOrModifyList.list.array[0]; + protocol_ie_field_pair = protocol_ie_container_pair->list.array[0]; + + return protocol_ie_field_pair; +} + +/* See also comment above prot_ie_field_pair_from_ass_req_ies */ +static RANAP_IE_t *setup_or_modif_item_from_rab_ass_resp(const RANAP_RAB_AssignmentResponseIEs_t *ies) +{ + /* Make sure we indeed deal with a setup-or-modified list */ + if (!(ies->presenceMask & RAB_ASSIGNMENTRESPONSEIES_RANAP_RAB_SETUPORMODIFIEDLIST_PRESENT)) { + RANAP_DEBUG + ("Decoding failed, the RANAP RAB AssignmentResponse did not contain a setup-or-modified list!\n"); + return NULL; + } + + return ies->raB_SetupOrModifiedList.raB_SetupOrModifiedList_ies.list.array[0]; +} + +/*! Extract IP address and port from RANAP_RAB_AssignmentRequestIEs. + * \ptmap[out] addr user provided memory to store extracted RTP stream IP-Address and port number. + * \ptmap[out] rab_id pointer to store RAB-ID (optional, can be NULL). + * \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentRequestIEs. + * \returns 0 on success; negative on error. */ +int ranap_rab_ass_req_ies_extract_inet_addr(struct osmo_sockaddr *addr, uint8_t *rab_id, + RANAP_RAB_AssignmentRequestIEs_t *ies) +{ + RANAP_ProtocolIE_FieldPair_t *protocol_ie_field_pair; + RANAP_RAB_SetupOrModifyItemFirst_t _rab_setup_or_modify_item_first; + RANAP_RAB_SetupOrModifyItemFirst_t *rab_setup_or_modify_item_first = &_rab_setup_or_modify_item_first; + RANAP_TransportLayerAddress_t *trasp_layer_addr; + RANAP_IuTransportAssociation_t *transp_assoc; + uint16_t port; + int rc; + + protocol_ie_field_pair = prot_ie_field_pair_from_ass_req_ies(ies); + if (!protocol_ie_field_pair) + return -EINVAL; + + if (protocol_ie_field_pair->id != RANAP_ProtocolIE_ID_id_RAB_SetupOrModifyItem) { + RANAP_DEBUG + ("Decoding failed, the protocol IE field-pair is not of type RANAP RAB setup-or-modify-item!\n"); + return -EINVAL; + } + + rc = ranap_decode_rab_setupormodifyitemfirst(rab_setup_or_modify_item_first, + &protocol_ie_field_pair->firstValue); + if (rc < 0) + return -EINVAL; + + if (rab_id) { + /* The RAB-ID is defined as a bitstring with a size of 8 (1 byte), + * See also RANAP-IEs.asn, RAB-ID ::= BIT STRING (SIZE (8)) */ + *rab_id = rab_setup_or_modify_item_first->rAB_ID.buf[0]; + } + + /* Decode IP-Address */ + trasp_layer_addr = &rab_setup_or_modify_item_first->transportLayerInformation->transportLayerAddress; + rc = ranap_transp_layer_addr_decode2(addr, NULL, trasp_layer_addr); + if (rc < 0) { + rc = -EINVAL; + goto error; + } + + /* Decode port number */ + transp_assoc = &rab_setup_or_modify_item_first->transportLayerInformation->iuTransportAssociation; + rc = ranap_transp_assoc_decode(&port, transp_assoc); + if (rc < 0) { + rc = -EINVAL; + goto error; + } + + switch (addr->u.sin.sin_family) { + case AF_INET: + addr->u.sin.sin_port = htons(port); + break; + case AF_INET6: + addr->u.sin6.sin6_port = htons(port); + break; + default: + rc = -EINVAL; + goto error; + } + + rc = 0; +error: + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, rab_setup_or_modify_item_first); + return rc; +} + +/*! Extract IP address and port from RANAP_RAB_AssignmentResponseIEs. + * \ptmap[out] addr user provided memory to store extracted RTP stream IP-Address and port number. + * \ptmap[in] ies user provided memory with RANAP_RAB_AssignmentResponseIEs. + * \returns 0 on success; negative on error. */ +int ranap_rab_ass_resp_ies_extract_inet_addr(struct osmo_sockaddr *addr, RANAP_RAB_AssignmentResponseIEs_t *ies) +{ + RANAP_IE_t *setup_or_modified_list_ie; + RANAP_RAB_SetupOrModifiedItemIEs_t _rab_setup_or_modified_items_ies; + RANAP_RAB_SetupOrModifiedItemIEs_t *rab_setup_or_modified_items_ies = &_rab_setup_or_modified_items_ies; + RANAP_RAB_SetupOrModifiedItem_t *rab_setup_or_modified_item; + uint16_t port; + int rc; + + setup_or_modified_list_ie = setup_or_modif_item_from_rab_ass_resp(ies); + if (!setup_or_modified_list_ie) + return -EINVAL; + + rc = ranap_decode_rab_setupormodifieditemies_fromlist(rab_setup_or_modified_items_ies, + &setup_or_modified_list_ie->value); + if (rc < 0) { + return -EINVAL; + } + + rab_setup_or_modified_item = &rab_setup_or_modified_items_ies->raB_SetupOrModifiedItem; + + /* Decode IP-Address */ + rc = ranap_transp_layer_addr_decode2(addr, NULL, rab_setup_or_modified_item->transportLayerAddress); + if (rc < 0) { + rc = -EINVAL; + goto error; + } + + /* Decode port number */ + rc = ranap_transp_assoc_decode(&port, rab_setup_or_modified_item->iuTransportAssociation); + if (rc < 0) { + rc = -EINVAL; + goto error; + } + + switch (addr->u.sin.sin_family) { + case AF_INET: + addr->u.sin.sin_port = htons(port); + break; + case AF_INET6: + addr->u.sin6.sin6_port = htons(port); + break; + default: + rc = -EINVAL; + goto error; + } + + rc = 0; +error: + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedItem, rab_setup_or_modified_items_ies); + return rc; +} + +/*! Replace IP address and port in RANAP_RAB_AssignmentRequestIEs. + * \ptmap[inout] ies user provided memory with RANAP_RAB_AssignmentRequestIEs. + * \ptmap[in] addr user provided memory that contains the new RTP stream IP-Address and port number. + * \returns 0 on success; negative on error. */ +int ranap_rab_ass_req_ies_replace_inet_addr(RANAP_RAB_AssignmentRequestIEs_t *ies, struct osmo_sockaddr *addr) +{ + RANAP_ProtocolIE_FieldPair_t *protocol_ie_field_pair; + RANAP_RAB_SetupOrModifyItemFirst_t _rab_setup_or_modify_item_first; + RANAP_RAB_SetupOrModifyItemFirst_t *rab_setup_or_modify_item_first = &_rab_setup_or_modify_item_first; + RANAP_TransportLayerInformation_t *old_transport_layer_information = NULL; + RANAP_TransportLayerInformation_t *new_transport_layer_information = NULL; + struct osmo_sockaddr addr_old; + bool uses_x213_nsap; + int rc; + + protocol_ie_field_pair = prot_ie_field_pair_from_ass_req_ies(ies); + if (!protocol_ie_field_pair) + return -EINVAL; + + if (protocol_ie_field_pair->id != RANAP_ProtocolIE_ID_id_RAB_SetupOrModifyItem) { + RANAP_DEBUG("Rewriting transport layer information failed, unexpected IE field-pair type!\n"); + return -EINVAL; + } + + /* Decode setup-or-modifiy item (first) */ + rc = ranap_decode_rab_setupormodifyitemfirst(rab_setup_or_modify_item_first, + &protocol_ie_field_pair->firstValue); + if (rc < 0) + return -EINVAL; + + /* Replace transport-layer-information */ + if (rab_setup_or_modify_item_first->transportLayerInformation->iuTransportAssociation.present == + RANAP_IuTransportAssociation_PR_bindingID) { + old_transport_layer_information = rab_setup_or_modify_item_first->transportLayerInformation; + + /* Before we can re-encode the transport layer information, we need to know the format it was + * encoded in. */ + rc = ranap_transp_layer_addr_decode2(&addr_old, &uses_x213_nsap, + &old_transport_layer_information->transportLayerAddress); + if (rc < 0) { + rc = -EINVAL; + goto error; + } + + /* Encode a new transport layer information field */ + new_transport_layer_information = ranap_new_transp_info_rtp(addr, uses_x213_nsap); + if (!new_transport_layer_information) { + rc = -EINVAL; + goto error; + } + + rab_setup_or_modify_item_first->transportLayerInformation = new_transport_layer_information; + } else { + RANAP_DEBUG("Rewriting transport layer information failed, no bindingID (port)!\n"); + rc = -EINVAL; + goto error; + } + + /* Reencode transport-layer-information */ + rc = ANY_fromType_aper(&protocol_ie_field_pair->firstValue, &asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, + rab_setup_or_modify_item_first); + if (rc < 0) { + RANAP_DEBUG("Rewriting transport layer information failed, could not reencode\n"); + rc = -EINVAL; + goto error; + } + +error: + /* Restore original state of the modified ASN.1 struct so that the asn1c free mechanisms can work properly */ + if (old_transport_layer_information) + rab_setup_or_modify_item_first->transportLayerInformation = old_transport_layer_information; + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifyItemFirst, rab_setup_or_modify_item_first); + if (new_transport_layer_information) + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, new_transport_layer_information); + return rc; +} + +/*! Replace IP address and port in RANAP_RAB_AssignmentResponseIEs. + * \ptmap[inout] ies user provided memory with RANAP_RAB_AssignmentResponseIEs. + * \ptmap[in] addr user provided memory that contains the new RTP stream IP-Address and port number. + * \returns 0 on success; negative on error. */ +int ranap_rab_ass_resp_ies_replace_inet_addr(RANAP_RAB_AssignmentResponseIEs_t *ies, struct osmo_sockaddr *addr) +{ + RANAP_IE_t *setup_or_modified_list_ie; + RANAP_RAB_SetupOrModifiedItemIEs_t _rab_setup_or_modified_items_ies; + RANAP_RAB_SetupOrModifiedItemIEs_t *rab_setup_or_modified_items_ies = &_rab_setup_or_modified_items_ies; + RANAP_RAB_SetupOrModifiedItem_t *rab_setup_or_modified_item; + RANAP_TransportLayerInformation_t *temp_transport_layer_information = NULL; + RANAP_TransportLayerAddress_t *old_transport_layer_address = NULL; + RANAP_IuTransportAssociation_t *old_iu_transport_association = NULL; + struct osmo_sockaddr addr_old; + bool uses_x213_nsap; + int rc; + + setup_or_modified_list_ie = setup_or_modif_item_from_rab_ass_resp(ies); + if (!setup_or_modified_list_ie) + return -EINVAL; + + rc = ranap_decode_rab_setupormodifieditemies_fromlist(rab_setup_or_modified_items_ies, + &setup_or_modified_list_ie->value); + if (rc < 0) + return -EINVAL; + + rab_setup_or_modified_item = &rab_setup_or_modified_items_ies->raB_SetupOrModifiedItem; + + /* Before we can re-encode the transport layer address, we need to know the format it was encoded in. */ + rc = ranap_transp_layer_addr_decode2(&addr_old, &uses_x213_nsap, + rab_setup_or_modified_item->transportLayerAddress); + if (rc < 0) { + rc = -EINVAL; + goto error; + } + + /* Generate a temporary transport layer information, from which we can use the transport layer address and + * the iu transport association to update the setup or modified item */ + temp_transport_layer_information = ranap_new_transp_info_rtp(addr, uses_x213_nsap); + if (!temp_transport_layer_information) { + rc = -EINVAL; + goto error; + } + + /* Replace transport layer address and iu transport association */ + old_transport_layer_address = rab_setup_or_modified_item->transportLayerAddress; + old_iu_transport_association = rab_setup_or_modified_item->iuTransportAssociation; + rab_setup_or_modified_item->transportLayerAddress = &temp_transport_layer_information->transportLayerAddress; + rab_setup_or_modified_item->iuTransportAssociation = &temp_transport_layer_information->iuTransportAssociation; + + /* Reencode modified setup or modified list */ + rc = ANY_fromType_aper(&setup_or_modified_list_ie->value, &asn_DEF_RANAP_RAB_SetupOrModifiedItem, + rab_setup_or_modified_items_ies); + if (rc < 0) { + RANAP_DEBUG("Rewriting transport layer address failed, could not reencode\n"); + rc = -EINVAL; + goto error; + } + +error: + /* Restore original state of the modified ASN.1 struct so that the asn1c free mechanisms can work properly */ + if (old_transport_layer_address) + rab_setup_or_modified_item->transportLayerAddress = old_transport_layer_address; + if (old_iu_transport_association) + rab_setup_or_modified_item->iuTransportAssociation = old_iu_transport_association; + if (temp_transport_layer_information) + ASN_STRUCT_FREE(asn_DEF_RANAP_TransportLayerInformation, temp_transport_layer_information); + + ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_RANAP_RAB_SetupOrModifiedItem, rab_setup_or_modified_items_ies); + + return rc; +} diff --git a/tests/Makefile.am b/tests/Makefile.am index 899e436..f9da51f 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,4 +1,5 @@ SUBDIRS = \ + ranap_rab_ass \ $(NULL) # The `:;' works around a Bash 3.2 bug when the output is not writeable. diff --git a/tests/ranap_rab_ass/Makefile.am b/tests/ranap_rab_ass/Makefile.am new file mode 100644 index 0000000..8d1df7a --- /dev/null +++ b/tests/ranap_rab_ass/Makefile.am @@ -0,0 +1,37 @@ +AM_CPPFLAGS = \ + $(all_includes) \ + -I$(top_srcdir)/include \ + $(NULL) + +AM_CFLAGS = \ + -Wall \ + -ggdb3 \ + $(LIBASN1C_CFLAGS) \ + $(LIBOSMOCORE_CFLAGS) \ + $(LIBOSMOVTY_CFLAGS) \ + $(LIBOSMORANAP_CFLAGS) \ + $(LIBOSMOSIGTRAN_CFLAGS) \ + $(COVERAGE_CFLAGS) \ + $(NULL) + +EXTRA_DIST = \ + ranap_rab_ass_test.ok \ + $(NULL) + +noinst_PROGRAMS = \ + ranap_rab_ass_test \ + $(NULL) + +ranap_rab_ass_test_SOURCES = \ + ranap_rab_ass_test.c \ + $(NULL) + +ranap_rab_ass_test_LDADD = \ + $(LIBASN1C_LIBS) \ + $(LIBOSMOCORE_LIBS) \ + $(LIBOSMOVTY_LIBS) \ + $(LIBOSMORANAP_LIBS) \ + $(LIBOSMOSIGTRAN_LIBS) \ + $(COVERAGE_LDFLAGS) \ + $(top_builddir)/src/osmo-hnbgw/ranap_rab_ass.o \ + $(NULL) diff --git a/tests/ranap_rab_ass/ranap_rab_ass_test.c b/tests/ranap_rab_ass/ranap_rab_ass_test.c new file mode 100644 index 0000000..c67b5aa --- /dev/null +++ b/tests/ranap_rab_ass/ranap_rab_ass_test.c @@ -0,0 +1,340 @@ +/* (C) 2021 by sysmocom s.f.m.c. GmbH + * All Rights Reserved + * + * Author: Philipp Maier + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +static void *tall_hnb_ctx; +static void *msgb_ctx; +extern void *talloc_asn1_ctx; + +void test_ranap_rab_ass_req_decode_encode(void) +{ + int rc; + ranap_message message; + uint8_t testvec[] = { + 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00, + 0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35, + 0x00, 0x48, 0x78, 0x22, 0xcd, 0x80, 0x10, 0x2f, + 0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c, + 0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00, + 0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00, + 0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00, + 0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27, + 0xc0, 0x35, 0x00, 0x01, 0x0a, 0x09, 0x01, 0xa2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x76, + 0x00, 0x00, 0x40, 0x01, 0x00, 0x00 + }; + uint8_t encoded[sizeof(testvec)]; + + rc = ranap_ran_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec)); + OSMO_ASSERT(rc == 0); + + rc = ranap_rab_ass_req_encode(encoded, sizeof(encoded), &message.msg.raB_AssignmentRequestIEs); + printf("ranap_rab_ass_req_encode rc=%d\n", rc); + + printf("INPUT: %s\n", osmo_hexdump_nospc(testvec, sizeof(testvec))); + printf("RESULT: %s\n", osmo_hexdump_nospc(encoded, sizeof(encoded))); + OSMO_ASSERT(memcmp(testvec, encoded, sizeof(testvec)) == 0); + + ranap_ran_rx_co_free(&message); +} + +void test_ranap_rab_ass_resp_decode_encode(void) +{ + int rc; + ranap_message message; + uint8_t testvec[] = { + 0x60, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x00, + 0x34, 0x40, 0x23, 0x00, 0x00, 0x01, 0x00, 0x33, + 0x40, 0x1c, 0x60, 0x3a, 0x7c, 0x35, 0x00, 0x01, + 0x0a, 0x09, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x04, 0x0a, 0x00, 0x00 + }; + uint8_t encoded[sizeof(testvec)]; + + rc = ranap_cn_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec)); + OSMO_ASSERT(rc == 0); + + rc = ranap_rab_ass_resp_encode(encoded, sizeof(encoded), &message.msg.raB_AssignmentResponseIEs); + printf("ranap_rab_ass_resp_encode rc=%d\n", rc); + + printf("INPUT: %s\n", osmo_hexdump_nospc(testvec, sizeof(testvec))); + printf("RESULT: %s\n", osmo_hexdump_nospc(encoded, sizeof(encoded))); + OSMO_ASSERT(memcmp(testvec, encoded, sizeof(testvec)) == 0); + + ranap_cn_rx_co_free(&message); +} + +void test_ranap_rab_ass_req_extract_inet_addr(void) +{ + int rc; + struct osmo_sockaddr addr; + struct osmo_sockaddr_str addr_str; + uint8_t rab_id; + ranap_message message; + uint8_t testvec[] = { + 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00, + 0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35, + 0x00, 0x48, 0x78, 0x22, 0xcd, 0x80, 0x10, 0x2f, + 0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c, + 0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00, + 0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00, + 0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00, + 0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27, + 0xc0, 0x35, 0x00, 0x01, 0x0a, 0x09, 0x01, 0xa2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0x76, + 0x00, 0x00, 0x40, 0x01, 0x00, 0x00 + }; + + rc = ranap_ran_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec)); + OSMO_ASSERT(rc == 0); + rc = ranap_rab_ass_req_ies_extract_inet_addr(&addr, &rab_id, &message.msg.raB_AssignmentRequestIEs); + osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas); + printf("ranap_rab_ass_req_extract_inet_addr rc=%d\n", rc); + printf("RESULT: addr=%s, port=%u, rab-id=%02x\n", addr_str.ip, addr_str.port, rab_id); + ranap_ran_rx_co_free(&message); +} + +void test_ranap_rab_ass_resp_extract_inet_addr(void) +{ + int rc; + struct osmo_sockaddr addr; + struct osmo_sockaddr_str addr_str; + ranap_message message; + uint8_t testvec[] = { + 0x60, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x00, + 0x34, 0x40, 0x23, 0x00, 0x00, 0x01, 0x00, 0x33, + 0x40, 0x1c, 0x60, 0x3a, 0x7c, 0x35, 0x00, 0x01, + 0x0a, 0x09, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x04, 0x0a, 0x00, 0x00 + }; + + rc = ranap_cn_rx_co_decode(talloc_asn1_ctx, &message, testvec, sizeof(testvec)); + OSMO_ASSERT(rc == 0); + rc = ranap_rab_ass_resp_ies_extract_inet_addr(&addr, &message.msg.raB_AssignmentResponseIEs); + osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas); + printf("ranap_rab_ass_resp_extract_inet_addr rc=%d\n", rc); + printf("RESULT: addr=%s, port=%u\n", addr_str.ip, addr_str.port); + ranap_cn_rx_co_free(&message); +} + +void test_ranap_rab_ass_req_replace_inet_addr(void) +{ + int rc; + struct osmo_sockaddr addr; + struct osmo_sockaddr_str addr_str; + ranap_message message; + uint8_t testvec_in[] = { + 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00, + 0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35, + 0x00, 0x48, 0x78, 0x4e, 0xcd, 0x80, 0x10, 0x2f, + 0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c, + 0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00, + 0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00, + 0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00, + 0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27, + 0xc0, 0x35, 0x00, 0x01, 0x0a, 0x09, 0x01, 0xa2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x1f, 0xba, + 0x00, 0x00, 0x40, 0x01, 0x00 + }; + uint8_t testvec_expected_out[] = { + 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x01, 0x00, + 0x36, 0x40, 0x52, 0x00, 0x00, 0x01, 0x00, 0x35, + 0x00, 0x48, 0x78, 0x4e, 0xcd, 0x80, 0x10, 0x2f, + 0xa7, 0x20, 0x1a, 0x2c, 0x00, 0x00, 0xf4, 0x4c, + 0x08, 0x0a, 0x02, 0x80, 0x00, 0x51, 0x40, 0x00, + 0x27, 0x20, 0x28, 0x14, 0x00, 0x67, 0x40, 0x00, + 0x00, 0x22, 0x28, 0x14, 0x00, 0x3c, 0x40, 0x00, + 0x00, 0x00, 0x50, 0x3d, 0x02, 0x00, 0x02, 0x27, + 0xc0, 0x35, 0x00, 0x01, 0x01, 0x02, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x04, 0xd2, + 0x00, 0x00, 0x40, 0x01, 0x00 + }; + + rc = ranap_ran_rx_co_decode(talloc_asn1_ctx, &message, testvec_in, sizeof(testvec_in)); + OSMO_ASSERT(rc == 0); + + rc = ranap_rab_ass_req_ies_extract_inet_addr(&addr, NULL, &message.msg.raB_AssignmentRequestIEs); + OSMO_ASSERT(rc == 0); + osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas); + printf("before: addr=%s, port=%u\n", addr_str.ip, addr_str.port); + + memset(&addr_str, 0, sizeof(addr_str)); + addr_str.af = AF_INET; + addr_str.port = 1234; + osmo_strlcpy(addr_str.ip, "1.2.3.4", sizeof(addr_str.ip)); + osmo_sockaddr_str_to_sockaddr(&addr_str, &addr.u.sas); + + rc = ranap_rab_ass_req_ies_replace_inet_addr(&message.msg.raB_AssignmentRequestIEs, &addr); + printf("ranap_rab_ass_req_replace_inet_addr rc=%d\n", rc); + + rc = ranap_rab_ass_req_ies_extract_inet_addr(&addr, NULL, &message.msg.raB_AssignmentRequestIEs); + OSMO_ASSERT(rc == 0); + osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas); + printf("after: addr=%s, port=%u\n", addr_str.ip, addr_str.port); + + rc = ranap_rab_ass_req_encode(testvec_in, sizeof(testvec_in), &message.msg.raB_AssignmentRequestIEs); + OSMO_ASSERT(rc == sizeof(testvec_in)); + OSMO_ASSERT(memcmp(testvec_in, testvec_expected_out, sizeof(testvec_in)) == 0); + + ranap_ran_rx_co_free(&message); +} + +void test_ranap_rab_ass_resp_replace_inet_addr(void) +{ + int rc; + struct osmo_sockaddr addr; + struct osmo_sockaddr_str addr_str; + ranap_message message; + uint8_t testvec_in[] = { + 0x60, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x00, + 0x34, 0x40, 0x23, 0x00, 0x00, 0x01, 0x00, 0x33, + 0x40, 0x1c, 0x60, 0x32, 0x7c, 0x35, 0x00, 0x01, + 0x0a, 0x09, 0x01, 0xa4, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x04, 0x0a, 0x00, 0x00 + }; + uint8_t testvec_expected_out[] = { + 0x60, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x01, 0x00, + 0x34, 0x40, 0x23, 0x00, 0x00, 0x01, 0x00, 0x33, + 0x40, 0x1c, 0x60, 0x32, 0x7c, 0x35, 0x00, 0x01, + 0x01, 0x02, 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x04, 0xd2, 0x00, 0x00 + }; + + rc = ranap_cn_rx_co_decode(talloc_asn1_ctx, &message, testvec_in, sizeof(testvec_in)); + OSMO_ASSERT(rc == 0); + + rc = ranap_rab_ass_resp_ies_extract_inet_addr(&addr, &message.msg.raB_AssignmentResponseIEs); + OSMO_ASSERT(rc == 0); + osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas); + printf("before: addr=%s, port=%u\n", addr_str.ip, addr_str.port); + + memset(&addr_str, 0, sizeof(addr_str)); + addr_str.af = AF_INET; + addr_str.port = 1234; + osmo_strlcpy(addr_str.ip, "1.2.3.4", sizeof(addr_str.ip)); + osmo_sockaddr_str_to_sockaddr(&addr_str, &addr.u.sas); + + rc = ranap_rab_ass_resp_ies_replace_inet_addr(&message.msg.raB_AssignmentResponseIEs, &addr); + printf("ranap_rab_ass_resp_replace_inet_addr rc=%d\n", rc); + + rc = ranap_rab_ass_resp_ies_extract_inet_addr(&addr, &message.msg.raB_AssignmentResponseIEs); + OSMO_ASSERT(rc == 0); + osmo_sockaddr_str_from_sockaddr(&addr_str, &addr.u.sas); + printf("after: addr=%s, port=%u\n", addr_str.ip, addr_str.port); + + rc = ranap_rab_ass_resp_encode(testvec_in, sizeof(testvec_in), &message.msg.raB_AssignmentResponseIEs); + OSMO_ASSERT(rc == sizeof(testvec_in)); + OSMO_ASSERT(memcmp(testvec_in, testvec_expected_out, sizeof(testvec_in)) == 0); + + ranap_cn_rx_co_free(&message); +} + +static const struct log_info_cat log_cat[] = { + [DRANAP] = { + .name = "RANAP", .loglevel = LOGL_DEBUG, .enabled = 1, + .color = "", + .description = "RAN Application Part", + }, +}; + +static const struct log_info test_log_info = { + .cat = log_cat, + .num_cat = ARRAY_SIZE(log_cat), +}; + +int test_init(void) +{ + int rc; + + tall_hnb_ctx = talloc_named_const(NULL, 0, "hnb_context"); + msgb_ctx = msgb_talloc_ctx_init(NULL, 0); + talloc_asn1_ctx = talloc_named_const(NULL, 0, "asn1_context"); + + rc = osmo_init_logging2(tall_hnb_ctx, &test_log_info); + if (rc < 0) + exit(1); + + log_set_print_filename2(osmo_stderr_target, LOG_FILENAME_NONE); + log_set_use_color(osmo_stderr_target, 0); + log_set_print_category(osmo_stderr_target, 0); + log_set_print_category_hex(osmo_stderr_target, 0); + return rc; +} + +void test_cleanup(void) +{ + if (talloc_total_blocks(msgb_ctx) != 1 || talloc_total_size(msgb_ctx) != 0) + talloc_report_full(msgb_ctx, stderr); + + OSMO_ASSERT(talloc_total_blocks(msgb_ctx) == 1); + OSMO_ASSERT(talloc_total_size(msgb_ctx) == 0); + talloc_free(msgb_ctx); + + if (talloc_total_blocks(talloc_asn1_ctx) != 1 || talloc_total_size(talloc_asn1_ctx) != 0) + talloc_report_full(talloc_asn1_ctx, stderr); + + OSMO_ASSERT(talloc_total_blocks(talloc_asn1_ctx) == 1); + OSMO_ASSERT(talloc_total_size(talloc_asn1_ctx) == 0); + talloc_free(talloc_asn1_ctx); +} + +int main(int argc, char **argv) +{ + test_init(); + + test_ranap_rab_ass_req_decode_encode(); + test_ranap_rab_ass_resp_decode_encode(); + + test_ranap_rab_ass_req_extract_inet_addr(); + test_ranap_rab_ass_resp_extract_inet_addr(); + test_ranap_rab_ass_req_replace_inet_addr(); + test_ranap_rab_ass_resp_replace_inet_addr(); + + test_cleanup(); + return 0; +} + +/* Stub */ +const char *hnb_context_name(struct hnb_context *ctx) +{ + return "TEST"; +} diff --git a/tests/ranap_rab_ass/ranap_rab_ass_test.ok b/tests/ranap_rab_ass/ranap_rab_ass_test.ok new file mode 100644 index 0000000..f7b4b67 --- /dev/null +++ b/tests/ranap_rab_ass/ranap_rab_ass_test.ok @@ -0,0 +1,16 @@ +ranap_rab_ass_req_encode rc=93 +INPUT: 0000005900000100364052000001003500487822cd80102fa7201a2c0000f44c080a028000514000272028140067400000222814003c40000000503d02000227c03500010a0901a200000000000000000000000000401f76000040010000 +RESULT: 0000005900000100364052000001003500487822cd80102fa7201a2c0000f44c080a028000514000272028140067400000222814003c40000000503d02000227c03500010a0901a200000000000000000000000000401f76000040010000 +ranap_rab_ass_resp_encode rc=46 +INPUT: 6000002a000001003440230000010033401c603a7c3500010a0901a40000000000000000000000000040040a0000 +RESULT: 6000002a000001003440230000010033401c603a7c3500010a0901a40000000000000000000000000040040a0000 +ranap_rab_ass_req_extract_inet_addr rc=0 +RESULT: addr=10.9.1.162, port=8054, rab-id=11 +ranap_rab_ass_resp_extract_inet_addr rc=0 +RESULT: addr=10.9.1.164, port=1034 +before: addr=10.9.1.162, port=8122 +ranap_rab_ass_req_replace_inet_addr rc=0 +after: addr=1.2.3.4, port=1234 +before: addr=10.9.1.164, port=1034 +ranap_rab_ass_resp_replace_inet_addr rc=0 +after: addr=1.2.3.4, port=1234 diff --git a/tests/testsuite.at b/tests/testsuite.at index 65d1ca0..84d85cf 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -1,8 +1,8 @@ AT_INIT AT_BANNER([Regression tests.]) -#AT_SETUP([foobar]) -#AT_KEYWORDS([foobar]) -#cat $abs_srcdir/foobar/foobar_test.ok > expout -#AT_CHECK([$abs_top_builddir/tests/foobar/foobar_test], [], [expout], [ignore]) -#AT_CLEANUP +AT_SETUP([ranap_rab_ass]) +AT_KEYWORDS([ranap_rab_ass]) +cat $abs_srcdir/ranap_rab_ass/ranap_rab_ass_test.ok > expout +AT_CHECK([$abs_top_builddir/tests/ranap_rab_ass/ranap_rab_ass_test], [0], [expout], [ignore]) +AT_CLEANUP \ No newline at end of file