diff --git a/CMakeLists.txt b/CMakeLists.txt index 627b87593d..e6c9abdb9a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -435,20 +435,18 @@ add_library(f1ap ${F1AP_DIR}/f1ap_cu_rrc_message_transfer.c ${F1AP_DIR}/f1ap_cu_task.c ${F1AP_DIR}/f1ap_cu_ue_context_management.c - ${F1AP_DIR}/f1ap_cu_warning_message_transmission.c ${F1AP_DIR}/f1ap_du_interface_management.c ${F1AP_DIR}/f1ap_du_paging.c ${F1AP_DIR}/f1ap_du_rrc_message_transfer.c - ${F1AP_DIR}/f1ap_du_system_information.c ${F1AP_DIR}/f1ap_du_task.c ${F1AP_DIR}/f1ap_du_ue_context_management.c - ${F1AP_DIR}/f1ap_du_warning_message_transmission.c ${F1AP_DIR}/f1ap_encoder.c ${F1AP_DIR}/f1ap_handlers.c ${F1AP_DIR}/f1ap_itti_messaging.c) target_include_directories(f1ap PUBLIC F1AP_DIR) target_link_libraries(f1ap PUBLIC asn1_f1ap L2_NR) -target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE) +target_link_libraries(f1ap PRIVATE ngap nr_rrc HASHTABLE f1ap_lib) +target_include_directories(f1ap PRIVATE ${F1AP_DIR}/lib) # LPP ############## @@ -1438,6 +1436,8 @@ add_library(L2_NR ${GNB_APP_SRC} ) target_link_libraries(L2_NR PRIVATE ds alg) +target_link_libraries(L2_NR PRIVATE f1ap_lib) +target_include_directories(L2_NR PRIVATE ${F1AP_DIR}/lib) add_library(e1_if ${NR_RRC_DIR}/cucp_cuup_direct.c diff --git a/openair2/F1AP/f1ap_du_warning_message_transmission.h b/common/5g_platform_types.h similarity index 81% rename from openair2/F1AP/f1ap_du_warning_message_transmission.h rename to common/5g_platform_types.h index b6bbedba2f..05fc2be28d 100644 --- a/openair2/F1AP/f1ap_du_warning_message_transmission.h +++ b/common/5g_platform_types.h @@ -19,13 +19,16 @@ * contact@openairinterface.org */ -/*! \file f1ap_du_interface_management.h - * \brief f1ap interface management for DU - * \author EURECOM/NTUST - * \date 2018 - * \version 0.1 - * \company Eurecom - * \email: navid.nikaein@eurecom.fr, bing-kai.hong@eurecom.fr - * \note - * \warning - */ \ No newline at end of file +#ifndef FIVEG_PLATFORM_TYPES_H__ +#define FIVEG_PLATFORM_TYPES_H__ + +#include + +typedef struct nssai_s { + uint8_t sst; + uint32_t sd; +} nssai_t; + +typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t; + +#endif diff --git a/common/ngran_types.h b/common/ngran_types.h index 37a6ea9177..ac5af71f23 100644 --- a/common/ngran_types.h +++ b/common/ngran_types.h @@ -55,5 +55,4 @@ typedef enum { CPtype = 0, UPtype } E1_t; #define NODE_IS_MBMS(nOdE_TyPe) ((nOdE_TyPe) == ngran_eNB_MBMS_STA) #define GTPV1_U_PORT_NUMBER (2152) -typedef enum { non_dynamic, dynamic } fiveQI_type_t; #endif diff --git a/doc/E1AP/E1-design.md b/doc/E1AP/E1-design.md index 04d19bb514..4dd042f87d 100644 --- a/doc/E1AP/E1-design.md +++ b/doc/E1AP/E1-design.md @@ -79,7 +79,7 @@ More details about the E1AP procedures in OAI are available in this document: [E # 2. Running the E1 Split -The setup is assuming that all modules are running on the same machine. The user can refer to the [F1 design document](./../F1-design.md) for local deployment of the DU. +The setup is assuming that all modules are running on the same machine. The user can refer to the [F1 design document](./../F1AP/F1-design.md) for local deployment of the DU. ## 2.1 Configuration File diff --git a/doc/F1-design.md b/doc/F1AP/F1-design.md similarity index 100% rename from doc/F1-design.md rename to doc/F1AP/F1-design.md diff --git a/doc/F1AP/F1AP-lib.md b/doc/F1AP/F1AP-lib.md new file mode 100644 index 0000000000..46712914ed --- /dev/null +++ b/doc/F1AP/F1AP-lib.md @@ -0,0 +1,69 @@ + + + + + +
+ + + + + + F1AP Messages Encoding & Decoding Library +
+ +[[_TOC_]] + + +# Intro + +This library is for the encoding, decoding and testing of F1AP (F1 Application Protocol) messages. + +# Implementation Details + +The library includes the following components: + +1. **Common Functions**: + +This file [f1ap_lib_common.c](../../openair2/F1AP/lib/f1ap_lib_common.c) and its corresponding header contain utility functions and macros shared across different F1AP functions. + +2. **Message-Specific Modules**: + +Each F1AP message (e.g., DL RRC, UL RRC, etc.) has its corresponding modules and each module will include the encoder, decoder, equality check, and memory management functions specific to that message type. Specifically, the goal is to achieve the following: + +* **Encoder & Decoder**: Implement encoding and decoding functions for each F1AP message. These functions will convert F1AP messages coming from upper or lower layers into an F1AP PDU to be sent over F1 interface. +* **Equality Check (eq_X)**: `eq_X()` function that compares two messages for equality. This function is useful for testing purposes, ensuring that encoded and decoded messages match. +* **Deep Copy (cp_X)**: `cp_X()` function that performs a deep copy of a message. This function is beneficial when sending ITTI messages, as it avoids manual copying. +* **Memory Management (free_X)**: `free_X()` function to release memory associated with a message. Proper memory management helps prevent memory leaks. + +e.g. The following module contains functions that performs the encoding/decoding, equality check, deep copy and memory management for DL/UL RRC message transfer: + +* [f1ap_rrc_message_transfer.c](../../openair2/F1AP/lib/f1ap_rrc_message_transfer.c) + +# Testing + +The functions in the file [f1ap_lib_common.c](../../openair2/F1AP/tests/f1ap_lib_test.c) are used to test F1AP message encoding and decoding functionalities, according to the following steps: + +* call the encoder function for the message to be transferred into a F1AP PDU +* use `f1ap_encode_decode` to perform the following steps: + - Validates the input encoded PDU against constraints. + - Encodes the PDU using APER into a binary buffer. + - Decodes the binary buffer back into a PDU. + - Returns the decoded PDU. +* call the decoder function for the decoded F1AP PDU to obtain the decoded message +* call `eq_dl_rrc_message_transfer` to compare the original message with the decoded one +* call `cp_dl_rrc_message_transfer` to deep copy the original message, then compare the with the original one +* free all messages and PDUs + +A flowchart for a function testing F1AP messages, such as `test_f1ap_setup_request`, would look like this: + +```mermaid +flowchart TD + create[Create F1AP message]-->|f1ap_setup_req_t msg|enc[encode_f1ap_setup_request] + enc-->|F1AP_F1AP_PDU_t *f1enc|encdec[f1ap_encode_decode] + encdec-->|F1AP_F1AP_PDU_t *f1dec|dec[decode_f1ap_setup_request] + create-->|f1ap_setup_req_t msg|eq + dec-->|f1ap_setup_req_t decoded|eq[eq_f1ap_setup_request] + create-->|f1ap_setup_req_t msg|cp[cp_f1ap_setup_request] + cp-->|f1ap_setup_req_t cp|eq[eq_f1ap_setup_request] +``` diff --git a/doc/README.md b/doc/README.md index 70e8bf05be..7f57a24eb0 100644 --- a/doc/README.md +++ b/doc/README.md @@ -65,7 +65,7 @@ Legacy unmaintained files: - General software architecture notes: [SW_archi.md](./SW_archi.md) - [Information on E1](./E1AP/E1-design.md) -- [Information on F1](./F1-design.md) +- [Information on F1](./F1AP/F1-design.md) - [Information on how NR nFAPI works](./NR_NFAPI_archi.md) - [Flow graph of the L1 in gNB](SW-archi-graph.md) - [L1 threads in NR-UE](./nr-ue-design.md) diff --git a/doc/UnitTests.md b/doc/UnitTests.md index aa6b7b1123..76cfe7bee1 100644 --- a/doc/UnitTests.md +++ b/doc/UnitTests.md @@ -24,6 +24,10 @@ cmake .. -GNinja -DENABLE_TESTS=ON ninja tests ``` +The user can use either `ninja` or `make`. + +# Run unit tests + Then, you can run `ctest` to run all tests: ```bash diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index cc48a6f9e9..f2fd64252c 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -163,7 +163,7 @@ typedef struct qos_characteristics_s { } packet_error_rate; } dynamic; }; - fiveQI_type_t qos_type; + fiveQI_t qos_type; } qos_characteristics_t; typedef struct ngran_allocation_retention_priority_s { diff --git a/openair2/COMMON/f1ap_messages_types.h b/openair2/COMMON/f1ap_messages_types.h index 3b6082e221..f159e63ca3 100644 --- a/openair2/COMMON/f1ap_messages_types.h +++ b/openair2/COMMON/f1ap_messages_types.h @@ -24,8 +24,7 @@ #include #include -#include "s1ap_messages_types.h" -#include "ngap_messages_types.h" +#include "common/5g_platform_types.h" //-------------------------------------------------------------------------------------------// // Defines to access message fields. @@ -82,12 +81,12 @@ #define F1AP_MAX_NO_UE_ID 1024 #define F1AP_MAX_NO_OF_INDIVIDUAL_CONNECTIONS_TO_RESET 65536 - -typedef net_ip_address_t f1ap_net_ip_address_t; +/* 9.3.1.42 of 3GPP TS 38.473 - gNB-CU System Information */ +#define F1AP_MAX_NO_SIB_TYPES 32 typedef struct f1ap_net_config_t { - f1ap_net_ip_address_t CU_f1_ip_address; - f1ap_net_ip_address_t DU_f1c_ip_address; + char *CU_f1_ip_address; + char *DU_f1c_ip_address; char *DU_f1u_ip_address; uint16_t CUport; uint16_t DUport; @@ -99,6 +98,11 @@ typedef struct f1ap_plmn_t { uint8_t mnc_digit_length; } f1ap_plmn_t; +typedef struct f1ap_cp_tnl_s { + in_addr_t tl_address; // currently only IPv4 supported + uint16_t port; +} f1ap_cp_tnl_t; + typedef enum f1ap_mode_t { F1AP_MODE_TDD = 0, F1AP_MODE_FDD = 1 } f1ap_mode_t; typedef struct f1ap_nr_frequency_info_t { @@ -179,18 +183,24 @@ typedef struct f1ap_du_register_req_t { f1ap_net_config_t net_config; } f1ap_du_register_req_t; +typedef struct f1ap_sib_msg_t { + /// RRC container with system information owned by gNB-CU + uint8_t *SI_container; + int SI_container_length; + /// SIB block type, e.g. 2 for sibType2 + int SI_type; +} f1ap_sib_msg_t; + typedef struct served_cells_to_activate_s { f1ap_plmn_t plmn; // NR Global Cell Id uint64_t nr_cellid; - /// NRPCI + /// NRPCI [int 0..1007] uint16_t nrpci; /// num SI messages per DU cell uint8_t num_SI; - /// SI message containers (up to 21 messages per cell) - uint8_t *SI_container[21]; - int SI_container_length[21]; - int SI_type[21]; + /// gNB-CU System Information message (up to 32 messages per cell) + f1ap_sib_msg_t SI_msg[F1AP_MAX_NO_SIB_TYPES]; } served_cells_to_activate_t; typedef struct f1ap_setup_resp_s { @@ -208,18 +218,8 @@ typedef struct f1ap_setup_resp_s { } f1ap_setup_resp_t; typedef struct f1ap_gnb_cu_configuration_update_s { - /* Connexion id used between SCTP/F1AP */ - uint16_t cnx_id; - - /* SCTP association id */ - sctp_assoc_t assoc_id; - - /* Number of SCTP streams used for a mme association */ - uint16_t sctp_in_streams; - uint16_t sctp_out_streams; - - /// string holding gNB_CU_name - char *gNB_CU_name; + /// Transaction ID + uint64_t transaction_id; /// number of DU cells to activate uint16_t num_cells_to_activate; //0< num_cells_to_activate/mod <= 512; served_cells_to_activate_t cells_to_activate[F1AP_MAX_NB_CELLS]; @@ -228,26 +228,37 @@ typedef struct f1ap_gnb_cu_configuration_update_s { typedef struct f1ap_setup_failure_s { uint16_t cause; uint16_t time_to_wait; - uint16_t criticality_diagnostics; + uint16_t criticality_diagnostics; + /// Transaction ID (M) + uint64_t transaction_id; } f1ap_setup_failure_t; typedef struct f1ap_gnb_cu_configuration_update_acknowledge_s { + uint64_t transaction_id; + // Cells Failed to be Activated List uint16_t num_cells_failed_to_be_activated; - f1ap_plmn_t plmn[F1AP_MAX_NB_CELLS]; - uint64_t nr_cellid[F1AP_MAX_NB_CELLS]; - uint16_t cause[F1AP_MAX_NB_CELLS]; + struct { + // NR CGI + f1ap_plmn_t plmn; + uint64_t nr_cellid; + uint16_t cause; + } cells_failed_to_be_activated[F1AP_MAX_NB_CELLS]; int have_criticality; - uint16_t criticality_diagnostics; + uint16_t criticality_diagnostics; + // gNB-CU TNL Association Setup List uint16_t noofTNLAssociations_to_setup; - uint16_t have_port[F1AP_MAX_NO_OF_TNL_ASSOCIATIONS]; - in_addr_t tl_address[F1AP_MAX_NO_OF_TNL_ASSOCIATIONS]; // currently only IPv4 supported + f1ap_cp_tnl_t tnlAssociations_to_setup[F1AP_MAX_NO_OF_TNL_ASSOCIATIONS]; + // gNB-CU TNL Association Failed to Setup List uint16_t noofTNLAssociations_failed; - in_addr_t tl_address_failed[F1AP_MAX_NO_OF_TNL_ASSOCIATIONS]; // currently only IPv4 supported - uint16_t cause_failed[F1AP_MAX_NO_OF_TNL_ASSOCIATIONS]; + f1ap_cp_tnl_t tnlAssociations_failed[F1AP_MAX_NO_OF_TNL_ASSOCIATIONS]; + // Dedicated SI Delivery Needed UE List uint16_t noofDedicatedSIDeliveryNeededUEs; - uint32_t gNB_CU_ue_id[F1AP_MAX_NO_UE_ID]; - f1ap_plmn_t ue_plmn[F1AP_MAX_NO_UE_ID]; - uint64_t ue_nr_cellid[F1AP_MAX_NO_UE_ID]; + struct { + uint32_t gNB_CU_ue_id; + // NR CGI + f1ap_plmn_t ue_plmn; + uint64_t ue_nr_cellid; + } dedicatedSIDeliveryNeededUEs[F1AP_MAX_NO_UE_ID]; } f1ap_gnb_cu_configuration_update_acknowledge_t; typedef struct f1ap_gnb_cu_configuration_update_failure_s { @@ -285,16 +296,13 @@ typedef struct f1ap_gnb_du_configuration_update_s { f1ap_plmn_t plmn; uint64_t nr_cellid; // NR Global Cell Id } cell_to_delete[F1AP_MAX_NB_CELLS]; - - /// string holding gNB_CU_name + /// gNB-DU unique ID, at least within a gNB-CU (0 .. 2^36 - 1) uint64_t *gNB_DU_ID; } f1ap_gnb_du_configuration_update_t; typedef struct f1ap_gnb_du_configuration_update_acknowledge_s { /// ulong transaction id uint64_t transaction_id; - /// string holding gNB_CU_name - char *gNB_CU_name; /// number of DU cells to activate uint16_t num_cells_to_activate; // 0< num_cells_to_activate <= 512; served_cells_to_activate_t cells_to_activate[F1AP_MAX_NB_CELLS]; @@ -334,6 +342,7 @@ typedef struct f1ap_initial_ul_rrc_message_s { int rrc_container_length; uint8_t *du2cu_rrc_container; int du2cu_rrc_container_length; + uint8_t transaction_id; } f1ap_initial_ul_rrc_message_t; typedef struct f1ap_ul_rrc_message_s { @@ -346,7 +355,7 @@ typedef struct f1ap_ul_rrc_message_s { typedef struct f1ap_up_tnl_s { in_addr_t tl_address; // currently only IPv4 supported - teid_t teid; + uint32_t teid; uint16_t port; } f1ap_up_tnl_t; @@ -376,7 +385,7 @@ typedef struct f1ap_qos_characteristics_s { } packet_error_rate; } dynamic; }; - fiveQI_type_t qos_type; + fiveQI_t qos_type; } f1ap_qos_characteristics_t; typedef struct f1ap_ngran_allocation_retention_priority_s { @@ -401,6 +410,7 @@ typedef struct f1ap_drb_information_s { uint8_t flows_to_be_setup_length; } f1ap_drb_information_t; +typedef enum f1ap_rlc_mode_t { F1AP_RLC_MODE_AM, F1AP_RLC_MODE_UM_BIDIR, F1AP_RLC_UM_UNI_UL, F1AP_RLC_UM_UNI_DL } f1ap_rlc_mode_t; typedef struct f1ap_drb_to_be_setup_s { long drb_id; f1ap_up_tnl_t up_ul_tnl[2]; @@ -408,7 +418,7 @@ typedef struct f1ap_drb_to_be_setup_s { f1ap_up_tnl_t up_dl_tnl[2]; uint8_t up_dl_tnl_length; f1ap_drb_information_t drb_info; - rlc_mode_t rlc_mode; + f1ap_rlc_mode_t rlc_mode; nssai_t nssai; } f1ap_drb_to_be_setup_t; diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index 861f5e6d2c..0f1555cfdf 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -31,8 +31,9 @@ #define NGAP_MESSAGES_TYPES_H_ #include "common/platform_constants.h" #include "common/platform_types.h" -#include "common/ngran_types.h" +#include "common/5g_platform_types.h" #include "LTE_asn_constant.h" +#include "s1ap_messages_types.h" //-------------------------------------------------------------------------------------------// // Defines to access message fields. @@ -196,16 +197,11 @@ typedef enum ngap_rrc_establishment_cause_e { NGAP_RRC_CAUSE_LAST } ngap_rrc_establishment_cause_t; -typedef struct nssai_s { - uint8_t sst; - uint32_t sd; -} nssai_t; - typedef struct pdusession_level_qos_parameter_s { uint8_t qfi; uint64_t fiveQI; uint64_t qos_priority; - fiveQI_type_t fiveQI_type; + fiveQI_t fiveQI_type; ngap_allocation_retention_priority_t allocation_retention_priority; } pdusession_level_qos_parameter_t; diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index fda507ef4e..df359c9234 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -686,7 +686,7 @@ static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bear ieC6_1_1_1->qoS_Flow_Identifier = k->qfi; /* QoS Characteristics */ qos_characteristics_t *qos_char_in = &k->qos_params.qos_characteristics; - if (qos_char_in->qos_type == non_dynamic) { // non Dynamic 5QI + if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI; asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI); non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi; @@ -1002,12 +1002,12 @@ static void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1a qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; if (qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.present == E1AP_QoS_Characteristics_PR_non_Dynamic_5QI) { - qos_char->qos_type = non_dynamic; + qos_char->qos_type = NON_DYNAMIC; qos_char->non_dynamic.fiveqi = qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI->fiveQI; } else { E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI; - qos_char->qos_type = dynamic; + qos_char->qos_type = DYNAMIC; qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel; qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget; qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar; diff --git a/openair2/F1AP/CMakeLists.txt b/openair2/F1AP/CMakeLists.txt index e6490b96b0..78bc9435a2 100644 --- a/openair2/F1AP/CMakeLists.txt +++ b/openair2/F1AP/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(lib) add_subdirectory(MESSAGES) if(ENABLE_TESTS) @@ -5,4 +6,6 @@ if(ENABLE_TESTS) target_link_libraries(f1ap_ids_test UTIL HASHTABLE minimal_lib) add_dependencies(tests f1ap_ids_test) add_test(NAME F1AP_ID_test COMMAND f1ap_ids_test) + + add_subdirectory(tests) endif() diff --git a/openair2/F1AP/f1ap_common.h b/openair2/F1AP/f1ap_common.h index 13f1d8f53b..83781484c7 100644 --- a/openair2/F1AP/f1ap_common.h +++ b/openair2/F1AP/f1ap_common.h @@ -411,8 +411,6 @@ typedef struct f1ap_cudu_inst_s { instance_t gtpInst; } f1ap_cudu_inst_t; -static const int nrb_lut[29] = {11, 18, 24, 25, 31, 32, 38, 51, 52, 65, 66, 78, 79, 93, 106, 107, 121, 132, 133, 135, 160, 162, 189, 216, 217, 245, 264, 270, 273}; - uint8_t F1AP_get_next_transaction_identifier(instance_t mod_idP, instance_t cu_mod_idP); f1ap_cudu_inst_t *getCxt(instance_t instanceP); diff --git a/openair2/F1AP/f1ap_cu_interface_management.c b/openair2/F1AP/f1ap_cu_interface_management.c index 2e73172e2b..aed1ae6d23 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.c +++ b/openair2/F1AP/f1ap_cu_interface_management.c @@ -34,926 +34,187 @@ #include "f1ap_encoder.h" #include "f1ap_itti_messaging.h" #include "f1ap_cu_interface_management.h" - -int CU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset) -{ - AssertFatal(1==0,"Not implemented yet\n"); -} +#include "f1ap_default_values.h" +#include "lib/f1ap_interface_management.h" +#include "lib/f1ap_lib_common.h" int CU_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - AssertFatal(1==0,"Not implemented yet\n"); -} - -int CU_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) -{ - AssertFatal(1==0,"Not implemented yet\n"); + AssertFatal(1 == 0, "Not implemented yet\n"); } int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack) { - AssertFatal(1==0,"Not implemented yet\n"); + AssertFatal(1 == 0, "Not implemented yet\n"); } -/* - Error Indication -*/ -int CU_handle_ERROR_INDICATION(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) -{ - AssertFatal(1==0,"Not implemented yet\n"); -} - -int CU_send_ERROR_INDICATION(sctp_assoc_t assoc_id, F1AP_ErrorIndication_t *ErrorIndication) { - AssertFatal(1==0,"Not implemented yet\n"); -} - -static uint8_t *cp_octet_string(const OCTET_STRING_t *os, int *len) -{ - uint8_t *buf = calloc(os->size, sizeof(*buf)); - AssertFatal(buf != NULL, "out of memory\n"); - memcpy(buf, os->buf, os->size); - *len = os->size; - return buf; -} - -static int read_slice_info(const F1AP_ServedPLMNs_Item_t *plmn, nssai_t *nssai, int max_nssai) -{ - if (plmn->iE_Extensions == NULL) - return 0; - - const F1AP_ProtocolExtensionContainer_10696P34_t *p = (F1AP_ProtocolExtensionContainer_10696P34_t *)plmn->iE_Extensions; - if (p->list.count == 0) - return 0; - - const F1AP_ServedPLMNs_ItemExtIEs_t *splmn = p->list.array[0]; - DevAssert(splmn->id == F1AP_ProtocolIE_ID_id_TAISliceSupportList); - DevAssert(splmn->extensionValue.present == F1AP_ServedPLMNs_ItemExtIEs__extensionValue_PR_SliceSupportList); - const F1AP_SliceSupportList_t *ssl = &splmn->extensionValue.choice.SliceSupportList; - AssertFatal(ssl->list.count <= max_nssai, "cannot handle more than 16 slices\n"); - for (int s = 0; s < ssl->list.count; ++s) { - const F1AP_SliceSupportItem_t *sl = ssl->list.array[s]; - nssai_t *n = &nssai[s]; - OCTET_STRING_TO_INT8(&sl->sNSSAI.sST, n->sst); - n->sd = 0xffffff; - if (sl->sNSSAI.sD != NULL) - OCTET_STRING_TO_INT24(sl->sNSSAI.sD, n->sd); - } - - return ssl->list.count; -} - -/* - F1 Setup -*/ +/** + * @brief F1AP Setup Request decoding (9.2.1.4 of 3GPP TS 38.473) and transfer to RRC + */ int CU_handle_F1_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { LOG_D(F1AP, "CU_handle_F1_SETUP_REQUEST\n"); - F1AP_F1SetupRequest_t *container; - F1AP_F1SetupRequestIEs_t *ie; - int i = 0; DevAssert(pdu != NULL); - container = &pdu->choice.initiatingMessage->value.choice.F1SetupRequest; - /* F1 Setup Request == Non UE-related procedure -> stream 0 */ if (stream != 0) { LOG_W(F1AP, "[SCTP %d] Received f1 setup request on stream != 0 (%d)\n", assoc_id, stream); } - + f1ap_setup_req_t msg = {0}; + /* Decode */ + if (!decode_f1ap_setup_request(pdu, &msg)) { + LOG_E(F1AP, "cannot decode F1AP Setup Request\n"); + free_f1ap_setup_request(&msg); + return -1; + } + /* Send to RRC (ITTI) */ MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_SETUP_REQ); message_p->ittiMsgHeader.originInstance = assoc_id; f1ap_setup_req_t *req = &F1AP_SETUP_REQ(message_p); - - /* Transaction ID*/ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupRequestIEs_t, ie, container, F1AP_ProtocolIE_ID_id_TransactionID, true); - req->transaction_id = ie->value.choice.TransactionID; - LOG_D(F1AP, "req->transaction_id %lu \n", req->transaction_id); - - /* gNB_DU_id */ - // this function exits if the ie is mandatory - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupRequestIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_ID, true); - asn_INTEGER2ulong(&ie->value.choice.GNB_DU_ID, &req->gNB_DU_id); - LOG_D(F1AP, "req->gNB_DU_id %lu \n", req->gNB_DU_id); - /* gNB_DU_name */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupRequestIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_Name, false); - req->gNB_DU_name = NULL; - if (ie != NULL) { - req->gNB_DU_name = calloc(ie->value.choice.GNB_DU_Name.size + 1, sizeof(char)); - memcpy(req->gNB_DU_name, ie->value.choice.GNB_DU_Name.buf, ie->value.choice.GNB_DU_Name.size); - LOG_D(F1AP, "req->gNB_DU_name %s \n", req->gNB_DU_name); - } - /* GNB_DU_Served_Cells_List */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupRequestIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_Served_Cells_List, true); - req->num_cells_available = ie->value.choice.GNB_DU_Served_Cells_List.list.count; - LOG_D(F1AP, "req->num_cells_available %d \n", req->num_cells_available); - - for (i=0; inum_cells_available; i++) { - F1AP_GNB_DU_Served_Cells_Item_t *served_cells_item = &(((F1AP_GNB_DU_Served_Cells_ItemIEs_t *) - ie->value.choice.GNB_DU_Served_Cells_List.list.array[i])-> - value.choice.GNB_DU_Served_Cells_Item); - F1AP_Served_Cell_Information_t *servedCellInformation= &served_cells_item->served_Cell_Information; - /* tac */ - if (servedCellInformation->fiveGS_TAC) { - req->cell[i].info.tac = malloc(sizeof(*req->cell[i].info.tac)); - AssertFatal(req->cell[i].info.tac != NULL, "out of memory\n"); - OCTET_STRING_TO_INT24(servedCellInformation->fiveGS_TAC, *req->cell[i].info.tac); - LOG_D(F1AP, "req->tac[%d] %d \n", i, *req->cell[i].info.tac); - } - - /* - nRCGI */ - TBCD_TO_MCC_MNC(&(servedCellInformation->nRCGI.pLMN_Identity), - req->cell[i].info.plmn.mcc, - req->cell[i].info.plmn.mnc, - req->cell[i].info.plmn.mnc_digit_length); - // NR cellID - BIT_STRING_TO_NR_CELL_IDENTITY(&servedCellInformation->nRCGI.nRCellIdentity, - req->cell[i].info.nr_cellid); - LOG_D(F1AP, "[SCTP %d] Received nRCGI: MCC %d, MNC %d, CELL_ID %llu\n", assoc_id, - req->cell[i].info.plmn.mcc, - req->cell[i].info.plmn.mnc, - (long long unsigned int)req->cell[i].info.nr_cellid); - /* - nRPCI */ - req->cell[i].info.nr_pci = servedCellInformation->nRPCI; - LOG_D(F1AP, "req->nr_pci[%d] %d \n", i, req->cell[i].info.nr_pci); - - AssertFatal(servedCellInformation->servedPLMNs.list.count == 1, "only one PLMN handled\n"); - req->cell[i].info.num_ssi = read_slice_info(servedCellInformation->servedPLMNs.list.array[0], req->cell[i].info.nssai, 16); - - // FDD Cells - if (servedCellInformation->nR_Mode_Info.present==F1AP_NR_Mode_Info_PR_fDD) { - req->cell[i].info.mode = F1AP_MODE_FDD; - f1ap_fdd_info_t *FDDs = &req->cell[i].info.fdd; - F1AP_FDD_Info_t * fDD_Info=servedCellInformation->nR_Mode_Info.choice.fDD; - FDDs->ul_freqinfo.arfcn = fDD_Info->uL_NRFreqInfo.nRARFCN; - AssertFatal(fDD_Info->uL_NRFreqInfo.freqBandListNr.list.count == 1, "cannot handle more than one frequency band\n"); - for (int f=0; f < fDD_Info->uL_NRFreqInfo.freqBandListNr.list.count; f++) { - F1AP_FreqBandNrItem_t * FreqItem=fDD_Info->uL_NRFreqInfo.freqBandListNr.list.array[f]; - FDDs->ul_freqinfo.band = FreqItem->freqBandIndicatorNr; - AssertFatal(FreqItem->supportedSULBandList.list.count == 0, "cannot handle SUL bands!\n"); - } - FDDs->dl_freqinfo.arfcn = fDD_Info->dL_NRFreqInfo.nRARFCN; - int dlBands=fDD_Info->dL_NRFreqInfo.freqBandListNr.list.count; - AssertFatal(dlBands == 1, "cannot handled more than one frequency band\n"); - for (int dlB=0; dlB < dlBands; dlB++) { - F1AP_FreqBandNrItem_t * FreqItem=fDD_Info->dL_NRFreqInfo.freqBandListNr.list.array[dlB]; - FDDs->dl_freqinfo.band = FreqItem->freqBandIndicatorNr; - int num_available_supported_SULBands = FreqItem->supportedSULBandList.list.count; - AssertFatal(num_available_supported_SULBands == 0, "cannot handle SUL bands!\n"); - } - FDDs->ul_tbw.scs = fDD_Info->uL_Transmission_Bandwidth.nRSCS; - FDDs->ul_tbw.nrb = nrb_lut[fDD_Info->uL_Transmission_Bandwidth.nRNRB]; - FDDs->dl_tbw.scs = fDD_Info->dL_Transmission_Bandwidth.nRSCS; - FDDs->dl_tbw.nrb = nrb_lut[fDD_Info->dL_Transmission_Bandwidth.nRNRB]; - } else if (servedCellInformation->nR_Mode_Info.present==F1AP_NR_Mode_Info_PR_tDD) { - req->cell[i].info.mode = F1AP_MODE_TDD; - f1ap_tdd_info_t *TDDs = &req->cell[i].info.tdd; - F1AP_TDD_Info_t *tDD_Info = servedCellInformation->nR_Mode_Info.choice.tDD; - TDDs->freqinfo.arfcn = tDD_Info->nRFreqInfo.nRARFCN; - AssertFatal(tDD_Info->nRFreqInfo.freqBandListNr.list.count == 1, "cannot handle more than one frequency band\n"); - for (int f=0; f < tDD_Info->nRFreqInfo.freqBandListNr.list.count; f++) { - struct F1AP_FreqBandNrItem * FreqItem=tDD_Info->nRFreqInfo.freqBandListNr.list.array[f]; - TDDs->freqinfo.band = FreqItem->freqBandIndicatorNr; - int num_available_supported_SULBands = FreqItem->supportedSULBandList.list.count; - AssertFatal(num_available_supported_SULBands == 0, "cannot hanlde SUL bands!\n"); - } - TDDs->tbw.scs = tDD_Info->transmission_Bandwidth.nRSCS; - TDDs->tbw.nrb = nrb_lut[tDD_Info->transmission_Bandwidth.nRNRB]; - } else { - AssertFatal(false, "unknown NR Mode info %d\n", servedCellInformation->nR_Mode_Info.present); - } - - /* MeasurementConfig */ - if (servedCellInformation->measurementTimingConfiguration.size > 0) - req->cell[i].info.measurement_timing_config = - cp_octet_string(&servedCellInformation->measurementTimingConfiguration, &req->cell[i].info.measurement_timing_config_len); - - struct F1AP_GNB_DU_System_Information * DUsi=served_cells_item->gNB_DU_System_Information; - if (DUsi != NULL) { - // System Information - req->cell[i].sys_info = calloc(1, sizeof(*req->cell[i].sys_info)); - AssertFatal(req->cell[i].sys_info != NULL, "out of memory\n"); - f1ap_gnb_du_system_info_t *sys_info = req->cell[i].sys_info; - /* mib */ - sys_info->mib = calloc(DUsi->mIB_message.size, sizeof(char)); - memcpy(sys_info->mib, DUsi->mIB_message.buf, DUsi->mIB_message.size); - sys_info->mib_length = DUsi->mIB_message.size; - /* sib1 */ - sys_info->sib1 = calloc(DUsi->sIB1_message.size, sizeof(char)); - memcpy(sys_info->sib1, DUsi->sIB1_message.buf, DUsi->sIB1_message.size); - sys_info->sib1_length = DUsi->sIB1_message.size; - } - } - - /* Handle RRC Version */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupRequestIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version, true); - // Latest RRC Version: "This IE is not used in this release." - // BIT_STRING_to_uint8(&ie->value.choice.RRC_Version.latest_RRC_Version); - if (ie->value.choice.RRC_Version.iE_Extensions) { - F1AP_ProtocolExtensionContainer_10696P228_t *ext = - (F1AP_ProtocolExtensionContainer_10696P228_t *)ie->value.choice.RRC_Version.iE_Extensions; - if (ext->list.count > 0) { - F1AP_RRC_Version_ExtIEs_t *rrcext = ext->list.array[0]; - OCTET_STRING_t *os = &rrcext->extensionValue.choice.OCTET_STRING_SIZE_3_; - DevAssert(os->size == 3); - for (int i = 0; i < 3; ++i) - req->rrc_ver[i] = os->buf[i]; - } - } + *req = msg; /* "move" message into ITTI, RRC thread will free it */ itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p); - return 0; } +/** + * @brief F1AP Setup Response encoding (9.2.1.5 of 3GPP TS 38.473) and message transfer + */ int CU_send_F1_SETUP_RESPONSE(sctp_assoc_t assoc_id, f1ap_setup_resp_t *f1ap_setup_resp) { - F1AP_F1AP_PDU_t pdu= {0}; uint8_t *buffer=NULL; - uint32_t len=0; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu.choice.successfulOutcome, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_F1Setup; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_SuccessfulOutcome__value_PR_F1SetupResponse; - F1AP_F1SetupResponse_t *out = &pdu.choice.successfulOutcome->value.choice.F1SetupResponse; - /* mandatory */ - /* c1. Transaction ID (integer value)*/ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_F1SetupResponseIEs__value_PR_TransactionID; - ie1->value.choice.TransactionID = f1ap_setup_resp->transaction_id; + uint32_t len = 0; - /* optional */ - /* c2. GNB_CU_Name */ - if (f1ap_setup_resp->gNB_CU_name != NULL) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_CU_Name; - ie2->criticality = F1AP_Criticality_ignore; - ie2->value.present = F1AP_F1SetupResponseIEs__value_PR_GNB_CU_Name; - OCTET_STRING_fromBuf(&ie2->value.choice.GNB_CU_Name, f1ap_setup_resp->gNB_CU_name, - strlen(f1ap_setup_resp->gNB_CU_name)); - } - - /* mandatory */ - /* c3. cells to be Activated list */ - int num_cells_to_activate = f1ap_setup_resp->num_cells_to_activate; - LOG_D(F1AP, "num_cells_to_activate = %d \n", num_cells_to_activate); - - if (num_cells_to_activate >0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_F1SetupResponseIEs__value_PR_Cells_to_be_Activated_List; - - for (int i=0; ivalue.choice.Cells_to_be_Activated_List.list, - F1AP_Cells_to_be_Activated_List_ItemIEs_t, cells_to_be_activated_ies); - cells_to_be_activated_ies->id = F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item; - cells_to_be_activated_ies->criticality = F1AP_Criticality_reject; - cells_to_be_activated_ies->value.present = F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item; - /* 3.1 cells to be Activated list item */ - F1AP_Cells_to_be_Activated_List_Item_t *cells_to_be_activated_item= - &cells_to_be_activated_ies->value.choice.Cells_to_be_Activated_List_Item; - /* - nRCGI */ - addnRCGI(cells_to_be_activated_item->nRCGI, f1ap_setup_resp->cells_to_activate+i); - - /* optional */ - /* - nRPCI */ - if (1) { - cells_to_be_activated_item->nRPCI = (F1AP_NRPCI_t *)calloc(1, sizeof(F1AP_NRPCI_t)); - *cells_to_be_activated_item->nRPCI = f1ap_setup_resp->cells_to_activate[i].nrpci; // int 0..1007 - } - - /* optional */ - /* - gNB-CU System Information */ - if (f1ap_setup_resp->cells_to_activate[i].num_SI > 0) { - /* 3.1.2 gNB-CUSystem Information */ - F1AP_ProtocolExtensionContainer_10696P112_t *p = calloc(1, sizeof(* p)); - cells_to_be_activated_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *) p; - asn1cSequenceAdd(p->list, F1AP_Cells_to_be_Activated_List_ItemExtIEs_t, cells_to_be_activated_itemExtIEs); - cells_to_be_activated_itemExtIEs->id = F1AP_ProtocolIE_ID_id_gNB_CUSystemInformation; - cells_to_be_activated_itemExtIEs->criticality = F1AP_Criticality_reject; - cells_to_be_activated_itemExtIEs->extensionValue.present = F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_GNB_CUSystemInformation; - F1AP_GNB_CUSystemInformation_t *gNB_CUSystemInformation = - &cells_to_be_activated_itemExtIEs->extensionValue.choice.GNB_CUSystemInformation; - - // for (int sIBtype=2;sIBtype<33;sIBtype++) { //21 ? 33 ? - for (int sIBtype=2; sIBtype<21; sIBtype++) { - if (f1ap_setup_resp->cells_to_activate[i].SI_container[sIBtype]!=NULL) { - AssertFatal(sIBtype < 6 || sIBtype == 9, "Illegal SI type %d\n",sIBtype); - asn1cSequenceAdd(gNB_CUSystemInformation->sibtypetobeupdatedlist.list, F1AP_SibtypetobeupdatedListItem_t, sib_item); - sib_item->sIBtype = sIBtype; - OCTET_STRING_fromBuf(&sib_item->sIBmessage, - (const char *)f1ap_setup_resp->cells_to_activate[i].SI_container[sIBtype], - f1ap_setup_resp->cells_to_activate[i].SI_container_length[sIBtype]); - LOG_D(F1AP, "f1ap_setup_resp->SI_container_length[%d][%d] = %d \n", i,sIBtype,f1ap_setup_resp->cells_to_activate[i].SI_container_length[sIBtype]); - } - } - } - } - } - - /* c5. RRC VERSION */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_F1SetupResponseIEs__value_PR_RRC_Version; - // RRC Version: "This IE is not used in this release." - // we put one bit for each byte in rrc_ver that is != 0 - uint8_t bits = 0; - for (int i = 0; i < 3; ++i) - bits |= (f1ap_setup_resp->rrc_ver[i] != 0) << i; - BIT_STRING_t *bs = &ie4->value.choice.RRC_Version.latest_RRC_Version; - bs->buf = calloc(1, sizeof(char)); - AssertFatal(bs->buf != NULL, "out of memory\n"); - bs->buf[0] = bits; - bs->size = 1; - bs->bits_unused = 5; - - F1AP_ProtocolExtensionContainer_10696P228_t *p = (F1AP_ProtocolExtensionContainer_10696P228_t*)calloc(1, sizeof(F1AP_ProtocolExtensionContainer_10696P228_t)); - asn1cSequenceAdd(p->list, F1AP_RRC_Version_ExtIEs_t, rrcv_ext); - rrcv_ext->id = F1AP_ProtocolIE_ID_id_latest_RRC_Version_Enhanced; - rrcv_ext->criticality = F1AP_Criticality_ignore; - rrcv_ext->extensionValue.present = F1AP_RRC_Version_ExtIEs__extensionValue_PR_OCTET_STRING_SIZE_3_; - OCTET_STRING_t *os = &rrcv_ext->extensionValue.choice.OCTET_STRING_SIZE_3_; - os->size = 3; - os->buf = malloc(3 * sizeof(*os->buf)); - AssertFatal(os->buf != NULL, "out of memory\n"); - for (int i = 0; i < 3; ++i) - os->buf[i] = f1ap_setup_resp->rrc_ver[i]; - ie4->value.choice.RRC_Version.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; + /* Encode F1 Setup Response */ + F1AP_F1AP_PDU_t *pdu = encode_f1ap_setup_response(f1ap_setup_resp); + /* Free after encode */ + free_f1ap_setup_response(f1ap_setup_resp); /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 setup response\n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return -1; } - - ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } +/** + * @brief F1 Setup Failure encoding and transmission + */ int CU_send_F1_SETUP_FAILURE(sctp_assoc_t assoc_id, const f1ap_setup_failure_t *fail) { LOG_D(F1AP, "CU_send_F1_SETUP_FAILURE\n"); - F1AP_F1AP_PDU_t pdu= {0}; - uint8_t *buffer=NULL; - uint32_t len=0; - /* Create */ - /* 0. Message Type */ - asn1cCalloc(pdu.choice.unsuccessfulOutcome, UnsuccessfulOutcome); - pdu.present = F1AP_F1AP_PDU_PR_unsuccessfulOutcome; - UnsuccessfulOutcome->procedureCode = F1AP_ProcedureCode_id_F1Setup; - UnsuccessfulOutcome->criticality = F1AP_Criticality_reject; - UnsuccessfulOutcome->value.present = F1AP_UnsuccessfulOutcome__value_PR_F1SetupFailure; - F1AP_F1SetupFailure_t *out = &pdu.choice.unsuccessfulOutcome->value.choice.F1SetupFailure; - /* mandatory */ - /* c1. Transaction ID (integer value)*/ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupFailureIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_F1SetupFailureIEs__value_PR_TransactionID; - ie1->value.choice.TransactionID = F1AP_get_next_transaction_identifier(0, 0); - /* mandatory */ - /* c2. Cause */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupFailureIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_Cause; - ie2->criticality = F1AP_Criticality_ignore; - ie2->value.present = F1AP_F1SetupFailureIEs__value_PR_Cause; - ie2->value.choice.Cause.present = F1AP_Cause_PR_radioNetwork; - ie2->value.choice.Cause.choice.radioNetwork = F1AP_CauseRadioNetwork_unspecified; - - /* optional */ - /* c3. TimeToWait */ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupFailureIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_TimeToWait; - ie3->criticality = F1AP_Criticality_ignore; - ie3->value.present = F1AP_F1SetupFailureIEs__value_PR_TimeToWait; - ie3->value.choice.TimeToWait = F1AP_TimeToWait_v10s; - } - - /* optional */ - /* c4. CriticalityDiagnostics*/ - if (0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupFailureIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_CriticalityDiagnostics; - ie4->criticality = F1AP_Criticality_ignore; - ie4->value.present = F1AP_F1SetupFailureIEs__value_PR_CriticalityDiagnostics; - asn1cCallocOne(ie4->value.choice.CriticalityDiagnostics.procedureCode, - F1AP_ProcedureCode_id_UEContextSetup); - asn1cCallocOne(ie4->value.choice.CriticalityDiagnostics.triggeringMessage, - F1AP_TriggeringMessage_initiating_message); - asn1cCallocOne(ie4->value.choice.CriticalityDiagnostics.procedureCriticality, - F1AP_Criticality_reject); - asn1cCallocOne(ie4->value.choice.CriticalityDiagnostics.transactionID, - 0); - } - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + uint8_t *buffer = NULL; + uint32_t len = 0; + /* Encode F1 Setup Failure */ + F1AP_F1AP_PDU_t *pdu = encode_f1ap_setup_failure(fail); + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 setup failure\n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return -1; } - - ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } -/* - gNB-DU Configuration Update -*/ - +/** + * @brief Decode and send F1 gNB-DU Configuration Update message to RRC + */ int CU_handle_gNB_DU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - LOG_D(F1AP, "CU_handle_gNB_DU_CONFIGURATION_UPDATE\n"); - F1AP_GNBDUConfigurationUpdate_t *container; - F1AP_GNBDUConfigurationUpdateIEs_t *ie; - int i = 0; + LOG_D(F1AP, "[SCTP %d] CU_handle_gNB_DU_CONFIGURATION_UPDATE\n", assoc_id); DevAssert(pdu != NULL); - container = &pdu->choice.initiatingMessage->value.choice.GNBDUConfigurationUpdate; - /* gNB DU Configuration Update == Non UE-related procedure -> stream 0 */ if (stream != 0) { LOG_W(F1AP, "[SCTP %d] Received f1 setup request on stream != 0 (%d)\n", assoc_id, stream); } - + /* Decode */ + f1ap_gnb_du_configuration_update_t msg = {0}; + if (!decode_f1ap_du_configuration_update(pdu, &msg)) { + LOG_E(F1AP, "cannot decode F1AP gNB-DU Configuration Update\n"); + free_f1ap_du_configuration_update(&msg); + return -1; + } + /* Send to RRC */ MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE); message_p->ittiMsgHeader.originInstance = assoc_id; - f1ap_gnb_du_configuration_update_t *req = &F1AP_GNB_DU_CONFIGURATION_UPDATE(message_p); - - /* 3GPP TS 38.473 Transaction ID*/ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_GNBDUConfigurationUpdateIEs_t, ie, container, F1AP_ProtocolIE_ID_id_TransactionID, true); - req->transaction_id = ie->value.choice.TransactionID; - LOG_D(F1AP, "req->transaction_id %lu \n", req->transaction_id); - - /* 3GPP TS 38.473 Served Cells To Add List */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_GNBDUConfigurationUpdateIEs_t, - ie, - container, - F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List, - false); - - if (ie != NULL) { - req->num_cells_to_add = ie->value.choice.Served_Cells_To_Add_List.list.count; - LOG_D(F1AP, "req->num_cells_to_add %d \n", req->num_cells_to_add); - - for (i = 0; i < req->num_cells_to_add; i++) { - F1AP_Served_Cells_To_Add_Item_t *served_cells_item = - &((F1AP_Served_Cells_To_Add_ItemIEs_t *)ie->value.choice.Served_Cells_To_Add_List.list.array[i]) - ->value.choice.Served_Cells_To_Add_Item; - F1AP_Served_Cell_Information_t *servedCellInformation = &served_cells_item->served_Cell_Information; - /* tac */ - if (servedCellInformation->fiveGS_TAC) { - req->cell_to_add[i].info.tac = malloc(sizeof(*req->cell_to_add[i].info.tac)); - AssertFatal(req->cell_to_add[i].info.tac != NULL, "out of memory\n"); - OCTET_STRING_TO_INT24(servedCellInformation->fiveGS_TAC, *req->cell_to_add[i].info.tac); - LOG_D(F1AP, "req->tac[%d] %d \n", i, *req->cell_to_add[i].info.tac); - } - - /* - nRCGI */ - TBCD_TO_MCC_MNC(&(servedCellInformation->nRCGI.pLMN_Identity), - req->cell_to_add[i].info.plmn.mcc, - req->cell_to_add[i].info.plmn.mnc, - req->cell_to_add[i].info.plmn.mnc_digit_length); - // NR cellID - BIT_STRING_TO_NR_CELL_IDENTITY(&servedCellInformation->nRCGI.nRCellIdentity, req->cell_to_add[i].info.nr_cellid); - LOG_D(F1AP, - "[SCTP %d] Received nRCGI: MCC %d, MNC %d, CELL_ID %llu\n", - assoc_id, - req->cell_to_add[i].info.plmn.mcc, - req->cell_to_add[i].info.plmn.mnc, - (long long unsigned int)req->cell_to_add[i].info.nr_cellid); - - /* - nRPCI */ - req->cell_to_add[i].info.nr_pci = servedCellInformation->nRPCI; - LOG_D(F1AP, "req->nr_pci[%d] %d \n", i, req->cell_to_add[i].info.nr_pci); - - AssertFatal(servedCellInformation->servedPLMNs.list.count == 1, "only one PLMN handled\n"); - req->cell_to_add[i].info.num_ssi = - read_slice_info(servedCellInformation->servedPLMNs.list.array[0], req->cell_to_add[i].info.nssai, 16); - - // FDD Cells - if (servedCellInformation->nR_Mode_Info.present == F1AP_NR_Mode_Info_PR_fDD) { - req->cell_to_add[i].info.mode = F1AP_MODE_FDD; - f1ap_fdd_info_t *FDDs = &req->cell_to_add[i].info.fdd; - F1AP_FDD_Info_t *fDD_Info = servedCellInformation->nR_Mode_Info.choice.fDD; - FDDs->ul_freqinfo.arfcn = fDD_Info->uL_NRFreqInfo.nRARFCN; - AssertFatal(fDD_Info->uL_NRFreqInfo.freqBandListNr.list.count == 1, "cannot handle more than one frequency band\n"); - for (int f = 0; f < fDD_Info->uL_NRFreqInfo.freqBandListNr.list.count; f++) { - F1AP_FreqBandNrItem_t *FreqItem = fDD_Info->uL_NRFreqInfo.freqBandListNr.list.array[f]; - FDDs->ul_freqinfo.band = FreqItem->freqBandIndicatorNr; - AssertFatal(FreqItem->supportedSULBandList.list.count == 0, "cannot handle SUL bands!\n"); - } - FDDs->dl_freqinfo.arfcn = fDD_Info->dL_NRFreqInfo.nRARFCN; - int dlBands = fDD_Info->dL_NRFreqInfo.freqBandListNr.list.count; - AssertFatal(dlBands == 0, "cannot handled more than one frequency band\n"); - for (int dlB = 0; dlB < dlBands; dlB++) { - F1AP_FreqBandNrItem_t *FreqItem = fDD_Info->dL_NRFreqInfo.freqBandListNr.list.array[dlB]; - FDDs->dl_freqinfo.band = FreqItem->freqBandIndicatorNr; - int num_available_supported_SULBands = FreqItem->supportedSULBandList.list.count; - AssertFatal(num_available_supported_SULBands == 0, "cannot handle SUL bands!\n"); - } - FDDs->ul_tbw.scs = fDD_Info->uL_Transmission_Bandwidth.nRSCS; - FDDs->ul_tbw.nrb = nrb_lut[fDD_Info->uL_Transmission_Bandwidth.nRNRB]; - FDDs->dl_tbw.scs = fDD_Info->dL_Transmission_Bandwidth.nRSCS; - FDDs->dl_tbw.nrb = nrb_lut[fDD_Info->dL_Transmission_Bandwidth.nRNRB]; - } else if (servedCellInformation->nR_Mode_Info.present == F1AP_NR_Mode_Info_PR_tDD) { - req->cell_to_add[i].info.mode = F1AP_MODE_TDD; - f1ap_tdd_info_t *TDDs = &req->cell_to_add[i].info.tdd; - F1AP_TDD_Info_t *tDD_Info = servedCellInformation->nR_Mode_Info.choice.tDD; - TDDs->freqinfo.arfcn = tDD_Info->nRFreqInfo.nRARFCN; - AssertFatal(tDD_Info->nRFreqInfo.freqBandListNr.list.count == 1, "cannot handle more than one frequency band\n"); - for (int f = 0; f < tDD_Info->nRFreqInfo.freqBandListNr.list.count; f++) { - struct F1AP_FreqBandNrItem *FreqItem = tDD_Info->nRFreqInfo.freqBandListNr.list.array[f]; - TDDs->freqinfo.band = FreqItem->freqBandIndicatorNr; - int num_available_supported_SULBands = FreqItem->supportedSULBandList.list.count; - AssertFatal(num_available_supported_SULBands == 0, "cannot hanlde SUL bands!\n"); - } - TDDs->tbw.scs = tDD_Info->transmission_Bandwidth.nRSCS; - TDDs->tbw.nrb = nrb_lut[tDD_Info->transmission_Bandwidth.nRNRB]; - } else { - AssertFatal(false, "unknown NR Mode info %d\n", servedCellInformation->nR_Mode_Info.present); - } - - /* MeasurementConfig */ - if (servedCellInformation->measurementTimingConfiguration.size > 0) - req->cell_to_add[i].info.measurement_timing_config = - cp_octet_string(&servedCellInformation->measurementTimingConfiguration, - &req->cell_to_add[i].info.measurement_timing_config_len); - - struct F1AP_GNB_DU_System_Information *DUsi = served_cells_item->gNB_DU_System_Information; - // System Information - req->cell_to_add[i].sys_info = calloc(1, sizeof(*req->cell_to_add[i].sys_info)); - AssertFatal(req->cell_to_add[i].sys_info != NULL, "out of memory\n"); - f1ap_gnb_du_system_info_t *sys_info = req->cell_to_add[i].sys_info; - /* mib */ - sys_info->mib = calloc(DUsi->mIB_message.size, sizeof(char)); - memcpy(sys_info->mib, DUsi->mIB_message.buf, DUsi->mIB_message.size); - sys_info->mib_length = DUsi->mIB_message.size; - /* sib1 */ - sys_info->sib1 = calloc(DUsi->sIB1_message.size, sizeof(char)); - memcpy(sys_info->sib1, DUsi->sIB1_message.buf, DUsi->sIB1_message.size); - sys_info->sib1_length = DUsi->sIB1_message.size; - } - } else { - req->num_cells_to_add = 0; - } - /* 3GPP TS 38.473 Served Cells To Modify List */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_GNBDUConfigurationUpdateIEs_t, - ie, - container, - F1AP_ProtocolIE_ID_id_Served_Cells_To_Modify_List, - false); - - if (ie) { - req->num_cells_to_modify = ie->value.choice.Served_Cells_To_Modify_List.list.count; - LOG_D(F1AP, "req->num_cells_to_modify %d \n", req->num_cells_to_modify); - - for (i = 0; i < req->num_cells_to_modify; i++) { - F1AP_Served_Cells_To_Modify_Item_t *served_cells_item = - &((F1AP_Served_Cells_To_Modify_ItemIEs_t *)ie->value.choice.Served_Cells_To_Modify_List.list.array[i]) - ->value.choice.Served_Cells_To_Modify_Item; - - /* OLD NRCGI */ - TBCD_TO_MCC_MNC(&(served_cells_item->oldNRCGI.pLMN_Identity), - req->cell_to_modify[i].old_plmn.mcc, - req->cell_to_modify[i].old_plmn.mnc, - req->cell_to_modify[i].old_plmn.mnc_digit_length); - - BIT_STRING_TO_NR_CELL_IDENTITY(&served_cells_item->oldNRCGI.nRCellIdentity, req->cell_to_modify[i].old_nr_cellid); - - F1AP_Served_Cell_Information_t *servedCellInformation = &served_cells_item->served_Cell_Information; - /* SERVED CELL INFORMATION*/ - /* tac */ - if (servedCellInformation->fiveGS_TAC) { - req->cell_to_modify[i].info.tac = malloc(sizeof(*req->cell_to_modify[i].info.tac)); - AssertFatal(req->cell_to_modify[i].info.tac != NULL, "out of memory\n"); - OCTET_STRING_TO_INT24(servedCellInformation->fiveGS_TAC, *req->cell_to_modify[i].info.tac); - LOG_D(F1AP, "req->tac[%d] %d \n", i, *req->cell_to_modify[i].info.tac); - } - - /* - nRCGI */ - TBCD_TO_MCC_MNC(&(servedCellInformation->nRCGI.pLMN_Identity), - req->cell_to_modify[i].info.plmn.mcc, - req->cell_to_modify[i].info.plmn.mnc, - req->cell_to_modify[i].info.plmn.mnc_digit_length); - // NR cellID - BIT_STRING_TO_NR_CELL_IDENTITY(&servedCellInformation->nRCGI.nRCellIdentity, req->cell_to_modify[i].info.nr_cellid); - LOG_D(F1AP, - "[SCTP %d] Received nRCGI: MCC %d, MNC %d, CELL_ID %llu\n", - assoc_id, - req->cell_to_modify[i].info.plmn.mcc, - req->cell_to_modify[i].info.plmn.mnc, - (long long unsigned int)req->cell_to_modify[i].info.nr_cellid); - - /* - nRPCI */ - req->cell_to_modify[i].info.nr_pci = servedCellInformation->nRPCI; - LOG_D(F1AP, "req->nr_pci[%d] %d \n", i, req->cell_to_modify[i].info.nr_pci); - - // FDD Cells - if (servedCellInformation->nR_Mode_Info.present == F1AP_NR_Mode_Info_PR_fDD) { - req->cell_to_modify[i].info.mode = F1AP_MODE_FDD; - f1ap_fdd_info_t *FDDs = &req->cell_to_modify[i].info.fdd; - F1AP_FDD_Info_t *fDD_Info = servedCellInformation->nR_Mode_Info.choice.fDD; - FDDs->ul_freqinfo.arfcn = fDD_Info->uL_NRFreqInfo.nRARFCN; - AssertFatal(fDD_Info->uL_NRFreqInfo.freqBandListNr.list.count == 1, "cannot handle more than one frequency band\n"); - for (int f = 0; f < fDD_Info->uL_NRFreqInfo.freqBandListNr.list.count; f++) { - F1AP_FreqBandNrItem_t *FreqItem = fDD_Info->uL_NRFreqInfo.freqBandListNr.list.array[f]; - FDDs->ul_freqinfo.band = FreqItem->freqBandIndicatorNr; - AssertFatal(FreqItem->supportedSULBandList.list.count == 0, "cannot handle SUL bands!\n"); - } - FDDs->dl_freqinfo.arfcn = fDD_Info->dL_NRFreqInfo.nRARFCN; - int dlBands = fDD_Info->dL_NRFreqInfo.freqBandListNr.list.count; - AssertFatal(dlBands == 0, "cannot handled more than one frequency band\n"); - for (int dlB = 0; dlB < dlBands; dlB++) { - F1AP_FreqBandNrItem_t *FreqItem = fDD_Info->dL_NRFreqInfo.freqBandListNr.list.array[dlB]; - FDDs->dl_freqinfo.band = FreqItem->freqBandIndicatorNr; - int num_available_supported_SULBands = FreqItem->supportedSULBandList.list.count; - AssertFatal(num_available_supported_SULBands == 0, "cannot handle SUL bands!\n"); - } - FDDs->ul_tbw.scs = fDD_Info->uL_Transmission_Bandwidth.nRSCS; - FDDs->ul_tbw.nrb = nrb_lut[fDD_Info->uL_Transmission_Bandwidth.nRNRB]; - FDDs->dl_tbw.scs = fDD_Info->dL_Transmission_Bandwidth.nRSCS; - FDDs->dl_tbw.nrb = nrb_lut[fDD_Info->dL_Transmission_Bandwidth.nRNRB]; - } else if (servedCellInformation->nR_Mode_Info.present == F1AP_NR_Mode_Info_PR_tDD) { - req->cell_to_modify[i].info.mode = F1AP_MODE_TDD; - f1ap_tdd_info_t *TDDs = &req->cell_to_modify[i].info.tdd; - F1AP_TDD_Info_t *tDD_Info = servedCellInformation->nR_Mode_Info.choice.tDD; - TDDs->freqinfo.arfcn = tDD_Info->nRFreqInfo.nRARFCN; - AssertFatal(tDD_Info->nRFreqInfo.freqBandListNr.list.count == 1, "cannot handle more than one frequency band\n"); - for (int f = 0; f < tDD_Info->nRFreqInfo.freqBandListNr.list.count; f++) { - struct F1AP_FreqBandNrItem *FreqItem = tDD_Info->nRFreqInfo.freqBandListNr.list.array[f]; - TDDs->freqinfo.band = FreqItem->freqBandIndicatorNr; - int num_available_supported_SULBands = FreqItem->supportedSULBandList.list.count; - AssertFatal(num_available_supported_SULBands == 0, "cannot hanlde SUL bands!\n"); - } - TDDs->tbw.scs = tDD_Info->transmission_Bandwidth.nRSCS; - TDDs->tbw.nrb = nrb_lut[tDD_Info->transmission_Bandwidth.nRNRB]; - } else { - AssertFatal(false, "unknown NR Mode info %d\n", servedCellInformation->nR_Mode_Info.present); - } - - /* MeasurementConfig */ - if (servedCellInformation->measurementTimingConfiguration.size > 0) - req->cell_to_modify[i].info.measurement_timing_config = - cp_octet_string(&servedCellInformation->measurementTimingConfiguration, - &req->cell_to_modify[i].info.measurement_timing_config_len); - - /*gNB DU SYSTEM INFORMATION */ - struct F1AP_GNB_DU_System_Information *DUsi = served_cells_item->gNB_DU_System_Information; - if (DUsi != NULL) { - // System Information - req->cell_to_modify[i].sys_info = calloc(1, sizeof(*req->cell_to_modify[i].sys_info)); - AssertFatal(req->cell_to_modify[i].sys_info != NULL, "out of memory\n"); - f1ap_gnb_du_system_info_t *sys_info = req->cell_to_modify[i].sys_info; - /* mib */ - sys_info->mib = calloc(DUsi->mIB_message.size, sizeof(char)); - AssertFatal(req->cell_to_modify[i].sys_info->mib != NULL, "out of memory\n"); - memcpy(sys_info->mib, DUsi->mIB_message.buf, DUsi->mIB_message.size); - sys_info->mib_length = DUsi->mIB_message.size; - - /* sib1 */ - sys_info->sib1 = calloc(DUsi->sIB1_message.size, sizeof(char)); - AssertFatal(req->cell_to_modify[i].sys_info->sib1 != NULL, "out of memory\n"); - memcpy(sys_info->sib1, DUsi->sIB1_message.buf, DUsi->sIB1_message.size); - sys_info->sib1_length = DUsi->sIB1_message.size; - } - } - } else { - req->num_cells_to_modify = 0; - } - - /* 3GPP TS 38.473 Served Cells To Delete List */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_GNBDUConfigurationUpdateIEs_t, - ie, - container, - F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List, - false); - if (ie) { - req->num_cells_to_delete = ie->value.choice.Served_Cells_To_Delete_List.list.count; - LOG_D(F1AP, "req->num_cells_to_delete %d \n", req->num_cells_to_delete); - - for (i = 0; i < req->num_cells_to_delete; i++) { - F1AP_Served_Cells_To_Delete_Item_t *served_cells_item = - &((F1AP_Served_Cells_To_Delete_ItemIEs_t *)ie->value.choice.Served_Cells_To_Delete_List.list.array[i]) - ->value.choice.Served_Cells_To_Delete_Item; - /* - Old nRCGI */ - TBCD_TO_MCC_MNC(&(served_cells_item->oldNRCGI.pLMN_Identity), - req->cell_to_delete[i].plmn.mcc, - req->cell_to_delete[i].plmn.mnc, - req->cell_to_delete[i].plmn.mnc_digit_length); - // NR cellID - BIT_STRING_TO_NR_CELL_IDENTITY(&served_cells_item->oldNRCGI.nRCellIdentity, req->cell_to_delete[i].nr_cellid); - LOG_D(F1AP, - "[SCTP %d] Received nRCGI to delete: MCC %d, MNC %d, CELL_ID %llu\n", - assoc_id, - req->cell_to_delete[i].plmn.mcc, - req->cell_to_delete[i].plmn.mnc, - (long long unsigned int)req->cell_to_delete[i].nr_cellid); - } - } else { - req->num_cells_to_delete = 0; - } - - /* 3GPP TS 38.473 Cells Status List */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_GNBDUConfigurationUpdateIEs_t, ie, container, F1AP_ProtocolIE_ID_id_Cells_Status_List, false); - - /* 3GPP TS 38.473 Dedicated SI Delivery Needed UE List */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_GNBDUConfigurationUpdateIEs_t, - ie, - container, - F1AP_ProtocolIE_ID_id_Dedicated_SIDelivery_NeededUE_List, - false); - - /* 3GPP TS 38.473 gNB-DU ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_GNBDUConfigurationUpdateIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_ID, false); - if (ie != NULL) - asn_INTEGER2ulong(&ie->value.choice.GNB_DU_ID, req->gNB_DU_ID); - - /* 3GPP TS 38.473 gNB-DU TNL Association To Remove List */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_GNBDUConfigurationUpdateIEs_t, - ie, - container, - F1AP_ProtocolIE_ID_id_GNB_DU_TNL_Association_To_Remove_List, - false); - + f1ap_gnb_du_configuration_update_t *req = &F1AP_GNB_DU_CONFIGURATION_UPDATE(message_p); // RRC thread will free it + *req = msg; // copy F1 message to ITTI + free_f1ap_du_configuration_update(&msg); LOG_D(F1AP, "Sending F1AP_GNB_DU_CONFIGURATION_UPDATE ITTI message \n"); itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p); return 0; } -int CU_send_gNB_DU_CONFIGURATION_FAILURE(sctp_assoc_t assoc_id, - f1ap_gnb_du_configuration_update_failure_t *GNBDUConfigurationUpdateFailure) +int CU_send_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(sctp_assoc_t assoc_id, f1ap_gnb_du_configuration_update_acknowledge_t *msg) { - AssertFatal(1==0,"Not implemented yet\n"); -} - -int CU_send_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE( - sctp_assoc_t assoc_id, - f1ap_gnb_du_configuration_update_acknowledge_t *GNBDUConfigurationUpdateAcknowledge) -{ - F1AP_F1AP_PDU_t pdu = {}; uint8_t *buffer; uint32_t len; - - /* Create */ - /* 0. Message */ - - pdu.present = F1AP_F1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu.choice.successfulOutcome, succOut); - succOut->procedureCode = F1AP_ProcedureCode_id_gNBDUConfigurationUpdate; - succOut->criticality = F1AP_Criticality_reject; - succOut->value.present = F1AP_SuccessfulOutcome__value_PR_GNBDUConfigurationUpdateAcknowledge; - F1AP_GNBDUConfigurationUpdateAcknowledge_t *ack = &succOut->value.choice.GNBDUConfigurationUpdateAcknowledge; - - /* Mandatory */ - /* Transaction Id */ - asn1cSequenceAdd(ack->protocolIEs.list, F1AP_GNBDUConfigurationUpdateAcknowledgeIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_GNBDUConfigurationUpdateAcknowledgeIEs__value_PR_TransactionID; - ie1->value.choice.TransactionID = GNBDUConfigurationUpdateAcknowledge->transaction_id; - - /* Todo add optional fields */ - /* encode */ - - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { - LOG_E(F1AP, "Failed to encode F1 gNB-DU CONFIGURATION UPDATE\n"); + /* Encode F1 gNB-CU Configuration Update message */ + F1AP_F1AP_PDU_t *pdu = encode_f1ap_du_configuration_update_acknowledge(msg); + /* Encode F1AP PDU */ + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + LOG_E(F1AP, "Failed to encode F1 gNB-DU Configuration Update Acknowledge\n"); return -1; } - LOG_DUMPMSG(F1AP, LOG_DUMP_CHAR, buffer, len, "F1AP gNB-DU CONFIGURATION UPDATE : "); - ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } -/* - gNB-CU Configuration Update -*/ - -int CU_send_gNB_CU_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id, f1ap_gnb_cu_configuration_update_t *f1ap_gnb_cu_configuration_update) +/** + * @brief F1 gNB-CU Configuration Update message encoding and transfer + */ +int CU_send_gNB_CU_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id, f1ap_gnb_cu_configuration_update_t *msg) { - F1AP_F1AP_PDU_t pdu= {0}; + /* complete F1AP message */ + msg->transaction_id = F1AP_get_next_transaction_identifier(0, 0); // note: has to be done in the caller uint8_t *buffer; uint32_t len; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, initMsg); - initMsg->procedureCode = F1AP_ProcedureCode_id_gNBCUConfigurationUpdate; - initMsg->criticality = F1AP_Criticality_reject; - initMsg->value.present = F1AP_InitiatingMessage__value_PR_GNBCUConfigurationUpdate; - F1AP_GNBCUConfigurationUpdate_t *cfgUpdate = &pdu.choice.initiatingMessage->value.choice.GNBCUConfigurationUpdate; - /* mandatory */ - /* c1. Transaction ID (integer value) */ - asn1cSequenceAdd(cfgUpdate->protocolIEs.list, F1AP_GNBCUConfigurationUpdateIEs_t, ieC1); - ieC1->id = F1AP_ProtocolIE_ID_id_TransactionID; - ieC1->criticality = F1AP_Criticality_reject; - ieC1->value.present = F1AP_GNBCUConfigurationUpdateIEs__value_PR_TransactionID; - ieC1->value.choice.TransactionID = F1AP_get_next_transaction_identifier(0, 0); - - // mandatory - // c2. Cells_to_be_Activated_List - if (f1ap_gnb_cu_configuration_update->num_cells_to_activate > 0) { - asn1cSequenceAdd(cfgUpdate->protocolIEs.list, F1AP_GNBCUConfigurationUpdateIEs_t, ieC3); - ieC3->id = F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List; - ieC3->criticality = F1AP_Criticality_reject; - ieC3->value.present = F1AP_GNBCUConfigurationUpdateIEs__value_PR_Cells_to_be_Activated_List; - - for (int i=0; inum_cells_to_activate; i++) { - asn1cSequenceAdd(ieC3->value.choice.Cells_to_be_Activated_List.list,F1AP_Cells_to_be_Activated_List_ItemIEs_t, - cells_to_be_activated_ies); - cells_to_be_activated_ies->id = F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item; - cells_to_be_activated_ies->criticality = F1AP_Criticality_reject; - cells_to_be_activated_ies->value.present = F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item; - // 2.1 cells to be Activated list item - F1AP_Cells_to_be_Activated_List_Item_t *cells_to_be_activated_list_item= - &cells_to_be_activated_ies->value.choice.Cells_to_be_Activated_List_Item; - // - nRCGI - addnRCGI(cells_to_be_activated_list_item->nRCGI, f1ap_gnb_cu_configuration_update->cells_to_activate+i); - // optional - // -nRPCI - asn1cCalloc(cells_to_be_activated_list_item->nRPCI, tmp); - *tmp = f1ap_gnb_cu_configuration_update->cells_to_activate[i].nrpci; // int 0..1007 - // optional - // 3.1.2 gNB-CUSystem Information - F1AP_ProtocolExtensionContainer_10696P112_t *p = calloc(1,sizeof(*p)); - cells_to_be_activated_list_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *) p; - //F1AP_ProtocolExtensionContainer_154P112_t - asn1cSequenceAdd(p->list, F1AP_Cells_to_be_Activated_List_ItemExtIEs_t, cells_to_be_activated_itemExtIEs); - cells_to_be_activated_itemExtIEs->id = F1AP_ProtocolIE_ID_id_gNB_CUSystemInformation; - cells_to_be_activated_itemExtIEs->criticality = F1AP_Criticality_reject; - cells_to_be_activated_itemExtIEs->extensionValue.present = F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_GNB_CUSystemInformation; - - if (f1ap_gnb_cu_configuration_update->cells_to_activate[i].num_SI > 0) { - F1AP_GNB_CUSystemInformation_t *gNB_CUSystemInformation = - &cells_to_be_activated_itemExtIEs->extensionValue.choice.GNB_CUSystemInformation; - //LOG_I(F1AP, "%s() SI %d size %d: ", __func__, i, f1ap_setup_resp->SI_container_length[i][0]); - //for (int n = 0; n < f1ap_setup_resp->SI_container_length[i][0]; n++) - // printf("%02x ", f1ap_setup_resp->SI_container[i][0][n]); - //printf("\n"); - - // for (int sIBtype=2;sIBtype<33;sIBtype++) { //21 ? 33 ? - for (int sIBtype=2; sIBtype<21; sIBtype++) { - if (f1ap_gnb_cu_configuration_update->cells_to_activate[i].SI_container[sIBtype]!=NULL) { - AssertFatal(sIBtype < 6 || sIBtype == 9, "Illegal SI type %d\n",sIBtype); - asn1cSequenceAdd(gNB_CUSystemInformation->sibtypetobeupdatedlist.list, F1AP_SibtypetobeupdatedListItem_t, sib_item); - sib_item->sIBtype = sIBtype; - OCTET_STRING_fromBuf(&sib_item->sIBmessage, - (const char *)f1ap_gnb_cu_configuration_update->cells_to_activate[i].SI_container[sIBtype], - f1ap_gnb_cu_configuration_update->cells_to_activate[i].SI_container_length[sIBtype]); - LOG_D(F1AP, "f1ap_setup_resp->SI_container_length[%d][%d] = %d \n", i,sIBtype, - f1ap_gnb_cu_configuration_update->cells_to_activate[i].SI_container_length[sIBtype]); - } - } - } - } - } - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { - LOG_E(F1AP, "Failed to encode F1 gNB-CU CONFIGURATION UPDATE\n"); + /* Encode F1 gNB-CU Configuration Update message */ + F1AP_F1AP_PDU_t *pdu = encode_f1ap_cu_configuration_update(msg); + /* Free after encoding */ + free_f1ap_cu_configuration_update(msg); + /* Encode F1AP PDU */ + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + LOG_E(F1AP, "Failed to encode F1 gNB-CU Configuration Update\n"); return -1; } - LOG_DUMPMSG(F1AP, LOG_DUMP_CHAR, buffer, len, "F1AP gNB-CU CONFIGURATION UPDATE : "); - ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } -int CU_handle_gNB_CU_CONFIGURATION_UPDATE_FAILURE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) -{ - AssertFatal(1==0,"Not implemented yet\n"); -} - +/** + * @brief gNB CU Configuration Update Acknowledge decoding (9.2.1.11 of 3GPP TS 38.473) + * and handling by CU + */ int CU_handle_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - LOG_I(F1AP,"Cell Configuration ok (assoc_id %d)\n",assoc_id); - return(0); -} - -int CU_handle_gNB_DU_RESOURCE_COORDINATION_REQUEST(instance_t instance, - sctp_assoc_t assoc_id, - uint32_t stream, - F1AP_F1AP_PDU_t *pdu) -{ - AssertFatal(0, "Not implemented yet\n"); -} - -int CU_send_gNB_DU_RESOURCE_COORDINATION_RESPONSE(sctp_assoc_t assoc_id, - F1AP_GNBDUResourceCoordinationResponse_t *GNBDUResourceCoordinationResponse) { - AssertFatal(0, "Not implemented yet\n"); + DevAssert(pdu != NULL); + if (stream != 0) + LOG_W(F1AP, "[SCTP %d] Received gNB CU Configuration Update Acknowledge on stream != 0 (%d)\n", assoc_id, stream); + // Decode + f1ap_gnb_cu_configuration_update_acknowledge_t msg = {0}; + if (!decode_f1ap_cu_configuration_update_acknowledge(pdu, &msg)) { + LOG_E(F1AP, "Failed to decode gNB CU Configuration Update Acknowledge\n"); + return -1; + } + // Allocate ITTI message and send to RRC + MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE); + message_p->ittiMsgHeader.originInstance = assoc_id; + f1ap_gnb_cu_configuration_update_acknowledge_t *ack = &F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(message_p); + *ack = msg; // copy decoded message to ITTI, the RRC thread will free it + itti_send_msg_to_task(TASK_RRC_GNB, GNB_MODULE_ID_TO_INSTANCE(instance), message_p); + return 0; } diff --git a/openair2/F1AP/f1ap_cu_interface_management.h b/openair2/F1AP/f1ap_cu_interface_management.h index 11a45868e1..9d0bf4a391 100644 --- a/openair2/F1AP/f1ap_cu_interface_management.h +++ b/openair2/F1AP/f1ap_cu_interface_management.h @@ -36,17 +36,9 @@ /* * Reset */ -int CU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset); int CU_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); -int CU_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); int CU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack); -/* - * Error Indication - */ -int CU_handle_ERROR_INDICATION(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); -int CU_send_ERROR_INDICATION(sctp_assoc_t assoc_id, F1AP_ErrorIndication_t *ErrorIndication); - /* * F1 Setup */ @@ -61,9 +53,6 @@ int CU_send_F1_SETUP_FAILURE(sctp_assoc_t assoc_id, const f1ap_setup_failure_t * */ int CU_handle_gNB_DU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); -int CU_send_gNB_DU_CONFIGURATION_FAILURE(sctp_assoc_t assoc_id, - f1ap_gnb_du_configuration_update_failure_t *GNBDUConfigurationUpdateFailure); - int CU_send_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE( sctp_assoc_t assoc_id, f1ap_gnb_du_configuration_update_acknowledge_t *GNBDUConfigurationUpdateAcknowledge); @@ -72,25 +61,10 @@ int CU_send_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE( * gNB-CU Configuration Update */ int CU_send_gNB_CU_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id, f1ap_gnb_cu_configuration_update_t *f1ap_gnb_cu_configuration_update); -int CU_handle_gNB_CU_CONFIGURATION_UPDATE_FAILURE(instance_t instance, - sctp_assoc_t assoc_id, - uint32_t stream, - F1AP_F1AP_PDU_t *pdu); int CU_handle_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); -/* - * gNB-DU Resource Coordination - */ -int CU_handle_gNB_DU_RESOURCE_COORDINATION_REQUEST(instance_t instance, - sctp_assoc_t assoc_id, - uint32_t stream, - F1AP_F1AP_PDU_t *pdu); - -int CU_send_gNB_DU_RESOURCE_COORDINATION_RESPONSE(sctp_assoc_t assoc_id, - F1AP_GNBDUResourceCoordinationResponse_t *GNBDUResourceCoordinationResponse); - #endif /* F1AP_CU_INTERFACE_MANAGEMENT_H_ */ diff --git a/openair2/F1AP/f1ap_cu_rrc_message_transfer.c b/openair2/F1AP/f1ap_cu_rrc_message_transfer.c index 8ccca9f478..cf85961ff5 100644 --- a/openair2/F1AP/f1ap_cu_rrc_message_transfer.c +++ b/openair2/F1AP/f1ap_cu_rrc_message_transfer.c @@ -39,67 +39,25 @@ #include "openair3/UTILS/conversions.h" #include "LAYER2/nr_pdcp/nr_pdcp_oai_api.h" +#include "f1ap_rrc_message_transfer.h" + /* Initial UL RRC Message Transfer */ int CU_handle_INITIAL_UL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - LOG_D(F1AP, "CU_handle_INITIAL_UL_RRC_MESSAGE_TRANSFER\n"); - // decode the F1 message - // get the rrc message from the contauiner - // call func rrc_eNB_decode_ccch: <-- needs some update here - MessageDef *message_p; - F1AP_InitialULRRCMessageTransfer_t *container; - F1AP_InitialULRRCMessageTransferIEs_t *ie; - DevAssert(pdu != NULL); - - if (stream != 0) { - LOG_E(F1AP, "[SCTP %d] Received F1 on stream != 0 (%d)\n", - assoc_id, stream); + f1ap_initial_ul_rrc_message_t msg; + if (!decode_initial_ul_rrc_message_transfer(pdu, &msg)) { + LOG_E(F1AP, "cannot decode F1 initial UL RRC message Transfer\n"); return -1; } - container = &pdu->choice.initiatingMessage->value.choice.InitialULRRCMessageTransfer; - /* GNB_DU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - uint32_t du_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; - - /* NRCGI - * Fixme: process NRCGI - */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_NRCGI, true); - uint64_t nr_cellid; - BIT_STRING_TO_NR_CELL_IDENTITY(&ie->value.choice.NRCGI.nRCellIdentity,nr_cellid); - /* RNTI */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_C_RNTI, true); - rnti_t rnti = ie->value.choice.C_RNTI; - F1AP_InitialULRRCMessageTransferIEs_t *rrccont; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, rrccont, container, - F1AP_ProtocolIE_ID_id_RRCContainer, true); - AssertFatal(rrccont!=NULL,"RRCContainer is missing\n"); - - F1AP_InitialULRRCMessageTransferIEs_t *du2cu; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_InitialULRRCMessageTransferIEs_t, du2cu, container, - F1AP_ProtocolIE_ID_id_DUtoCURRCContainer, false); - // create an ITTI message and copy SDU - message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_INITIAL_UL_RRC_MESSAGE); + MessageDef *message_p = itti_alloc_new_message(TASK_CU_F1, 0, F1AP_INITIAL_UL_RRC_MESSAGE); message_p->ittiMsgHeader.originInstance = assoc_id; f1ap_initial_ul_rrc_message_t *ul_rrc = &F1AP_INITIAL_UL_RRC_MESSAGE(message_p); - ul_rrc->gNB_DU_ue_id = du_ue_id; - ul_rrc->nr_cellid = nr_cellid; // CU instance - ul_rrc->crnti = rnti; - ul_rrc->rrc_container_length = rrccont->value.choice.RRCContainer.size; - ul_rrc->rrc_container = malloc(ul_rrc->rrc_container_length); - memcpy(ul_rrc->rrc_container, rrccont->value.choice.RRCContainer.buf, ul_rrc->rrc_container_length); - AssertFatal(du2cu != NULL, "no masterCellGroup in initial UL RRC message\n"); - ul_rrc->du2cu_rrc_container_length = du2cu->value.choice.DUtoCURRCContainer.size; - ul_rrc->du2cu_rrc_container = malloc(ul_rrc->du2cu_rrc_container_length); - memcpy(ul_rrc->du2cu_rrc_container, du2cu->value.choice.DUtoCURRCContainer.buf, ul_rrc->du2cu_rrc_container_length); + *ul_rrc = msg; /* "move" message into ITTI, RRC thread will free it */ itti_send_msg_to_task(TASK_RRC_GNB, instance, message_p); return 0; @@ -108,105 +66,27 @@ int CU_handle_INITIAL_UL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t /* DL RRC Message Transfer. */ -int CU_send_DL_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, f1ap_dl_rrc_message_t *f1ap_dl_rrc) +int CU_send_DL_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, f1ap_dl_rrc_message_t *msg) { - LOG_D(F1AP, "CU send DL_RRC_MESSAGE_TRANSFER \n"); - F1AP_F1AP_PDU_t pdu= {0}; - F1AP_DLRRCMessageTransfer_t *out; - uint8_t *buffer=NULL; - uint32_t len=0; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_DLRRCMessageTransfer; - tmp->criticality = F1AP_Criticality_ignore; - tmp->value.present = F1AP_InitiatingMessage__value_PR_DLRRCMessageTransfer; - out = &tmp->value.choice.DLRRCMessageTransfer; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_GNB_CU_UE_F1AP_ID; - DevAssert(f1ap_dl_rrc->gNB_CU_ue_id != 0); - ie1->value.choice.GNB_CU_UE_F1AP_ID = f1ap_dl_rrc->gNB_CU_ue_id; - - /* mandatory */ - /* c2. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID; - DevAssert(f1ap_dl_rrc->gNB_DU_ue_id != 0); - ie2->value.choice.GNB_DU_UE_F1AP_ID = f1ap_dl_rrc->gNB_DU_ue_id; - - /* optional */ - /* c3. oldgNB_DU_UE_F1AP_ID */ - if (f1ap_dl_rrc->old_gNB_DU_ue_id != NULL) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID_1; - ie3->value.choice.GNB_DU_UE_F1AP_ID_1 = *f1ap_dl_rrc->old_gNB_DU_ue_id; - } - - /* mandatory */ - /* c4. SRBID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_SRBID; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_SRBID; - ie4->value.choice.SRBID = f1ap_dl_rrc->srb_id; - - /* optional */ - /* c5. ExecuteDuplication */ - if (f1ap_dl_rrc->execute_duplication) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_ExecuteDuplication; - ie5->criticality = F1AP_Criticality_ignore; - ie5->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_ExecuteDuplication; - ie5->value.choice.ExecuteDuplication = F1AP_ExecuteDuplication_true; - } - - // issue in here - /* mandatory */ - /* c6. RRCContainer */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie6); - ie6->id = F1AP_ProtocolIE_ID_id_RRCContainer; - ie6->criticality = F1AP_Criticality_reject; - ie6->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie6->value.choice.RRCContainer, - (const char *)f1ap_dl_rrc->rrc_container, f1ap_dl_rrc->rrc_container_length); - - /* optional */ - /* c7. RAT_FrequencyPriorityInformation */ - /* TODO */ - if (0) { - int endc=1; - asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie7); - ie7->id = F1AP_ProtocolIE_ID_id_RAT_FrequencyPriorityInformation; - ie7->criticality = F1AP_Criticality_reject; - ie7->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_RAT_FrequencyPriorityInformation; - - if (endc==1) { - ie7->value.choice.RAT_FrequencyPriorityInformation.present = F1AP_RAT_FrequencyPriorityInformation_PR_eNDC; - ie7->value.choice.RAT_FrequencyPriorityInformation.choice.eNDC = 123L; - } else { - ie7->value.choice.RAT_FrequencyPriorityInformation.present = F1AP_RAT_FrequencyPriorityInformation_PR_nGRAN; - ie7->value.choice.RAT_FrequencyPriorityInformation.choice.nGRAN = 11L; - } - - //ie->value.choice.RAT_FrequencyPriorityInformation.present = F1AP_RAT_FrequencyPriorityInformation_PR_rAT_FrequencySelectionPriority; - //ie->value.choice.RAT_FrequencyPriorityInformation.choice.rAT_FrequencySelectionPriority = 123L; - } - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { - LOG_E(F1AP, "Failed to encode F1 DL RRC MESSAGE TRANSFER \n"); + /* encode DL RRC Message Transfer */ + F1AP_F1AP_PDU_t *pdu = encode_dl_rrc_message_transfer(msg); + if (pdu == NULL) { + LOG_E(F1AP, "Failed to encode F1 DL RRC MESSAGE TRANSFER: can't send message!\n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return -1; } - + /* encode F1AP PDU */ + uint8_t *buffer = NULL; + uint32_t len = 0; + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { + LOG_E(F1AP, "Failed to encode F1 DL RRC MESSAGE TRANSFER \n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + return -1; + } + /* Free F1AP PDU */ + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + /* Send to DU */ + LOG_D(F1AP, "CU send DL_RRC_MESSAGE_TRANSFER \n"); f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } @@ -216,76 +96,67 @@ int CU_send_DL_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, f1ap_dl_rrc_message_t */ int CU_handle_UL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - LOG_D(F1AP, "CU_handle_UL_RRC_MESSAGE_TRANSFER \n"); - F1AP_ULRRCMessageTransfer_t *container; - F1AP_ULRRCMessageTransferIEs_t *ie; - uint64_t cu_ue_f1ap_id; - uint64_t du_ue_f1ap_id; - uint64_t srb_id; - DevAssert(pdu != NULL); - if (stream != 0) { LOG_E(F1AP, "[SCTP %d] Received F1 on stream != 0 (%d)\n", assoc_id, stream); return -1; } - container = &pdu->choice.initiatingMessage->value.choice.ULRRCMessageTransfer; - /* GNB_CU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_ULRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - cu_ue_f1ap_id = ie->value.choice.GNB_CU_UE_F1AP_ID; - /* GNB_DU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_ULRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - du_ue_f1ap_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + f1ap_ul_rrc_message_t msg = {0}; - if (!cu_exists_f1_ue_data(cu_ue_f1ap_id)) { - LOG_E(F1AP, "unknown CU UE ID %ld\n", cu_ue_f1ap_id); - return 1; + LOG_D(F1AP, "CU_handle_UL_RRC_MESSAGE_TRANSFER \n"); + if (!decode_ul_rrc_message_transfer(pdu, &msg)) { + LOG_E(F1AP, "cannot decode F1 UL RRC message Transfer\n"); + free_ul_rrc_message_transfer(&msg); + return -1; + } + + if (!cu_exists_f1_ue_data(msg.gNB_CU_ue_id)) { + LOG_E(F1AP, "unknown CU UE ID %d\n", msg.gNB_CU_ue_id); + free_ul_rrc_message_transfer(&msg); + return -1; } /* the RLC-PDCP does not transport the DU UE ID (yet), so we drop it here. * For the moment, let's hope this won't become relevant; to sleep in peace, * let's put an assert to check that it is the expected DU UE ID. */ - f1_ue_data_t ue_data = cu_get_f1_ue_data(cu_ue_f1ap_id); - if (ue_data.secondary_ue != du_ue_f1ap_id) { - LOG_E(F1AP, "unexpected DU UE ID %u received, expected it to be %lu\n", ue_data.secondary_ue, du_ue_f1ap_id); - return 1; + f1_ue_data_t ue_data = cu_get_f1_ue_data(msg.gNB_CU_ue_id); + if (ue_data.secondary_ue != msg.gNB_DU_ue_id) { + LOG_E(F1AP, "unexpected DU UE ID %u received, expected it to be %u\n", ue_data.secondary_ue, msg.gNB_DU_ue_id); + free_ul_rrc_message_transfer(&msg); + return -1; } - /* mandatory */ - /* SRBID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_ULRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SRBID, true); - srb_id = ie->value.choice.SRBID; - - if (srb_id < 1 ) - LOG_E(F1AP, "Unexpected UL RRC MESSAGE for srb_id %lu \n", srb_id); + if (msg.srb_id < 1) + LOG_E(F1AP, "Unexpected UL RRC MESSAGE for SRB %d \n", msg.srb_id); else - LOG_D(F1AP, "UL RRC MESSAGE for srb_id %lu in DCCH \n", srb_id); + LOG_D(F1AP, "UL RRC MESSAGE for SRB %d in DCCH \n", msg.srb_id); + + protocol_ctxt_t ctxt = { + .instance = instance, + .module_id = instance, + .enb_flag = 1, + .eNB_index = 0, + .rntiMaybeUEid = msg.gNB_CU_ue_id, + }; + + LOG_D(F1AP, + "[UE %lx] calling pdcp_data_ind for SRB %d with size %d (DCCH) \n", + ctxt.rntiMaybeUEid, + msg.srb_id, + msg.rrc_container_length); + uint8_t *mb = malloc16(msg.rrc_container_length); + memcpy(mb, msg.rrc_container, msg.rrc_container_length); - // issue in here - /* mandatory */ - /* RRC Container */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_ULRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_RRCContainer, true); - protocol_ctxt_t ctxt={0}; - ctxt.instance = instance; - ctxt.module_id = instance; - ctxt.rntiMaybeUEid = cu_ue_f1ap_id; - ctxt.enb_flag = 1; - ctxt.eNB_index = 0; - uint8_t *mb = malloc16(ie->value.choice.RRCContainer.size); - memcpy(mb, ie->value.choice.RRCContainer.buf, ie->value.choice.RRCContainer.size); - LOG_D(F1AP, "Calling pdcp_data_ind for UE RNTI %lx srb_id %lu with size %ld (DCCH) \n", ctxt.rntiMaybeUEid, srb_id, ie->value.choice.RRCContainer.size); nr_pdcp_data_ind(&ctxt, 1, // srb_flag 0, // embms_flag - srb_id, - ie->value.choice.RRCContainer.size, + msg.srb_id, + msg.rrc_container_length, mb, NULL, NULL); + /* Free UL RRC Message Transfer */ + free_ul_rrc_message_transfer(&msg); return 0; } diff --git a/openair2/F1AP/f1ap_cu_ue_context_management.c b/openair2/F1AP/f1ap_cu_ue_context_management.c index 8451fb7062..78e0ba02e9 100644 --- a/openair2/F1AP/f1ap_cu_ue_context_management.c +++ b/openair2/F1AP/f1ap_cu_ue_context_management.c @@ -44,7 +44,7 @@ static void f1ap_write_drb_qos_param(const f1ap_qos_flow_level_qos_parameters_t int type = drb_qos_in->qos_characteristics.qos_type; const f1ap_qos_characteristics_t *drb_qos_char_in = &drb_qos_in->qos_characteristics; - if (type == non_dynamic) { + if (type == NON_DYNAMIC) { asn1_qosparam->qoS_Characteristics.present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; asn1cCalloc(asn1_qosparam->qoS_Characteristics.choice.non_Dynamic_5QI, tmp); @@ -130,7 +130,7 @@ static void f1ap_write_flows_mapped(const f1ap_flows_mapped_to_drb_t *flows_mapp const f1ap_qos_characteristics_t *flow_qos_char_in = &flow_qos_params_in->qos_characteristics; int type = flow_qos_params_in->qos_characteristics.qos_type; - if (type == non_dynamic) { + if (type == NON_DYNAMIC) { QosParams->present = F1AP_QoS_Characteristics_PR_non_Dynamic_5QI; asn1cCalloc(QosParams->choice.non_Dynamic_5QI, tmp); @@ -483,12 +483,15 @@ int CU_send_UE_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_context_setu /* 12.1.4 rLCMode */ /* TODO use rlc_mode from f1ap_drb_to_be_setup */ switch (f1ap_ue_context_setup_req->drbs_to_be_setup[i].rlc_mode) { - case RLC_MODE_AM: + case F1AP_RLC_MODE_AM: drbs_toBeSetup_item->rLCMode = F1AP_RLCMode_rlc_am; break; - - default: + case F1AP_RLC_MODE_UM_BIDIR: drbs_toBeSetup_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; + break; + default: + AssertFatal(false, "modes other than AM/UM-Bidir not supported\n"); + break; } /* OPTIONAL */ @@ -1218,12 +1221,15 @@ int CU_send_UE_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, f1ap_ue_conte /* 12.1.4 rLCMode */ /* TODO use rlc_mode from f1ap_drb_to_be_setup */ switch (f1ap_ue_context_modification_req->drbs_to_be_setup[i].rlc_mode) { - case RLC_MODE_AM: + case F1AP_RLC_MODE_AM: drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_am; break; - - default: + case F1AP_RLC_MODE_UM_BIDIR: drbs_toBeSetupMod_item->rLCMode = F1AP_RLCMode_rlc_um_bidirectional; + break; + default: + AssertFatal(false, "modes other than AM/UM-Bidir not supported\n"); + break; } /* OPTIONAL */ diff --git a/openair2/F1AP/f1ap_du_interface_management.c b/openair2/F1AP/f1ap_du_interface_management.c index f560754bf3..85e963ea6a 100644 --- a/openair2/F1AP/f1ap_du_interface_management.c +++ b/openair2/F1AP/f1ap_du_interface_management.c @@ -34,22 +34,13 @@ #include "f1ap_encoder.h" #include "f1ap_itti_messaging.h" #include "f1ap_du_interface_management.h" +#include "lib/f1ap_interface_management.h" +#include "lib/f1ap_lib_common.h" #include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" #include "assertions.h" #include "GNB_APP/gnb_paramdef.h" -int to_NRNRB(int nrb) { - for (int i=0; inr_pci; // int 0..1007 - - /* - fiveGS_TAC */ - if (c->tac != NULL) { - uint32_t tac = htonl(*c->tac); - asn1cCalloc(scell_info.fiveGS_TAC, netOrder); - OCTET_STRING_fromBuf(netOrder, ((char *)&tac) + 1, 3); - } - - /* - Configured_EPS_TAC */ - if (0) { - scell_info.configured_EPS_TAC = (F1AP_Configured_EPS_TAC_t *)calloc(1, sizeof(F1AP_Configured_EPS_TAC_t)); - OCTET_STRING_fromBuf(scell_info.configured_EPS_TAC, "2", 2); - } - - /* servedPLMN information */ - asn1cSequenceAdd(scell_info.servedPLMNs.list, F1AP_ServedPLMNs_Item_t, servedPLMN_item); - MCC_MNC_TO_PLMNID(c->plmn.mcc, c->plmn.mnc, c->plmn.mnc_digit_length, &servedPLMN_item->pLMN_Identity); - - F1AP_NR_Mode_Info_t *nR_Mode_Info = &scell_info.nR_Mode_Info; - if (c->num_ssi > 0) { - F1AP_ProtocolExtensionContainer_10696P34_t *p = calloc(1, sizeof(*p)); - servedPLMN_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; - asn1cSequenceAdd(p->list, F1AP_ServedPLMNs_ItemExtIEs_t, served_plmns_itemExtIEs); - served_plmns_itemExtIEs->criticality = F1AP_Criticality_ignore; - served_plmns_itemExtIEs->id = F1AP_ProtocolIE_ID_id_TAISliceSupportList; - served_plmns_itemExtIEs->extensionValue.present = F1AP_ServedPLMNs_ItemExtIEs__extensionValue_PR_SliceSupportList; - F1AP_SliceSupportList_t *slice_support_list = &served_plmns_itemExtIEs->extensionValue.choice.SliceSupportList; - - for (int s = 0; s < c->num_ssi; s++) { - asn1cSequenceAdd(slice_support_list->list, F1AP_SliceSupportItem_t, slice); - const nssai_t *nssai = &c->nssai[s]; - INT8_TO_OCTET_STRING(nssai->sst, &slice->sNSSAI.sST); - if (nssai->sd != 0xffffff) { - asn1cCalloc(slice->sNSSAI.sD, tmp); - INT24_TO_OCTET_STRING(nssai->sd, tmp); - } - } - } - - if (c->mode == F1AP_MODE_FDD) { // FDD - const f1ap_fdd_info_t *fdd = &c->fdd; - nR_Mode_Info->present = F1AP_NR_Mode_Info_PR_fDD; - asn1cCalloc(nR_Mode_Info->choice.fDD, fDD_Info); - /* FDD.1.1 UL NRFreqInfo ARFCN */ - fDD_Info->uL_NRFreqInfo.nRARFCN = fdd->ul_freqinfo.arfcn; // Integer - - /* FDD.1.2 F1AP_SUL_Information */ - - /* FDD.1.3 freqBandListNr */ - int ul_band = 1; - for (int j = 0; j < ul_band; j++) { - asn1cSequenceAdd(fDD_Info->uL_NRFreqInfo.freqBandListNr.list, F1AP_FreqBandNrItem_t, nr_freqBandNrItem); - /* FDD.1.3.1 freqBandIndicatorNr*/ - nr_freqBandNrItem->freqBandIndicatorNr = fdd->ul_freqinfo.band; - - /* FDD.1.3.2 supportedSULBandList*/ - } - - /* FDD.2.1 DL NRFreqInfo ARFCN */ - fDD_Info->dL_NRFreqInfo.nRARFCN = fdd->dl_freqinfo.arfcn; // Integer - - /* FDD.2.2 F1AP_SUL_Information */ - - /* FDD.2.3 freqBandListNr */ - int dl_bands = 1; - for (int j = 0; j < dl_bands; j++) { - asn1cSequenceAdd(fDD_Info->dL_NRFreqInfo.freqBandListNr.list, F1AP_FreqBandNrItem_t, nr_freqBandNrItem); - /* FDD.2.3.1 freqBandIndicatorNr*/ - nr_freqBandNrItem->freqBandIndicatorNr = fdd->dl_freqinfo.band; - - /* FDD.2.3.2 supportedSULBandList*/ - } // for FDD : DL freq_Bands - - /* FDD.3 UL Transmission Bandwidth */ - fDD_Info->uL_Transmission_Bandwidth.nRSCS = fdd->ul_tbw.scs; - fDD_Info->uL_Transmission_Bandwidth.nRNRB = to_NRNRB(fdd->ul_tbw.nrb); - /* FDD.4 DL Transmission Bandwidth */ - fDD_Info->dL_Transmission_Bandwidth.nRSCS = fdd->dl_tbw.scs; - fDD_Info->dL_Transmission_Bandwidth.nRNRB = to_NRNRB(fdd->dl_tbw.nrb); - } else if (c->mode == F1AP_MODE_TDD) { - const f1ap_tdd_info_t *tdd = &c->tdd; - nR_Mode_Info->present = F1AP_NR_Mode_Info_PR_tDD; - asn1cCalloc(nR_Mode_Info->choice.tDD, tDD_Info); - /* TDD.1.1 nRFreqInfo ARFCN */ - tDD_Info->nRFreqInfo.nRARFCN = tdd->freqinfo.arfcn; - - /* TDD.1.2 F1AP_SUL_Information */ - - /* TDD.1.3 freqBandListNr */ - int bands = 1; - for (int j = 0; j < bands; j++) { - asn1cSequenceAdd(tDD_Info->nRFreqInfo.freqBandListNr.list, F1AP_FreqBandNrItem_t, nr_freqBandNrItem); - /* TDD.1.3.1 freqBandIndicatorNr*/ - nr_freqBandNrItem->freqBandIndicatorNr = tdd->freqinfo.band; - /* TDD.1.3.2 supportedSULBandList*/ - } - - /* TDD.2 transmission_Bandwidth */ - tDD_Info->transmission_Bandwidth.nRSCS = tdd->tbw.scs; - tDD_Info->transmission_Bandwidth.nRNRB = to_NRNRB(tdd->tbw.nrb); - } else { - AssertFatal(false, "unknown mode %d\n", c->mode); - } - - /* - measurementTimingConfiguration */ - OCTET_STRING_fromBuf(&scell_info.measurementTimingConfiguration, - (const char *)c->measurement_timing_config, - c->measurement_timing_config_len); - - return scell_info; -} - -static F1AP_GNB_DU_System_Information_t *encode_system_info(const f1ap_gnb_du_system_info_t *sys_info) -{ - if (sys_info == NULL) - return NULL; /* optional: can be NULL */ - - F1AP_GNB_DU_System_Information_t *enc_sys_info = calloc(1, sizeof(*enc_sys_info)); - AssertFatal(enc_sys_info != NULL, "out of memory\n"); - - AssertFatal(sys_info->mib != NULL, "MIB must be present in DU sys info\n"); - OCTET_STRING_fromBuf(&enc_sys_info->mIB_message, (const char *)sys_info->mib, sys_info->mib_length); - - AssertFatal(sys_info->sib1 != NULL, "SIB1 must be present in DU sys info\n"); - OCTET_STRING_fromBuf(&enc_sys_info->sIB1_message, (const char *)sys_info->sib1, sys_info->sib1_length); - - return enc_sys_info; -} - -// SETUP REQUEST +/** + * @brief F1AP Setup Request + */ int DU_send_F1_SETUP_REQUEST(sctp_assoc_t assoc_id, const f1ap_setup_req_t *setup_req) { LOG_D(F1AP, "DU_send_F1_SETUP_REQUEST\n"); - - F1AP_F1AP_PDU_t pdu= {0}; + F1AP_F1AP_PDU_t *pdu = encode_f1ap_setup_request(setup_req); uint8_t *buffer; uint32_t len; - /* Create */ - /* 0. pdu Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, initMsg); - initMsg->procedureCode = F1AP_ProcedureCode_id_F1Setup; - initMsg->criticality = F1AP_Criticality_reject; - initMsg->value.present = F1AP_InitiatingMessage__value_PR_F1SetupRequest; - F1AP_F1SetupRequest_t *f1Setup = &initMsg->value.choice.F1SetupRequest; - /* mandatory */ - /* c1. Transaction ID (integer value) */ - asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ieC1); - ieC1->id = F1AP_ProtocolIE_ID_id_TransactionID; - ieC1->criticality = F1AP_Criticality_reject; - ieC1->value.present = F1AP_F1SetupRequestIEs__value_PR_TransactionID; - ieC1->value.choice.TransactionID = F1AP_get_next_transaction_identifier(0, 0); - /* mandatory */ - /* c2. GNB_DU_ID (integer value) */ - asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ieC2); - ieC2->id = F1AP_ProtocolIE_ID_id_gNB_DU_ID; - ieC2->criticality = F1AP_Criticality_reject; - ieC2->value.present = F1AP_F1SetupRequestIEs__value_PR_GNB_DU_ID; - asn_int642INTEGER(&ieC2->value.choice.GNB_DU_ID, setup_req->gNB_DU_id); - - /* optional */ - /* c3. GNB_DU_Name */ - if (setup_req->gNB_DU_name != NULL) { - asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ieC3); - ieC3->id = F1AP_ProtocolIE_ID_id_gNB_DU_Name; - ieC3->criticality = F1AP_Criticality_ignore; - ieC3->value.present = F1AP_F1SetupRequestIEs__value_PR_GNB_DU_Name; - char *gNB_DU_name=setup_req->gNB_DU_name; - OCTET_STRING_fromBuf(&ieC3->value.choice.GNB_DU_Name, gNB_DU_name, strlen(gNB_DU_name)); - } - - /* mandatory */ - /* c4. served cells list */ - asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ieCells); - ieCells->id = F1AP_ProtocolIE_ID_id_gNB_DU_Served_Cells_List; - ieCells->criticality = F1AP_Criticality_reject; - ieCells->value.present = F1AP_F1SetupRequestIEs__value_PR_GNB_DU_Served_Cells_List; - int num_cells_available = setup_req->num_cells_available; - LOG_D(F1AP, "num_cells_available = %d \n", num_cells_available); - - for (int i=0; icell[i].info; - const f1ap_gnb_du_system_info_t *sys_info = setup_req->cell[i].sys_info; - asn1cSequenceAdd(ieCells->value.choice.GNB_DU_Served_Cells_List.list, - F1AP_GNB_DU_Served_Cells_ItemIEs_t, duServedCell); - duServedCell->id = F1AP_ProtocolIE_ID_id_GNB_DU_Served_Cells_Item; - duServedCell->criticality = F1AP_Criticality_reject; - duServedCell->value.present = F1AP_GNB_DU_Served_Cells_ItemIEs__value_PR_GNB_DU_Served_Cells_Item; - F1AP_GNB_DU_Served_Cells_Item_t *scell_item = &duServedCell->value.choice.GNB_DU_Served_Cells_Item; - scell_item->served_Cell_Information = encode_served_cell_info(cell); - scell_item->gNB_DU_System_Information = encode_system_info(sys_info); - } - - /* mandatory */ - /* c5. RRC VERSION */ - asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_F1SetupRequestIEs__value_PR_RRC_Version; - // RRC Version: "This IE is not used in this release." - // we put one bit for each byte in rrc_ver that is != 0 - uint8_t bits = 0; - for (int i = 0; i < 3; ++i) - bits |= (setup_req->rrc_ver[i] != 0) << i; - BIT_STRING_t *bs = &ie2->value.choice.RRC_Version.latest_RRC_Version; - bs->buf = calloc(1, sizeof(char)); - AssertFatal(bs->buf != NULL, "out of memory\n"); - bs->buf[0] = bits; - bs->size = 1; - bs->bits_unused = 5; - - F1AP_ProtocolExtensionContainer_10696P228_t *p = calloc(1, sizeof(F1AP_ProtocolExtensionContainer_10696P228_t)); - asn1cSequenceAdd(p->list, F1AP_RRC_Version_ExtIEs_t, rrcv_ext); - rrcv_ext->id = F1AP_ProtocolIE_ID_id_latest_RRC_Version_Enhanced; - rrcv_ext->criticality = F1AP_Criticality_ignore; - rrcv_ext->extensionValue.present = F1AP_RRC_Version_ExtIEs__extensionValue_PR_OCTET_STRING_SIZE_3_; - OCTET_STRING_t *os = &rrcv_ext->extensionValue.choice.OCTET_STRING_SIZE_3_; - os->size = 3; - os->buf = malloc(3 * sizeof(*os->buf)); - AssertFatal(os->buf != NULL, "out of memory\n"); - for (int i = 0; i < 3; ++i) - os->buf[i] = setup_req->rrc_ver[i]; - ie2->value.choice.RRC_Version.iE_Extensions = (struct F1AP_ProtocolExtensionContainer*)p; - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 setup request\n"); + /* free PDU */ + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return -1; } - - ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu); + /* free PDU */ + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + /* Send to ITTI */ f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } @@ -432,475 +177,94 @@ int DU_send_F1_SETUP_REQUEST(sctp_assoc_t assoc_id, const f1ap_setup_req_t *setu int DU_handle_F1_SETUP_RESPONSE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { LOG_D(F1AP, "DU_handle_F1_SETUP_RESPONSE\n"); - AssertFatal(pdu->present == F1AP_F1AP_PDU_PR_successfulOutcome, - "pdu->present != F1AP_F1AP_PDU_PR_successfulOutcome\n"); - AssertFatal(pdu->choice.successfulOutcome->procedureCode == F1AP_ProcedureCode_id_F1Setup, - "pdu->choice.successfulOutcome->procedureCode != F1AP_ProcedureCode_id_F1Setup\n"); - AssertFatal(pdu->choice.successfulOutcome->criticality == F1AP_Criticality_reject, - "pdu->choice.successfulOutcome->criticality != F1AP_Criticality_reject\n"); - AssertFatal(pdu->choice.successfulOutcome->value.present == F1AP_SuccessfulOutcome__value_PR_F1SetupResponse, - "pdu->choice.successfulOutcome->value.present != F1AP_SuccessfulOutcome__value_PR_F1SetupResponse\n"); - F1AP_F1SetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.F1SetupResponse; - F1AP_F1SetupResponseIEs_t *ie; - int TransactionId = -1; - int num_cells_to_activate = 0; + /* Decode */ f1ap_setup_resp_t resp = {0}; - - for (int i=0; i < in->protocolIEs.list.count; i++) { - ie = in->protocolIEs.list.array[i]; - - switch (ie->id) { - case F1AP_ProtocolIE_ID_id_TransactionID: - AssertFatal(ie->criticality == F1AP_Criticality_reject, - "ie->criticality != F1AP_Criticality_reject\n"); - AssertFatal(ie->value.present == F1AP_F1SetupResponseIEs__value_PR_TransactionID, - "ie->value.present != F1AP_F1SetupResponseIEs__value_PR_TransactionID\n"); - TransactionId=ie->value.choice.TransactionID; - LOG_D(F1AP, "F1AP: F1Setup-Resp: TransactionId %d\n", - TransactionId); - break; - - case F1AP_ProtocolIE_ID_id_gNB_CU_Name: - AssertFatal(ie->criticality == F1AP_Criticality_ignore, - "ie->criticality != F1AP_Criticality_ignore\n"); - AssertFatal(ie->value.present == F1AP_F1SetupResponseIEs__value_PR_GNB_CU_Name, - "ie->value.present != F1AP_F1SetupResponseIEs__value_PR_GNB_CU_Name\n"); - resp.gNB_CU_name = malloc(ie->value.choice.GNB_CU_Name.size+1); - memcpy(resp.gNB_CU_name, ie->value.choice.GNB_CU_Name.buf, ie->value.choice.GNB_CU_Name.size); - resp.gNB_CU_name[ie->value.choice.GNB_CU_Name.size] = '\0'; - LOG_D(F1AP, "F1AP: F1Setup-Resp: gNB_CU_name %s\n", resp.gNB_CU_name); - break; - - case F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version: - AssertFatal(ie->criticality == F1AP_Criticality_reject, - "ie->criticality != F1AP_Criticality_reject\n"); - AssertFatal(ie->value.present == F1AP_F1SetupResponseIEs__value_PR_RRC_Version, - "ie->value.present != F1AP_F1SetupResponseIEs__value_PR_RRC_Version\n"); - // RRC Version: "This IE is not used in this release." - if(ie->value.choice.RRC_Version.iE_Extensions) { - F1AP_ProtocolExtensionContainer_10696P228_t *ext = - (F1AP_ProtocolExtensionContainer_10696P228_t *)ie->value.choice.RRC_Version.iE_Extensions; - if(ext->list.count > 0){ - F1AP_RRC_Version_ExtIEs_t *rrcext = ext->list.array[0]; - OCTET_STRING_t *os = &rrcext->extensionValue.choice.OCTET_STRING_SIZE_3_; - for (int i = 0; i < 3; i++) - resp.rrc_ver[i] = os->buf[i]; - } - } - break; - - case F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List: { - AssertFatal(ie->criticality == F1AP_Criticality_reject, - "ie->criticality != F1AP_Criticality_reject\n"); - AssertFatal(ie->value.present == F1AP_F1SetupResponseIEs__value_PR_Cells_to_be_Activated_List, - "ie->value.present != F1AP_F1SetupResponseIEs__value_PR_Cells_to_be_Activated_List\n"); - num_cells_to_activate = ie->value.choice.Cells_to_be_Activated_List.list.count; - LOG_D(F1AP, "F1AP: Activating %d cells\n",num_cells_to_activate); - - for (int i=0; ivalue.choice.Cells_to_be_Activated_List.list.array[i]; - AssertFatal(cells_to_be_activated_list_item_ies->id == F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item, - "cells_to_be_activated_list_item_ies->id != F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item"); - AssertFatal(cells_to_be_activated_list_item_ies->criticality == F1AP_Criticality_reject, - "cells_to_be_activated_list_item_ies->criticality == F1AP_Criticality_reject"); - AssertFatal(cells_to_be_activated_list_item_ies->value.present == F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item, - "cells_to_be_activated_list_item_ies->value.present == F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item"); - F1AP_Cells_to_be_Activated_List_Item_t *cell = - &cells_to_be_activated_list_item_ies->value.choice.Cells_to_be_Activated_List_Item; - TBCD_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, - resp.cells_to_activate[i].plmn.mcc, - resp.cells_to_activate[i].plmn.mnc, - resp.cells_to_activate[i].plmn.mnc_digit_length); - LOG_D(F1AP, "nr_cellId : %x %x %x %x %x\n", - cell->nRCGI.nRCellIdentity.buf[0], - cell->nRCGI.nRCellIdentity.buf[1], - cell->nRCGI.nRCellIdentity.buf[2], - cell->nRCGI.nRCellIdentity.buf[3], - cell->nRCGI.nRCellIdentity.buf[4]); - BIT_STRING_TO_NR_CELL_IDENTITY(&cell->nRCGI.nRCellIdentity, resp.cells_to_activate[i].nr_cellid); - if (cell->nRPCI != NULL) - resp.cells_to_activate[i].nrpci = *cell->nRPCI; - F1AP_ProtocolExtensionContainer_10696P112_t *ext = (F1AP_ProtocolExtensionContainer_10696P112_t *)cell->iE_Extensions; - - if (ext==NULL) - continue; - - for (int cnt=0; cntlist.count; cnt++) { - F1AP_Cells_to_be_Activated_List_ItemExtIEs_t *cells_to_be_activated_list_itemExtIEs=(F1AP_Cells_to_be_Activated_List_ItemExtIEs_t *)ext->list.array[cnt]; - - switch (cells_to_be_activated_list_itemExtIEs->id) { - /* - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_NOTHING: - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_GNB_CUSystemInformation, - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_AvailablePLMNList, - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_ExtendedAvailablePLMN_List, - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_IAB_Info_IAB_donor_CU, - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_AvailableSNPN_ID_List - */ - case F1AP_ProtocolIE_ID_id_gNB_CUSystemInformation: { - resp.cells_to_activate[i].nrpci = (cell->nRPCI != NULL) ? *cell->nRPCI : 0; - F1AP_GNB_CUSystemInformation_t *gNB_CUSystemInformation = (F1AP_GNB_CUSystemInformation_t *)&cells_to_be_activated_list_itemExtIEs->extensionValue.choice.GNB_CUSystemInformation; - resp.cells_to_activate[i].num_SI = gNB_CUSystemInformation->sibtypetobeupdatedlist.list.count; - AssertFatal(ext->list.count==1,"At least one SI message should be there, and only 1 for now!\n"); - LOG_D(F1AP, - "F1AP: Cell %d MCC %d MNC %d NRCellid %lx num_si %d\n", - i, - resp.cells_to_activate[i].plmn.mcc, - resp.cells_to_activate[i].plmn.mnc, - resp.cells_to_activate[i].nr_cellid, - resp.cells_to_activate[i].num_SI); - - for (int si = 0; si < gNB_CUSystemInformation->sibtypetobeupdatedlist.list.count; si++) { - F1AP_SibtypetobeupdatedListItem_t *sib_item = gNB_CUSystemInformation->sibtypetobeupdatedlist.list.array[si]; - size_t size = sib_item->sIBmessage.size; - resp.cells_to_activate[i].SI_container_length[si] = size; - LOG_D(F1AP, "F1AP: SI_container_length[%d][%ld] %ld bytes\n", i, sib_item->sIBtype, size); - resp.cells_to_activate[i].SI_container[si] = malloc(resp.cells_to_activate[i].SI_container_length[si]); - memcpy(resp.cells_to_activate[i].SI_container[si], sib_item->sIBmessage.buf, size); - resp.cells_to_activate[i].SI_type[si]=sib_item->sIBtype; - } - - break; - } - - case F1AP_ProtocolIE_ID_id_AvailablePLMNList: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id_AvailablePLMNList not supported yet\n"); - break; - - case F1AP_ProtocolIE_ID_id_ExtendedAvailablePLMN_List: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id_AvailablePLMNList not supported yet\n"); - break; - - case F1AP_ProtocolIE_ID_id_IAB_Info_IAB_donor_CU: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id_AvailablePLMNList not supported yet\n"); - break; - - case F1AP_ProtocolIE_ID_id_AvailableSNPN_ID_List: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id_AvailablePLMNList not supported yet\n"); - break; - - default: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id %d unknown\n",(int)cells_to_be_activated_list_itemExtIEs->id); - break; - } - } // for (cnt=... - } // for (cells_to_activate... - - break; - } // case F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List - - default: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id %d unknown\n", (int)ie->id); - break; - } // switch ie - } // for IE - - AssertFatal(TransactionId!=-1,"TransactionId was not sent\n"); - LOG_D(F1AP,"F1AP: num_cells_to_activate %d\n",num_cells_to_activate); - resp.num_cells_to_activate = num_cells_to_activate; - - // tmp - for (int i=0; ichoice.unsuccessfulOutcome->value.choice.F1SetupFailure; - /* Transaction ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupFailureIEs_t, ie, out, F1AP_ProtocolIE_ID_id_TransactionID, true); - /* Cause */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupFailureIEs_t, ie, out, - F1AP_ProtocolIE_ID_id_Cause, true); - - if(0) { - /* TimeToWait */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_F1SetupFailureIEs_t, ie, out, - F1AP_ProtocolIE_ID_id_TimeToWait, true); + f1ap_setup_failure_t fail; + if (!decode_f1ap_setup_failure(pdu, &fail)) { + LOG_E(F1AP, "Failed to decode F1AP Setup Failure\n"); + return -1; } - f1_setup_failure(&fail); return 0; } -/* - gNB-DU Configuration Update -*/ - -int DU_send_gNB_DU_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id, const f1ap_gnb_du_configuration_update_t *upd) +/** + * @brief F1 gNB-DU Configuration Update: encoding and ITTI transmission + */ +int DU_send_gNB_DU_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id, f1ap_gnb_du_configuration_update_t *msg) { - F1AP_F1AP_PDU_t pdu= {0}; uint8_t *buffer=NULL; uint32_t len=0; - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, initMsg); - initMsg->procedureCode = F1AP_ProcedureCode_id_gNBDUConfigurationUpdate; - initMsg->criticality = F1AP_Criticality_reject; - initMsg->value.present = F1AP_InitiatingMessage__value_PR_GNBDUConfigurationUpdate; - F1AP_GNBDUConfigurationUpdate_t *out = &initMsg->value.choice.GNBDUConfigurationUpdate; - - /* mandatory */ - /* c1. Transaction ID (integer value) */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_TransactionID; - ie1->value.choice.TransactionID = upd->transaction_id; - - /* mandatory */ - /* c2. Served_Cells_To_Add */ - if (upd->num_cells_to_add > 0) { - AssertFatal(false, "code for adding cells not tested\n"); - asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Add_List; - - for (int j = 0; j < upd->num_cells_to_add; j++) { - const f1ap_served_cell_info_t *cell = &upd->cell_to_add[j].info; - const f1ap_gnb_du_system_info_t *sys_info = upd->cell_to_add[j].sys_info; - asn1cSequenceAdd(ie2->value.choice.Served_Cells_To_Add_List.list, - F1AP_Served_Cells_To_Add_ItemIEs_t, - served_cells_to_add_item_ies); - served_cells_to_add_item_ies->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_Item; - served_cells_to_add_item_ies->criticality = F1AP_Criticality_reject; - served_cells_to_add_item_ies->value.present = F1AP_Served_Cells_To_Add_ItemIEs__value_PR_Served_Cells_To_Add_Item; - F1AP_Served_Cells_To_Add_Item_t *served_cells_to_add_item = - &served_cells_to_add_item_ies->value.choice.Served_Cells_To_Add_Item; - served_cells_to_add_item->served_Cell_Information = encode_served_cell_info(cell); - served_cells_to_add_item->gNB_DU_System_Information = encode_system_info(sys_info); - } - } - - /* mandatory */ - /* c3. Served_Cells_To_Modify */ - if (upd->num_cells_to_modify > 0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Modify_List; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Modify_List; - for (int i = 0; i < upd->num_cells_to_modify; i++) { - const f1ap_served_cell_info_t *cell = &upd->cell_to_modify[i].info; - const f1ap_gnb_du_system_info_t *sys_info = upd->cell_to_modify[i].sys_info; - asn1cSequenceAdd(ie3->value.choice.Served_Cells_To_Modify_List.list, - F1AP_Served_Cells_To_Modify_ItemIEs_t, - served_cells_to_modify_item_ies); - served_cells_to_modify_item_ies->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Modify_Item; - served_cells_to_modify_item_ies->criticality = F1AP_Criticality_reject; - served_cells_to_modify_item_ies->value.present = F1AP_Served_Cells_To_Modify_ItemIEs__value_PR_Served_Cells_To_Modify_Item; - F1AP_Served_Cells_To_Modify_Item_t *served_cells_to_modify_item = - &served_cells_to_modify_item_ies->value.choice.Served_Cells_To_Modify_Item; - - F1AP_NRCGI_t *oldNRCGI = &served_cells_to_modify_item->oldNRCGI; - const f1ap_plmn_t *old_plmn = &upd->cell_to_modify[i].old_plmn; - MCC_MNC_TO_PLMNID(old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length, &oldNRCGI->pLMN_Identity); - NR_CELL_ID_TO_BIT_STRING(upd->cell_to_modify[i].old_nr_cellid, &oldNRCGI->nRCellIdentity); - - served_cells_to_modify_item->served_Cell_Information = encode_served_cell_info(cell); - served_cells_to_modify_item->gNB_DU_System_Information = encode_system_info(sys_info); - } - } - - /* mandatory */ - /* c4. Served_Cells_To_Delete */ - if (upd->num_cells_to_delete > 0) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Delete_List; - AssertFatal(upd->num_cells_to_delete == 0, "code for deleting cells not tested\n"); - for (int i = 0; i < upd->num_cells_to_delete; i++) { - asn1cSequenceAdd(ie4->value.choice.Served_Cells_To_Delete_List.list, - F1AP_Served_Cells_To_Delete_ItemIEs_t, - served_cells_to_delete_item_ies); - served_cells_to_delete_item_ies->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_Item; - served_cells_to_delete_item_ies->criticality = F1AP_Criticality_reject; - served_cells_to_delete_item_ies->value.present = F1AP_Served_Cells_To_Delete_ItemIEs__value_PR_Served_Cells_To_Delete_Item; - F1AP_Served_Cells_To_Delete_Item_t *served_cells_to_delete_item = - &served_cells_to_delete_item_ies->value.choice.Served_Cells_To_Delete_Item; - addnRCGI(served_cells_to_delete_item->oldNRCGI, &upd->cell_to_delete[i]); - } - } - - AssertFatal(upd->gNB_DU_ID == 0, "encoding of gNB-DU Id not handled yet\n"); - - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { + /* encode F1AP message */ + F1AP_F1AP_PDU_t *pdu = encode_f1ap_du_configuration_update(msg); + /* free anfter encoding */ + free_f1ap_du_configuration_update(msg); + /* encode F1AP pdu */ + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { LOG_E(F1AP, "Failed to encode F1 gNB-DU CONFIGURATION UPDATE\n"); return -1; } - - ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu); + /* transfer the message */ + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } -int DU_handle_gNB_DU_CONFIGURATION_FAILURE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) +/** + * @brief F1 gNB-CU Configuration Update decoding and message transfer + */ +int DU_handle_gNB_CU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - AssertFatal(1==0,"Not implemented yet\n"); + LOG_D(F1AP, "DU_handle_gNB_CU_CONFIGURATION_UPDATE\n"); + f1ap_gnb_cu_configuration_update_t in = {0}; + if (!decode_f1ap_cu_configuration_update(pdu, &in)) { + LOG_E(F1AP, "Failed to decode F1AP Setup Failure\n"); + free_f1ap_cu_configuration_update(&in); + return -1; + } + MessageDef *msg_p = itti_alloc_new_message (TASK_DU_F1, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE); + f1ap_gnb_cu_configuration_update_t *msg = &F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p); // RRC thread will free it + *msg = in; // copy F1 message to ITTI + LOG_D(F1AP, "Sending F1AP_GNB_CU_CONFIGURATION_UPDATE ITTI message \n"); + itti_send_msg_to_task(TASK_GNB_APP, GNB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); + return 0; } +/** + * @brief F1 gNB-DU Configuration Update Acknowledge decoding and message transfer + */ int DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - AssertFatal(1==0,"Not implemented yet\n"); -} - -int DU_handle_gNB_CU_CONFIGURATION_UPDATE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) -{ - LOG_D(F1AP, "DU_handle_gNB_CU_CONFIGURATION_UPDATE\n"); - AssertFatal(pdu->present == F1AP_F1AP_PDU_PR_initiatingMessage, - "pdu->present != F1AP_F1AP_PDU_PR_initiatingMessage\n"); - AssertFatal(pdu->choice.initiatingMessage->procedureCode == F1AP_ProcedureCode_id_gNBCUConfigurationUpdate, - "pdu->choice.initiatingMessage->procedureCode != F1AP_ProcedureCode_id_gNBCUConfigurationUpdate\n"); - AssertFatal(pdu->choice.initiatingMessage->criticality == F1AP_Criticality_reject, - "pdu->choice.initiatingMessage->criticality != F1AP_Criticality_reject\n"); - AssertFatal(pdu->choice.initiatingMessage->value.present == F1AP_InitiatingMessage__value_PR_GNBCUConfigurationUpdate, - "pdu->choice.initiatingMessage->value.present != F1AP_InitiatingMessage__value_PR_GNBCUConfigurationUpdate\n"); - F1AP_GNBCUConfigurationUpdate_t *in = &pdu->choice.initiatingMessage->value.choice.GNBCUConfigurationUpdate; - F1AP_GNBCUConfigurationUpdateIEs_t *ie; - int TransactionId = -1; - int num_cells_to_activate = 0; - F1AP_Cells_to_be_Activated_List_Item_t *cell; - MessageDef *msg_p = itti_alloc_new_message (TASK_DU_F1, 0, F1AP_GNB_CU_CONFIGURATION_UPDATE); - LOG_D(F1AP, "F1AP: gNB_CU_Configuration_Update: protocolIEs.list.count %d\n", - in->protocolIEs.list.count); - - for (int i=0; i < in->protocolIEs.list.count; i++) { - ie = in->protocolIEs.list.array[i]; - - switch (ie->id) { - case F1AP_ProtocolIE_ID_id_TransactionID: - AssertFatal(ie->criticality == F1AP_Criticality_reject, - "ie->criticality != F1AP_Criticality_reject\n"); - AssertFatal(ie->value.present == F1AP_GNBCUConfigurationUpdateIEs__value_PR_TransactionID, - "ie->value.present != F1AP_GNBCUConfigurationUpdateIEs__value_PR_TransactionID\n"); - TransactionId=ie->value.choice.TransactionID; - LOG_D(F1AP, "F1AP: GNB-CU-ConfigurationUpdate: TransactionId %d\n", - TransactionId); - break; - - case F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List: { - AssertFatal(ie->criticality == F1AP_Criticality_reject, - "ie->criticality != F1AP_Criticality_reject\n"); - AssertFatal(ie->value.present == F1AP_GNBCUConfigurationUpdateIEs__value_PR_Cells_to_be_Activated_List, - "ie->value.present != F1AP_GNBCUConfigurationUpdateIEs__value_PR_Cells_to_be_Activated_List\n"); - num_cells_to_activate = ie->value.choice.Cells_to_be_Activated_List.list.count; - LOG_D(F1AP, "F1AP: Activating %d cells\n",num_cells_to_activate); - - for (int i=0; ivalue.choice.Cells_to_be_Activated_List.list.array[i]; - AssertFatal(cells_to_be_activated_list_item_ies->id == F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item, - "cells_to_be_activated_list_item_ies->id != F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item"); - AssertFatal(cells_to_be_activated_list_item_ies->criticality == F1AP_Criticality_reject, - "cells_to_be_activated_list_item_ies->criticality == F1AP_Criticality_reject"); - AssertFatal(cells_to_be_activated_list_item_ies->value.present == F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item, - "cells_to_be_activated_list_item_ies->value.present == F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item"); - cell = &cells_to_be_activated_list_item_ies->value.choice.Cells_to_be_Activated_List_Item; - TBCD_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, - F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).cells_to_activate[i].plmn.mcc, - F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).cells_to_activate[i].plmn.mnc, - F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).cells_to_activate[i].plmn.mnc_digit_length); - LOG_D(F1AP, "nr_cellId : %x %x %x %x %x\n", - cell->nRCGI.nRCellIdentity.buf[0], - cell->nRCGI.nRCellIdentity.buf[1], - cell->nRCGI.nRCellIdentity.buf[2], - cell->nRCGI.nRCellIdentity.buf[3], - cell->nRCGI.nRCellIdentity.buf[4]); - BIT_STRING_TO_NR_CELL_IDENTITY(&cell->nRCGI.nRCellIdentity, - F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).cells_to_activate[i].nr_cellid); - F1AP_ProtocolExtensionContainer_10696P112_t *ext = (F1AP_ProtocolExtensionContainer_10696P112_t *)cell->iE_Extensions; - - if (ext==NULL) - continue; - - for (int cnt=0; cntlist.count; cnt++) { - F1AP_Cells_to_be_Activated_List_ItemExtIEs_t *cells_to_be_activated_list_itemExtIEs=(F1AP_Cells_to_be_Activated_List_ItemExtIEs_t *)ext->list.array[cnt]; - - switch (cells_to_be_activated_list_itemExtIEs->id) { - /* - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_NOTHING: - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_GNB_CUSystemInformation, - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_AvailablePLMNList, - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_ExtendedAvailablePLMN_List, - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_IAB_Info_IAB_donor_CU, - case F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_AvailableSNPN_ID_List - */ - case F1AP_ProtocolIE_ID_id_gNB_CUSystemInformation: { - F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).cells_to_activate[i].nrpci = (cell->nRPCI != NULL) ? *cell->nRPCI : 0; - F1AP_GNB_CUSystemInformation_t *gNB_CUSystemInformation = (F1AP_GNB_CUSystemInformation_t *)&cells_to_be_activated_list_itemExtIEs->extensionValue.choice.GNB_CUSystemInformation; - F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).cells_to_activate[i].num_SI = gNB_CUSystemInformation->sibtypetobeupdatedlist.list.count; - AssertFatal(ext->list.count==1,"At least one SI message should be there, and only 1 for now!\n"); - LOG_D(F1AP, - "F1AP: Cell %d MCC %d MNC %d NRCellid %lx num_si %d\n", - i, - F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).cells_to_activate[i].plmn.mcc, - F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).cells_to_activate[i].plmn.mnc, - F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).cells_to_activate[i].nr_cellid, - F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).cells_to_activate[i].num_SI); - - for (int si = 0; si < gNB_CUSystemInformation->sibtypetobeupdatedlist.list.count; si++) { - F1AP_SibtypetobeupdatedListItem_t *sib_item = gNB_CUSystemInformation->sibtypetobeupdatedlist.list.array[si]; - size_t size = sib_item->sIBmessage.size; - F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).cells_to_activate[i].SI_container_length[si] = size; - LOG_D(F1AP, "F1AP: SI_container_length[%d][%ld] %ld bytes\n", i, sib_item->sIBtype, size); - F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).cells_to_activate[i].SI_container[si] = malloc(F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).cells_to_activate[i].SI_container_length[si]); - memcpy((void *)F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).cells_to_activate[i].SI_container[si], - (void *)sib_item->sIBmessage.buf, - size); - F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).cells_to_activate[i].SI_type[si]=sib_item->sIBtype; - } - - break; - } - - case F1AP_ProtocolIE_ID_id_AvailablePLMNList: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id_AvailablePLMNList not supported yet\n"); - break; - - case F1AP_ProtocolIE_ID_id_ExtendedAvailablePLMN_List: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id_AvailablePLMNList not supported yet\n"); - break; - - case F1AP_ProtocolIE_ID_id_IAB_Info_IAB_donor_CU: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id_AvailablePLMNList not supported yet\n"); - break; - - case F1AP_ProtocolIE_ID_id_AvailableSNPN_ID_List: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id_AvailablePLMNList not supported yet\n"); - break; - - default: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id %d unknown\n",(int)cells_to_be_activated_list_itemExtIEs->id); - break; - } - } // for (cnt=... - } // for (cells_to_activate... - - break; - } // case F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List - - default: - AssertFatal(1==0,"F1AP_ProtocolIE_ID_id %d unknown\n", (int)ie->id); - break; - } // switch ie - } // for IE - - AssertFatal(TransactionId!=-1,"TransactionId was not sent\n"); - LOG_D(F1AP,"F1AP: num_cells_to_activate %d\n",num_cells_to_activate); - F1AP_GNB_CU_CONFIGURATION_UPDATE (msg_p).num_cells_to_activate = num_cells_to_activate; - LOG_D(F1AP, "Sending F1AP_GNB_CU_CONFIGURATION_UPDATE ITTI message \n"); + // Decoding + f1ap_gnb_du_configuration_update_acknowledge_t in = {0}; + if (!decode_f1ap_du_configuration_update_acknowledge(pdu, &in)) { + LOG_E(F1AP, "Failed to decode gNB-DU Configuration Update Acknowledge\n"); + free_f1ap_du_configuration_update_acknowledge(&in); + return -1; + } + // Allocate and send an ITTI message + MessageDef *msg_p = itti_alloc_new_message(TASK_DU_F1, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE); + f1ap_gnb_du_configuration_update_acknowledge_t *msg = &F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_p); + // Copy the decoded message to the ITTI message (RRC thread will free it) + *msg = in; // Copy the decoded message to the ITTI message (RRC thread will free it) itti_send_msg_to_task(TASK_GNB_APP, GNB_MODULE_ID_TO_INSTANCE(assoc_id), msg_p); return 0; } @@ -911,62 +275,22 @@ int DU_send_gNB_CU_CONFIGURATION_UPDATE_FAILURE(sctp_assoc_t assoc_id, GNBCUConfigurationUpdateFailure->cause); } -int DU_send_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE( - sctp_assoc_t assoc_id, - f1ap_gnb_cu_configuration_update_acknowledge_t *GNBCUConfigurationUpdateAcknowledge) +/** + * @brief Encode and transfer F1 GNB CU Configuration Update Acknowledge message + */ +int DU_send_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(sctp_assoc_t assoc_id, f1ap_gnb_cu_configuration_update_acknowledge_t *msg) { - AssertFatal(GNBCUConfigurationUpdateAcknowledge->num_cells_failed_to_be_activated == 0, - "%d cells failed to activate\n", - GNBCUConfigurationUpdateAcknowledge->num_cells_failed_to_be_activated); - AssertFatal(GNBCUConfigurationUpdateAcknowledge->noofTNLAssociations_to_setup == 0, - "%d TNLAssociations to setup, handle this ...\n", - GNBCUConfigurationUpdateAcknowledge->noofTNLAssociations_to_setup); - AssertFatal(GNBCUConfigurationUpdateAcknowledge->noofTNLAssociations_failed == 0, - "%d TNLAssociations failed\n", - GNBCUConfigurationUpdateAcknowledge->noofTNLAssociations_failed); - AssertFatal(GNBCUConfigurationUpdateAcknowledge->noofDedicatedSIDeliveryNeededUEs == 0, - "%d DedicatedSIDeliveryNeededUEs\n", - GNBCUConfigurationUpdateAcknowledge->noofDedicatedSIDeliveryNeededUEs); - F1AP_F1AP_PDU_t pdu= {0}; - uint8_t *buffer=NULL; - uint32_t len=0; - /* Create */ - /* 0. pdu Type */ - pdu.present = F1AP_F1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu.choice.successfulOutcome, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_gNBCUConfigurationUpdate; - tmp->criticality = F1AP_Criticality_reject; - tmp->value.present = F1AP_SuccessfulOutcome__value_PR_GNBCUConfigurationUpdateAcknowledge; - F1AP_GNBCUConfigurationUpdateAcknowledge_t *out = &tmp->value.choice.GNBCUConfigurationUpdateAcknowledge; - /* mandatory */ - /* c1. Transaction ID (integer value)*/ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBCUConfigurationUpdateAcknowledgeIEs_t, ie); - ie->id = F1AP_ProtocolIE_ID_id_TransactionID; - ie->criticality = F1AP_Criticality_reject; - ie->value.present = F1AP_GNBCUConfigurationUpdateAcknowledgeIEs__value_PR_TransactionID; - ie->value.choice.TransactionID = F1AP_get_next_transaction_identifier(0, 0); - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { - LOG_E(F1AP, "Failed to encode GNB-DU-Configuration-Update-Acknowledge\n"); + uint8_t *buffer = NULL; + uint32_t len = 0; + /* encode F1 message */ + F1AP_F1AP_PDU_t *pdu = encode_f1ap_cu_configuration_update_acknowledge(msg); + /* encode F1AP PDU */ + if (!pdu || f1ap_encode_pdu(pdu, &buffer, &len) < 0) { + LOG_E(F1AP, "Failed to encode GNB-CU-Configuration-Update-Acknowledge\n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return -1; } - - ASN_STRUCT_RESET(asn_DEF_F1AP_F1AP_PDU, &pdu); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } - -int DU_send_gNB_DU_RESOURCE_COORDINATION_REQUEST(sctp_assoc_t assoc_id, - F1AP_GNBDUResourceCoordinationRequest_t *GNBDUResourceCoordinationRequest) -{ - AssertFatal(0, "Not implemented yet\n"); -} - -int DU_handle_gNB_DU_RESOURCE_COORDINATION_RESPONSE(instance_t instance, - sctp_assoc_t assoc_id, - uint32_t stream, - F1AP_F1AP_PDU_t *pdu) -{ - AssertFatal(0, "Not implemented yet\n"); -} diff --git a/openair2/F1AP/f1ap_du_interface_management.h b/openair2/F1AP/f1ap_du_interface_management.h index f8d7eafb02..bb5caf90df 100644 --- a/openair2/F1AP/f1ap_du_interface_management.h +++ b/openair2/F1AP/f1ap_du_interface_management.h @@ -38,14 +38,6 @@ */ int DU_handle_RESET(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); int DU_send_RESET_ACKNOWLEDGE(sctp_assoc_t assoc_id, const f1ap_reset_ack_t *ack); -int DU_send_RESET(sctp_assoc_t assoc_id, const f1ap_reset_t *reset); -int DU_handle_RESET_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); - -/* - * Error Indication - */ -int DU_send_ERROR_INDICATION(sctp_assoc_t assoc_id, F1AP_F1AP_PDU_t *pdu_p); -int DU_handle_ERROR_INDICATION(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); /* * F1 Setup @@ -59,14 +51,7 @@ int DU_handle_F1_SETUP_FAILURE(instance_t instance, sctp_assoc_t assoc_id, uint3 /* * gNB-DU Configuration Update */ -int DU_send_gNB_DU_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id, const f1ap_gnb_du_configuration_update_t *upd); - -int DU_handle_gNB_DU_CONFIGURATION_FAILURE(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu); - -int DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, - sctp_assoc_t assoc_id, - uint32_t stream, - F1AP_F1AP_PDU_t *pdu); +int DU_send_gNB_DU_CONFIGURATION_UPDATE(sctp_assoc_t assoc_id, f1ap_gnb_du_configuration_update_t *msg); /* * gNB-CU Configuration Update @@ -79,17 +64,9 @@ int DU_send_gNB_CU_CONFIGURATION_UPDATE_FAILURE(sctp_assoc_t assoc_id, int DU_send_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(sctp_assoc_t assoc_id, f1ap_gnb_cu_configuration_update_acknowledge_t *GNBCUConfigurationUpdateAcknowledge); - - -/* - * gNB-DU Resource Coordination - */ -int DU_send_gNB_DU_RESOURCE_COORDINATION_REQUEST(sctp_assoc_t assoc_id, - F1AP_GNBDUResourceCoordinationRequest_t *GNBDUResourceCoordinationRequest); - -int DU_handle_gNB_DU_RESOURCE_COORDINATION_RESPONSE(instance_t instance, - sctp_assoc_t assoc_id, - uint32_t stream, - F1AP_F1AP_PDU_t *pdu); +int DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE(instance_t instance, + sctp_assoc_t assoc_id, + uint32_t stream, + F1AP_F1AP_PDU_t *pdu); #endif /* F1AP_DU_INTERFACE_MANAGEMENT_H_ */ diff --git a/openair2/F1AP/f1ap_du_rrc_message_transfer.c b/openair2/F1AP/f1ap_du_rrc_message_transfer.c index 4a3526dd0a..7fd83ecd78 100644 --- a/openair2/F1AP/f1ap_du_rrc_message_transfer.c +++ b/openair2/F1AP/f1ap_du_rrc_message_transfer.c @@ -53,226 +53,78 @@ #include "openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.h" +#include "f1ap_rrc_message_transfer.h" + /* DL RRC Message Transfer */ int DU_handle_DL_RRC_MESSAGE_TRANSFER(instance_t instance, sctp_assoc_t assoc_id, uint32_t stream, F1AP_F1AP_PDU_t *pdu) { - F1AP_DLRRCMessageTransfer_t *container; - F1AP_DLRRCMessageTransferIEs_t *ie; - int executeDuplication; - //uint64_t subscriberProfileIDforRFP; - //uint64_t rAT_FrequencySelectionPriority; - DevAssert(pdu != NULL); - container = &pdu->choice.initiatingMessage->value.choice.DLRRCMessageTransfer; - /* GNB_CU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); - uint32_t cu_ue_f1ap_id = ie->value.choice.GNB_CU_UE_F1AP_ID; - /* GNB_DU_UE_F1AP_ID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); - uint32_t du_ue_f1ap_id = ie->value.choice.GNB_DU_UE_F1AP_ID; - - /* optional */ - /* oldgNB_DU_UE_F1AP_ID */ - uint32_t *old_gNB_DU_ue_id = NULL; - uint32_t old_gNB_DU_ue_id_stack = 0; - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID, false); - if (ie) { - /* strange: it is not named OLD_GNB_DU_UE... */ - old_gNB_DU_ue_id_stack = ie->value.choice.GNB_DU_UE_F1AP_ID_1; - old_gNB_DU_ue_id = &old_gNB_DU_ue_id_stack; + f1ap_dl_rrc_message_t msg = {0}; + if (!decode_dl_rrc_message_transfer(pdu, &msg)) { + LOG_E(F1AP, "cannot decode F1 DL RRC message Transfer\n"); + free_dl_rrc_message_transfer(&msg); + return -1; } - /* mandatory */ - /* SRBID */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_SRBID, true); - uint64_t srb_id = ie->value.choice.SRBID; - LOG_D(F1AP, "srb_id %lu \n", srb_id); - - /* optional */ - /* ExecuteDuplication */ - if (0) { - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_ExecuteDuplication, true); - executeDuplication = ie->value.choice.ExecuteDuplication; - LOG_D(F1AP, "ExecuteDuplication %d \n", executeDuplication); - } - - // issue in here - /* mandatory */ - /* RRC Container */ - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_RRCContainer, true); - /* optional */ - /* RAT_FrequencyPriorityInformation */ - if (0) { - F1AP_FIND_PROTOCOLIE_BY_ID(F1AP_DLRRCMessageTransferIEs_t, ie, container, - F1AP_ProtocolIE_ID_id_RAT_FrequencyPriorityInformation, true); - - switch(ie->value.choice.RAT_FrequencyPriorityInformation.present) { - case F1AP_RAT_FrequencyPriorityInformation_PR_eNDC: - //subscriberProfileIDforRFP = ie->value.choice.RAT_FrequencyPriorityInformation.choice.subscriberProfileIDforRFP; - break; - - case F1AP_RAT_FrequencyPriorityInformation_PR_nGRAN: - //rAT_FrequencySelectionPriority = ie->value.choice.RAT_FrequencyPriorityInformation.choice.rAT_FrequencySelectionPriority; - break; - - default: - LOG_W(F1AP, "unhandled IE RAT_FrequencyPriorityInformation.present\n"); - break; - } - } - - f1ap_dl_rrc_message_t dl_rrc = { - .gNB_CU_ue_id = cu_ue_f1ap_id, - .gNB_DU_ue_id = du_ue_f1ap_id, - .old_gNB_DU_ue_id = old_gNB_DU_ue_id, - .rrc_container_length = ie->value.choice.RRCContainer.size, - .rrc_container = ie->value.choice.RRCContainer.buf, - .srb_id = srb_id - }; - dl_rrc_message_transfer(&dl_rrc); + dl_rrc_message_transfer(&msg); + /* Free DL RRC Message Transfer */ + free_dl_rrc_message_transfer(&msg); return 0; } /* UL RRC Message Transfer */ int DU_send_INITIAL_UL_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, const f1ap_initial_ul_rrc_message_t *msg) { - F1AP_F1AP_PDU_t pdu= {0}; - F1AP_InitialULRRCMessageTransfer_t *out; - uint8_t *buffer=NULL; - uint32_t len=0; + /* encode Initial UL RRC Message Transfer */ + F1AP_F1AP_PDU_t *pdu = encode_initial_ul_rrc_message_transfer(msg); + /* free F1AP message after encoding */ + free_initial_ul_rrc_message_transfer(msg); - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_InitialULRRCMessageTransfer; - tmp->criticality = F1AP_Criticality_ignore; - tmp->value.present = F1AP_InitiatingMessage__value_PR_InitialULRRCMessageTransfer; - out = &tmp->value.choice.InitialULRRCMessageTransfer; - /* mandatory */ - /* c1. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie1->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id; - /* mandatory */ - /* c2. NRCGI */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_NRCGI; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_NRCGI; - //Fixme: takes always the first cell - addnRCGI(ie2->value.choice.NRCGI, &getCxt(0)->setupReq.cell[0].info); - /* mandatory */ - /* c3. C_RNTI */ // 16 - asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_C_RNTI; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_C_RNTI; - ie3->value.choice.C_RNTI = msg->crnti; - /* mandatory */ - /* c4. RRCContainer */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, (const char *)msg->rrc_container, msg->rrc_container_length); - - /* optional */ - /* c5. DUtoCURRCContainer */ - if (msg->du2cu_rrc_container != NULL) { - asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie5); - ie5->id = F1AP_ProtocolIE_ID_id_DUtoCURRCContainer; - ie5->criticality = F1AP_Criticality_reject; - ie5->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_DUtoCURRCContainer; - OCTET_STRING_fromBuf(&ie5->value.choice.DUtoCURRCContainer, - (const char *)msg->du2cu_rrc_container, - msg->du2cu_rrc_container_length); - } - /* mandatory */ - /* c6. Transaction ID (integer value) */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie6); - ie6->id = F1AP_ProtocolIE_ID_id_TransactionID; - ie6->criticality = F1AP_Criticality_ignore; - ie6->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_TransactionID; - ie6->value.choice.TransactionID = F1AP_get_next_transaction_identifier(0, 0); - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { - LOG_E(F1AP, "Failed to encode F1 INITIAL UL RRC MESSAGE TRANSFER\n"); + if (pdu == NULL) { + LOG_E(F1AP, "cannot encode F1 INITIAL UL RRC MESSAGE TRANSFER, can't send message\n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return -1; } + /* encode F1AP PDU */ + uint8_t *buffer = NULL; + uint32_t len = 0; + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { + LOG_E(F1AP, "Failed to encode F1 INITIAL UL RRC MESSAGE TRANSFER\n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + return -1; + } + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + + /* Send to ITTI */ f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } int DU_send_UL_NR_RRC_MESSAGE_TRANSFER(sctp_assoc_t assoc_id, const f1ap_ul_rrc_message_t *msg) { - F1AP_F1AP_PDU_t pdu= {0}; - F1AP_ULRRCMessageTransfer_t *out; - uint8_t *buffer = NULL; - uint32_t len; LOG_D(F1AP, "size %d UE RNTI %x in SRB %d\n", msg->rrc_container_length, msg->gNB_DU_ue_id, msg->srb_id); - //for (int i = 0;i < msg->rrc_container_length; i++) - // printf("%02x ", msg->rrc_container[i]); - //printf("\n"); - /* Create */ - /* 0. Message Type */ - pdu.present = F1AP_F1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu.choice.initiatingMessage, tmp); - tmp->procedureCode = F1AP_ProcedureCode_id_ULRRCMessageTransfer; - tmp->criticality = F1AP_Criticality_ignore; - tmp->value.present = F1AP_InitiatingMessage__value_PR_ULRRCMessageTransfer; - out = &tmp->value.choice.ULRRCMessageTransfer; - /* mandatory */ - /* c1. GNB_CU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_ULRRCMessageTransferIEs_t, ie1); - ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; - ie1->criticality = F1AP_Criticality_reject; - ie1->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_GNB_CU_UE_F1AP_ID; - ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id; - /* mandatory */ - /* c2. GNB_DU_UE_F1AP_ID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_ULRRCMessageTransferIEs_t, ie2); - ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; - ie2->criticality = F1AP_Criticality_reject; - ie2->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID; - ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id; - /* mandatory */ - /* c3. SRBID */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_ULRRCMessageTransferIEs_t, ie3); - ie3->id = F1AP_ProtocolIE_ID_id_SRBID; - ie3->criticality = F1AP_Criticality_reject; - ie3->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_SRBID; - ie3->value.choice.SRBID = msg->srb_id; - // issue in here - /* mandatory */ - /* c4. RRCContainer */ - asn1cSequenceAdd(out->protocolIEs.list, F1AP_ULRRCMessageTransferIEs_t, ie4); - ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer; - ie4->criticality = F1AP_Criticality_reject; - ie4->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_RRCContainer; - OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, - (const char *) msg->rrc_container, - msg->rrc_container_length); - - /* encode */ - if (f1ap_encode_pdu(&pdu, &buffer, &len) < 0) { - LOG_E(F1AP, "Failed to encode F1 UL RRC MESSAGE TRANSFER \n"); + /* encode UL RRC Message Transfer */ + F1AP_F1AP_PDU_t *pdu = encode_ul_rrc_message_transfer(msg); + if (pdu == NULL) { + LOG_E(F1AP, "Failed to encode F1 UL RRC MESSAGE TRANSFER: cannot send message\n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); return -1; } - + /* encode F1AP PDU */ + uint8_t *buffer = NULL; + uint32_t len; + if (f1ap_encode_pdu(pdu, &buffer, &len) < 0) { + LOG_E(F1AP, "Failed to encode F1 UL RRC MESSAGE TRANSFER \n"); + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + return -1; + } + /* Free F1AP PDU */ + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); + /* Send to ITTI */ f1ap_itti_send_sctp_data_req(assoc_id, buffer, len); return 0; } diff --git a/openair2/F1AP/f1ap_du_system_information.c b/openair2/F1AP/f1ap_du_system_information.c deleted file mode 100644 index 725bb4e1af..0000000000 --- a/openair2/F1AP/f1ap_du_system_information.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file f1ap_du_interface_management.h - * \brief f1ap interface management for DU - * \author EURECOM/NTUST - * \date 2018 - * \version 0.1 - * \company Eurecom - * \email: navid.nikaein@eurecom.fr, bing-kai.hong@eurecom.fr - * \note - * \warning - */ diff --git a/openair2/F1AP/f1ap_du_system_information.h b/openair2/F1AP/f1ap_du_system_information.h deleted file mode 100644 index b6bbedba2f..0000000000 --- a/openair2/F1AP/f1ap_du_system_information.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file f1ap_du_interface_management.h - * \brief f1ap interface management for DU - * \author EURECOM/NTUST - * \date 2018 - * \version 0.1 - * \company Eurecom - * \email: navid.nikaein@eurecom.fr, bing-kai.hong@eurecom.fr - * \note - * \warning - */ \ No newline at end of file diff --git a/openair2/F1AP/f1ap_du_task.c b/openair2/F1AP/f1ap_du_task.c index ff188e52df..6c4f8c3be6 100644 --- a/openair2/F1AP/f1ap_du_task.c +++ b/openair2/F1AP/f1ap_du_task.c @@ -44,7 +44,7 @@ static instance_t du_create_gtpu_instance_to_cu(const f1ap_net_config_t *nc) { openAddr_t tmp = {0}; strncpy(tmp.originHost, nc->DU_f1u_ip_address, sizeof(tmp.originHost) - 1); - strncpy(tmp.destinationHost, nc->CU_f1_ip_address.ipv4_address, sizeof(tmp.destinationHost) - 1); + strncpy(tmp.destinationHost, nc->CU_f1_ip_address, sizeof(tmp.destinationHost) - 1); sprintf(tmp.originService, "%d", nc->DUport); sprintf(tmp.destinationService, "%d", nc->CUport); return gtpv1Init(tmp); @@ -63,9 +63,20 @@ void du_task_send_sctp_association_req(instance_t instance, f1ap_net_config_t *n sctp_new_association_req_p->in_streams = 2; //du_inst->sctp_in_streams; sctp_new_association_req_p->out_streams = 2; //du_inst->sctp_out_streams; // remote - memcpy(&sctp_new_association_req_p->remote_address, &nc->CU_f1_ip_address, sizeof(nc->CU_f1_ip_address)); + sctp_new_association_req_p->remote_address.ipv4 = 1; + strncpy(sctp_new_association_req_p->remote_address.ipv4_address, + nc->CU_f1_ip_address, + sizeof(sctp_new_association_req_p->remote_address.ipv4_address) - 1); // local - memcpy(&sctp_new_association_req_p->local_address, &nc->DU_f1c_ip_address, sizeof(nc->DU_f1c_ip_address)); + sctp_new_association_req_p->local_address.ipv4 = 1; + strncpy(sctp_new_association_req_p->local_address.ipv4_address, + nc->DU_f1c_ip_address, + sizeof(sctp_new_association_req_p->local_address.ipv4_address) - 1); + LOG_D(F1AP, + "Local IPv4 Address: %s, Remote IPv4 Address: %s\n", + sctp_new_association_req_p->local_address.ipv4_address, + sctp_new_association_req_p->remote_address.ipv4_address); + // du_f1ap_register_to_sctp itti_send_msg_to_task(TASK_SCTP, instance, message_p); } @@ -89,6 +100,8 @@ void du_task_handle_sctp_association_resp(instance_t instance, sctp_new_associat f1ap_du_data->du.assoc_id = sctp_new_association_resp->assoc_id; f1ap_du_data->sctp_in_streams = sctp_new_association_resp->in_streams; f1ap_du_data->sctp_out_streams = sctp_new_association_resp->out_streams; + /* next transaction ID */ + f1ap_du_data->setupReq.transaction_id = F1AP_get_next_transaction_identifier(0, 0); /* setup parameters for F1U and start the server */ DU_send_F1_SETUP_REQUEST(f1ap_du_data->du.assoc_id, &f1ap_du_data->setupReq); } diff --git a/openair2/F1AP/f1ap_du_ue_context_management.c b/openair2/F1AP/f1ap_du_ue_context_management.c index 6d9771f1f4..529c478ac2 100644 --- a/openair2/F1AP/f1ap_du_ue_context_management.c +++ b/openair2/F1AP/f1ap_du_ue_context_management.c @@ -45,13 +45,13 @@ static void f1ap_read_drb_qos_param(const F1AP_QoSFlowLevelQoSParameters_t *asn1 const F1AP_QoS_Characteristics_t *dRB_QoS_Char = &asn1_qos->qoS_Characteristics; if (dRB_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) { - drb_qos_char->qos_type = non_dynamic; + drb_qos_char->qos_type = NON_DYNAMIC; drb_qos_char->non_dynamic.fiveqi = dRB_QoS_Char->choice.non_Dynamic_5QI->fiveQI; drb_qos_char->non_dynamic.qos_priority_level = (dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL) ? *dRB_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel : -1; } else { - drb_qos_char->qos_type = dynamic; + drb_qos_char->qos_type = DYNAMIC; drb_qos_char->dynamic.fiveqi = (dRB_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *dRB_QoS_Char->choice.dynamic_5QI->fiveQI : -1; drb_qos_char->dynamic.qos_priority_level = dRB_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel; @@ -84,13 +84,13 @@ static void f1ap_read_flows_mapped(const F1AP_Flows_Mapped_To_DRB_List_t *asn1_f const F1AP_QoS_Characteristics_t *Flow_QoS_Char = &Flow_QoS->qoS_Characteristics; if (Flow_QoS_Char->present == F1AP_QoS_Characteristics_PR_non_Dynamic_5QI) { - flow_qos_char->qos_type = non_dynamic; + flow_qos_char->qos_type = NON_DYNAMIC; flow_qos_char->non_dynamic.fiveqi = Flow_QoS_Char->choice.non_Dynamic_5QI->fiveQI; flow_qos_char->non_dynamic.qos_priority_level = (Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel != NULL) ? *Flow_QoS_Char->choice.non_Dynamic_5QI->qoSPriorityLevel : -1; } else { - flow_qos_char->qos_type = dynamic; + flow_qos_char->qos_type = DYNAMIC; flow_qos_char->dynamic.fiveqi = (Flow_QoS_Char->choice.dynamic_5QI->fiveQI != NULL) ? *Flow_QoS_Char->choice.dynamic_5QI->fiveQI : -1; flow_qos_char->dynamic.qos_priority_level = Flow_QoS_Char->choice.dynamic_5QI->qoSPriorityLevel; @@ -209,11 +209,14 @@ int DU_handle_UE_CONTEXT_SETUP_REQUEST(instance_t instance, sctp_assoc_t assoc_i switch (drbs_tobesetup_item_p->rLCMode) { case F1AP_RLCMode_rlc_am: - drb_p->rlc_mode = RLC_MODE_AM; + drb_p->rlc_mode = F1AP_RLC_MODE_AM; + break; + case F1AP_RLCMode_rlc_um_bidirectional: + drb_p->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; break; - default: - drb_p->rlc_mode = RLC_MODE_TM; + LOG_W(F1AP, "unsupported RLC Mode %ld received: setting UM bidir\n", drbs_tobesetup_item_p->rLCMode); + drb_p->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; break; } @@ -930,13 +933,16 @@ int DU_handle_UE_CONTEXT_MODIFICATION_REQUEST(instance_t instance, sctp_assoc_t drb_p->up_ul_tnl[0].port = getCxt(instance)->net_config.CUport; switch (drbs_tobesetupmod_item_p->rLCMode) { - case F1AP_RLCMode_rlc_am: - drb_p->rlc_mode = RLC_MODE_AM; - break; - - default: - drb_p->rlc_mode = RLC_MODE_TM; - break; + case F1AP_RLCMode_rlc_am: + drb_p->rlc_mode = F1AP_RLC_MODE_AM; + break; + case F1AP_RLCMode_rlc_um_bidirectional: + drb_p->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; + break; + default: + LOG_W(F1AP, "unsupported RLC Mode %ld received: setting UM bidir\n", drbs_tobesetupmod_item_p->rLCMode); + drb_p->rlc_mode = F1AP_RLC_MODE_UM_BIDIR; + break; } if (drbs_tobesetupmod_item_p->qoSInformation.present == F1AP_QoSInformation_PR_eUTRANQoS) { diff --git a/openair2/F1AP/f1ap_du_warning_message_transmission.c b/openair2/F1AP/f1ap_du_warning_message_transmission.c deleted file mode 100644 index 725bb4e1af..0000000000 --- a/openair2/F1AP/f1ap_du_warning_message_transmission.c +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The OpenAirInterface Software Alliance licenses this file to You under - * the OAI Public License, Version 1.1 (the "License"); you may not use this file - * except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.openairinterface.org/?page_id=698 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - *------------------------------------------------------------------------------- - * For more information about the OpenAirInterface (OAI) Software Alliance: - * contact@openairinterface.org - */ - -/*! \file f1ap_du_interface_management.h - * \brief f1ap interface management for DU - * \author EURECOM/NTUST - * \date 2018 - * \version 0.1 - * \company Eurecom - * \email: navid.nikaein@eurecom.fr, bing-kai.hong@eurecom.fr - * \note - * \warning - */ diff --git a/openair2/F1AP/f1ap_handlers.c b/openair2/F1AP/f1ap_handlers.c index bfaa9959dc..6234dcd624 100644 --- a/openair2/F1AP/f1ap_handlers.c +++ b/openair2/F1AP/f1ap_handlers.c @@ -48,10 +48,8 @@ static const f1ap_message_processing_t f1ap_messages_processing[][3] = { // {CU_handle_RESET, DU_handle_RESET_ACKNOWLEDGE, 0}, /* Reset */ {CU_handle_F1_SETUP_REQUEST, DU_handle_F1_SETUP_RESPONSE, DU_handle_F1_SETUP_FAILURE}, /* F1Setup */ {0, 0, 0}, /* ErrorIndication */ - {CU_handle_gNB_DU_CONFIGURATION_UPDATE, 0, 0}, /* gNBDUConfigurationUpdate */ - {DU_handle_gNB_CU_CONFIGURATION_UPDATE, - CU_handle_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE, - CU_handle_gNB_CU_CONFIGURATION_UPDATE_FAILURE}, /* gNBCUConfigurationUpdate */ + {CU_handle_gNB_DU_CONFIGURATION_UPDATE, DU_handle_gNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE, 0}, /* gNBDUConfigurationUpdate */ + {DU_handle_gNB_CU_CONFIGURATION_UPDATE, CU_handle_gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE, 0}, /* gNBCUConfigurationUpdate */ {DU_handle_UE_CONTEXT_SETUP_REQUEST, CU_handle_UE_CONTEXT_SETUP_RESPONSE, 0}, /* UEContextSetup */ {DU_handle_UE_CONTEXT_RELEASE_COMMAND, CU_handle_UE_CONTEXT_RELEASE_COMPLETE, 0}, /* UEContextRelease */ {DU_handle_UE_CONTEXT_MODIFICATION_REQUEST, CU_handle_UE_CONTEXT_MODIFICATION_RESPONSE, 0}, /* UEContextModification */ diff --git a/openair2/F1AP/lib/CMakeLists.txt b/openair2/F1AP/lib/CMakeLists.txt new file mode 100644 index 0000000000..cb8d8b9712 --- /dev/null +++ b/openair2/F1AP/lib/CMakeLists.txt @@ -0,0 +1,10 @@ +add_library(f1ap_lib OBJECT + f1ap_lib_common.c + f1ap_rrc_message_transfer.c + f1ap_interface_management.c +) +target_link_libraries(f1ap_lib PRIVATE asn1_f1ap) +target_include_directories(f1ap_lib PUBLIC + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/openair2/F1AP/lib/f1ap_interface_management.c b/openair2/F1AP/lib/f1ap_interface_management.c new file mode 100644 index 0000000000..cb0b6ab8aa --- /dev/null +++ b/openair2/F1AP/lib/f1ap_interface_management.c @@ -0,0 +1,1767 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include + +#include "common/utils/assertions.h" +#include "openair3/UTILS/conversions.h" +#include "common/utils/oai_asn1.h" +#include "common/utils/utils.h" + +#include "f1ap_interface_management.h" +#include "f1ap_lib_common.h" +#include "f1ap_lib_includes.h" +#include "f1ap_messages_types.h" +#include "f1ap_lib_extern.h" + +static const int nrb_lut[29] = {11, 18, 24, 25, 31, 32, 38, 51, 52, 65, 66, 78, 79, 93, 106, + 107, 121, 132, 133, 135, 160, 162, 189, 216, 217, 245, 264, 270, 273}; + +static int to_NRNRB(int nrb) +{ + for (int i = 0; i < sizeofArray(nrb_lut); i++) + if (nrb_lut[i] == nrb) + return i; + AssertFatal(1 == 0, "nrb %d is not in the list of possible NRNRB\n", nrb); +} + +static int read_slice_info(const F1AP_ServedPLMNs_Item_t *plmn, nssai_t *nssai, int max_nssai) +{ + if (plmn->iE_Extensions == NULL) + return 0; + + const F1AP_ProtocolExtensionContainer_10696P34_t *p = (F1AP_ProtocolExtensionContainer_10696P34_t *)plmn->iE_Extensions; + if (p->list.count == 0) + return 0; + + const F1AP_ServedPLMNs_ItemExtIEs_t *splmn = p->list.array[0]; + DevAssert(splmn->id == F1AP_ProtocolIE_ID_id_TAISliceSupportList); + DevAssert(splmn->extensionValue.present == F1AP_ServedPLMNs_ItemExtIEs__extensionValue_PR_SliceSupportList); + const F1AP_SliceSupportList_t *ssl = &splmn->extensionValue.choice.SliceSupportList; + AssertFatal(ssl->list.count <= max_nssai, "cannot handle more than 16 slices\n"); + for (int s = 0; s < ssl->list.count; ++s) { + const F1AP_SliceSupportItem_t *sl = ssl->list.array[s]; + nssai_t *n = &nssai[s]; + OCTET_STRING_TO_INT8(&sl->sNSSAI.sST, n->sst); + n->sd = 0xffffff; + if (sl->sNSSAI.sD != NULL) + OCTET_STRING_TO_INT24(sl->sNSSAI.sD, n->sd); + } + + return ssl->list.count; +} + +/** + * @brief F1AP Setup Request memory management + */ +static void free_f1ap_cell(const f1ap_served_cell_info_t *info, const f1ap_gnb_du_system_info_t *sys_info) +{ + if (sys_info) { + free(sys_info->mib); + free(sys_info->sib1); + free((void *)sys_info); + } + free(info->measurement_timing_config); + free(info->tac); +} + +/** + * @brief Encoding of Served Cell Information (9.3.1.10 of 3GPP TS 38.473) + */ +static F1AP_Served_Cell_Information_t encode_served_cell_info(const f1ap_served_cell_info_t *c) +{ + F1AP_Served_Cell_Information_t scell_info = {0}; + // NR CGI + MCC_MNC_TO_PLMNID(c->plmn.mcc, c->plmn.mnc, c->plmn.mnc_digit_length, &(scell_info.nRCGI.pLMN_Identity)); + NR_CELL_ID_TO_BIT_STRING(c->nr_cellid, &(scell_info.nRCGI.nRCellIdentity)); + // NR PCI + scell_info.nRPCI = c->nr_pci; // int 0..1007 + // 5GS TAC + if (c->tac != NULL) { + uint32_t tac = htonl(*c->tac); + asn1cCalloc(scell_info.fiveGS_TAC, netOrder); + OCTET_STRING_fromBuf(netOrder, ((char *)&tac) + 1, 3); + } + // Served PLMNs + asn1cSequenceAdd(scell_info.servedPLMNs.list, F1AP_ServedPLMNs_Item_t, servedPLMN_item); + MCC_MNC_TO_PLMNID(c->plmn.mcc, c->plmn.mnc, c->plmn.mnc_digit_length, &servedPLMN_item->pLMN_Identity); + // NR-Mode-Info + F1AP_NR_Mode_Info_t *nR_Mode_Info = &scell_info.nR_Mode_Info; + if (c->mode == F1AP_MODE_FDD) { // FDD + const f1ap_fdd_info_t *fdd = &c->fdd; + nR_Mode_Info->present = F1AP_NR_Mode_Info_PR_fDD; + asn1cCalloc(nR_Mode_Info->choice.fDD, fDD_Info); + /* FDD.1.1 UL NRFreqInfo ARFCN */ + fDD_Info->uL_NRFreqInfo.nRARFCN = fdd->ul_freqinfo.arfcn; + /* FDD.1.3 freqBandListNr */ + int ul_band = 1; + for (int j = 0; j < ul_band; j++) { + asn1cSequenceAdd(fDD_Info->uL_NRFreqInfo.freqBandListNr.list, F1AP_FreqBandNrItem_t, nr_freqBandNrItem); + /* FDD.1.3.1 freqBandIndicatorNr*/ + nr_freqBandNrItem->freqBandIndicatorNr = fdd->ul_freqinfo.band; + } + /* FDD.2.1 DL NRFreqInfo ARFCN */ + fDD_Info->dL_NRFreqInfo.nRARFCN = fdd->dl_freqinfo.arfcn; + /* FDD.2.3 freqBandListNr */ + int dl_bands = 1; + for (int j = 0; j < dl_bands; j++) { + asn1cSequenceAdd(fDD_Info->dL_NRFreqInfo.freqBandListNr.list, F1AP_FreqBandNrItem_t, nr_freqBandNrItem); + /* FDD.2.3.1 freqBandIndicatorNr*/ + nr_freqBandNrItem->freqBandIndicatorNr = fdd->dl_freqinfo.band; + } // for FDD : DL freq_Bands + /* FDD.3 UL Transmission Bandwidth */ + fDD_Info->uL_Transmission_Bandwidth.nRSCS = fdd->ul_tbw.scs; + fDD_Info->uL_Transmission_Bandwidth.nRNRB = to_NRNRB(fdd->ul_tbw.nrb); + /* FDD.4 DL Transmission Bandwidth */ + fDD_Info->dL_Transmission_Bandwidth.nRSCS = fdd->dl_tbw.scs; + fDD_Info->dL_Transmission_Bandwidth.nRNRB = to_NRNRB(fdd->dl_tbw.nrb); + } else if (c->mode == F1AP_MODE_TDD) { + const f1ap_tdd_info_t *tdd = &c->tdd; + nR_Mode_Info->present = F1AP_NR_Mode_Info_PR_tDD; + asn1cCalloc(nR_Mode_Info->choice.tDD, tDD_Info); + /* TDD.1.1 nRFreqInfo ARFCN */ + tDD_Info->nRFreqInfo.nRARFCN = tdd->freqinfo.arfcn; + /* TDD.1.3 freqBandListNr */ + int bands = 1; + for (int j = 0; j < bands; j++) { + asn1cSequenceAdd(tDD_Info->nRFreqInfo.freqBandListNr.list, F1AP_FreqBandNrItem_t, nr_freqBandNrItem); + /* TDD.1.3.1 freqBandIndicatorNr*/ + nr_freqBandNrItem->freqBandIndicatorNr = tdd->freqinfo.band; + } + /* TDD.2 transmission_Bandwidth */ + tDD_Info->transmission_Bandwidth.nRSCS = tdd->tbw.scs; + tDD_Info->transmission_Bandwidth.nRNRB = to_NRNRB(tdd->tbw.nrb); + } else { + AssertFatal(false, "unknown duplex mode %d\n", c->mode); + } + // Measurement Timing Configuration + OCTET_STRING_fromBuf(&scell_info.measurementTimingConfiguration, + (const char *)c->measurement_timing_config, + c->measurement_timing_config_len); + + return scell_info; +} + +static bool decode_served_cell_info(const F1AP_Served_Cell_Information_t *in, f1ap_served_cell_info_t *info) +{ + AssertError(in != NULL, return false, "Input message pointer is NULL"); + // 5GS TAC (O) + if (in->fiveGS_TAC) { + info->tac = malloc_or_fail(sizeof(*info->tac)); + OCTET_STRING_TO_INT24(in->fiveGS_TAC, *info->tac); + } + // NR CGI (M) + TBCD_TO_MCC_MNC(&(in->nRCGI.pLMN_Identity), info->plmn.mcc, info->plmn.mnc, info->plmn.mnc_digit_length); + // NR Cell Identity (M) + BIT_STRING_TO_NR_CELL_IDENTITY(&in->nRCGI.nRCellIdentity, info->nr_cellid); + // NR PCI (M) + info->nr_pci = in->nRPCI; + // Served PLMNs (>= 1) + AssertError(in->servedPLMNs.list.count == 1, return false, "at least and only 1 PLMN must be present"); + info->num_ssi = read_slice_info(in->servedPLMNs.list.array[0], info->nssai, 16); + // FDD Info + if (in->nR_Mode_Info.present == F1AP_NR_Mode_Info_PR_fDD) { + info->mode = F1AP_MODE_FDD; + f1ap_fdd_info_t *FDDs = &info->fdd; + F1AP_FDD_Info_t *fDD_Info = in->nR_Mode_Info.choice.fDD; + FDDs->ul_freqinfo.arfcn = fDD_Info->uL_NRFreqInfo.nRARFCN; + // Note: cannot handle more than one UL frequency band + int num_ulBands = fDD_Info->uL_NRFreqInfo.freqBandListNr.list.count; + AssertError(num_ulBands == 1, return false, "1 FDD UL frequency band must be present, more is not supported"); + for (int f = 0; f < num_ulBands && f < 1; f++) { + F1AP_FreqBandNrItem_t *FreqItem = fDD_Info->uL_NRFreqInfo.freqBandListNr.list.array[f]; + FDDs->ul_freqinfo.band = FreqItem->freqBandIndicatorNr; + AssertError(FreqItem->supportedSULBandList.list.count == 0, return false, "cannot handle FDD SUL bands"); + } + // Note: cannot handle more than one DL frequency band + FDDs->dl_freqinfo.arfcn = fDD_Info->dL_NRFreqInfo.nRARFCN; + int num_dlBands = fDD_Info->dL_NRFreqInfo.freqBandListNr.list.count; + AssertError(num_dlBands == 1, return false, "1 FDD DL frequency band must be present, more is not supported"); + for (int dlB = 0; dlB < num_dlBands && dlB < 1; dlB++) { + F1AP_FreqBandNrItem_t *FreqItem = fDD_Info->dL_NRFreqInfo.freqBandListNr.list.array[dlB]; + FDDs->dl_freqinfo.band = FreqItem->freqBandIndicatorNr; + AssertError(FreqItem->supportedSULBandList.list.count == 0, return false, "cannot handle FDD SUL bands"); + } + FDDs->ul_tbw.scs = fDD_Info->uL_Transmission_Bandwidth.nRSCS; + FDDs->ul_tbw.nrb = nrb_lut[fDD_Info->uL_Transmission_Bandwidth.nRNRB]; + FDDs->dl_tbw.scs = fDD_Info->dL_Transmission_Bandwidth.nRSCS; + FDDs->dl_tbw.nrb = nrb_lut[fDD_Info->dL_Transmission_Bandwidth.nRNRB]; + } else if (in->nR_Mode_Info.present == F1AP_NR_Mode_Info_PR_tDD) { + info->mode = F1AP_MODE_TDD; + f1ap_tdd_info_t *TDDs = &info->tdd; + F1AP_TDD_Info_t *tDD_Info = in->nR_Mode_Info.choice.tDD; + TDDs->freqinfo.arfcn = tDD_Info->nRFreqInfo.nRARFCN; + // Handle frequency bands + int num_tddBands = tDD_Info->nRFreqInfo.freqBandListNr.list.count; + AssertError(num_tddBands == 1, return false, "1 TDD DL frequency band must be present, more is not supported"); + for (int f = 0; f < num_tddBands && f < 1; f++) { + struct F1AP_FreqBandNrItem *FreqItem = tDD_Info->nRFreqInfo.freqBandListNr.list.array[f]; + TDDs->freqinfo.band = FreqItem->freqBandIndicatorNr; + AssertError(FreqItem->supportedSULBandList.list.count == 0, return false, "cannot handle TDD SUL bands"); + } + TDDs->tbw.scs = tDD_Info->transmission_Bandwidth.nRSCS; + TDDs->tbw.nrb = nrb_lut[tDD_Info->transmission_Bandwidth.nRNRB]; + } else { + AssertError(1 == 0, return false, "unknown or missing NR Mode info %d\n", in->nR_Mode_Info.present); + } + // MeasurementConfig (M) + AssertError(in->measurementTimingConfiguration.size > 0, return false, "measurementTimingConfigurationc size is 0"); + info->measurement_timing_config = cp_octet_string(&in->measurementTimingConfiguration, &info->measurement_timing_config_len); + return true; +} + +static F1AP_GNB_DU_System_Information_t *encode_system_info(const f1ap_gnb_du_system_info_t *sys_info) +{ + if (sys_info == NULL) + return NULL; /* optional: can be NULL */ + + F1AP_GNB_DU_System_Information_t *enc_sys_info = calloc_or_fail(1, sizeof(*enc_sys_info)); + + AssertFatal(sys_info->mib != NULL, "MIB must be present in DU sys info\n"); + OCTET_STRING_fromBuf(&enc_sys_info->mIB_message, (const char *)sys_info->mib, sys_info->mib_length); + + AssertFatal(sys_info->sib1 != NULL, "SIB1 must be present in DU sys info\n"); + OCTET_STRING_fromBuf(&enc_sys_info->sIB1_message, (const char *)sys_info->sib1, sys_info->sib1_length); + + return enc_sys_info; +} + +static void decode_system_info(struct F1AP_GNB_DU_System_Information *DUsi, f1ap_gnb_du_system_info_t *sys_info) +{ + /* mib */ + sys_info->mib = calloc_or_fail(DUsi->mIB_message.size, sizeof(*sys_info->mib)); + memcpy(sys_info->mib, DUsi->mIB_message.buf, DUsi->mIB_message.size); + sys_info->mib_length = DUsi->mIB_message.size; + /* sib1 */ + sys_info->sib1 = calloc_or_fail(DUsi->sIB1_message.size, sizeof(*sys_info->sib1)); + memcpy(sys_info->sib1, DUsi->sIB1_message.buf, DUsi->sIB1_message.size); + sys_info->sib1_length = DUsi->sIB1_message.size; +} + +static void encode_cells_to_activate(const served_cells_to_activate_t *cell, F1AP_Cells_to_be_Activated_List_ItemIEs_t *cells_to_be_activated_ies) +{ + cells_to_be_activated_ies->id = F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item; + cells_to_be_activated_ies->criticality = F1AP_Criticality_reject; + cells_to_be_activated_ies->value.present = F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item; + // Cells to be Activated List Item (M) + F1AP_Cells_to_be_Activated_List_Item_t *cells_to_be_activated_item = + &cells_to_be_activated_ies->value.choice.Cells_to_be_Activated_List_Item; + // NR CGI (M) + MCC_MNC_TO_PLMNID(cell->plmn.mcc, + cell->plmn.mnc, + cell->plmn.mnc_digit_length, + &(cells_to_be_activated_item->nRCGI.pLMN_Identity)); + NR_CELL_ID_TO_BIT_STRING(cell->nr_cellid, &(cells_to_be_activated_item->nRCGI.nRCellIdentity)); + // NR PCI (O) + asn1cCalloc(cells_to_be_activated_item->nRPCI, tmp); + *tmp = cell->nrpci; + // gNB-CU System Information (O) + for (int n = 0; n < cell->num_SI; n++) { + F1AP_ProtocolExtensionContainer_10696P112_t *p = calloc_or_fail(1, sizeof(*p)); + cells_to_be_activated_item->iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; + asn1cSequenceAdd(p->list, F1AP_Cells_to_be_Activated_List_ItemExtIEs_t, cells_to_be_activated_itemExtIEs); + cells_to_be_activated_itemExtIEs->id = F1AP_ProtocolIE_ID_id_gNB_CUSystemInformation; + cells_to_be_activated_itemExtIEs->criticality = F1AP_Criticality_reject; + cells_to_be_activated_itemExtIEs->extensionValue.present = + F1AP_Cells_to_be_Activated_List_ItemExtIEs__extensionValue_PR_GNB_CUSystemInformation; + // gNB-CU System Information message + F1AP_GNB_CUSystemInformation_t *gNB_CUSystemInformation = + &cells_to_be_activated_itemExtIEs->extensionValue.choice.GNB_CUSystemInformation; + const f1ap_sib_msg_t *SI_msg = &cell->SI_msg[n]; + if (SI_msg->SI_container != NULL) { + if (SI_msg->SI_type > 6 && SI_msg->SI_type != 9) { + asn1cSequenceAdd(gNB_CUSystemInformation->sibtypetobeupdatedlist.list, F1AP_SibtypetobeupdatedListItem_t, sib_item); + sib_item->sIBtype = SI_msg->SI_type; + OCTET_STRING_fromBuf(&sib_item->sIBmessage, (const char *)SI_msg->SI_container, SI_msg->SI_container_length); + } + } + } +} + +static bool decode_cells_to_activate(served_cells_to_activate_t *out, const F1AP_Cells_to_be_Activated_List_ItemIEs_t *in) +{ + AssertError(in->id == F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item, + return false, + "ID != F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List_Item\n"); + AssertError(in->value.present == F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item, + return false, + "in->value.present != F1AP_Cells_to_be_Activated_List_ItemIEs__value_PR_Cells_to_be_Activated_List_Item\n"); + const F1AP_Cells_to_be_Activated_List_Item_t *cell = &in->value.choice.Cells_to_be_Activated_List_Item; + // NR CGI (M) + TBCD_TO_MCC_MNC(&cell->nRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length); + BIT_STRING_TO_NR_CELL_IDENTITY(&cell->nRCGI.nRCellIdentity, out->nr_cellid); + // NR PCI (O) + if (cell->nRPCI != NULL) + out->nrpci = *cell->nRPCI; + /* IE extensions (O) */ + F1AP_ProtocolExtensionContainer_10696P112_t *ext = (F1AP_ProtocolExtensionContainer_10696P112_t *)cell->iE_Extensions; + if (ext != NULL) { + for (int cnt = 0; cnt < ext->list.count; cnt++) { + AssertError(ext->list.count == 1, return false, "At least one SI message should be present, and only 1 is supported"); + F1AP_Cells_to_be_Activated_List_ItemExtIEs_t *cells_to_be_activated_list_itemExtIEs = + (F1AP_Cells_to_be_Activated_List_ItemExtIEs_t *)ext->list.array[cnt]; + /* IE extensions items (O) */ + switch (cells_to_be_activated_list_itemExtIEs->id) { + /* gNB-CU System Information */ + case F1AP_ProtocolIE_ID_id_gNB_CUSystemInformation: { + out->nrpci = (cell->nRPCI != NULL) ? *cell->nRPCI : 0; + F1AP_GNB_CUSystemInformation_t *gNB_CUSystemInformation = + (F1AP_GNB_CUSystemInformation_t *)&cells_to_be_activated_list_itemExtIEs->extensionValue.choice.GNB_CUSystemInformation; + /* System Information */ + out->num_SI = gNB_CUSystemInformation->sibtypetobeupdatedlist.list.count; + for (int s = 0; s < out->num_SI; s++) { + F1AP_SibtypetobeupdatedListItem_t *sib_item = gNB_CUSystemInformation->sibtypetobeupdatedlist.list.array[s]; + /* SI container */ + f1ap_sib_msg_t *SI_msg = &out->SI_msg[s]; + SI_msg->SI_container = cp_octet_string(&sib_item->sIBmessage, &SI_msg->SI_container_length); + /* SIB type */ + SI_msg->SI_type = sib_item->sIBtype; + } + break; + } + case F1AP_ProtocolIE_ID_id_AvailablePLMNList: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_AvailablePLMNList is not supported"); + break; + case F1AP_ProtocolIE_ID_id_ExtendedAvailablePLMN_List: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_ExtendedAvailablePLMN_List is not supported"); + break; + case F1AP_ProtocolIE_ID_id_IAB_Info_IAB_donor_CU: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_IAB_Info_IAB_donor_CU is not supported"); + break; + case F1AP_ProtocolIE_ID_id_AvailableSNPN_ID_List: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_AvailableSNPN_ID_List is not supported"); + break; + default: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id %ld unknown\n", cells_to_be_activated_list_itemExtIEs->id); + break; + } + } + } + return true; +} + +/* ==================================== + * F1 SETUP REQUEST + * ==================================== */ + +/** + * @brief F1 SETUP REQUEST encoding (9.2.1.4 of 3GPP TS 38.473) + * gNB-DU → gNB-CU + */ +F1AP_F1AP_PDU_t *encode_f1ap_setup_request(const f1ap_setup_req_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Create */ + /* 0. pdu Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, initMsg); + initMsg->procedureCode = F1AP_ProcedureCode_id_F1Setup; + initMsg->criticality = F1AP_Criticality_reject; + initMsg->value.present = F1AP_InitiatingMessage__value_PR_F1SetupRequest; + F1AP_F1SetupRequest_t *f1Setup = &initMsg->value.choice.F1SetupRequest; + // Transaction ID (M) + asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ieC1); + ieC1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ieC1->criticality = F1AP_Criticality_reject; + ieC1->value.present = F1AP_F1SetupRequestIEs__value_PR_TransactionID; + ieC1->value.choice.TransactionID = msg->transaction_id; + // gNB-DU ID (M) + asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ieC2); + ieC2->id = F1AP_ProtocolIE_ID_id_gNB_DU_ID; + ieC2->criticality = F1AP_Criticality_reject; + ieC2->value.present = F1AP_F1SetupRequestIEs__value_PR_GNB_DU_ID; + asn_int642INTEGER(&ieC2->value.choice.GNB_DU_ID, msg->gNB_DU_id); + // gNB-DU Name (O) + if (msg->gNB_DU_name) { + asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ieC3); + ieC3->id = F1AP_ProtocolIE_ID_id_gNB_DU_Name; + ieC3->criticality = F1AP_Criticality_ignore; + ieC3->value.present = F1AP_F1SetupRequestIEs__value_PR_GNB_DU_Name; + OCTET_STRING_fromBuf(&ieC3->value.choice.GNB_DU_Name, msg->gNB_DU_name, strlen(msg->gNB_DU_name)); + } + /// gNB-DU Served Cells List (0..1) + asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ieCells); + ieCells->id = F1AP_ProtocolIE_ID_id_gNB_DU_Served_Cells_List; + ieCells->criticality = F1AP_Criticality_reject; + ieCells->value.present = F1AP_F1SetupRequestIEs__value_PR_GNB_DU_Served_Cells_List; + for (int i = 0; i < msg->num_cells_available; i++) { + // gNB-DU Served Cells Item (M) + const f1ap_served_cell_info_t *cell = &msg->cell[i].info; + const f1ap_gnb_du_system_info_t *sys_info = msg->cell[i].sys_info; + asn1cSequenceAdd(ieCells->value.choice.GNB_DU_Served_Cells_List.list, F1AP_GNB_DU_Served_Cells_ItemIEs_t, duServedCell); + duServedCell->id = F1AP_ProtocolIE_ID_id_GNB_DU_Served_Cells_Item; + duServedCell->criticality = F1AP_Criticality_reject; + duServedCell->value.present = F1AP_GNB_DU_Served_Cells_ItemIEs__value_PR_GNB_DU_Served_Cells_Item; + F1AP_GNB_DU_Served_Cells_Item_t *scell_item = &duServedCell->value.choice.GNB_DU_Served_Cells_Item; + scell_item->served_Cell_Information = encode_served_cell_info(cell); + scell_item->gNB_DU_System_Information = encode_system_info(sys_info); + } + // gNB-DU RRC version (M) + asn1cSequenceAdd(f1Setup->protocolIEs.list, F1AP_F1SetupRequestIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_F1SetupRequestIEs__value_PR_RRC_Version; + // RRC Version: "This IE is not used in this release." + // we put one bit for each byte in rrc_ver that is != 0 + uint8_t bits = 0; + for (int i = 0; i < sizeofArray(msg->rrc_ver); ++i) + bits |= (msg->rrc_ver[i] != 0) << i; + BIT_STRING_t *bs = &ie2->value.choice.RRC_Version.latest_RRC_Version; + bs->buf = calloc_or_fail(1, sizeof(*bs->buf)); + bs->buf[0] = bits; + bs->size = 1; + bs->bits_unused = 5; + + F1AP_ProtocolExtensionContainer_10696P228_t *p = calloc_or_fail(1, sizeof(*p)); + asn1cSequenceAdd(p->list, F1AP_RRC_Version_ExtIEs_t, rrcv_ext); + rrcv_ext->id = F1AP_ProtocolIE_ID_id_latest_RRC_Version_Enhanced; + rrcv_ext->criticality = F1AP_Criticality_ignore; + rrcv_ext->extensionValue.present = F1AP_RRC_Version_ExtIEs__extensionValue_PR_OCTET_STRING_SIZE_3_; + OCTET_STRING_t *os = &rrcv_ext->extensionValue.choice.OCTET_STRING_SIZE_3_; + os->size = sizeofArray(msg->rrc_ver); + os->buf = malloc_or_fail(sizeof(msg->rrc_ver)); + for (int i = 0; i < sizeofArray(msg->rrc_ver); ++i) + os->buf[i] = msg->rrc_ver[i]; + ie2->value.choice.RRC_Version.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; + return pdu; +} + +/** + * @brief F1AP Setup Request decoding + */ +bool decode_f1ap_setup_request(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_req_t *out) +{ + /* Check presence of message type */ + _F1_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_initiatingMessage); + AssertError(pdu->choice.initiatingMessage != NULL, return false, "pdu->choice.initiatingMessage is NULL"); + _F1_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, F1AP_ProcedureCode_id_F1Setup); + _F1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, F1AP_InitiatingMessage__value_PR_F1SetupRequest); + /* Check presence of mandatory IEs */ + F1AP_F1SetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.F1SetupRequest; + F1AP_F1SetupRequestIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, in, F1AP_ProtocolIE_ID_id_gNB_DU_ID, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupRequestIEs_t, ie, in, F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version, true); + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + AssertError(in->protocolIEs.list.array[i] != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: + // Transaction ID (M) + _F1_EQ_CHECK_INT(ie->value.present, F1AP_F1SetupRequestIEs__value_PR_TransactionID); + AssertError(ie->value.choice.TransactionID != -1, return false, "ie->value.choice.TransactionID is -1"); + out->transaction_id = ie->value.choice.TransactionID; + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_ID: + // gNB-DU ID (M) + _F1_EQ_CHECK_INT(ie->value.present, F1AP_F1SetupRequestIEs__value_PR_GNB_DU_ID); + asn_INTEGER2ulong(&ie->value.choice.GNB_DU_ID, &out->gNB_DU_id); + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_Name: { + const F1AP_GNB_DU_Name_t *du_name = &ie->value.choice.GNB_DU_Name; + out->gNB_DU_name = calloc_or_fail(du_name->size + 1, sizeof(*out->gNB_DU_name)); + strncpy(out->gNB_DU_name, (char *)du_name->buf, du_name->size); + break; + } + case F1AP_ProtocolIE_ID_id_gNB_DU_Served_Cells_List: + /* GNB_DU_Served_Cells_List */ + out->num_cells_available = ie->value.choice.GNB_DU_Served_Cells_List.list.count; + AssertError(out->num_cells_available > 0, return false, "at least 1 cell must be present"); + /* Loop over gNB-DU Served Cells Items */ + for (int i = 0; i < out->num_cells_available; i++) { + F1AP_GNB_DU_Served_Cells_Item_t *served_cells_item = + &(((F1AP_GNB_DU_Served_Cells_ItemIEs_t *)ie->value.choice.GNB_DU_Served_Cells_List.list.array[i]) + ->value.choice.GNB_DU_Served_Cells_Item); + // gNB-DU System Information (O) + struct F1AP_GNB_DU_System_Information *DUsi = served_cells_item->gNB_DU_System_Information; + if (DUsi != NULL) { + // System Information + out->cell[i].sys_info = calloc_or_fail(1, sizeof(*out->cell[i].sys_info)); + f1ap_gnb_du_system_info_t *sys_info = out->cell[i].sys_info; + /* mib */ + sys_info->mib = cp_octet_string(&DUsi->mIB_message, &sys_info->mib_length); + /* sib1 */ + sys_info->sib1 = cp_octet_string(&DUsi->sIB1_message, &sys_info->sib1_length); + } + /* Served Cell Information (M) */ + if (!decode_served_cell_info(&served_cells_item->served_Cell_Information, &out->cell[i].info)) + return false; + } + break; + case F1AP_ProtocolIE_ID_id_GNB_DU_RRC_Version: + /* gNB-DU RRC version (M) */ + if (ie->value.choice.RRC_Version.iE_Extensions) { + F1AP_ProtocolExtensionContainer_10696P228_t *ext = + (F1AP_ProtocolExtensionContainer_10696P228_t *)ie->value.choice.RRC_Version.iE_Extensions; + if (ext->list.count > 0) { + F1AP_RRC_Version_ExtIEs_t *rrcext = ext->list.array[0]; + OCTET_STRING_t *os = &rrcext->extensionValue.choice.OCTET_STRING_SIZE_3_; + DevAssert(os->size == sizeofArray(out->rrc_ver)); + for (int i = 0; i < os->size; ++i) + out->rrc_ver[i] = os->buf[i]; + } + } + break; + default: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id %ld unknown\n", ie->id); + break; + } + } + return true; +} + +static void copy_f1ap_served_cell_info(f1ap_served_cell_info_t *dest, const f1ap_served_cell_info_t *src) { + *dest = *src; + dest->mode = src->mode; + dest->tdd = src->tdd; + dest->fdd = src->fdd; + dest->plmn = src->plmn; + if (src->tac) { + dest->tac = malloc_or_fail(sizeof(*dest->tac)); + *dest->tac = *src->tac; + } + if (src->measurement_timing_config_len) { + dest->measurement_timing_config = calloc_or_fail(src->measurement_timing_config_len, sizeof(*dest->measurement_timing_config)); + memcpy(dest->measurement_timing_config, src->measurement_timing_config, src->measurement_timing_config_len); + } +} + +/** + * @brief F1AP Setup Request deep copy + */ +f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg) +{ + f1ap_setup_req_t cp = {0}; + /* gNB_DU_id */ + cp.gNB_DU_id = msg->gNB_DU_id; + /* gNB_DU_name */ + if (msg->gNB_DU_name != NULL) + cp.gNB_DU_name = strdup(msg->gNB_DU_name); + /* transaction_id */ + cp.transaction_id = msg->transaction_id; + /* num_cells_available */ + cp.num_cells_available = msg->num_cells_available; + for (int n = 0; n < msg->num_cells_available; n++) { + /* cell.info */ + f1ap_served_cell_info_t *sci = &cp.cell[n].info; + const f1ap_served_cell_info_t *msg_sci = &msg->cell[n].info; + copy_f1ap_served_cell_info(sci, msg_sci); + /* cell.sys_info */ + if (msg->cell[n].sys_info) { + f1ap_gnb_du_system_info_t *orig_sys_info = msg->cell[n].sys_info; + f1ap_gnb_du_system_info_t *copy_sys_info = calloc_or_fail(1, sizeof(*copy_sys_info)); + cp.cell[n].sys_info = copy_sys_info; + if (orig_sys_info->mib_length > 0) { + copy_sys_info->mib = calloc_or_fail(orig_sys_info->mib_length, sizeof(*copy_sys_info->mib)); + copy_sys_info->mib_length = orig_sys_info->mib_length; + memcpy(copy_sys_info->mib, orig_sys_info->mib, copy_sys_info->mib_length); + } + if (orig_sys_info->sib1_length > 0) { + copy_sys_info->sib1 = calloc_or_fail(orig_sys_info->sib1_length, sizeof(*copy_sys_info->sib1)); + copy_sys_info->sib1_length = orig_sys_info->sib1_length; + memcpy(copy_sys_info->sib1, orig_sys_info->sib1, copy_sys_info->sib1_length); + } + } + } + for (int i = 0; i < sizeofArray(msg->rrc_ver); i++) + cp.rrc_ver[i] = msg->rrc_ver[i]; + return cp; +} + +/** + * @brief F1AP Setup Request equality check + */ +bool eq_f1ap_setup_request(const f1ap_setup_req_t *a, const f1ap_setup_req_t *b) +{ + _F1_EQ_CHECK_LONG(a->gNB_DU_id, b->gNB_DU_id); + _F1_EQ_CHECK_STR(a->gNB_DU_name, b->gNB_DU_name); + _F1_EQ_CHECK_LONG(a->transaction_id, b->transaction_id); + _F1_EQ_CHECK_INT(a->num_cells_available, b->num_cells_available); + for (int i = 0; i < a->num_cells_available; i++) { + if (!eq_f1ap_cell_info(&a->cell[i].info, &b->cell[i].info)) + return false; + if (!eq_f1ap_sys_info(a->cell[i].sys_info, b->cell[i].sys_info)) + return false; + } + _F1_EQ_CHECK_LONG(sizeofArray(a->rrc_ver), sizeofArray(b->rrc_ver)); + for (int i = 0; i < sizeofArray(a->rrc_ver); i++) { + _F1_EQ_CHECK_INT(a->rrc_ver[i], b->rrc_ver[i]); + } + return true; +} + +/** + * @brief F1AP Setup Request memory management + */ +void free_f1ap_setup_request(const f1ap_setup_req_t *msg) +{ + DevAssert(msg != NULL); + free(msg->gNB_DU_name); + for (int i = 0; i < msg->num_cells_available; i++) { + free_f1ap_cell(&msg->cell[i].info, msg->cell[i].sys_info); + } +} + +/* ==================================== + * F1 Setup Response + * ==================================== */ + +/** + * @brief F1 Setup Response encoding (9.2.1.5 of 3GPP TS 38.473) + * gNB-CU → gNB-DU + */ +F1AP_F1AP_PDU_t *encode_f1ap_setup_response(const f1ap_setup_resp_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* Create */ + /* 0. Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_F1Setup; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_SuccessfulOutcome__value_PR_F1SetupResponse; + F1AP_F1SetupResponse_t *out = &pdu->choice.successfulOutcome->value.choice.F1SetupResponse; + // Transaction ID (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_F1SetupResponseIEs__value_PR_TransactionID; + ie1->value.choice.TransactionID = msg->transaction_id; + // gNB-CU Name (O) + if (msg->gNB_CU_name != NULL) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_CU_Name; + ie2->criticality = F1AP_Criticality_ignore; + ie2->value.present = F1AP_F1SetupResponseIEs__value_PR_GNB_CU_Name; + OCTET_STRING_fromBuf(&ie2->value.choice.GNB_CU_Name, msg->gNB_CU_name, strlen(msg->gNB_CU_name)); + } + // Cells to be Activated List (O) + for (int i = 0; i < msg->num_cells_to_activate; i++) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_F1SetupResponseIEs__value_PR_Cells_to_be_Activated_List; + asn1cSequenceAdd(ie3->value.choice.Cells_to_be_Activated_List.list, + F1AP_Cells_to_be_Activated_List_ItemIEs_t, + cells_to_be_activated_ies); + encode_cells_to_activate(&msg->cells_to_activate[i], cells_to_be_activated_ies); + } + // gNB-CU RRC version (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupResponseIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_F1SetupResponseIEs__value_PR_RRC_Version; + // RRC Version: "This IE is not used in this release." + // we put one bit for each byte in rrc_ver that is != 0 + uint8_t bits = 0; + for (int i = 0; i < sizeofArray(msg->rrc_ver); ++i) + bits |= (msg->rrc_ver[i] != 0) << i; + BIT_STRING_t *bs = &ie4->value.choice.RRC_Version.latest_RRC_Version; + bs->buf = calloc_or_fail(1, sizeof(*bs->buf)); + bs->buf[0] = bits; + bs->size = 1; + bs->bits_unused = 5; + + F1AP_ProtocolExtensionContainer_10696P228_t *p = calloc_or_fail(1, sizeof(*p)); + asn1cSequenceAdd(p->list, F1AP_RRC_Version_ExtIEs_t, rrcv_ext); + rrcv_ext->id = F1AP_ProtocolIE_ID_id_latest_RRC_Version_Enhanced; + rrcv_ext->criticality = F1AP_Criticality_ignore; + rrcv_ext->extensionValue.present = F1AP_RRC_Version_ExtIEs__extensionValue_PR_OCTET_STRING_SIZE_3_; + OCTET_STRING_t *os = &rrcv_ext->extensionValue.choice.OCTET_STRING_SIZE_3_; + os->size = sizeofArray(msg->rrc_ver); + os->buf = malloc_or_fail(sizeof(msg->rrc_ver)); + for (int i = 0; i < sizeofArray(msg->rrc_ver); ++i) + os->buf[i] = msg->rrc_ver[i]; + ie4->value.choice.RRC_Version.iE_Extensions = (struct F1AP_ProtocolExtensionContainer *)p; + + return pdu; +} + +/** + * @brief F1 Setup Response decoding (9.2.1.5 of 3GPP TS 38.473) + * gNB-CU → gNB-DU + */ +bool decode_f1ap_setup_response(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_resp_t *out) +{ + /* Check presence of message type */ + _F1_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_successfulOutcome); + _F1_EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, F1AP_ProcedureCode_id_F1Setup); + _F1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, F1AP_SuccessfulOutcome__value_PR_F1SetupResponse); + /* Check presence of mandatory IEs */ + F1AP_F1SetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.F1SetupResponse; + F1AP_F1SetupResponseIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_F1SetupResponseIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupResponseIEs_t, ie, in, F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version, true); + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: + // Transaction ID (M) + _F1_EQ_CHECK_INT(ie->value.present, F1AP_F1SetupResponseIEs__value_PR_TransactionID); + AssertError(ie->value.choice.TransactionID != -1, return false, "ie->value.choice.TransactionID is -1"); + out->transaction_id = ie->value.choice.TransactionID; + break; + + case F1AP_ProtocolIE_ID_id_gNB_CU_Name: { + // gNB-CU Name (O) + _F1_EQ_CHECK_INT(ie->value.present, F1AP_F1SetupResponseIEs__value_PR_GNB_CU_Name); + const F1AP_GNB_CU_Name_t *cu_name = &ie->value.choice.GNB_CU_Name; + out->gNB_CU_name = calloc_or_fail(cu_name->size + 1, sizeof(*out->gNB_CU_name)); + strncpy(out->gNB_CU_name, (char *)cu_name->buf, cu_name->size); + } break; + + case F1AP_ProtocolIE_ID_id_GNB_CU_RRC_Version: + // gNB-CU RRC version (M) + _F1_EQ_CHECK_INT(ie->value.present, F1AP_F1SetupResponseIEs__value_PR_RRC_Version); + // RRC Version: "This IE is not used in this release." + if (ie->value.choice.RRC_Version.iE_Extensions) { + F1AP_ProtocolExtensionContainer_10696P228_t *ext = + (F1AP_ProtocolExtensionContainer_10696P228_t *)ie->value.choice.RRC_Version.iE_Extensions; + if (ext->list.count > 0) { + F1AP_RRC_Version_ExtIEs_t *rrcext = ext->list.array[0]; + OCTET_STRING_t *os = &rrcext->extensionValue.choice.OCTET_STRING_SIZE_3_; + for (int i = 0; i < sizeofArray(out->rrc_ver); i++) + out->rrc_ver[i] = os->buf[i]; + } + } + break; + + case F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List: { + // Cells to be Activated List (O) + if (ie->value.present != F1AP_F1SetupResponseIEs__value_PR_Cells_to_be_Activated_List) + break; + struct F1AP_Cells_to_be_Activated_List *Cells_to_be_Activated_List = &ie->value.choice.Cells_to_be_Activated_List; + out->num_cells_to_activate = Cells_to_be_Activated_List->list.count; + // Loop Cells to be Activated List Items (count >= 1) + AssertError(out->num_cells_to_activate > 0, return false, "At least 1 cell must be present"); + for (int i = 0; i < out->num_cells_to_activate; i++) { + const F1AP_Cells_to_be_Activated_List_ItemIEs_t *itemIEs + = (F1AP_Cells_to_be_Activated_List_ItemIEs_t *)Cells_to_be_Activated_List->list.array[i]; + if (!decode_cells_to_activate(&out->cells_to_activate[i], itemIEs)) + return false; + } + break; + } + default: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id %ld unknown\n", ie->id); + break; + } + } + + return true; +} + +/** + * @brief F1AP Setup Response equality check + */ +bool eq_f1ap_setup_response(const f1ap_setup_resp_t *a, const f1ap_setup_resp_t *b) +{ + _F1_EQ_CHECK_STR(a->gNB_CU_name, b->gNB_CU_name); + _F1_EQ_CHECK_INT(a->num_cells_to_activate, b->num_cells_to_activate); + _F1_EQ_CHECK_LONG(a->transaction_id, b->transaction_id); + if (a->num_cells_to_activate) { + for (int i = 0; i < a->num_cells_to_activate; i++) { + const served_cells_to_activate_t *a_cell = &a->cells_to_activate[i]; + const served_cells_to_activate_t *b_cell = &b->cells_to_activate[i]; + _F1_EQ_CHECK_LONG(a_cell->nr_cellid, b_cell->nr_cellid); + _F1_EQ_CHECK_INT(a_cell->nrpci, b_cell->nrpci); + _F1_EQ_CHECK_INT(a_cell->num_SI, b_cell->num_SI); + _F1_EQ_CHECK_LONG(a_cell->nr_cellid, b_cell->nr_cellid); + if (!eq_f1ap_plmn(&a_cell->plmn, &b_cell->plmn)) + return false; + if (sizeofArray(a->cells_to_activate[i].SI_msg) != sizeofArray(b->cells_to_activate[i].SI_msg)) + return false; + for (int j = 0; j < b->cells_to_activate[i].num_SI; j++) { + const f1ap_sib_msg_t *a_SI_msg = &a->cells_to_activate[i].SI_msg[j]; + const f1ap_sib_msg_t *b_SI_msg = &b->cells_to_activate[i].SI_msg[j]; + _F1_EQ_CHECK_INT(*a_SI_msg->SI_container, *b_SI_msg->SI_container); + _F1_EQ_CHECK_INT(a_SI_msg->SI_container_length, b_SI_msg->SI_container_length); + _F1_EQ_CHECK_INT(a_SI_msg->SI_type, b_SI_msg->SI_type); + } + } + } + _F1_EQ_CHECK_LONG(sizeofArray(a->rrc_ver), sizeofArray(b->rrc_ver)); + for (int i = 0; i < sizeofArray(a->rrc_ver); i++) { + _F1_EQ_CHECK_INT(a->rrc_ver[i], b->rrc_ver[i]); + } + return true; +} + +/** + * @brief F1AP Setup Response deep copy + */ +f1ap_setup_resp_t cp_f1ap_setup_response(const f1ap_setup_resp_t *msg) +{ + f1ap_setup_resp_t cp = {0}; + /* gNB_CU_name */ + if (msg->gNB_CU_name != NULL) + cp.gNB_CU_name = strdup(msg->gNB_CU_name); + /* transaction_id */ + cp.transaction_id = msg->transaction_id; + /* num_cells_available */ + cp.num_cells_to_activate = msg->num_cells_to_activate; + for (int n = 0; n < msg->num_cells_to_activate; n++) { + /* cell.info */ + served_cells_to_activate_t *cp_cell = &cp.cells_to_activate[n]; + const served_cells_to_activate_t *msg_cell = &msg->cells_to_activate[n]; + cp_cell->nr_cellid = msg_cell->nr_cellid; + cp_cell->nrpci = msg_cell->nrpci; + cp_cell->num_SI = msg_cell->num_SI; + cp_cell->plmn = msg_cell->plmn; + for (int j = 0; j < cp_cell->num_SI; j++) { + f1ap_sib_msg_t *cp_SI_msg = &cp_cell->SI_msg[j]; + const f1ap_sib_msg_t *b_SI_msg = &msg_cell->SI_msg[j]; + cp_SI_msg->SI_container_length = b_SI_msg->SI_container_length; + cp_SI_msg->SI_container = malloc_or_fail(cp_SI_msg->SI_container_length); + *cp_SI_msg->SI_container = *b_SI_msg->SI_container; + cp_SI_msg->SI_type = b_SI_msg->SI_type; + } + } + for (int i = 0; i < sizeofArray(msg->rrc_ver); i++) + cp.rrc_ver[i] = msg->rrc_ver[i]; + return cp; +} + +/** + * @brief F1AP Setup Response memory management + */ +void free_f1ap_setup_response(const f1ap_setup_resp_t *msg) +{ + DevAssert(msg != NULL); + free(msg->gNB_CU_name); + for (int i = 0; i < msg->num_cells_to_activate; i++) + for (int j = 0; j < msg->cells_to_activate[i].num_SI; j++) + if (msg->cells_to_activate[i].SI_msg[j].SI_container_length > 0) + free(msg->cells_to_activate[i].SI_msg[j].SI_container); +} + +/* ==================================== + * F1AP Setup Failure + * ==================================== */ + +/** + * @brief F1AP Setup Failure encoding + */ +F1AP_F1AP_PDU_t *encode_f1ap_setup_failure(const f1ap_setup_failure_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + /* Create */ + /* 0. Message Type */ + asn1cCalloc(pdu->choice.unsuccessfulOutcome, UnsuccessfulOutcome); + pdu->present = F1AP_F1AP_PDU_PR_unsuccessfulOutcome; + UnsuccessfulOutcome->procedureCode = F1AP_ProcedureCode_id_F1Setup; + UnsuccessfulOutcome->criticality = F1AP_Criticality_reject; + UnsuccessfulOutcome->value.present = F1AP_UnsuccessfulOutcome__value_PR_F1SetupFailure; + F1AP_F1SetupFailure_t *out = &pdu->choice.unsuccessfulOutcome->value.choice.F1SetupFailure; + /* mandatory */ + /* c1. Transaction ID (integer value)*/ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupFailureIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_F1SetupFailureIEs__value_PR_TransactionID; + ie1->value.choice.TransactionID = msg->transaction_id; + /* mandatory */ + /* c2. Cause */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupFailureIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_Cause; + ie2->criticality = F1AP_Criticality_ignore; + ie2->value.present = F1AP_F1SetupFailureIEs__value_PR_Cause; + ie2->value.choice.Cause.present = F1AP_Cause_PR_radioNetwork; + ie2->value.choice.Cause.choice.radioNetwork = msg->cause; + /* optional */ + /* c3. TimeToWait */ + if (msg->time_to_wait > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupFailureIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_TimeToWait; + ie3->criticality = F1AP_Criticality_ignore; + ie3->value.present = F1AP_F1SetupFailureIEs__value_PR_TimeToWait; + ie3->value.choice.TimeToWait = F1AP_TimeToWait_v10s; + } + /* optional */ + /* c4. CriticalityDiagnostics*/ + if (msg->criticality_diagnostics) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_F1SetupFailureIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_CriticalityDiagnostics; + ie4->criticality = F1AP_Criticality_ignore; + ie4->value.present = F1AP_F1SetupFailureIEs__value_PR_CriticalityDiagnostics; + asn1cCallocOne(ie4->value.choice.CriticalityDiagnostics.procedureCode, F1AP_ProcedureCode_id_UEContextSetup); + asn1cCallocOne(ie4->value.choice.CriticalityDiagnostics.triggeringMessage, F1AP_TriggeringMessage_initiating_message); + asn1cCallocOne(ie4->value.choice.CriticalityDiagnostics.procedureCriticality, F1AP_Criticality_reject); + asn1cCallocOne(ie4->value.choice.CriticalityDiagnostics.transactionID, 0); + } + return pdu; +} + +/** + * @brief F1AP Setup Failure decoding + */ +bool decode_f1ap_setup_failure(const F1AP_F1AP_PDU_t *pdu, f1ap_setup_failure_t *out) +{ + F1AP_F1SetupFailureIEs_t *ie; + F1AP_F1SetupFailure_t *in = &pdu->choice.unsuccessfulOutcome->value.choice.F1SetupFailure; + /* Check presence of mandatory IEs */ + F1AP_LIB_FIND_IE(F1AP_F1SetupFailureIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + F1AP_LIB_FIND_IE(F1AP_F1SetupFailureIEs_t, ie, in, F1AP_ProtocolIE_ID_id_Cause, true); + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: + /* Transaction ID (M) */ + out->transaction_id = ie->value.choice.TransactionID; + break; + case F1AP_ProtocolIE_ID_id_Cause: + /* Cause (M) */ + out->cause = ie->value.choice.Cause.choice.radioNetwork; + break; + case F1AP_ProtocolIE_ID_id_TimeToWait: + out->time_to_wait = ie->value.choice.TimeToWait; + break; + case F1AP_ProtocolIE_ID_id_CriticalityDiagnostics: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_CriticalityDiagnostics is not supported"); + break; + default: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id %ld unknown\n", ie->id); + break; + } + } + return true; +} + +/** + * @brief F1AP Setup Failure equality check + */ +bool eq_f1ap_setup_failure(const f1ap_setup_failure_t *a, const f1ap_setup_failure_t *b) +{ + if (a->transaction_id != b->transaction_id) + return false; + return true; +} + +/** + * @brief F1AP Setup Failure deep copy + */ +f1ap_setup_failure_t cp_f1ap_setup_failure(const f1ap_setup_failure_t *msg) +{ + f1ap_setup_failure_t cp = {0}; + /* transaction_id */ + cp.transaction_id = msg->transaction_id; + return cp; +} + +/* ==================================== + * F1AP gNB-DU Configuration Update + * ==================================== */ + +/** + * @brief F1 gNB-DU Configuration Update encoding (9.2.1.7 of 3GPP TS 38.473) + */ +F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + /* Create */ + /* 0. Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, initMsg); + initMsg->procedureCode = F1AP_ProcedureCode_id_gNBDUConfigurationUpdate; + initMsg->criticality = F1AP_Criticality_reject; + initMsg->value.present = F1AP_InitiatingMessage__value_PR_GNBDUConfigurationUpdate; + F1AP_GNBDUConfigurationUpdate_t *out = &initMsg->value.choice.GNBDUConfigurationUpdate; + /* mandatory */ + /* c1. Transaction ID (integer value) */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_TransactionID; + ie1->value.choice.TransactionID = msg->transaction_id; + /* mandatory */ + /* c2. Served_Cells_To_Add */ + if (msg->num_cells_to_add > 0) { + AssertFatal(false, "code for adding cells not tested\n"); + asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Add_List; + + for (int j = 0; j < msg->num_cells_to_add; j++) { + const f1ap_served_cell_info_t *cell = &msg->cell_to_add[j].info; + const f1ap_gnb_du_system_info_t *sys_info = msg->cell_to_add[j].sys_info; + asn1cSequenceAdd(ie2->value.choice.Served_Cells_To_Add_List.list, + F1AP_Served_Cells_To_Add_ItemIEs_t, + served_cells_to_add_item_ies); + served_cells_to_add_item_ies->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_Item; + served_cells_to_add_item_ies->criticality = F1AP_Criticality_reject; + served_cells_to_add_item_ies->value.present = F1AP_Served_Cells_To_Add_ItemIEs__value_PR_Served_Cells_To_Add_Item; + F1AP_Served_Cells_To_Add_Item_t *served_cells_to_add_item = + &served_cells_to_add_item_ies->value.choice.Served_Cells_To_Add_Item; + served_cells_to_add_item->served_Cell_Information = encode_served_cell_info(cell); + served_cells_to_add_item->gNB_DU_System_Information = encode_system_info(sys_info); + } + } + + /* mandatory */ + /* c3. Served_Cells_To_Modify */ + if (msg->num_cells_to_modify > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Modify_List; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Modify_List; + for (int i = 0; i < msg->num_cells_to_modify; i++) { + const f1ap_served_cell_info_t *cell = &msg->cell_to_modify[i].info; + const f1ap_gnb_du_system_info_t *sys_info = msg->cell_to_modify[i].sys_info; + asn1cSequenceAdd(ie3->value.choice.Served_Cells_To_Modify_List.list, + F1AP_Served_Cells_To_Modify_ItemIEs_t, + served_cells_to_modify_item_ies); + served_cells_to_modify_item_ies->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Modify_Item; + served_cells_to_modify_item_ies->criticality = F1AP_Criticality_reject; + served_cells_to_modify_item_ies->value.present = F1AP_Served_Cells_To_Modify_ItemIEs__value_PR_Served_Cells_To_Modify_Item; + F1AP_Served_Cells_To_Modify_Item_t *served_cells_to_modify_item = + &served_cells_to_modify_item_ies->value.choice.Served_Cells_To_Modify_Item; + + F1AP_NRCGI_t *oldNRCGI = &served_cells_to_modify_item->oldNRCGI; + const f1ap_plmn_t *old_plmn = &msg->cell_to_modify[i].old_plmn; + MCC_MNC_TO_PLMNID(old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length, &oldNRCGI->pLMN_Identity); + NR_CELL_ID_TO_BIT_STRING(msg->cell_to_modify[i].old_nr_cellid, &oldNRCGI->nRCellIdentity); + + served_cells_to_modify_item->served_Cell_Information = encode_served_cell_info(cell); + served_cells_to_modify_item->gNB_DU_System_Information = encode_system_info(sys_info); + } + } + + /* mandatory */ + /* c4. Served_Cells_To_Delete */ + if (msg->num_cells_to_delete > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_Served_Cells_To_Delete_List; + AssertFatal(msg->num_cells_to_delete == 0, "code for deleting cells not tested\n"); + for (int i = 0; i < msg->num_cells_to_delete; i++) { + asn1cSequenceAdd(ie4->value.choice.Served_Cells_To_Delete_List.list, + F1AP_Served_Cells_To_Delete_ItemIEs_t, + served_cells_to_delete_item_ies); + served_cells_to_delete_item_ies->id = F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_Item; + served_cells_to_delete_item_ies->criticality = F1AP_Criticality_reject; + served_cells_to_delete_item_ies->value.present = F1AP_Served_Cells_To_Delete_ItemIEs__value_PR_Served_Cells_To_Delete_Item; + F1AP_Served_Cells_To_Delete_Item_t *served_cells_to_delete_item = + &served_cells_to_delete_item_ies->value.choice.Served_Cells_To_Delete_Item; + F1AP_NRCGI_t *oldNRCGI = &served_cells_to_delete_item->oldNRCGI; + const f1ap_plmn_t *plmn = &msg->cell_to_delete[i].plmn; + MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &(oldNRCGI->pLMN_Identity)); + NR_CELL_ID_TO_BIT_STRING(msg->cell_to_delete[i].nr_cellid, &(oldNRCGI->nRCellIdentity)); + } + } + + /* optional */ + /* c5. GNB_DU_ID (integer value) */ + if (msg->gNB_DU_ID != NULL) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBDUConfigurationUpdateIEs_t, ie5); + ie5->id = F1AP_ProtocolIE_ID_id_gNB_DU_ID; + ie5->criticality = F1AP_Criticality_reject; + ie5->value.present = F1AP_GNBDUConfigurationUpdateIEs__value_PR_GNB_DU_ID; + asn_int642INTEGER(&ie5->value.choice.GNB_DU_ID, *msg->gNB_DU_ID); + } + + return pdu; +} + +/** + * @brief F1 gNB-DU Configuration Update decoding (9.2.1.7 of 3GPP TS 38.473) + */ +bool decode_f1ap_du_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_du_configuration_update_t *out) +{ + /* Check presence of message type */ + _F1_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_initiatingMessage); + _F1_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, F1AP_ProcedureCode_id_gNBDUConfigurationUpdate); + _F1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, F1AP_InitiatingMessage__value_PR_GNBDUConfigurationUpdate); + /* Check presence of mandatory IEs */ + F1AP_GNBDUConfigurationUpdate_t *in = &pdu->choice.initiatingMessage->value.choice.GNBDUConfigurationUpdate; + F1AP_GNBDUConfigurationUpdateIEs_t *ie; + /* Check mandatory IEs */ + F1AP_LIB_FIND_IE(F1AP_GNBDUConfigurationUpdateIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + AssertError(in->protocolIEs.list.array[i] != NULL, return false, "in->protocolIEs.list.array[i] is NULL"); + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: { + out->transaction_id = ie->value.choice.TransactionID; + } break; + case F1AP_ProtocolIE_ID_id_Served_Cells_To_Add_List: { + /* Served Cells To Add List */ + AssertError(out->num_cells_to_add > 0, return false, "at least 1 cell to add shall to be present"); + out->num_cells_to_add = ie->value.choice.Served_Cells_To_Add_List.list.count; + for (int i = 0; i < out->num_cells_to_add; i++) { + F1AP_Served_Cells_To_Add_Item_t *served_cells_item = + &((F1AP_Served_Cells_To_Add_ItemIEs_t *)ie->value.choice.Served_Cells_To_Add_List.list.array[i]) + ->value.choice.Served_Cells_To_Add_Item; + /* Served Cell Information (M) */ + if (!decode_served_cell_info(&served_cells_item->served_Cell_Information, &out->cell_to_add[i].info)) + return false; + /* gNB-DU System Information */ + if (served_cells_item->gNB_DU_System_Information != NULL) { + out->cell_to_add[i].sys_info = calloc_or_fail(1, sizeof(*out->cell_to_add[i].sys_info)); + decode_system_info(served_cells_item->gNB_DU_System_Information, out->cell_to_add[i].sys_info); + } + } + } break; + case F1AP_ProtocolIE_ID_id_Served_Cells_To_Modify_List: { + /* Served Cells To Modify List (O) */ + out->num_cells_to_modify = ie->value.choice.Served_Cells_To_Modify_List.list.count; + AssertError(out->num_cells_to_modify > 0, return false, "at least 1 cell to modify shall to be present"); + for (int i = 0; i < out->num_cells_to_modify; i++) { + /* Served Cells To Modify List item (count >= 1) */ + F1AP_Served_Cells_To_Modify_Item_t *served_cells_item = + &((F1AP_Served_Cells_To_Modify_ItemIEs_t *)ie->value.choice.Served_Cells_To_Modify_List.list.array[i]) + ->value.choice.Served_Cells_To_Modify_Item; + /* Old NR CGI (M) */ + F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI; + f1ap_plmn_t *old_plmn = &out->cell_to_modify[i].old_plmn; + TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), old_plmn->mcc, old_plmn->mnc, old_plmn->mnc_digit_length); + /* Old NR CGI Cell ID */ + BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_modify[i].old_nr_cellid); + /* Served Cell Information (M) */ + if (!decode_served_cell_info(&served_cells_item->served_Cell_Information, &out->cell_to_modify[i].info)) + return false; + /* gNB-DU System Information (O) */ + if (served_cells_item->gNB_DU_System_Information != NULL) { + out->cell_to_modify[i].sys_info = calloc_or_fail(1, sizeof(*out->cell_to_modify[i].sys_info)); + decode_system_info(served_cells_item->gNB_DU_System_Information, out->cell_to_modify[i].sys_info); + } + } + } break; + case F1AP_ProtocolIE_ID_id_Served_Cells_To_Delete_List: { + /* Served Cells To Delete List */ + out->num_cells_to_delete = ie->value.choice.Served_Cells_To_Delete_List.list.count; + AssertError(out->num_cells_to_delete > 0, return false, "at least 1 cell to delete shall to be present"); + for (int i = 0; i < out->num_cells_to_delete; i++) { + F1AP_Served_Cells_To_Delete_Item_t *served_cells_item = + &((F1AP_Served_Cells_To_Delete_ItemIEs_t *)ie->value.choice.Served_Cells_To_Delete_List.list.array[i]) + ->value.choice.Served_Cells_To_Delete_Item; + F1AP_NRCGI_t *oldNRCGI = &served_cells_item->oldNRCGI; + f1ap_plmn_t *plmn = &out->cell_to_delete[i].plmn; + /* Old NR CGI (M) */ + TBCD_TO_MCC_MNC(&(oldNRCGI->pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length); + // NR cellID + BIT_STRING_TO_NR_CELL_IDENTITY(&oldNRCGI->nRCellIdentity, out->cell_to_delete[i].nr_cellid); + } + } break; + case F1AP_ProtocolIE_ID_id_Cells_Status_List: + /* Cells Status List (O) */ + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_Cells_Status_List is not supported"); + break; + case F1AP_ProtocolIE_ID_id_Dedicated_SIDelivery_NeededUE_List: + /* Dedicated SI Delivery Needed UE List (O) */ + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_Dedicated_SIDelivery_NeededUE_List is not supported"); + break; + case F1AP_ProtocolIE_ID_id_gNB_DU_ID: + /* gNB-DU ID (O)*/ + asn_INTEGER2ulong(&ie->value.choice.GNB_DU_ID, out->gNB_DU_ID); + break; + case F1AP_ProtocolIE_ID_id_GNB_DU_TNL_Association_To_Remove_List: + /* Cells Status List (O) */ + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id_GNB_DU_TNL_Association_To_Remove_List is not supported"); + break; + } + } + return true; +} + +void free_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *msg) +{ + free(msg->gNB_DU_ID); + for (int i = 0; i < msg->num_cells_to_add; i++) { + free_f1ap_cell(&msg->cell_to_add[i].info, msg->cell_to_add[i].sys_info); + } + for (int i = 0; i < msg->num_cells_to_modify; i++) { + free_f1ap_cell(&msg->cell_to_modify[i].info, msg->cell_to_modify[i].sys_info); + } +} + +/** + * @brief F1 gNB-DU Configuration Update check + */ +bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a, const f1ap_gnb_du_configuration_update_t *b) +{ + if (a->gNB_DU_ID != NULL && b->gNB_DU_ID != NULL) + _F1_EQ_CHECK_LONG(*a->gNB_DU_ID, *b->gNB_DU_ID); + _F1_EQ_CHECK_LONG(a->transaction_id, b->transaction_id); + /* to add */ + _F1_EQ_CHECK_INT(a->num_cells_to_add, b->num_cells_to_add); + for (int i = 0; i < a->num_cells_to_add; i++) { + if (!eq_f1ap_cell_info(&a->cell_to_add[i].info, &b->cell_to_add[i].info)) + return false; + if (a->cell_to_add[i].sys_info && b->cell_to_add[i].sys_info) { + if (!eq_f1ap_sys_info(a->cell_to_add[i].sys_info, b->cell_to_add[i].sys_info)) + return false; + } + } + /* to delete */ + _F1_EQ_CHECK_INT(a->num_cells_to_delete, b->num_cells_to_delete); + for (int i = 0; i < a->num_cells_to_delete; i++) { + _F1_EQ_CHECK_LONG(a->cell_to_delete[i].nr_cellid, b->cell_to_delete[i].nr_cellid); + if (!eq_f1ap_plmn(&a->cell_to_delete[i].plmn, &b->cell_to_delete[i].plmn)) + return false; + } + /* to modify */ + _F1_EQ_CHECK_INT(a->num_cells_to_modify, b->num_cells_to_modify); + for (int i = 0; i < a->num_cells_to_modify; i++) { + if (!eq_f1ap_cell_info(&a->cell_to_modify[i].info, &b->cell_to_modify[i].info)) + return false; + if (a->cell_to_modify[i].sys_info && b->cell_to_modify[i].sys_info) { + if (!eq_f1ap_sys_info(a->cell_to_modify[i].sys_info, b->cell_to_modify[i].sys_info)) + return false; + } + } + return true; +} + +/** + * @brief F1 gNB-DU Configuration Update deep copy + */ +f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *msg) +{ + f1ap_gnb_du_configuration_update_t cp = {0}; + /* gNB_DU_ID */ + if (msg->gNB_DU_ID != NULL) { + cp.gNB_DU_ID = calloc_or_fail(1, sizeof(*cp.gNB_DU_ID)); + *cp.gNB_DU_ID = *msg->gNB_DU_ID; + } + /* transaction_id */ + cp.transaction_id = msg->transaction_id; + /* to add */ + cp.num_cells_to_add = msg->num_cells_to_add; + /* to delete */ + cp.num_cells_to_delete = msg->num_cells_to_delete; + for (int i = 0; i < cp.num_cells_to_delete; i++) { + cp.cell_to_delete[i].nr_cellid = msg->cell_to_delete[i].nr_cellid; + cp.cell_to_delete[i].plmn = msg->cell_to_delete[i].plmn; + } + /* to modify */ + cp.num_cells_to_modify = msg->num_cells_to_modify; + for (int i = 0; i < cp.num_cells_to_modify; i++) { + cp.cell_to_modify[i].info = msg->cell_to_modify[i].info; + f1ap_served_cell_info_t *info = &cp.cell_to_modify[i].info; + if (info->measurement_timing_config_len > 0) { + info->measurement_timing_config = malloc_or_fail(info->measurement_timing_config_len * sizeof(*info->measurement_timing_config)); + for (int j = 0; j < info->measurement_timing_config_len; j++) + info->measurement_timing_config[j] = msg->cell_to_modify[i].info.measurement_timing_config[j]; + } + /* TAC */ + info->tac = calloc_or_fail(1, sizeof(*info->tac)); + *info->tac = *msg->cell_to_modify[i].info.tac; + /* System information */ + cp.cell_to_modify[i].sys_info = malloc_or_fail(sizeof(*cp.cell_to_modify[i].sys_info)); + f1ap_gnb_du_system_info_t *sys_info = cp.cell_to_modify[i].sys_info; + if (msg->cell_to_modify[i].sys_info->mib_length > 0) { + sys_info->mib_length = msg->cell_to_modify[i].sys_info->mib_length; + sys_info->mib = calloc_or_fail(msg->cell_to_modify[i].sys_info->mib_length, sizeof(*sys_info->mib)); + for (int j = 0; j < sys_info->mib_length; j++) + sys_info->mib[j] = msg->cell_to_modify[i].sys_info->mib[j]; + } + if (msg->cell_to_modify[i].sys_info->sib1_length > 0) { + sys_info->sib1_length = msg->cell_to_modify[i].sys_info->sib1_length; + sys_info->sib1 = calloc_or_fail(msg->cell_to_modify[i].sys_info->sib1_length, sizeof(*sys_info->sib1)); + for (int j = 0; j < sys_info->sib1_length; j++) + sys_info->sib1[j] = msg->cell_to_modify[i].sys_info->sib1[j]; + } + } + return cp; +} + +/* ==================================== + * F1AP gNB-CU Configuration Update + * ==================================== */ + +/** + * @brief F1 gNB-CU Configuration Update encoding (9.2.1.10 of 3GPP TS 38.473) + */ +F1AP_F1AP_PDU_t *encode_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + /* Create + 0. Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, initMsg); + initMsg->procedureCode = F1AP_ProcedureCode_id_gNBCUConfigurationUpdate; + initMsg->criticality = F1AP_Criticality_reject; + initMsg->value.present = F1AP_InitiatingMessage__value_PR_GNBCUConfigurationUpdate; + F1AP_GNBCUConfigurationUpdate_t *cfgUpdate = &pdu->choice.initiatingMessage->value.choice.GNBCUConfigurationUpdate; + /* mandatory + c1. Transaction ID (integer value) */ + asn1cSequenceAdd(cfgUpdate->protocolIEs.list, F1AP_GNBCUConfigurationUpdateIEs_t, ieC1); + ieC1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ieC1->criticality = F1AP_Criticality_reject; + ieC1->value.present = F1AP_GNBCUConfigurationUpdateIEs__value_PR_TransactionID; + ieC1->value.choice.TransactionID = msg->transaction_id; + /* optional + c2. Cells_to_be_Activated_List (O) */ + for (int i = 0; i < msg->num_cells_to_activate; i++) { + asn1cSequenceAdd(cfgUpdate->protocolIEs.list, F1AP_GNBCUConfigurationUpdateIEs_t, ieC3); + ieC3->id = F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List; + ieC3->criticality = F1AP_Criticality_reject; + ieC3->value.present = F1AP_GNBCUConfigurationUpdateIEs__value_PR_Cells_to_be_Activated_List; + asn1cSequenceAdd(ieC3->value.choice.Cells_to_be_Activated_List.list, + F1AP_Cells_to_be_Activated_List_ItemIEs_t, + cells_to_be_activated_ies); + encode_cells_to_activate(&msg->cells_to_activate[i], cells_to_be_activated_ies); + } + return pdu; +} + +/** + * @brief F1 gNB-CU Configuration Update decoding (9.2.1.10 of 3GPP TS 38.473) + */ +bool decode_f1ap_cu_configuration_update(const F1AP_F1AP_PDU_t *pdu, f1ap_gnb_cu_configuration_update_t *out) +{ + /* Check presence of message type */ + _F1_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_initiatingMessage); + AssertError(pdu->choice.initiatingMessage != NULL, return false, "pdu->choice.initiatingMessage is NULL"); + _F1_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, F1AP_ProcedureCode_id_gNBCUConfigurationUpdate); + _F1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, F1AP_InitiatingMessage__value_PR_GNBCUConfigurationUpdate); + /* Check presence of mandatory IEs */ + F1AP_GNBCUConfigurationUpdate_t *in = &pdu->choice.initiatingMessage->value.choice.GNBCUConfigurationUpdate; + F1AP_GNBCUConfigurationUpdateIEs_t *ie; + F1AP_LIB_FIND_IE(F1AP_GNBCUConfigurationUpdateIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_GNBCUConfigurationUpdateIEs__value_PR_TransactionID); + AssertError(ie->value.choice.TransactionID != -1, return false, "ie->value.choice.TransactionID is -1"); + out->transaction_id = ie->value.choice.TransactionID; + break; + case F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List: { + /* Cells to be Activated List (O) */ + _F1_EQ_CHECK_INT(ie->value.present, F1AP_GNBCUConfigurationUpdateIEs__value_PR_Cells_to_be_Activated_List); + /* Cells to be Activated List Item (count >= 1) */ + F1AP_Cells_to_be_Activated_List_t *Cells_to_be_Activated_List = &ie->value.choice.Cells_to_be_Activated_List; + out->num_cells_to_activate = Cells_to_be_Activated_List->list.count; + AssertError(out->num_cells_to_activate > 0, return false, "At least 1 cell to activate must be present"); + for (int i = 0; i < out->num_cells_to_activate; i++) { + if (!decode_cells_to_activate(&out->cells_to_activate[i], + (F1AP_Cells_to_be_Activated_List_ItemIEs_t *)Cells_to_be_Activated_List->list.array[i])) + return false; + } + break; + } + default: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id %ld unknown\n", ie->id); + break; + } + } + return true; +} + +void free_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *msg) +{ + for (int i = 0; i < msg->num_cells_to_activate; i++) + for (int j = 0; j < msg->cells_to_activate[j].num_SI; j++) + free(msg->cells_to_activate[i].SI_msg[j].SI_container); +} + +/** + * @brief F1 gNB-CU Configuration Update check + */ +bool eq_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *a, const f1ap_gnb_cu_configuration_update_t *b) +{ + _F1_EQ_CHECK_LONG(a->transaction_id, b->transaction_id); + /* to activate */ + _F1_EQ_CHECK_INT(a->num_cells_to_activate, b->num_cells_to_activate); + for (int i = 0; i < a->num_cells_to_activate; i++) { + _F1_EQ_CHECK_LONG(a->cells_to_activate[i].nr_cellid, b->cells_to_activate[i].nr_cellid); + _F1_EQ_CHECK_INT(a->cells_to_activate[i].nrpci, b->cells_to_activate[i].nrpci); + if (!eq_f1ap_plmn(&a->cells_to_activate[i].plmn, &b->cells_to_activate[i].plmn)) + return false; + _F1_EQ_CHECK_INT(a->cells_to_activate[i].num_SI, b->cells_to_activate[i].num_SI); + for (int s = 0; s < a->cells_to_activate[i].num_SI; s++) { + _F1_EQ_CHECK_INT(*a->cells_to_activate[i].SI_msg[s].SI_container, *a->cells_to_activate[i].SI_msg[s].SI_container); + _F1_EQ_CHECK_INT(a->cells_to_activate[i].SI_msg[s].SI_container_length, a->cells_to_activate[i].SI_msg[s].SI_container_length); + _F1_EQ_CHECK_INT(a->cells_to_activate[i].SI_msg[s].SI_type, a->cells_to_activate[i].SI_msg[s].SI_type); + } + } + return true; +} + +/** + * @brief F1 gNB-CU Configuration Update deep copy + */ +f1ap_gnb_cu_configuration_update_t cp_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *msg) +{ + f1ap_gnb_cu_configuration_update_t cp = {0}; + /* transaction_id */ + cp.transaction_id = msg->transaction_id; + cp.num_cells_to_activate = msg->num_cells_to_activate; + for (int i = 0; i < cp.num_cells_to_activate; i++) { + cp.cells_to_activate[i] = msg->cells_to_activate[i]; + for (int s = 0; s < cp.cells_to_activate[i].num_SI; s++) { + cp.cells_to_activate[i].SI_msg[s] = msg->cells_to_activate[i].SI_msg[s]; + f1ap_sib_msg_t *SI_msg = &cp.cells_to_activate[i].SI_msg[s]; + SI_msg->SI_container = calloc_or_fail(SI_msg->SI_container_length, sizeof(*SI_msg->SI_container)); + for (int j = 0; j < SI_msg->SI_container_length; j++) + SI_msg->SI_container[j] = msg->cells_to_activate[i].SI_msg[s].SI_container[j]; + } + } + return cp; +} + +/* ==================================== + * F1AP gNB-CU Configuration Ack + * ==================================== */ + +/** + * @brief F1 gNB-CU Configuration Update Acknowledge message encoding (9.2.1.11 of 3GPP TS 38.473) + * gNB-DU → gNB-CU + */ +F1AP_F1AP_PDU_t *encode_f1ap_cu_configuration_update_acknowledge(const f1ap_gnb_cu_configuration_update_acknowledge_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + /* Create */ + /* 0. pdu Type */ + pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_gNBCUConfigurationUpdate; + tmp->criticality = F1AP_Criticality_reject; + tmp->value.present = F1AP_SuccessfulOutcome__value_PR_GNBCUConfigurationUpdateAcknowledge; + F1AP_GNBCUConfigurationUpdateAcknowledge_t *out = &tmp->value.choice.GNBCUConfigurationUpdateAcknowledge; + // Transaction ID (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBCUConfigurationUpdateAcknowledgeIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_GNBCUConfigurationUpdateAcknowledgeIEs__value_PR_TransactionID; + ie1->value.choice.TransactionID = msg->transaction_id; + // Cells Failed to be Activated List (0..1) + if (msg->num_cells_failed_to_be_activated > 0) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_GNBCUConfigurationUpdateAcknowledgeIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_Cells_Failed_to_be_Activated_List; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_GNBCUConfigurationUpdateAcknowledgeIEs__value_PR_Cells_Failed_to_be_Activated_List; + F1AP_Cells_Failed_to_be_Activated_List_t *failedCellsList = &ie2->value.choice.Cells_Failed_to_be_Activated_List; + for (int i = 0; i < msg->num_cells_failed_to_be_activated; i++) { + asn1cSequenceAdd(failedCellsList->list, F1AP_Cells_Failed_to_be_Activated_List_ItemIEs_t, failedCellIE); + failedCellIE->id = F1AP_ProtocolIE_ID_id_Cells_Failed_to_be_Activated_List_Item; + failedCellIE->criticality = F1AP_Criticality_reject; + failedCellIE->value.present = F1AP_Cells_Failed_to_be_Activated_List_ItemIEs__value_PR_Cells_Failed_to_be_Activated_List_Item; + F1AP_Cells_Failed_to_be_Activated_List_Item_t *p1 = &failedCellIE->value.choice.Cells_Failed_to_be_Activated_List_Item; + // Cause (M) + p1->cause.present = F1AP_Cause_PR_radioNetwork; + p1->cause.choice.radioNetwork = msg->cells_failed_to_be_activated[i].cause; + // NR CGI (M) + const f1ap_plmn_t *plmn = &msg->cells_failed_to_be_activated[i].plmn; + MCC_MNC_TO_PLMNID(plmn->mcc, plmn->mnc, plmn->mnc_digit_length, &(p1->nRCGI.pLMN_Identity)); + printf("plmn->mcc %d %d %d %ld \n", + p1->nRCGI.pLMN_Identity.buf[0], p1->nRCGI.pLMN_Identity.buf[1], p1->nRCGI.pLMN_Identity.buf[2], p1->nRCGI.pLMN_Identity.size); + NR_CELL_ID_TO_BIT_STRING(msg->cells_failed_to_be_activated[i].nr_cellid, &(p1->nRCGI.nRCellIdentity)); + } + } + return pdu; +} + +/** + * @brief F1 gNB-CU Configuration Update Acknowledge decoding (9.2.1.11 of 3GPP TS 38.473) + */ +bool decode_f1ap_cu_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu, + f1ap_gnb_cu_configuration_update_acknowledge_t *out) +{ + /* Message type */ + _F1_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_successfulOutcome); + AssertError(pdu->choice.successfulOutcome != NULL, return false, "pdu->choice.successfulOutcome is NULL"); + _F1_EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, F1AP_ProcedureCode_id_gNBCUConfigurationUpdate); + _F1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, + F1AP_SuccessfulOutcome__value_PR_GNBCUConfigurationUpdateAcknowledge); + /* payload */ + F1AP_GNBCUConfigurationUpdateAcknowledge_t *in = &pdu->choice.successfulOutcome->value.choice.GNBCUConfigurationUpdateAcknowledge; + F1AP_GNBCUConfigurationUpdateAcknowledgeIEs_t *ie; + /* Check mandatory IEs */ + F1AP_LIB_FIND_IE(F1AP_GNBCUConfigurationUpdateAcknowledgeIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_GNBCUConfigurationUpdateAcknowledgeIEs__value_PR_TransactionID); + AssertError(ie->value.choice.TransactionID != -1, return false, "ie->value.choice.TransactionID is -1"); + out->transaction_id = ie->value.choice.TransactionID; + break; + case F1AP_ProtocolIE_ID_id_Cells_Failed_to_be_Activated_List: { + /* Decode Cells Failed to be Activated List */ + _F1_EQ_CHECK_INT(ie->value.present, + F1AP_GNBCUConfigurationUpdateAcknowledgeIEs__value_PR_Cells_Failed_to_be_Activated_List); + F1AP_Cells_Failed_to_be_Activated_List_t *cell_fail_list = &ie->value.choice.Cells_Failed_to_be_Activated_List; + out->num_cells_failed_to_be_activated = cell_fail_list->list.count; + for (int j = 0; j < out->num_cells_failed_to_be_activated; j++) { + const F1AP_Cells_Failed_to_be_Activated_List_ItemIEs_t *itemIE = + (F1AP_Cells_Failed_to_be_Activated_List_ItemIEs_t *)cell_fail_list->list.array[j]; + const F1AP_Cells_Failed_to_be_Activated_List_Item_t *item = &itemIE->value.choice.Cells_Failed_to_be_Activated_List_Item; + // NR CGI (M) + f1ap_plmn_t *plmn = &out->cells_failed_to_be_activated[j].plmn; + TBCD_TO_MCC_MNC(&(item->nRCGI.pLMN_Identity), plmn->mcc, plmn->mnc, plmn->mnc_digit_length); + BIT_STRING_TO_NR_CELL_IDENTITY(&item->nRCGI.nRCellIdentity, out->cells_failed_to_be_activated[j].nr_cellid); + // Cause (M) + switch (item->cause.present) { + case F1AP_Cause_PR_radioNetwork: + out->cells_failed_to_be_activated[j].cause = item->cause.choice.radioNetwork; + break; + case F1AP_Cause_PR_transport: + out->cells_failed_to_be_activated[j].cause = item->cause.choice.transport; + break; + case F1AP_Cause_PR_protocol: + out->cells_failed_to_be_activated[j].cause = item->cause.choice.protocol; + break; + case F1AP_Cause_PR_misc: + out->cells_failed_to_be_activated[j].cause = item->cause.choice.misc; + break; + default: + AssertError(1 == 0, return false, "Unknown cause type %d\n", item->cause.present); + break; + } + } + break; + } + default: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id %ld unknown\n", ie->id); + break; + } + } + return true; +} + +/** + * @brief F1 gNB-CU Configuration Update Acknowledge check + */ +bool eq_f1ap_cu_configuration_update_acknowledge(const f1ap_gnb_cu_configuration_update_acknowledge_t *a, + const f1ap_gnb_cu_configuration_update_acknowledge_t *b) +{ + // Transaction ID + _F1_EQ_CHECK_LONG(a->transaction_id, b->transaction_id); + // number of cells failed to be activated + _F1_EQ_CHECK_INT(a->num_cells_failed_to_be_activated, b->num_cells_failed_to_be_activated); + for (int i = 0; i < a->num_cells_failed_to_be_activated; i++) { + if (!eq_f1ap_plmn(&a->cells_failed_to_be_activated[i].plmn, &b->cells_failed_to_be_activated[i].plmn)) + return false; + _F1_EQ_CHECK_LONG(a->cells_failed_to_be_activated[i].nr_cellid, b->cells_failed_to_be_activated[i].nr_cellid); + _F1_EQ_CHECK_INT(a->cells_failed_to_be_activated[i].cause, b->cells_failed_to_be_activated[i].cause); + } + // TNL Associations to setup + _F1_EQ_CHECK_INT(a->noofTNLAssociations_to_setup, b->noofTNLAssociations_to_setup); + for (int i = 0; i < a->noofTNLAssociations_to_setup; i++) { + // Explicit comparison of TNL Association fields + _F1_EQ_CHECK_INT(a->tnlAssociations_to_setup[i].tl_address, b->tnlAssociations_to_setup[i].tl_address); + _F1_EQ_CHECK_INT(a->tnlAssociations_to_setup[i].port, b->tnlAssociations_to_setup[i].port); + } + // TNL Associations failed to setup + _F1_EQ_CHECK_INT(a->noofTNLAssociations_failed, b->noofTNLAssociations_failed); + for (int i = 0; i < a->noofTNLAssociations_failed; i++) { + // Explicit comparison of TNL Association fields + _F1_EQ_CHECK_INT(a->tnlAssociations_failed[i].tl_address, b->tnlAssociations_failed[i].tl_address); + _F1_EQ_CHECK_INT(a->tnlAssociations_failed[i].port, b->tnlAssociations_failed[i].port); + } + // Dedicated SI Delivery Needed UE List + _F1_EQ_CHECK_INT(a->noofDedicatedSIDeliveryNeededUEs, b->noofDedicatedSIDeliveryNeededUEs); + for (int i = 0; i < a->noofDedicatedSIDeliveryNeededUEs; i++) { + _F1_EQ_CHECK_INT(a->dedicatedSIDeliveryNeededUEs[i].gNB_CU_ue_id, b->dedicatedSIDeliveryNeededUEs[i].gNB_CU_ue_id); + if (!eq_f1ap_plmn(&a->dedicatedSIDeliveryNeededUEs[i].ue_plmn, &b->dedicatedSIDeliveryNeededUEs[i].ue_plmn)) + return false; + _F1_EQ_CHECK_LONG(a->dedicatedSIDeliveryNeededUEs[i].ue_nr_cellid, b->dedicatedSIDeliveryNeededUEs[i].ue_nr_cellid); + } + return true; +} + +/** + * @brief F1 gNB-CU Configuration Update Acknowledge deep copy + */ +f1ap_gnb_cu_configuration_update_acknowledge_t cp_f1ap_cu_configuration_update_acknowledge( + const f1ap_gnb_cu_configuration_update_acknowledge_t *msg) +{ + f1ap_gnb_cu_configuration_update_acknowledge_t cp = {0}; + // Transaction ID + cp.transaction_id = msg->transaction_id; + // number of cells failed to be activated + cp.num_cells_failed_to_be_activated = msg->num_cells_failed_to_be_activated; + for (int i = 0; i < cp.num_cells_failed_to_be_activated; i++) + cp.cells_failed_to_be_activated[i] = msg->cells_failed_to_be_activated[i]; + // TNL Associations to setup + cp.noofTNLAssociations_to_setup = msg->noofTNLAssociations_to_setup; + for (int i = 0; i < cp.noofTNLAssociations_to_setup; i++) + cp.tnlAssociations_to_setup[i] = msg->tnlAssociations_to_setup[i]; + // TNL Associations failed to setup + cp.noofTNLAssociations_failed = msg->noofTNLAssociations_failed; + for (int i = 0; i < cp.noofTNLAssociations_failed; i++) + cp.tnlAssociations_failed[i] = msg->tnlAssociations_failed[i]; + // Dedicated SI Delivery Needed UE List + cp.noofDedicatedSIDeliveryNeededUEs = msg->noofDedicatedSIDeliveryNeededUEs; + for (int i = 0; i < cp.noofDedicatedSIDeliveryNeededUEs; i++) + cp.dedicatedSIDeliveryNeededUEs[i] = msg->dedicatedSIDeliveryNeededUEs[i]; + return cp; +} + +/* ================================== + * F1AP gNB-DU Configuration Ack + * ================================== */ + +/** + * @brief F1 gNB-DU Configuration Update Acknowledge message encoding (9.2.1.8 of 3GPP TS 38.473) + */ +F1AP_F1AP_PDU_t *encode_f1ap_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_update_acknowledge_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + /* Create */ + /* 0. Message */ + pdu->present = F1AP_F1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, succOut); + succOut->procedureCode = F1AP_ProcedureCode_id_gNBDUConfigurationUpdate; + succOut->criticality = F1AP_Criticality_reject; + succOut->value.present = F1AP_SuccessfulOutcome__value_PR_GNBDUConfigurationUpdateAcknowledge; + F1AP_GNBDUConfigurationUpdateAcknowledge_t *ack = &succOut->value.choice.GNBDUConfigurationUpdateAcknowledge; + /* Mandatory */ + /* Transaction Id */ + asn1cSequenceAdd(ack->protocolIEs.list, F1AP_GNBDUConfigurationUpdateAcknowledgeIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_TransactionID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_GNBDUConfigurationUpdateAcknowledgeIEs__value_PR_TransactionID; + ie1->value.choice.TransactionID = msg->transaction_id; + // Cells to be Activated List (O) + for (int i = 0; i < msg->num_cells_to_activate; i++) { + asn1cSequenceAdd(ack->protocolIEs.list, F1AP_GNBDUConfigurationUpdateAcknowledgeIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_GNBDUConfigurationUpdateAcknowledgeIEs__value_PR_Cells_to_be_Activated_List; + asn1cSequenceAdd(ie3->value.choice.Cells_to_be_Activated_List.list, + F1AP_Cells_to_be_Activated_List_ItemIEs_t, + cells_to_be_activated_ies); + encode_cells_to_activate(&msg->cells_to_activate[i], cells_to_be_activated_ies); + } + return pdu; +} + +/** + * @brief F1 gNB-DU Configuration Update Acknowledge decoding + */ +bool decode_f1ap_du_configuration_update_acknowledge(const F1AP_F1AP_PDU_t *pdu, + f1ap_gnb_du_configuration_update_acknowledge_t *out) +{ + /* message type */ + _F1_EQ_CHECK_INT(pdu->present, F1AP_F1AP_PDU_PR_successfulOutcome); + AssertError(pdu->choice.successfulOutcome != NULL, return false, "pdu->choice.successfulOutcome is NULL"); + _F1_EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, F1AP_ProcedureCode_id_gNBDUConfigurationUpdate); + _F1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, + F1AP_SuccessfulOutcome__value_PR_GNBDUConfigurationUpdateAcknowledge); + F1AP_GNBDUConfigurationUpdateAcknowledge_t *in = &pdu->choice.successfulOutcome->value.choice.GNBDUConfigurationUpdateAcknowledge; + F1AP_GNBDUConfigurationUpdateAcknowledgeIEs_t *ie; + /* Check mandatory IEs */ + F1AP_LIB_FIND_IE(F1AP_GNBDUConfigurationUpdateAcknowledgeIEs_t, ie, in, F1AP_ProtocolIE_ID_id_TransactionID, true); + /* Loop over all IEs */ + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + switch (ie->id) { + case F1AP_ProtocolIE_ID_id_TransactionID: + _F1_EQ_CHECK_INT(ie->value.present, F1AP_GNBDUConfigurationUpdateAcknowledgeIEs__value_PR_TransactionID); + AssertError(ie->value.choice.TransactionID != -1, return false, "ie->value.choice.TransactionID is -1"); + out->transaction_id = ie->value.choice.TransactionID; + break; + case F1AP_ProtocolIE_ID_id_Cells_to_be_Activated_List: { + /* Decode Cells Failed to be Activated List */ + _F1_EQ_CHECK_INT(ie->value.present, F1AP_GNBDUConfigurationUpdateAcknowledgeIEs__value_PR_Cells_to_be_Activated_List); + F1AP_Cells_to_be_Activated_List_t *list = &ie->value.choice.Cells_to_be_Activated_List; + out->num_cells_to_activate = list->list.count; + for (int j = 0; j < out->num_cells_to_activate; j++) { + const F1AP_Cells_to_be_Activated_List_ItemIEs_t *itemIE = + (F1AP_Cells_to_be_Activated_List_ItemIEs_t *)list->list.array[j]; + decode_cells_to_activate(&out->cells_to_activate[0], itemIE); + } + break; + } + default: + AssertError(1 == 0, return false, "F1AP_ProtocolIE_ID_id %ld unknown\n", ie->id); + break; + } + } + return true; +} + +/** + * @brief F1 gNB-DU Configuration Update Acknowledge equality check + */ +bool eq_f1ap_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_update_acknowledge_t *a, + const f1ap_gnb_du_configuration_update_acknowledge_t *b) +{ + // Transaction ID + _F1_EQ_CHECK_LONG(a->transaction_id, b->transaction_id); + // number of cells to activate + _F1_EQ_CHECK_INT(a->num_cells_to_activate, b->num_cells_to_activate); + // loop over cells to activate + for (int i = 0; i < a->num_cells_to_activate; i++) { + _F1_EQ_CHECK_LONG(a->cells_to_activate[i].nr_cellid, b->cells_to_activate[i].nr_cellid); + _F1_EQ_CHECK_INT(a->cells_to_activate[i].nrpci, b->cells_to_activate[i].nrpci); + if (!eq_f1ap_plmn(&a->cells_to_activate[i].plmn, &b->cells_to_activate[i].plmn)) + return false; + _F1_EQ_CHECK_INT(a->cells_to_activate[i].num_SI, b->cells_to_activate[i].num_SI); + for (int s = 0; s < a->cells_to_activate[i].num_SI; s++) { + _F1_EQ_CHECK_INT(*a->cells_to_activate[i].SI_msg[s].SI_container, *b->cells_to_activate[i].SI_msg[s].SI_container); + _F1_EQ_CHECK_INT(a->cells_to_activate[i].SI_msg[s].SI_container_length, + b->cells_to_activate[i].SI_msg[s].SI_container_length); + _F1_EQ_CHECK_INT(a->cells_to_activate[i].SI_msg[s].SI_type, b->cells_to_activate[i].SI_msg[s].SI_type); + } + } + return true; +} + +/** + * @brief F1 gNB-DU Configuration Update Acknowledge deep copy + */ +f1ap_gnb_du_configuration_update_acknowledge_t cp_f1ap_du_configuration_update_acknowledge( + const f1ap_gnb_du_configuration_update_acknowledge_t *msg) +{ + f1ap_gnb_du_configuration_update_acknowledge_t cp = {0}; + // Transaction ID + cp.transaction_id = msg->transaction_id; + // number of cells to activate + cp.num_cells_to_activate = msg->num_cells_to_activate; + // Loop through cells to activate + for (int i = 0; i < cp.num_cells_to_activate; i++) { + cp.cells_to_activate[i] = msg->cells_to_activate[i]; + for (int s = 0; s < cp.cells_to_activate[i].num_SI; s++) { + cp.cells_to_activate[i].SI_msg[s].SI_container = calloc_or_fail(1, sizeof(*cp.cells_to_activate[i].SI_msg[s].SI_container)); + *cp.cells_to_activate[i].SI_msg[s].SI_container = *msg->cells_to_activate[i].SI_msg[s].SI_container; + } + } + return cp; +} + +/** + * @brief gNB-DU Configuration Update Acknowledge memory management + */ +void free_f1ap_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_update_acknowledge_t *msg) +{ + // SI_container + for (int i = 0; i < msg->num_cells_to_activate; i++) { + for (int j = 0; j < msg->cells_to_activate[i].num_SI; j++) { + if (msg->cells_to_activate[i].SI_msg[j].SI_container) { + free(msg->cells_to_activate[i].SI_msg[j].SI_container); + } + } + } +} diff --git a/openair2/F1AP/lib/f1ap_interface_management.h b/openair2/F1AP/lib/f1ap_interface_management.h new file mode 100644 index 0000000000..bdceee9a61 --- /dev/null +++ b/openair2/F1AP/lib/f1ap_interface_management.h @@ -0,0 +1,82 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef F1AP_INTERFACE_MANAGEMENT_H_ +#define F1AP_INTERFACE_MANAGEMENT_H_ + +#include +#include "f1ap_messages_types.h" + +struct F1AP_F1AP_PDU; + +struct F1AP_F1AP_PDU *encode_f1ap_setup_request(const f1ap_setup_req_t *msg); +bool decode_f1ap_setup_request(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_req_t *out); +f1ap_setup_req_t cp_f1ap_setup_request(const f1ap_setup_req_t *msg); +bool eq_f1ap_setup_request(const f1ap_setup_req_t *a, const f1ap_setup_req_t *b); +void free_f1ap_setup_request(const f1ap_setup_req_t *msg); + +/* F1 Setup Response */ +struct F1AP_F1AP_PDU *encode_f1ap_setup_response(const f1ap_setup_resp_t *msg); +bool decode_f1ap_setup_response(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_resp_t *out); +void free_f1ap_setup_response(const f1ap_setup_resp_t *msg); +f1ap_setup_resp_t cp_f1ap_setup_response(const f1ap_setup_resp_t *msg); +bool eq_f1ap_setup_response(const f1ap_setup_resp_t *a, const f1ap_setup_resp_t *b); + +/* F1 Setup Failure */ +struct F1AP_F1AP_PDU *encode_f1ap_setup_failure(const f1ap_setup_failure_t *msg); +bool decode_f1ap_setup_failure(const struct F1AP_F1AP_PDU *pdu, f1ap_setup_failure_t *out); +bool eq_f1ap_setup_failure(const f1ap_setup_failure_t *a, const f1ap_setup_failure_t *b); +f1ap_setup_failure_t cp_f1ap_setup_failure(const f1ap_setup_failure_t *msg); + +/* F1 gNB-DU Configuration Update */ +struct F1AP_F1AP_PDU *encode_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *msg); +bool decode_f1ap_du_configuration_update(const struct F1AP_F1AP_PDU *pdu, f1ap_gnb_du_configuration_update_t *out); +bool eq_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *a, const f1ap_gnb_du_configuration_update_t *b); +f1ap_gnb_du_configuration_update_t cp_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *msg); +void free_f1ap_du_configuration_update(const f1ap_gnb_du_configuration_update_t *msg); + +/* F1 gNB-CU Configuration Update */ +struct F1AP_F1AP_PDU *encode_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *msg); +bool decode_f1ap_cu_configuration_update(const struct F1AP_F1AP_PDU *pdu, f1ap_gnb_cu_configuration_update_t *out); +bool eq_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *a, const f1ap_gnb_cu_configuration_update_t *b); +f1ap_gnb_cu_configuration_update_t cp_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *msg); +void free_f1ap_cu_configuration_update(const f1ap_gnb_cu_configuration_update_t *msg); + +/* F1 gNB-CU Configuration Update Acknowledge */ +struct F1AP_F1AP_PDU *encode_f1ap_cu_configuration_update_acknowledge(const f1ap_gnb_cu_configuration_update_acknowledge_t *msg); +bool decode_f1ap_cu_configuration_update_acknowledge(const struct F1AP_F1AP_PDU *pdu, + f1ap_gnb_cu_configuration_update_acknowledge_t *out); +bool eq_f1ap_cu_configuration_update_acknowledge(const f1ap_gnb_cu_configuration_update_acknowledge_t *a, + const f1ap_gnb_cu_configuration_update_acknowledge_t *b); +f1ap_gnb_cu_configuration_update_acknowledge_t cp_f1ap_cu_configuration_update_acknowledge( + const f1ap_gnb_cu_configuration_update_acknowledge_t *msg); + +/* F1 gNB-DU Configuration Update Acknowledge */ +struct F1AP_F1AP_PDU *encode_f1ap_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_update_acknowledge_t *msg); +bool decode_f1ap_du_configuration_update_acknowledge(const struct F1AP_F1AP_PDU *pdu, + f1ap_gnb_du_configuration_update_acknowledge_t *out); +bool eq_f1ap_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_update_acknowledge_t *a, + const f1ap_gnb_du_configuration_update_acknowledge_t *b); +f1ap_gnb_du_configuration_update_acknowledge_t cp_f1ap_du_configuration_update_acknowledge( + const f1ap_gnb_du_configuration_update_acknowledge_t *msg); +void free_f1ap_du_configuration_update_acknowledge(const f1ap_gnb_du_configuration_update_acknowledge_t *msg); + +#endif /* F1AP_INTERFACE_MANAGEMENT_H_ */ diff --git a/openair2/F1AP/lib/f1ap_lib_common.c b/openair2/F1AP/lib/f1ap_lib_common.c new file mode 100644 index 0000000000..edf48f426c --- /dev/null +++ b/openair2/F1AP/lib/f1ap_lib_common.c @@ -0,0 +1,117 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "f1ap_lib_common.h" +#include "f1ap_messages_types.h" + +#include "OCTET_STRING.h" +#include "common/utils/utils.h" +#include "common/utils/assertions.h" +#include "common/utils/utils.h" + +bool eq_f1ap_plmn(const f1ap_plmn_t *a, const f1ap_plmn_t *b) +{ + _F1_EQ_CHECK_INT(a->mcc, b->mcc); + _F1_EQ_CHECK_INT(a->mnc, b->mnc); + _F1_EQ_CHECK_INT(a->mnc_digit_length, b->mnc_digit_length); + return true; +} + +bool eq_f1ap_freq_info(const f1ap_nr_frequency_info_t *a, const f1ap_nr_frequency_info_t *b) +{ + if (a->arfcn != b->arfcn) + return false; + if (a->band != b->band) + return false; + return true; +} + +bool eq_f1ap_tx_bandwidth(const f1ap_transmission_bandwidth_t *a, const f1ap_transmission_bandwidth_t *b) +{ + if (a->nrb != b->nrb) + return false; + if (a->scs != b->scs) + return false; + return true; +} + +bool eq_f1ap_cell_info(const f1ap_served_cell_info_t *a, const f1ap_served_cell_info_t *b) +{ + if (a->nr_cellid != b->nr_cellid) + return false; + if (a->nr_pci != b->nr_pci) + return false; + if (*a->tac != *b->tac) + return false; + if (a->mode != b->mode) + return false; + if (a->mode == F1AP_MODE_TDD) { + /* TDD */ + if (!eq_f1ap_tx_bandwidth(&a->tdd.tbw, &b->tdd.tbw)) + return false; + if (!eq_f1ap_freq_info(&a->tdd.freqinfo, &b->tdd.freqinfo)) + return false; + } else if (a->mode == F1AP_MODE_FDD) { + /* FDD */ + if (!eq_f1ap_tx_bandwidth(&a->fdd.dl_tbw, &b->fdd.dl_tbw)) + return false; + if (!eq_f1ap_freq_info(&a->fdd.dl_freqinfo, &b->fdd.dl_freqinfo)) + return false; + if (!eq_f1ap_tx_bandwidth(&a->fdd.ul_tbw, &b->fdd.ul_tbw)) + return false; + if (!eq_f1ap_freq_info(&a->fdd.ul_freqinfo, &b->fdd.ul_freqinfo)) + return false; + } + if (a->measurement_timing_config_len != b->measurement_timing_config_len) + return false; + if (*a->measurement_timing_config != *b->measurement_timing_config) + return false; + if (!eq_f1ap_plmn(&a->plmn, &b->plmn)) + return false; + return true; +} + +bool eq_f1ap_sys_info(const f1ap_gnb_du_system_info_t *a, const f1ap_gnb_du_system_info_t *b) +{ + /* MIB */ + if (a->mib_length != b->mib_length) + return false; + for (int i = 0; i < a->mib_length; i++) { + if (a->mib[i] != b->mib[i]) + return false; + } + /* SIB1 */ + if (a->sib1_length != b->sib1_length) + return false; + for (int i = 0; i < a->sib1_length; i++) { + if (a->sib1[i] != b->sib1[i]) + return false; + } + return true; +} + +uint8_t *cp_octet_string(const OCTET_STRING_t *os, int *len) +{ + uint8_t *buf = calloc_or_fail(os->size, sizeof(*buf)); + memcpy(buf, os->buf, os->size); + *len = os->size; + return buf; +} diff --git a/openair2/F1AP/lib/f1ap_lib_common.h b/openair2/F1AP/lib/f1ap_lib_common.h new file mode 100644 index 0000000000..2380a2da87 --- /dev/null +++ b/openair2/F1AP/lib/f1ap_lib_common.h @@ -0,0 +1,85 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef F1AP_LIB_COMMON_H_ +#define F1AP_LIB_COMMON_H_ + +#include +#include +#include +#include "openair3/UTILS/conversions.h" + +#ifdef ENABLE_TESTS + #define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__) +#else + #define PRINT_ERROR(...) // Do nothing +#endif + +#define _F1_EQ_CHECK_GENERIC(condition, fmt, ...) \ + do { \ + if (!(condition)) { \ + PRINT_ERROR("F1 Equality Check failure: %s:%d: Condition '%s' failed: " fmt " != " fmt "\n", \ + __FILE__, \ + __LINE__, \ + #condition, \ + ##__VA_ARGS__); \ + return false; \ + } \ + } while (0) + +#define _F1_EQ_CHECK_LONG(A, B) _F1_EQ_CHECK_GENERIC(A == B, "%ld", A, B); +#define _F1_EQ_CHECK_INT(A, B) _F1_EQ_CHECK_GENERIC(A == B, "%d", A, B); +#define _F1_EQ_CHECK_STR(A, B) _F1_EQ_CHECK_GENERIC(strcmp(A, B) == 0, "'%s'", A, B); + +/* macro to look up IE. If mandatory and not found, macro will print + * descriptive debug message to stderr and force exit in calling function */ +#define F1AP_LIB_FIND_IE(IE_TYPE, ie, container, IE_ID, mandatory) \ + do { \ + ie = NULL; \ + for (IE_TYPE **ptr = container->protocolIEs.list.array; \ + ptr < &container->protocolIEs.list.array[container->protocolIEs.list.count]; \ + ptr++) { \ + if ((*ptr)->id == IE_ID) { \ + ie = *ptr; \ + break; \ + } \ + } \ + if (mandatory && ie == NULL) { \ + fprintf(stderr, "%s(): could not find element " #IE_ID " with type " #IE_TYPE "\n", __func__); \ + return false; \ + } \ + } while (0) + +struct f1ap_plmn_t; +bool eq_f1ap_plmn(const struct f1ap_plmn_t *a, const struct f1ap_plmn_t *b); +struct f1ap_served_cell_info_t; +bool eq_f1ap_cell_info(const struct f1ap_served_cell_info_t *a, const struct f1ap_served_cell_info_t *b); +struct f1ap_gnb_du_system_info_t; +bool eq_f1ap_sys_info(const struct f1ap_gnb_du_system_info_t *a, const struct f1ap_gnb_du_system_info_t *b); +struct f1ap_nr_frequency_info_t; +bool eq_f1ap_freq_info(const struct f1ap_nr_frequency_info_t *a, const struct f1ap_nr_frequency_info_t *b); +struct f1ap_transmission_bandwidth_t; +bool eq_f1ap_tx_bandwidth(const struct f1ap_transmission_bandwidth_t *a, const struct f1ap_transmission_bandwidth_t *b); + +struct OCTET_STRING; +uint8_t *cp_octet_string(const struct OCTET_STRING *os, int *len); + +#endif /* F1AP_LIB_COMMON_H_ */ diff --git a/openair2/F1AP/f1ap_cu_warning_message_transmission.h b/openair2/F1AP/lib/f1ap_lib_extern.h similarity index 81% rename from openair2/F1AP/f1ap_cu_warning_message_transmission.h rename to openair2/F1AP/lib/f1ap_lib_extern.h index b6bbedba2f..f95b685540 100644 --- a/openair2/F1AP/f1ap_cu_warning_message_transmission.h +++ b/openair2/F1AP/lib/f1ap_lib_extern.h @@ -19,13 +19,9 @@ * contact@openairinterface.org */ -/*! \file f1ap_du_interface_management.h - * \brief f1ap interface management for DU - * \author EURECOM/NTUST - * \date 2018 - * \version 0.1 - * \company Eurecom - * \email: navid.nikaein@eurecom.fr, bing-kai.hong@eurecom.fr - * \note - * \warning - */ \ No newline at end of file +#ifndef F1AP_LIB_EXTERN_H_ +#define F1AP_LIB_EXTERN_H_ + +#include "f1ap_rrc_message_transfer.h" + +#endif /* F1AP_LIB_EXTERN_H_ */ diff --git a/openair2/F1AP/f1ap_cu_warning_message_transmission.c b/openair2/F1AP/lib/f1ap_lib_includes.h similarity index 58% rename from openair2/F1AP/f1ap_cu_warning_message_transmission.c rename to openair2/F1AP/lib/f1ap_lib_includes.h index 725bb4e1af..6ff60a4897 100644 --- a/openair2/F1AP/f1ap_cu_warning_message_transmission.c +++ b/openair2/F1AP/lib/f1ap_lib_includes.h @@ -19,13 +19,26 @@ * contact@openairinterface.org */ -/*! \file f1ap_du_interface_management.h - * \brief f1ap interface management for DU - * \author EURECOM/NTUST - * \date 2018 - * \version 0.1 - * \company Eurecom - * \email: navid.nikaein@eurecom.fr, bing-kai.hong@eurecom.fr - * \note - * \warning - */ +#ifndef F1AP_LIB_INCLUDES_H_ +#define F1AP_LIB_INCLUDES_H_ + +#include "F1AP_F1AP-PDU.h" +#include "F1AP_InitialULRRCMessageTransfer.h" +#include "F1AP_InitiatingMessage.h" +#include "F1AP_NRCellIdentity.h" +#include "F1AP_ProtocolIE-Field.h" +#include "F1AP_ServedPLMNs-Item.h" +#include "F1AP_ProtocolExtensionContainer.h" +#include "F1AP_ProtocolExtensionField.h" +#include "F1AP_ProtocolIE-Field.h" +#include "F1AP_SliceSupportItem.h" +#include "F1AP_NR-Mode-Info.h" +#include "F1AP_GNB-DU-System-Information.h" +#include "F1AP_FDD-Info.h" +#include "F1AP_TDD-Info.h" +#include "F1AP_FreqBandNrItem.h" +#include "F1AP_SuccessfulOutcome.h" +#include "F1AP_SibtypetobeupdatedListItem.h" +#include "F1AP_UnsuccessfulOutcome.h" + +#endif /* F1AP_LIB_INCLUDES_H_ */ diff --git a/openair2/F1AP/lib/f1ap_rrc_message_transfer.c b/openair2/F1AP/lib/f1ap_rrc_message_transfer.c new file mode 100644 index 0000000000..5fc9e2d622 --- /dev/null +++ b/openair2/F1AP/lib/f1ap_rrc_message_transfer.c @@ -0,0 +1,479 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "f1ap_rrc_message_transfer.h" + +#include "f1ap_lib_common.h" +#include "f1ap_lib_includes.h" +#include "f1ap_messages_types.h" + +#include "common/utils/assertions.h" +#include "openair3/UTILS/conversions.h" +#include "common/utils/oai_asn1.h" +#include "common/utils/utils.h" + +/* ==================================== + * F1AP Initial UL RRC Message Transfer + * ==================================== */ + +/** + * @brief Initial UL RRC Message Transfer encoding + */ +F1AP_F1AP_PDU_t *encode_initial_ul_rrc_message_transfer(const f1ap_initial_ul_rrc_message_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + /* 0. Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_InitialULRRCMessageTransfer; + tmp->criticality = F1AP_Criticality_ignore; + tmp->value.present = F1AP_InitiatingMessage__value_PR_InitialULRRCMessageTransfer; + F1AP_InitialULRRCMessageTransfer_t *out = &tmp->value.choice.InitialULRRCMessageTransfer; + + /* mandatory */ + /* c1. GNB_DU_UE_F1AP_ID */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie1->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id; + + /* mandatory */ + /* c2. NRCGI */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_NRCGI; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_NRCGI; + MCC_MNC_TO_PLMNID(msg->plmn.mcc, msg->plmn.mnc, msg->plmn.mnc_digit_length, &ie2->value.choice.NRCGI.pLMN_Identity); + NR_CELL_ID_TO_BIT_STRING(msg->nr_cellid, &ie2->value.choice.NRCGI.nRCellIdentity); + + /* mandatory */ + /* c3. C_RNTI */ // 16 + asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_C_RNTI; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_C_RNTI; + ie3->value.choice.C_RNTI = msg->crnti; + + /* mandatory */ + /* c4. RRCContainer */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_RRCContainer; + OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, (const char *)msg->rrc_container, msg->rrc_container_length); + + /* optional */ + /* c5. DUtoCURRCContainer */ + if (msg->du2cu_rrc_container != NULL) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie5); + ie5->id = F1AP_ProtocolIE_ID_id_DUtoCURRCContainer; + ie5->criticality = F1AP_Criticality_reject; + ie5->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_DUtoCURRCContainer; + OCTET_STRING_fromBuf(&ie5->value.choice.DUtoCURRCContainer, + (const char *)msg->du2cu_rrc_container, + msg->du2cu_rrc_container_length); + } + + /* mandatory */ + /* c6. Transaction ID (integer value) */ + asn1cSequenceAdd(out->protocolIEs.list, F1AP_InitialULRRCMessageTransferIEs_t, ie6); + ie6->id = F1AP_ProtocolIE_ID_id_TransactionID; + ie6->criticality = F1AP_Criticality_ignore; + ie6->value.present = F1AP_InitialULRRCMessageTransferIEs__value_PR_TransactionID; + ie6->value.choice.TransactionID = msg->transaction_id; + + return pdu; +} + +/** + * @brief Initial UL RRC Message Transfer decoding + */ +bool decode_initial_ul_rrc_message_transfer(const F1AP_F1AP_PDU_t *pdu, f1ap_initial_ul_rrc_message_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + F1AP_InitialULRRCMessageTransfer_t *container = &pdu->choice.initiatingMessage->value.choice.InitialULRRCMessageTransfer; + F1AP_InitialULRRCMessageTransferIEs_t *ie; + + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_NRCGI, true); + PLMNID_TO_MCC_MNC(&ie->value.choice.NRCGI.pLMN_Identity, out->plmn.mcc, out->plmn.mnc, out->plmn.mnc_digit_length); + BIT_STRING_TO_NR_CELL_IDENTITY(&ie->value.choice.NRCGI.nRCellIdentity, out->nr_cellid); + + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_C_RNTI, true); + out->crnti = ie->value.choice.C_RNTI; + + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_RRCContainer, true); + out->rrc_container = cp_octet_string(&ie->value.choice.RRCContainer, &out->rrc_container_length); + + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_DUtoCURRCContainer, false); + if (ie != NULL) + out->du2cu_rrc_container = cp_octet_string(&ie->value.choice.DUtoCURRCContainer, &out->du2cu_rrc_container_length); + + F1AP_LIB_FIND_IE(F1AP_InitialULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_TransactionID, true); + out->transaction_id = ie->value.choice.TransactionID; + + return true; +} + +/** + * @brief Initial UL RRC Message Transfer deep copy + */ +f1ap_initial_ul_rrc_message_t cp_initial_ul_rrc_message_transfer(const f1ap_initial_ul_rrc_message_t *msg) +{ + uint8_t *rrc_container = calloc_or_fail(msg->rrc_container_length, sizeof(*rrc_container)); + memcpy(rrc_container, msg->rrc_container, msg->rrc_container_length); + uint8_t *du2cu_rrc_container = NULL; + if (msg->du2cu_rrc_container_length > 0) { + DevAssert(msg->du2cu_rrc_container != NULL); + du2cu_rrc_container = calloc_or_fail(msg->du2cu_rrc_container_length, sizeof(*du2cu_rrc_container)); + memcpy(du2cu_rrc_container, msg->du2cu_rrc_container, msg->du2cu_rrc_container_length); + } + f1ap_initial_ul_rrc_message_t cp = { + .gNB_DU_ue_id = msg->gNB_DU_ue_id, + .plmn = msg->plmn, + .nr_cellid = msg->nr_cellid, + .crnti = msg->crnti, + .rrc_container = rrc_container, + .rrc_container_length = msg->rrc_container_length, + .du2cu_rrc_container = du2cu_rrc_container, + .du2cu_rrc_container_length = msg->du2cu_rrc_container_length, + .transaction_id = msg->transaction_id + }; + return cp; +} + +/** + * @brief Initial UL RRC Message Transfer equality check + */ +bool eq_initial_ul_rrc_message_transfer(const f1ap_initial_ul_rrc_message_t *a, const f1ap_initial_ul_rrc_message_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + if (!eq_f1ap_plmn(&a->plmn, &b->plmn)) + return false; + _F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid); + _F1_EQ_CHECK_INT(a->crnti, b->crnti); + _F1_EQ_CHECK_INT(a->rrc_container_length, b->rrc_container_length); + _F1_EQ_CHECK_LONG(a->nr_cellid, b->nr_cellid); + if (memcmp(a->rrc_container, b->rrc_container, a->rrc_container_length) != 0) + return false; + _F1_EQ_CHECK_INT(a->du2cu_rrc_container_length, b->du2cu_rrc_container_length); + if (memcmp(a->du2cu_rrc_container, b->du2cu_rrc_container, a->du2cu_rrc_container_length) != 0) + return false; + _F1_EQ_CHECK_INT(a->transaction_id, b->transaction_id); + return true; +} + +/** + * @brief Initial UL RRC Message Transfer memory management + */ +void free_initial_ul_rrc_message_transfer(const f1ap_initial_ul_rrc_message_t *msg) +{ + DevAssert(msg != NULL); + free(msg->rrc_container); + free(msg->du2cu_rrc_container); +} + +/* ==================================== + * F1AP UL RRC Message Transfer + * ==================================== */ + +/** + * @brief UL RRC Message Transfer encoding (9.2.3.3 of 3GPP TS 38.473) + * gNB-DU → gNB-CU + */ +F1AP_F1AP_PDU_t *encode_ul_rrc_message_transfer(const f1ap_ul_rrc_message_t *msg) +{ + + F1AP_F1AP_PDU_t *pdu = calloc(1, sizeof(*pdu)); + AssertFatal(pdu != NULL, "out of memory\n"); + + /* Create */ + /* 0. Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_ULRRCMessageTransfer; + tmp->criticality = F1AP_Criticality_ignore; + tmp->value.present = F1AP_InitiatingMessage__value_PR_ULRRCMessageTransfer; + F1AP_ULRRCMessageTransfer_t *out = &tmp->value.choice.ULRRCMessageTransfer; + // gNB-CU UE F1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_ULRRCMessageTransferIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id; + // gNB-DU UE F1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_ULRRCMessageTransferIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id; + // SRB ID (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_ULRRCMessageTransferIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_SRBID; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_SRBID; + ie3->value.choice.SRBID = msg->srb_id; + // RRC-Container (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_ULRRCMessageTransferIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_RRCContainer; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_ULRRCMessageTransferIEs__value_PR_RRCContainer; + OCTET_STRING_fromBuf(&ie4->value.choice.RRCContainer, (const char *)msg->rrc_container, msg->rrc_container_length); + + return pdu; +} + +/** + * @brief UL RRC Message Transfer decoding (9.2.3.3 of 3GPP TS 38.473) + * gNB-DU → gNB-CU + */ +bool decode_ul_rrc_message_transfer(const F1AP_F1AP_PDU_t *pdu, f1ap_ul_rrc_message_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + DevAssert(pdu != NULL); + + F1AP_ULRRCMessageTransfer_t *container = &pdu->choice.initiatingMessage->value.choice.ULRRCMessageTransfer; + F1AP_ULRRCMessageTransferIEs_t *ie; + + // gNB-CU UE F1AP ID (M) + F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + // gNB-DU UE F1AP ID (M) + F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + // SRB ID (M) + F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_SRBID, true); + out->srb_id = ie->value.choice.SRBID; + // RRC-Container (M) + F1AP_LIB_FIND_IE(F1AP_ULRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_RRCContainer, true); + out->rrc_container = cp_octet_string(&ie->value.choice.RRCContainer, &out->rrc_container_length); + + return true; +} + +/** + * @brief UL RRC Message Transfer deep copy + */ +f1ap_ul_rrc_message_t cp_ul_rrc_message_transfer(const f1ap_ul_rrc_message_t *msg) +{ + uint8_t *rrc_container = calloc_or_fail(msg->rrc_container_length, sizeof(*rrc_container)); + memcpy(rrc_container, msg->rrc_container, msg->rrc_container_length); + f1ap_ul_rrc_message_t cp = { + .gNB_DU_ue_id = msg->gNB_DU_ue_id, + .gNB_CU_ue_id = msg->gNB_CU_ue_id, + .srb_id = msg->srb_id, + .rrc_container = rrc_container, + .rrc_container_length = msg->rrc_container_length, + }; + return cp; +} + +/** + * @brief UL RRC Message Transfer equality check + */ +bool eq_ul_rrc_message_transfer(const f1ap_ul_rrc_message_t *a, const f1ap_ul_rrc_message_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_INT(a->rrc_container_length, b->rrc_container_length); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + if (memcmp(a->rrc_container, b->rrc_container, a->rrc_container_length) != 0) + return false; + return true; +} + +/** + * @brief UL RRC Message Transfer memory management + */ +void free_ul_rrc_message_transfer(const f1ap_ul_rrc_message_t *msg) +{ + DevAssert(msg != NULL); + free(msg->rrc_container); +} + +/* ============================ + * F1AP DL RRC Message Transfer + * ============================ */ + +/** + * @brief DL RRC Message Transfer encoding (9.2.3.2 of 3GPP TS 38.473) + * gNB-CU → gNB-DU + */ +F1AP_F1AP_PDU_t *encode_dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *msg) +{ + F1AP_F1AP_PDU_t *pdu = calloc(1, sizeof(*pdu)); + AssertFatal(pdu != NULL, "out of memory\n"); + + /* Create */ + /* 0. Message Type */ + pdu->present = F1AP_F1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, tmp); + tmp->procedureCode = F1AP_ProcedureCode_id_DLRRCMessageTransfer; + tmp->criticality = F1AP_Criticality_ignore; + tmp->value.present = F1AP_InitiatingMessage__value_PR_DLRRCMessageTransfer; + F1AP_DLRRCMessageTransfer_t *out = &tmp->value.choice.DLRRCMessageTransfer; + // gNB-CU UE F1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie1); + ie1->id = F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID; + ie1->criticality = F1AP_Criticality_reject; + ie1->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_GNB_CU_UE_F1AP_ID; + ie1->value.choice.GNB_CU_UE_F1AP_ID = msg->gNB_CU_ue_id; + // gNB-DU UE F1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie2); + ie2->id = F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID; + ie2->criticality = F1AP_Criticality_reject; + ie2->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID; + ie2->value.choice.GNB_DU_UE_F1AP_ID = msg->gNB_DU_ue_id; + // old gNB-DU UE F1AP ID (O) + if (msg->old_gNB_DU_ue_id) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie3); + ie3->id = F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID; + ie3->criticality = F1AP_Criticality_reject; + ie3->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_GNB_DU_UE_F1AP_ID_1; + ie3->value.choice.GNB_DU_UE_F1AP_ID_1 = *msg->old_gNB_DU_ue_id; + } + // SRB ID (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie4); + ie4->id = F1AP_ProtocolIE_ID_id_SRBID; + ie4->criticality = F1AP_Criticality_reject; + ie4->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_SRBID; + ie4->value.choice.SRBID = msg->srb_id; + // Execute Duplication (O) + if (msg->execute_duplication) { + asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie5); + ie5->id = F1AP_ProtocolIE_ID_id_ExecuteDuplication; + ie5->criticality = F1AP_Criticality_ignore; + ie5->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_ExecuteDuplication; + ie5->value.choice.ExecuteDuplication = F1AP_ExecuteDuplication_true; + } + // RRC-Container (M) + asn1cSequenceAdd(out->protocolIEs.list, F1AP_DLRRCMessageTransferIEs_t, ie6); + ie6->id = F1AP_ProtocolIE_ID_id_RRCContainer; + ie6->criticality = F1AP_Criticality_reject; + ie6->value.present = F1AP_DLRRCMessageTransferIEs__value_PR_RRCContainer; + OCTET_STRING_fromBuf(&ie6->value.choice.RRCContainer, (const char *)msg->rrc_container, msg->rrc_container_length); + + return pdu; +} + +/** + * @brief DL RRC Message Transfer decoding (9.2.3.2 of 3GPP TS 38.473) + * gNB-CU → gNB-DU + */ +bool decode_dl_rrc_message_transfer(const F1AP_F1AP_PDU_t *pdu, f1ap_dl_rrc_message_t *out) +{ + DevAssert(out != NULL); + memset(out, 0, sizeof(*out)); + + DevAssert(pdu != NULL); + F1AP_DLRRCMessageTransfer_t *container = &pdu->choice.initiatingMessage->value.choice.DLRRCMessageTransfer; + F1AP_DLRRCMessageTransferIEs_t *ie; + // gNB-CU UE F1AP ID (M) + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_CU_UE_F1AP_ID, true); + out->gNB_CU_ue_id = ie->value.choice.GNB_CU_UE_F1AP_ID; + // gNB-DU UE F1AP ID (M) + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_gNB_DU_UE_F1AP_ID, true); + out->gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID; + // old gNB-DU UE F1AP ID (O) + out->old_gNB_DU_ue_id = NULL; + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_oldgNB_DU_UE_F1AP_ID, false); + if (ie) { + out->old_gNB_DU_ue_id = malloc_or_fail(sizeof(*out->old_gNB_DU_ue_id)); + *out->old_gNB_DU_ue_id = ie->value.choice.GNB_DU_UE_F1AP_ID_1; + } + // SRB ID (M) + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_SRBID, true); + out->srb_id = ie->value.choice.SRBID; + // Execute Duplication (O) + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_ExecuteDuplication, false); + if (ie) { + out->execute_duplication = ie->value.choice.ExecuteDuplication; + } + // RRC-Container (M) + F1AP_LIB_FIND_IE(F1AP_DLRRCMessageTransferIEs_t, ie, container, F1AP_ProtocolIE_ID_id_RRCContainer, true); + out->rrc_container = cp_octet_string(&ie->value.choice.RRCContainer, &out->rrc_container_length); + + return true; +} + +/** + * @brief DL RRC Message Transfer deep copy + */ +f1ap_dl_rrc_message_t cp_dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *msg) +{ + uint8_t *rrc_container = calloc_or_fail(msg->rrc_container_length, sizeof(*rrc_container)); + memcpy(rrc_container, msg->rrc_container, msg->rrc_container_length); + + uint32_t *old_gNB_DU_ue_id = NULL; + if (msg->old_gNB_DU_ue_id) { + old_gNB_DU_ue_id = malloc_or_fail(sizeof(*old_gNB_DU_ue_id)); + *old_gNB_DU_ue_id = *(msg->old_gNB_DU_ue_id); + } + + f1ap_dl_rrc_message_t cp = { + .gNB_DU_ue_id = msg->gNB_DU_ue_id, + .gNB_CU_ue_id = msg->gNB_CU_ue_id, + .old_gNB_DU_ue_id = old_gNB_DU_ue_id, + .srb_id = msg->srb_id, + .execute_duplication = msg->execute_duplication, + .rrc_container = rrc_container, + .rrc_container_length = msg->rrc_container_length, + }; + + return cp; +} + +/** + * @brief DL RRC Message Transfer equality check + */ +bool eq_dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *a, const f1ap_dl_rrc_message_t *b) +{ + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_CU_ue_id, b->gNB_CU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + _F1_EQ_CHECK_INT(a->gNB_DU_ue_id, b->gNB_DU_ue_id); + if (!(a->old_gNB_DU_ue_id == NULL && b->old_gNB_DU_ue_id == NULL)) + _F1_EQ_CHECK_INT(*a->old_gNB_DU_ue_id, *b->old_gNB_DU_ue_id); + _F1_EQ_CHECK_INT(a->srb_id, b->srb_id); + _F1_EQ_CHECK_INT(a->execute_duplication, b->execute_duplication); + _F1_EQ_CHECK_INT(a->rrc_container_length, b->rrc_container_length); + if (memcmp(a->rrc_container, b->rrc_container, a->rrc_container_length) != 0) + return false; + return true; +} + +/** + * @brief DL RRC Message Transfer memory management + */ +void free_dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *msg) +{ + DevAssert(msg != NULL); + free(msg->rrc_container); + free(msg->old_gNB_DU_ue_id); +} diff --git a/openair2/F1AP/lib/f1ap_rrc_message_transfer.h b/openair2/F1AP/lib/f1ap_rrc_message_transfer.h new file mode 100644 index 0000000000..4e6d682f78 --- /dev/null +++ b/openair2/F1AP/lib/f1ap_rrc_message_transfer.h @@ -0,0 +1,50 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef F1AP_RRC_MESSAGE_TRANSFER_H_ +#define F1AP_RRC_MESSAGE_TRANSFER_H_ + +#include +#include "f1ap_messages_types.h" + +struct F1AP_F1AP_PDU; + +struct F1AP_F1AP_PDU *encode_initial_ul_rrc_message_transfer(const f1ap_initial_ul_rrc_message_t *msg); +bool decode_initial_ul_rrc_message_transfer(const struct F1AP_F1AP_PDU *pdu, f1ap_initial_ul_rrc_message_t *out); +f1ap_initial_ul_rrc_message_t cp_initial_ul_rrc_message_transfer(const f1ap_initial_ul_rrc_message_t *msg); +bool eq_initial_ul_rrc_message_transfer(const f1ap_initial_ul_rrc_message_t *a, const f1ap_initial_ul_rrc_message_t *b); +void free_initial_ul_rrc_message_transfer(const f1ap_initial_ul_rrc_message_t *msg); + +/* DL RRC Message transfer */ +struct F1AP_F1AP_PDU *encode_dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *msg); +bool decode_dl_rrc_message_transfer(const struct F1AP_F1AP_PDU *pdu, f1ap_dl_rrc_message_t *out); +f1ap_dl_rrc_message_t cp_dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *msg); +bool eq_dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *a, const f1ap_dl_rrc_message_t *b); +void free_dl_rrc_message_transfer(const f1ap_dl_rrc_message_t *msg); + +/* UL RRC Message transfer */ +struct F1AP_F1AP_PDU *encode_ul_rrc_message_transfer(const f1ap_ul_rrc_message_t *msg); +bool decode_ul_rrc_message_transfer(const struct F1AP_F1AP_PDU *pdu, f1ap_ul_rrc_message_t *out); +f1ap_ul_rrc_message_t cp_ul_rrc_message_transfer(const f1ap_ul_rrc_message_t *msg); +bool eq_ul_rrc_message_transfer(const f1ap_ul_rrc_message_t *a, const f1ap_ul_rrc_message_t *b); +void free_ul_rrc_message_transfer(const f1ap_ul_rrc_message_t *msg); + +#endif /* F1AP_RRC_MESSAGE_TRANSFER_H_ */ diff --git a/openair2/F1AP/tests/CMakeLists.txt b/openair2/F1AP/tests/CMakeLists.txt new file mode 100644 index 0000000000..a73334051a --- /dev/null +++ b/openair2/F1AP/tests/CMakeLists.txt @@ -0,0 +1,6 @@ +add_executable(f1ap_lib_test f1ap_lib_test.c) +add_dependencies(tests f1ap_lib_test) +add_test(NAME f1ap_lib_test COMMAND f1ap_lib_test) +target_link_libraries(f1ap_lib_test PRIVATE f1ap_lib) +target_link_libraries(f1ap_lib_test PRIVATE asn1_f1ap) +target_include_directories(f1ap_lib_test PRIVATE ${CMAKE_SOURCE_DIR}) diff --git a/openair2/F1AP/tests/f1ap_lib_test.c b/openair2/F1AP/tests/f1ap_lib_test.c new file mode 100644 index 0000000000..969efc5afa --- /dev/null +++ b/openair2/F1AP/tests/f1ap_lib_test.c @@ -0,0 +1,564 @@ +#include +#include +#include + +#include "common/utils/assertions.h" +#include "common/utils/utils.h" + +#include "f1ap_messages_types.h" +#include "F1AP_F1AP-PDU.h" + +#include "f1ap_lib_extern.h" +#include "lib/f1ap_interface_management.h" + +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + printf("detected error at %s:%d:%s: %s\n", file, line, function, s); + abort(); +} + +static F1AP_F1AP_PDU_t *f1ap_encode_decode(const F1AP_F1AP_PDU_t *enc_pdu) +{ + //xer_fprint(stdout, &asn_DEF_F1AP_F1AP_PDU, enc_pdu); + + DevAssert(enc_pdu != NULL); + char errbuf[1024]; + size_t errlen = sizeof(errbuf); + int ret = asn_check_constraints(&asn_DEF_F1AP_F1AP_PDU, enc_pdu, errbuf, &errlen); + AssertFatal(ret == 0, "asn_check_constraints() failed: %s\n", errbuf); + + uint8_t msgbuf[16384]; + asn_enc_rval_t enc = aper_encode_to_buffer(&asn_DEF_F1AP_F1AP_PDU, NULL, enc_pdu, msgbuf, sizeof(msgbuf)); + AssertFatal(enc.encoded > 0, "aper_encode_to_buffer() failed\n"); + + F1AP_F1AP_PDU_t *dec_pdu = NULL; + asn_codec_ctx_t st = {.max_stack_size = 100 * 1000}; + asn_dec_rval_t dec = aper_decode(&st, &asn_DEF_F1AP_F1AP_PDU, (void **)&dec_pdu, msgbuf, enc.encoded, 0, 0); + AssertFatal(dec.code == RC_OK, "aper_decode() failed\n"); + + //xer_fprint(stdout, &asn_DEF_F1AP_F1AP_PDU, dec_pdu); + return dec_pdu; +} + +static void f1ap_msg_free(F1AP_F1AP_PDU_t *pdu) +{ + ASN_STRUCT_FREE(asn_DEF_F1AP_F1AP_PDU, pdu); +} + +/** + * @brief Test Initial UL RRC Message Transfer encoding/decoding + */ +static void test_initial_ul_rrc_message_transfer(void) +{ + f1ap_plmn_t plmn = { .mcc = 208, .mnc = 95, .mnc_digit_length = 2 }; + uint8_t rrc[] = "RRC Container"; + uint8_t du2cu[] = "DU2CU Container"; + f1ap_initial_ul_rrc_message_t orig = { + .gNB_DU_ue_id = 12, + .plmn = plmn, + .nr_cellid = 135, + .crnti = 0x1234, + .rrc_container = rrc, + .rrc_container_length = sizeof(rrc), + .du2cu_rrc_container = du2cu, + .du2cu_rrc_container_length = sizeof(du2cu), + .transaction_id = 2, + }; + + F1AP_F1AP_PDU_t *f1enc = encode_initial_ul_rrc_message_transfer(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_initial_ul_rrc_message_t decoded; + bool ret = decode_initial_ul_rrc_message_transfer(f1dec, &decoded); + AssertFatal(ret, "decode_initial_ul_rrc_message_transfer(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_initial_ul_rrc_message_transfer(&orig, &decoded); + AssertFatal(ret, "eq_initial_ul_rrc_message_transfer(): decoded message doesn't match\n"); + free_initial_ul_rrc_message_transfer(&decoded); + + f1ap_initial_ul_rrc_message_t cp = cp_initial_ul_rrc_message_transfer(&orig); + ret = eq_initial_ul_rrc_message_transfer(&orig, &cp); + AssertFatal(ret, "eq_initial_ul_rrc_message_transfer(): copied message doesn't match\n"); + free_initial_ul_rrc_message_transfer(&cp); +} + +/** + * @brief Test DL RRC Message Transfer encoding/decoding + */ +static void test_dl_rrc_message_transfer(void) +{ + uint8_t *rrc = calloc(strlen("RRC Container") + 1, sizeof(uint8_t)); + uint32_t *old_gNB_DU_ue_id = calloc(1, sizeof(uint32_t)); + AssertFatal(rrc != NULL && old_gNB_DU_ue_id != NULL, "out of memory\n"); + memcpy((void *)rrc, "RRC Container", strlen("RRC Container") + 1); + + f1ap_dl_rrc_message_t orig = { + .gNB_DU_ue_id = 12, + .gNB_CU_ue_id = 12, + .old_gNB_DU_ue_id = old_gNB_DU_ue_id, + .srb_id = 1, + .rrc_container = rrc, + .rrc_container_length = sizeof(rrc), + }; + + F1AP_F1AP_PDU_t *f1enc = encode_dl_rrc_message_transfer(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_dl_rrc_message_t decoded = {0}; + bool ret = decode_dl_rrc_message_transfer(f1dec, &decoded); + AssertFatal(ret, "decode_initial_ul_rrc_message_transfer(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_dl_rrc_message_transfer(&orig, &decoded); + AssertFatal(ret, "eq_dl_rrc_message_transfer(): decoded message doesn't match\n"); + free_dl_rrc_message_transfer(&decoded); + + f1ap_dl_rrc_message_t cp = cp_dl_rrc_message_transfer(&orig); + ret = eq_dl_rrc_message_transfer(&orig, &cp); + AssertFatal(ret, "eq_dl_rrc_message_transfer(): copied message doesn't match\n"); + free_dl_rrc_message_transfer(&orig); + free_dl_rrc_message_transfer(&cp); +} + +/** + * @brief Test UL RRC Message Transfer encoding/decoding + */ +static void test_ul_rrc_message_transfer(void) +{ + uint8_t rrc[] = "RRC Container"; + + f1ap_ul_rrc_message_t orig = { + .gNB_DU_ue_id = 12, + .gNB_CU_ue_id = 12, + .srb_id = 1, + .rrc_container = rrc, + .rrc_container_length = sizeof(rrc), + }; + + F1AP_F1AP_PDU_t *f1enc = encode_ul_rrc_message_transfer(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_ul_rrc_message_t decoded = {0}; + bool ret = decode_ul_rrc_message_transfer(f1dec, &decoded); + AssertFatal(ret, "decode_initial_ul_rrc_message_transfer(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_ul_rrc_message_transfer(&orig, &decoded); + AssertFatal(ret, "eq_dl_rrc_message_transfer(): decoded message doesn't match\n"); + free_ul_rrc_message_transfer(&decoded); + + f1ap_ul_rrc_message_t cp = cp_ul_rrc_message_transfer(&orig); + ret = eq_ul_rrc_message_transfer(&orig, &cp); + AssertFatal(ret, "eq_dl_rrc_message_transfer(): copied message doesn't match\n"); + free_ul_rrc_message_transfer(&cp); +} + +/** + * @brief Test F1AP Setup Request Encoding/Decoding + */ +static void test_f1ap_setup_request(void) +{ + /* allocate memory */ + /* gNB_DU_name */ + uint8_t *gNB_DU_name = calloc(strlen("OAI DU") + 1, sizeof(uint8_t)); + AssertFatal(gNB_DU_name != NULL, "out of memory\n"); + memcpy((void *)gNB_DU_name, "OAI DU", strlen("OAI DU") + 1); + /* sys_info */ + uint8_t *mib = calloc(3, sizeof(uint8_t)); + uint8_t *sib1 = calloc(3, sizeof(uint8_t)); + f1ap_gnb_du_system_info_t sys_info = { + .mib_length = 3, + .mib = mib, + .sib1_length = 3, + .sib1 = sib1, + }; + /* measurement_timing_information */ + int measurement_timing_config_len = strlen("0") + 1; + uint8_t *measurement_timing_information = calloc(measurement_timing_config_len, sizeof(uint8_t)); + AssertFatal(measurement_timing_information != NULL, "out of memory\n"); + memcpy((void *)measurement_timing_information, "0", measurement_timing_config_len); + /* TAC */ + uint32_t *tac = calloc(1, sizeof(uint32_t)); + /* + * TDD test + */ + // Served Cell Info + f1ap_served_cell_info_t info = { + .mode = F1AP_MODE_TDD, + .tdd.freqinfo.arfcn = 640000, + .tdd.freqinfo.band = 78, + .tdd.tbw.nrb = 66, + .tdd.tbw.scs = 1, + .measurement_timing_config_len = measurement_timing_config_len, + .measurement_timing_config = measurement_timing_information, + .nr_cellid = 123456, + .plmn.mcc = 1, + .plmn.mnc = 1, + .plmn.mnc_digit_length = 3, + .num_ssi = 1, + .nssai[0].sst = 1, + .nssai[0].sd = 1, + .tac = tac, + }; + // create message + f1ap_setup_req_t orig = { + .gNB_DU_id = 1, + .gNB_DU_name = (char *)gNB_DU_name, + .num_cells_available = 1, + .transaction_id = 2, + .rrc_ver[0] = 12, + .rrc_ver[1] = 34, + .rrc_ver[2] = 56, + .cell[0].info = info, + }; + orig.cell[0].sys_info = calloc(1, sizeof(*orig.cell[0].sys_info)); + *orig.cell[0].sys_info = sys_info; + // encode + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_setup_request(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + // decode + f1ap_setup_req_t decoded = {0}; + bool ret = decode_f1ap_setup_request(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_setup_request(): could not decode message\n"); + f1ap_msg_free(f1dec); + // equality check + ret = eq_f1ap_setup_request(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_setup_request(): decoded message doesn't match\n"); + free_f1ap_setup_request(&decoded); + // deep copy + f1ap_setup_req_t cp = cp_f1ap_setup_request(&orig); + ret = eq_f1ap_setup_request(&orig, &cp); + AssertFatal(ret, "eq_f1ap_setup_request(): copied message doesn't match\n"); + free_f1ap_setup_request(&cp); + /* + * FDD test + */ + info.mode = F1AP_MODE_FDD; + info.tdd.freqinfo.arfcn = 0; + info.tdd.freqinfo.band = 0; + info.tdd.tbw.nrb = 0; + info.tdd.tbw.scs = 0; + info.fdd.ul_freqinfo.arfcn = 640000; + info.fdd.ul_freqinfo.band = 78; + info.fdd.dl_freqinfo.arfcn = 641000; + info.fdd.dl_freqinfo.band = 78; + info.fdd.ul_tbw.nrb = 66; + info.fdd.ul_tbw.scs = 1; + info.fdd.dl_tbw.nrb = 66; + info.fdd.dl_tbw.scs = 1; + // encode + f1enc = encode_f1ap_setup_request(&orig); + f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + // decode + ret = decode_f1ap_setup_request(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_setup_request(): could not decode message\n"); + f1ap_msg_free(f1dec); + // equality check + ret = eq_f1ap_setup_request(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_setup_request(): decoded message doesn't match\n"); + free_f1ap_setup_request(&decoded); + // copy + cp = cp_f1ap_setup_request(&orig); + ret = eq_f1ap_setup_request(&orig, &cp); + AssertFatal(ret, "eq_f1ap_setup_request(): copied message doesn't match\n"); + free_f1ap_setup_request(&cp); + // free original message + free_f1ap_setup_request(&orig); +} + +/** + * @brief Test F1AP Setup Response Encoding/Decoding + */ +static void test_f1ap_setup_response(void) +{ + /* allocate memory */ + /* gNB_CU_name */ + char *cu_name = "OAI-CU"; + int len = strlen(cu_name) + 1; + uint8_t *gNB_CU_name = calloc(len, sizeof(uint8_t)); + AssertFatal(gNB_CU_name != NULL, "out of memory\n"); + memcpy((void *)gNB_CU_name, cu_name, len); + /* create message */ + f1ap_setup_resp_t orig = { + .gNB_CU_name = (char *)gNB_CU_name, + .transaction_id = 2, + .rrc_ver[0] = 12, + .rrc_ver[1] = 34, + .rrc_ver[2] = 56, + .num_cells_to_activate = 1, + .cells_to_activate[0].nr_cellid = 123456, + .cells_to_activate[0].nrpci = 1, + .cells_to_activate[0].plmn.mcc = 12, + .cells_to_activate[0].plmn.mnc = 123, + .cells_to_activate[0].plmn.mnc_digit_length = 3, + }; + /* Cells to activate */ + if (orig.num_cells_to_activate) { + /* SI_container */ + char *s = "test"; + int SI_container_length = strlen(s) + 1; + orig.cells_to_activate[0].num_SI = 1; + f1ap_sib_msg_t *SI_msg = &orig.cells_to_activate[0].SI_msg[0]; + SI_msg->SI_container = malloc_or_fail(SI_container_length); + memcpy(SI_msg->SI_container, (uint8_t *)s, SI_container_length); + SI_msg->SI_container_length = SI_container_length; + SI_msg->SI_type = 7; + } + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_setup_response(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_setup_resp_t decoded = {0}; + bool ret = decode_f1ap_setup_response(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_setup_response(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_f1ap_setup_response(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_setup_response(): decoded message doesn't match\n"); + free_f1ap_setup_response(&decoded); + + f1ap_setup_resp_t cp = cp_f1ap_setup_response(&orig); + ret = eq_f1ap_setup_response(&orig, &cp); + AssertFatal(ret, "eq_f1ap_setup_response(): copied message doesn't match\n"); + free_f1ap_setup_response(&cp); + free_f1ap_setup_response(&orig); +} + +/** + * @brief Test F1AP Setup Failure Encoding/Decoding + */ +static void test_f1ap_setup_failure(void) +{ + /* create message */ + f1ap_setup_failure_t orig = { + .transaction_id = 2, + .cause = 4, + }; + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_setup_failure(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_setup_failure_t decoded = {0}; + bool ret = decode_f1ap_setup_failure(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_setup_failure(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_f1ap_setup_failure(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_setup_failure(): decoded message doesn't match\n"); + + f1ap_setup_failure_t cp = cp_f1ap_setup_failure(&orig); + ret = eq_f1ap_setup_failure(&orig, &cp); + AssertFatal(ret, "eq_f1ap_setup_failure(): copied message doesn't match\n"); +} + +/** + * @brief Test F1 gNB-DU Configuration Update + */ +static void test_f1ap_du_configuration_update(void) +{ + /* sys_info */ + uint8_t *mib = calloc(3, sizeof(uint8_t)); + uint8_t *sib1 = calloc(3, sizeof(uint8_t)); + f1ap_gnb_du_system_info_t sys_info = { + .mib_length = 3, + .mib = mib, + .sib1_length = 3, + .sib1 = sib1, + }; + /* measurement_timing_information modify */ + char *s = "1"; + int measurement_timing_config_len = strlen(s) + 1; + uint8_t *measurement_timing_config_mod = calloc(measurement_timing_config_len, sizeof(uint8_t)); + AssertFatal(measurement_timing_config_mod != NULL, "out of memory\n"); + memcpy((void *)measurement_timing_config_mod, s, measurement_timing_config_len); + /* TAC modify */ + uint32_t *tac = calloc(1, sizeof(uint32_t)); + AssertFatal(tac != NULL, "out of memory\n"); + *tac = 456; + /* info modify */ + f1ap_served_cell_info_t info = { + .mode = F1AP_MODE_TDD, + .tdd.freqinfo.arfcn = 640000, + .tdd.freqinfo.band = 78, + .tdd.tbw.nrb = 66, + .tdd.tbw.scs = 1, + .measurement_timing_config_len = measurement_timing_config_len, + .measurement_timing_config = measurement_timing_config_mod, + .nr_cellid = 123456, + .plmn.mcc = 1, + .plmn.mnc = 1, + .plmn.mnc_digit_length = 3, + .tac = tac, + }; + /* create message */ + f1ap_gnb_du_configuration_update_t orig = { + .transaction_id = 2, + .num_cells_to_modify = 1, + .cell_to_modify[0].info = info, + .num_cells_to_delete = 0, + .cell_to_delete[0].nr_cellid = 1234UL, + .cell_to_delete[0].plmn.mcc = 1, + .cell_to_delete[0].plmn.mnc = 1, + .cell_to_delete[0].plmn.mnc_digit_length = 3, + }; + orig.cell_to_modify[0].sys_info = calloc(1, sizeof(*orig.cell_to_modify[0].sys_info)); + AssertFatal(orig.cell_to_modify[0].sys_info != NULL, "out of memory\n"); + *orig.cell_to_modify[0].sys_info = sys_info; + + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_du_configuration_update(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_gnb_du_configuration_update_t decoded = {0}; + bool ret = decode_f1ap_du_configuration_update(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_setup_request(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_f1ap_du_configuration_update(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_setup_request(): decoded message doesn't match\n"); + free_f1ap_du_configuration_update(&decoded); + + f1ap_gnb_du_configuration_update_t cp = cp_f1ap_du_configuration_update(&orig); + ret = eq_f1ap_du_configuration_update(&orig, &cp); + AssertFatal(ret, "eq_f1ap_setup_request(): copied message doesn't match\n"); + free_f1ap_du_configuration_update(&cp); + free_f1ap_du_configuration_update(&orig); +} + +/** + * @brief Test F1 gNB-DU Configuration Update Acknowledge + */ +static void test_f1ap_du_configuration_update_acknowledge(void) +{ + // Create message + f1ap_gnb_du_configuration_update_acknowledge_t orig = { + .transaction_id = 5, + .num_cells_to_activate = 1, + .cells_to_activate = {{ + .nr_cellid = 987654321, + .nrpci = 50, + .plmn = {.mcc = 001, .mnc = 01, .mnc_digit_length = 2}, + .num_SI = 1, + .SI_msg = {{ + .SI_type = 7, + .SI_container_length = 10, + .SI_container = malloc(sizeof(uint8_t) * 10), + }}, + }}, + }; + for (int i = 0; i < orig.cells_to_activate[0].SI_msg[0].SI_container_length; i++) { + orig.cells_to_activate[0].SI_msg[0].SI_container[i] = i; + } + // ASN.1 enc/dec + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_du_configuration_update_acknowledge(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + // Decoding + f1ap_gnb_du_configuration_update_acknowledge_t decoded = {0}; + bool ret = decode_f1ap_du_configuration_update_acknowledge(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_du_configuration_update_acknowledge(): could not decode message\n"); + f1ap_msg_free(f1dec); + // Equality check + ret = eq_f1ap_du_configuration_update_acknowledge(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_du_configuration_update_acknowledge(): decoded message doesn't match\n"); + free_f1ap_du_configuration_update_acknowledge(&decoded); + // Deep copy + f1ap_gnb_du_configuration_update_acknowledge_t cp = cp_f1ap_du_configuration_update_acknowledge(&orig); + ret = eq_f1ap_du_configuration_update_acknowledge(&orig, &cp); + AssertFatal(ret, "eq_f1ap_du_configuration_update_acknowledge(): copied message doesn't match\n"); + // Free + free_f1ap_du_configuration_update_acknowledge(&cp); + free_f1ap_du_configuration_update_acknowledge(&orig); +} + +/** + * @brief Test F1 gNB-CU Configuration Update + */ +static void test_f1ap_cu_configuration_update(void) +{ + /* create message */ + f1ap_gnb_cu_configuration_update_t orig = {.transaction_id = 2, + .num_cells_to_activate = 1, + .cells_to_activate = {{.nr_cellid = 123456789, + .nrpci = 100, + .plmn = {.mcc = 001, .mnc = 01, .mnc_digit_length = 2}, + .num_SI = 1, + .SI_msg = {{ + .SI_type = 7, + .SI_container_length = 10, + .SI_container = malloc(sizeof(uint8_t) * 10), + }}}}}; + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_cu_configuration_update(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + + f1ap_gnb_cu_configuration_update_t decoded = {0}; + bool ret = decode_f1ap_cu_configuration_update(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_setup_request(): could not decode message\n"); + f1ap_msg_free(f1dec); + + ret = eq_f1ap_cu_configuration_update(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_setup_request(): decoded message doesn't match\n"); + free_f1ap_cu_configuration_update(&decoded); + + f1ap_gnb_cu_configuration_update_t cp = cp_f1ap_cu_configuration_update(&orig); + ret = eq_f1ap_cu_configuration_update(&orig, &cp); + AssertFatal(ret, "eq_f1ap_setup_request(): copied message doesn't match\n"); + free_f1ap_cu_configuration_update(&cp); + free_f1ap_cu_configuration_update(&orig); +} + +/** + * @brief Test F1 gNB-CU Configuration Update Acknowledge + */ +static void test_f1ap_cu_configuration_update_acknowledge(void) +{ + // Create the original message + f1ap_gnb_cu_configuration_update_acknowledge_t orig = { + .transaction_id = 2, + .num_cells_failed_to_be_activated = 1, + .cells_failed_to_be_activated = {{.nr_cellid = 123456789, + .plmn = {.mcc = 001, .mnc = 01, .mnc_digit_length = 2}, + .cause = F1AP_CAUSE_RADIO_NETWORK}} + }; + // F1AP Enc/dec + F1AP_F1AP_PDU_t *f1enc = encode_f1ap_cu_configuration_update_acknowledge(&orig); + F1AP_F1AP_PDU_t *f1dec = f1ap_encode_decode(f1enc); + f1ap_msg_free(f1enc); + // Decoding + f1ap_gnb_cu_configuration_update_acknowledge_t decoded = {0}; + bool ret = decode_f1ap_cu_configuration_update_acknowledge(f1dec, &decoded); + AssertFatal(ret, "decode_f1ap_cu_configuration_update_acknowledge(): could not decode message\n"); + f1ap_msg_free(f1dec); + // Equality check + ret = eq_f1ap_cu_configuration_update_acknowledge(&orig, &decoded); + AssertFatal(ret, "eq_f1ap_cu_configuration_update_acknowledge(): decoded message doesn't match\n"); + // No free needed + // Deep copy + f1ap_gnb_cu_configuration_update_acknowledge_t cp = cp_f1ap_cu_configuration_update_acknowledge(&orig); + // Equality check + ret = eq_f1ap_cu_configuration_update_acknowledge(&orig, &cp); + AssertFatal(ret, "eq_f1ap_cu_configuration_update_acknowledge(): copied message doesn't match\n"); + // No free needed +} + +int main() +{ + test_initial_ul_rrc_message_transfer(); + test_dl_rrc_message_transfer(); + test_ul_rrc_message_transfer(); + test_f1ap_setup_request(); + test_f1ap_setup_response(); + test_f1ap_setup_failure(); + test_f1ap_du_configuration_update(); + test_f1ap_cu_configuration_update(); + test_f1ap_cu_configuration_update_acknowledge(); + test_f1ap_du_configuration_update_acknowledge(); + return 0; +} diff --git a/openair2/GNB_APP/gnb_app.c b/openair2/GNB_APP/gnb_app.c index 39946c95f1..0e7e25e2c0 100644 --- a/openair2/GNB_APP/gnb_app.c +++ b/openair2/GNB_APP/gnb_app.c @@ -236,10 +236,10 @@ void *gNB_app_task(void *args_p) case F1AP_GNB_CU_CONFIGURATION_UPDATE: AssertFatal(NODE_IS_DU(node_type), "Should not have received F1AP_GNB_CU_CONFIGURATION_UPDATE in CU/gNB\n"); - - LOG_I(GNB_APP, "Received %s: associated ngran_gNB_CU %s with %d cells to activate\n", ITTI_MSG_NAME (msg_p), - F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).gNB_CU_name,F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).num_cells_to_activate); - + LOG_I(GNB_APP, + "Received %s: associated with %d cells to activate\n", + ITTI_MSG_NAME(msg_p), + F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).num_cells_to_activate); cell_to_activate += F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p).num_cells_to_activate; gNB_app_handle_f1ap_gnb_cu_configuration_update(&F1AP_GNB_CU_CONFIGURATION_UPDATE(msg_p)); @@ -247,6 +247,11 @@ void *gNB_app_task(void *args_p) AssertFatal(cell_to_activate == 1,"No cells to activate or cells > 1 %d\n",cell_to_activate); break; + + case F1AP_GNB_DU_CONFIGURATION_UPDATE_ACKNOWLEDGE: + LOG_E(GNB_APP, "[gNB %ld] Handling of %s message not implemented yet\n", instance, msg_name); + break; + case NGAP_DEREGISTERED_GNB_IND: LOG_W(GNB_APP, "[gNB %ld] Received %s: associated AMF %d\n", instance, msg_name, NGAP_DEREGISTERED_GNB_IND(msg_p).nb_amf); diff --git a/openair2/GNB_APP/gnb_config.c b/openair2/GNB_APP/gnb_config.c index d1ed728f35..2885204128 100644 --- a/openair2/GNB_APP/gnb_config.c +++ b/openair2/GNB_APP/gnb_config.c @@ -94,6 +94,7 @@ #ifdef ENABLE_AERIAL #include "nfapi/oai_integration/aerial/fapi_vnf_p5.h" #endif +#include "lib/f1ap_interface_management.h" extern uint16_t sf_ahead; @@ -2396,7 +2397,6 @@ int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_up ret++; mac->f1_config.setup_resp = malloc(sizeof(*mac->f1_config.setup_resp)); AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n"); - mac->f1_config.setup_resp->gNB_CU_name = gnb_cu_cfg_update->gNB_CU_name; mac->f1_config.setup_resp->num_cells_to_activate = gnb_cu_cfg_update->num_cells_to_activate; mac->f1_config.setup_resp->cells_to_activate[0] = gnb_cu_cfg_update->cells_to_activate[0]; } else { @@ -2405,6 +2405,8 @@ int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_up } } NR_SCHED_UNLOCK(&mac->sched_lock); + /* Free F1AP struct after use */ + free_f1ap_cu_configuration_update(gnb_cu_cfg_update); MessageDef *msg_ack_p = NULL; if (ret > 0) { // generate gNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE @@ -2414,6 +2416,7 @@ int gNB_app_handle_f1ap_gnb_cu_configuration_update(f1ap_gnb_cu_configuration_up F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofTNLAssociations_to_setup =0; F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofTNLAssociations_failed = 0; F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).noofDedicatedSIDeliveryNeededUEs = 0; + F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE(msg_ack_p).transaction_id = F1AP_get_next_transaction_identifier(0, 0); itti_send_msg_to_task (TASK_DU_F1, INSTANCE_DEFAULT, msg_ack_p); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c index bb84a4793c..407e5869ce 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_dl_handler.c @@ -28,6 +28,7 @@ #include "F1AP_CauseRadioNetwork.h" #include "openair3/ocp-gtpu/gtp_itf.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h" +#include "lib/f1ap_interface_management.h" #include "executables/softmodem-common.h" @@ -169,10 +170,10 @@ void f1_setup_response(const f1ap_setup_resp_t *resp) mac->f1_config.setup_resp = malloc(sizeof(*mac->f1_config.setup_resp)); AssertFatal(mac->f1_config.setup_resp != NULL, "out of memory\n"); - *mac->f1_config.setup_resp = *resp; - if (resp->gNB_CU_name) - mac->f1_config.setup_resp->gNB_CU_name = strdup(resp->gNB_CU_name); - + // Copy F1AP message + *mac->f1_config.setup_resp = cp_f1ap_setup_response(resp); + // free F1AP message after copy + free_f1ap_setup_response(resp); NR_SCHED_UNLOCK(&mac->sched_lock); // NOTE: Before accepting any UEs, we should initialize the UE states. @@ -244,7 +245,7 @@ static int handle_ue_context_srbs_setup(NR_UE_info_t *UE, static NR_RLC_BearerConfig_t *get_bearerconfig_from_drb(const f1ap_drb_to_be_setup_t *drb) { - const NR_RLC_Config_PR rlc_conf = drb->rlc_mode == RLC_MODE_UM ? NR_RLC_Config_PR_um_Bi_Directional : NR_RLC_Config_PR_am; + const NR_RLC_Config_PR rlc_conf = drb->rlc_mode == F1AP_RLC_MODE_AM ? NR_RLC_Config_PR_am : NR_RLC_Config_PR_um_Bi_Directional; long priority = 13; // hardcoded for the moment return get_DRB_RLC_BearerConfig(get_lcid_from_drbid(drb->drb_id), drb->drb_id, rlc_conf, priority); } @@ -262,11 +263,11 @@ static NR_QoS_config_t get_qos_config(const f1ap_qos_characteristics_t *qos_char { NR_QoS_config_t qos_c = {0}; switch (qos_char->qos_type) { - case dynamic: + case DYNAMIC: qos_c.priority = qos_char->dynamic.qos_priority_level; qos_c.fiveQI = qos_char->dynamic.fiveqi > 0 ? qos_char->dynamic.fiveqi : 0; break; - case non_dynamic: + case NON_DYNAMIC: qos_c.fiveQI = qos_char->non_dynamic.fiveqi; qos_c.priority = get_non_dynamic_priority(qos_char->non_dynamic.fiveqi); break; diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index 29a7bc8621..ad8978d514 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -23,6 +23,8 @@ #include "intertask_interface.h" #include "mac_rrc_ul.h" +#include "f1ap_lib_extern.h" +#include "lib/f1ap_interface_management.h" static void f1_reset_du_initiated_direct(const f1ap_reset_t *reset) { @@ -40,47 +42,8 @@ static void f1_setup_request_direct(const f1ap_setup_req_t *req) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_SETUP_REQ); msg->ittiMsgHeader.originInstance = -1; // means monolithic - f1ap_setup_req_t *f1ap_msg = &F1AP_SETUP_REQ(msg); - f1ap_msg->gNB_DU_id = req->gNB_DU_id; - f1ap_msg->gNB_DU_name = strdup(req->gNB_DU_name); - f1ap_msg->num_cells_available = req->num_cells_available; - for (int n = 0; n < req->num_cells_available; ++n) { - f1ap_msg->cell[n].info = req->cell[n].info; // copy most fields - if (req->cell[n].info.tac) { - f1ap_msg->cell[n].info.tac = malloc(sizeof(*f1ap_msg->cell[n].info.tac)); - AssertFatal(f1ap_msg->cell[n].info.tac != NULL, "out of memory\n"); - *f1ap_msg->cell[n].info.tac = *req->cell[n].info.tac; - } - if (req->cell[n].info.measurement_timing_config_len > 0) { - f1ap_msg->cell[n].info.measurement_timing_config = calloc(req->cell[n].info.measurement_timing_config_len, sizeof(uint8_t)); - AssertFatal(f1ap_msg->cell[n].info.measurement_timing_config != NULL, "out of memory\n"); - memcpy(f1ap_msg->cell[n].info.measurement_timing_config, - req->cell[n].info.measurement_timing_config, - req->cell[n].info.measurement_timing_config_len); - f1ap_msg->cell[n].info.measurement_timing_config_len = req->cell[n].info.measurement_timing_config_len; - } - - if (req->cell[n].sys_info) { - f1ap_gnb_du_system_info_t *orig_sys_info = req->cell[n].sys_info; - f1ap_gnb_du_system_info_t *copy_sys_info = calloc(1, sizeof(*copy_sys_info)); - AssertFatal(copy_sys_info, "out of memory\n"); - f1ap_msg->cell[n].sys_info = copy_sys_info; - - copy_sys_info->mib = calloc(orig_sys_info->mib_length, sizeof(uint8_t)); - AssertFatal(copy_sys_info->mib, "out of memory\n"); - memcpy(copy_sys_info->mib, orig_sys_info->mib, orig_sys_info->mib_length); - copy_sys_info->mib_length = orig_sys_info->mib_length; - - if (orig_sys_info->sib1_length > 0) { - copy_sys_info->sib1 = calloc(orig_sys_info->sib1_length, sizeof(uint8_t)); - AssertFatal(copy_sys_info->sib1, "out of memory\n"); - memcpy(copy_sys_info->sib1, orig_sys_info->sib1, orig_sys_info->sib1_length); - copy_sys_info->sib1_length = orig_sys_info->sib1_length; - } - } - } - memcpy(f1ap_msg->rrc_ver, req->rrc_ver, sizeof(req->rrc_ver)); - + f1ap_setup_req_t cp = cp_f1ap_setup_request(req); + F1AP_SETUP_REQ(msg) = cp; itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } @@ -88,51 +51,8 @@ static void gnb_du_configuration_update_direct(const f1ap_gnb_du_configuration_u { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE); msg->ittiMsgHeader.originInstance = -1; // means monolithic - f1ap_gnb_du_configuration_update_t *f1ap_msg = &F1AP_GNB_DU_CONFIGURATION_UPDATE(msg); - DevAssert(upd->gNB_DU_ID == NULL); - f1ap_msg->transaction_id = upd->transaction_id; - DevAssert(upd->num_cells_to_add == 0); - DevAssert(upd->num_cells_to_delete == 0); - - f1ap_msg->num_cells_to_modify = upd->num_cells_to_modify; - for (int n = 0; n < upd->num_cells_to_modify; ++n) { - f1ap_msg->cell_to_modify[n].old_nr_cellid = upd->cell_to_modify[n].old_nr_cellid; - f1ap_msg->cell_to_modify[n].info = upd->cell_to_modify[n].info; // copy most fields - if (upd->cell_to_modify[n].info.tac) { - f1ap_msg->cell_to_modify[n].info.tac = malloc(sizeof(*f1ap_msg->cell_to_modify[n].info.tac)); - AssertFatal(f1ap_msg->cell_to_modify[n].info.tac != NULL, "out of memory\n"); - *f1ap_msg->cell_to_modify[n].info.tac = *upd->cell_to_modify[n].info.tac; - } - if (upd->cell_to_modify[n].info.measurement_timing_config_len > 0) { - f1ap_msg->cell_to_modify[n].info.measurement_timing_config = - calloc(upd->cell_to_modify[n].info.measurement_timing_config_len, sizeof(uint8_t)); - AssertFatal(f1ap_msg->cell_to_modify[n].info.measurement_timing_config != NULL, "out of memory\n"); - memcpy(f1ap_msg->cell_to_modify[n].info.measurement_timing_config, - upd->cell_to_modify[n].info.measurement_timing_config, - upd->cell_to_modify[n].info.measurement_timing_config_len); - f1ap_msg->cell_to_modify[n].info.measurement_timing_config_len = upd->cell_to_modify[n].info.measurement_timing_config_len; - } - - if (upd->cell_to_modify[n].sys_info) { - f1ap_gnb_du_system_info_t *orig_sys_info = upd->cell_to_modify[n].sys_info; - f1ap_gnb_du_system_info_t *copy_sys_info = calloc(1, sizeof(*copy_sys_info)); - AssertFatal(copy_sys_info != NULL, "out of memory\n"); - f1ap_msg->cell_to_modify[n].sys_info = copy_sys_info; - - copy_sys_info->mib = calloc(orig_sys_info->mib_length, sizeof(uint8_t)); - AssertFatal(copy_sys_info->mib != NULL, "out of memory\n"); - memcpy(copy_sys_info->mib, orig_sys_info->mib, orig_sys_info->mib_length); - copy_sys_info->mib_length = orig_sys_info->mib_length; - - if (orig_sys_info->sib1_length > 0) { - copy_sys_info->sib1 = calloc(orig_sys_info->sib1_length, sizeof(uint8_t)); - AssertFatal(copy_sys_info->sib1 != NULL, "out of memory\n"); - memcpy(copy_sys_info->sib1, orig_sys_info->sib1, orig_sys_info->sib1_length); - copy_sys_info->sib1_length = orig_sys_info->sib1_length; - } - } - } - + /* transfer to RRC via ITTI */ + F1AP_GNB_DU_CONFIGURATION_UPDATE(msg) = cp_f1ap_du_configuration_update(upd); itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } @@ -277,20 +197,8 @@ static void initial_ul_rrc_message_transfer_direct(module_id_t module_id, const { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_INITIAL_UL_RRC_MESSAGE); msg->ittiMsgHeader.originInstance = -1; // means monolithic - /* copy all fields, but reallocate rrc_containers! */ f1ap_initial_ul_rrc_message_t *f1ap_msg = &F1AP_INITIAL_UL_RRC_MESSAGE(msg); - *f1ap_msg = *ul_rrc; - - f1ap_msg->rrc_container = malloc(ul_rrc->rrc_container_length); - DevAssert(f1ap_msg->rrc_container); - memcpy(f1ap_msg->rrc_container, ul_rrc->rrc_container, ul_rrc->rrc_container_length); - f1ap_msg->rrc_container_length = ul_rrc->rrc_container_length; - - f1ap_msg->du2cu_rrc_container = malloc(ul_rrc->du2cu_rrc_container_length); - DevAssert(f1ap_msg->du2cu_rrc_container); - memcpy(f1ap_msg->du2cu_rrc_container, ul_rrc->du2cu_rrc_container, ul_rrc->du2cu_rrc_container_length); - f1ap_msg->du2cu_rrc_container_length = ul_rrc->du2cu_rrc_container_length; - + *f1ap_msg = cp_initial_ul_rrc_message_transfer(ul_rrc); itti_send_msg_to_task(TASK_RRC_GNB, module_id, msg); } diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 742f85c390..2af81d0cfd 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -29,24 +29,23 @@ #include "mac_rrc_ul.h" +#include "f1ap_lib_extern.h" +#include "lib/f1ap_interface_management.h" + static f1ap_net_config_t read_DU_IP_config(const eth_params_t* f1_params, const char *f1u_ip_addr) { f1ap_net_config_t nc = {0}; - nc.CU_f1_ip_address.ipv6 = 0; - nc.CU_f1_ip_address.ipv4 = 1; - strcpy(nc.CU_f1_ip_address.ipv4_address, f1_params->remote_addr); + nc.CU_f1_ip_address= strdup(f1_params->remote_addr); nc.CUport = f1_params->remote_portd; - nc.DU_f1c_ip_address.ipv6 = 0; - nc.DU_f1c_ip_address.ipv4 = 1; - strcpy(nc.DU_f1c_ip_address.ipv4_address, f1_params->my_addr); + nc.DU_f1c_ip_address = strdup(f1_params->my_addr); nc.DU_f1u_ip_address = strdup(f1u_ip_addr); nc.DUport = f1_params->my_portd; LOG_I(F1AP, "F1-C DU IPaddr %s, connect to F1-C CU %s, binding GTP to %s\n", - nc.DU_f1c_ip_address.ipv4_address, - nc.CU_f1_ip_address.ipv4_address, + nc.DU_f1c_ip_address, + nc.CU_f1_ip_address, nc.DU_f1u_ip_address); // sctp_in_streams/sctp_out_streams are given by SCTP layer @@ -70,84 +69,23 @@ static void f1_reset_acknowledge_cu_initiated_f1ap(const f1ap_reset_ack_t *ack) static void f1_setup_request_f1ap(const f1ap_setup_req_t *req) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_DU_REGISTER_REQ); - - f1ap_setup_req_t *f1ap_setup = &F1AP_DU_REGISTER_REQ(msg).setup_req; - f1ap_setup->gNB_DU_id = req->gNB_DU_id; - f1ap_setup->gNB_DU_name = strdup(req->gNB_DU_name); - f1ap_setup->num_cells_available = req->num_cells_available; - for (int n = 0; n < req->num_cells_available; ++n) { - f1ap_setup->cell[n].info = req->cell[n].info; // copy most fields - if (req->cell[n].info.tac) { - f1ap_setup->cell[n].info.tac = malloc(sizeof(*f1ap_setup->cell[n].info.tac)); - AssertFatal(f1ap_setup->cell[n].info.tac != NULL, "out of memory\n"); - *f1ap_setup->cell[n].info.tac = *req->cell[n].info.tac; - } - if (req->cell[n].info.measurement_timing_config_len > 0) { - f1ap_setup->cell[n].info.measurement_timing_config = calloc(req->cell[n].info.measurement_timing_config_len, sizeof(uint8_t)); - AssertFatal(f1ap_setup->cell[n].info.measurement_timing_config != NULL, "out of memory\n"); - memcpy(f1ap_setup->cell[n].info.measurement_timing_config, - req->cell[n].info.measurement_timing_config, - req->cell[n].info.measurement_timing_config_len); - f1ap_setup->cell[n].info.measurement_timing_config_len = req->cell[n].info.measurement_timing_config_len; - } - - if (req->cell[n].sys_info) { - f1ap_gnb_du_system_info_t *orig_sys_info = req->cell[n].sys_info; - f1ap_gnb_du_system_info_t *copy_sys_info = calloc(1, sizeof(*copy_sys_info)); - AssertFatal(copy_sys_info, "out of memory\n"); - f1ap_setup->cell[n].sys_info = copy_sys_info; - - copy_sys_info->mib = calloc(orig_sys_info->mib_length, sizeof(uint8_t)); - AssertFatal(copy_sys_info->mib, "out of memory\n"); - memcpy(copy_sys_info->mib, orig_sys_info->mib, orig_sys_info->mib_length); - copy_sys_info->mib_length = orig_sys_info->mib_length; - - if (orig_sys_info->sib1_length > 0) { - copy_sys_info->sib1 = calloc(orig_sys_info->sib1_length, sizeof(uint8_t)); - AssertFatal(copy_sys_info->sib1, "out of memory\n"); - memcpy(copy_sys_info->sib1, orig_sys_info->sib1, orig_sys_info->sib1_length); - copy_sys_info->sib1_length = orig_sys_info->sib1_length; - } - } - } - memcpy(f1ap_setup->rrc_ver, req->rrc_ver, sizeof(req->rrc_ver)); - + f1ap_setup_req_t f1ap_setup = cp_f1ap_setup_request(req); + F1AP_DU_REGISTER_REQ(msg).setup_req = f1ap_setup; F1AP_DU_REGISTER_REQ(msg).net_config = read_DU_IP_config(&RC.nrmac[0]->eth_params_n, RC.nrmac[0]->f1u_addr); - itti_send_msg_to_task(TASK_DU_F1, 0, msg); } static void gnb_du_configuration_update_f1ap(const f1ap_gnb_du_configuration_update_t *upd) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_GNB_DU_CONFIGURATION_UPDATE); - f1ap_gnb_du_configuration_update_t *f1_upd = &F1AP_GNB_DU_CONFIGURATION_UPDATE(msg); - f1_upd->transaction_id = upd->transaction_id; - AssertFatal(upd->num_cells_to_add == 0, "gNB-DU config update: cells to add not supported\n"); - f1_upd->num_cells_to_modify = upd->num_cells_to_modify; - for (int n = 0; n < upd->num_cells_to_modify; ++n) { - f1_upd->cell_to_modify[n].old_plmn = upd->cell_to_modify[n].old_plmn; - f1_upd->cell_to_modify[n].old_nr_cellid = upd->cell_to_modify[n].old_nr_cellid; - f1_upd->cell_to_modify[n].info = upd->cell_to_modify[n].info; - if (upd->cell_to_modify[n].sys_info) { - f1ap_gnb_du_system_info_t *orig_sys_info = upd->cell_to_modify[n].sys_info; - f1ap_gnb_du_system_info_t *copy_sys_info = calloc(1, sizeof(*copy_sys_info)); - f1_upd->cell_to_modify[n].sys_info = copy_sys_info; - - copy_sys_info->mib = calloc(orig_sys_info->mib_length, sizeof(uint8_t)); - AssertFatal(copy_sys_info->mib != NULL, "out of memory\n"); - memcpy(copy_sys_info->mib, orig_sys_info->mib, orig_sys_info->mib_length); - copy_sys_info->mib_length = orig_sys_info->mib_length; - - if (orig_sys_info->sib1_length > 0) { - copy_sys_info->sib1 = calloc(orig_sys_info->sib1_length, sizeof(uint8_t)); - AssertFatal(copy_sys_info->sib1 != NULL, "out of memory\n"); - memcpy(copy_sys_info->sib1, orig_sys_info->sib1, orig_sys_info->sib1_length); - copy_sys_info->sib1_length = orig_sys_info->sib1_length; - } - } - } - AssertFatal(upd->num_cells_to_delete == 0, "gNB-DU config update: cells to add not supported\n"); - itti_send_msg_to_task(TASK_DU_F1, 0, msg); + /* copy F1AP message */ + f1ap_gnb_du_configuration_update_t cp = cp_f1ap_du_configuration_update(upd); + /* transfer to ITTI message */ + F1AP_GNB_DU_CONFIGURATION_UPDATE(msg) = cp; + /* free after copy */ + free_f1ap_du_configuration_update(upd); + /* send to RRC task */ + itti_send_msg_to_task(TASK_RRC_GNB, 0, msg); } static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) @@ -269,20 +207,8 @@ static void ue_context_release_complete_f1ap(const f1ap_ue_context_release_compl static void initial_ul_rrc_message_transfer_f1ap(module_id_t module_id, const f1ap_initial_ul_rrc_message_t *ul_rrc) { MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, F1AP_INITIAL_UL_RRC_MESSAGE); - /* copy all fields, but reallocate rrc_containers! */ f1ap_initial_ul_rrc_message_t *f1ap_msg = &F1AP_INITIAL_UL_RRC_MESSAGE(msg); - *f1ap_msg = *ul_rrc; - - f1ap_msg->rrc_container = malloc(ul_rrc->rrc_container_length); - DevAssert(f1ap_msg->rrc_container); - memcpy(f1ap_msg->rrc_container, ul_rrc->rrc_container, ul_rrc->rrc_container_length); - f1ap_msg->rrc_container_length = ul_rrc->rrc_container_length; - - f1ap_msg->du2cu_rrc_container = malloc(ul_rrc->du2cu_rrc_container_length); - DevAssert(f1ap_msg->du2cu_rrc_container); - memcpy(f1ap_msg->du2cu_rrc_container, ul_rrc->du2cu_rrc_container, ul_rrc->du2cu_rrc_container_length); - f1ap_msg->du2cu_rrc_container_length = ul_rrc->du2cu_rrc_container_length; - + *f1ap_msg = cp_initial_ul_rrc_message_transfer(ul_rrc); itti_send_msg_to_task(TASK_DU_F1, module_id, msg); } diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index 439712ec7e..e2e094d866 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -23,6 +23,8 @@ #include "mac_rrc_dl.h" #include "nr_rrc_defs.h" +#include "openair2/F1AP/lib/f1ap_rrc_message_transfer.h" +#include "openair2/F1AP/lib/f1ap_interface_management.h" static void f1_reset_cu_initiated_f1ap(sctp_assoc_t assoc_id, const f1ap_reset_t *reset) { @@ -44,6 +46,7 @@ static void f1_setup_response_f1ap(sctp_assoc_t assoc_id, const f1ap_setup_resp_ *f1ap_msg = *resp; if (resp->gNB_CU_name != NULL) f1ap_msg->gNB_CU_name = strdup(resp->gNB_CU_name); + free_f1ap_setup_response(resp); itti_send_msg_to_task(TASK_CU_F1, 0, msg); } @@ -210,18 +213,7 @@ static void dl_rrc_message_transfer_f1ap(sctp_assoc_t assoc_id, const f1ap_dl_rr MessageDef *message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, F1AP_DL_RRC_MESSAGE); message_p->ittiMsgHeader.originInstance = assoc_id; f1ap_dl_rrc_message_t *msg = &F1AP_DL_RRC_MESSAGE(message_p); - *msg = *dl_rrc; - if (dl_rrc->old_gNB_DU_ue_id) { - msg->old_gNB_DU_ue_id = malloc(sizeof(*msg->old_gNB_DU_ue_id)); - AssertFatal(msg->old_gNB_DU_ue_id != NULL, "out of memory\n"); - *msg->old_gNB_DU_ue_id = *dl_rrc->old_gNB_DU_ue_id; - } - if (dl_rrc->rrc_container) { - msg->rrc_container = malloc(dl_rrc->rrc_container_length); - AssertFatal(msg->rrc_container != NULL, "out of memory\n"); - msg->rrc_container_length = dl_rrc->rrc_container_length; - memcpy(msg->rrc_container, dl_rrc->rrc_container, dl_rrc->rrc_container_length); - } + *msg = cp_dl_rrc_message_transfer(dl_rrc); itti_send_msg_to_task (TASK_CU_F1, 0, message_p); } diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 2c5e45f428..c1c78943e5 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -94,6 +94,7 @@ #include #include "openair2/F1AP/f1ap_common.h" #include "openair2/F1AP/f1ap_ids.h" +#include "openair2/F1AP/lib/f1ap_lib_extern.h" #include "openair2/SDAP/nr_sdap/nr_sdap_entity.h" #include "openair2/E1AP/e1ap.h" #include "cucp_cuup_if.h" @@ -1839,11 +1840,6 @@ void rrc_gNB_process_initial_ul_rrc_message(sctp_assoc_t assoc_id, const f1ap_in } } ASN_STRUCT_FREE(asn_DEF_NR_UL_CCCH_Message, ul_ccch_msg); - - if (ul_rrc->rrc_container) - free(ul_rrc->rrc_container); - if (ul_rrc->du2cu_rrc_container) - free(ul_rrc->du2cu_rrc_container); } void rrc_gNB_process_release_request(const module_id_t gnb_mod_idP, x2ap_ENDC_sgnb_release_request_t *m) @@ -2161,12 +2157,12 @@ static pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, static f1ap_qos_characteristics_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param) { f1ap_qos_characteristics_t qos_char = {0}; - if (qos_param->fiveQI_type == dynamic) { - qos_char.qos_type = dynamic; + if (qos_param->fiveQI_type == DYNAMIC) { + qos_char.qos_type = DYNAMIC; qos_char.dynamic.fiveqi = qos_param->fiveQI; qos_char.dynamic.qos_priority_level = qos_param->qos_priority; } else { - qos_char.qos_type = non_dynamic; + qos_char.qos_type = NON_DYNAMIC; qos_char.non_dynamic.fiveqi = qos_param->fiveQI; qos_char.non_dynamic.qos_priority_level = qos_param->qos_priority; } @@ -2189,7 +2185,7 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, const DRB_nGRAN_setup_t *drb_config = &pduSession[p].DRBnGRanList[i]; f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; drb->drb_id = pduSession[p].DRBnGRanList[i].id; - drb->rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM; + drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; @@ -2439,6 +2435,7 @@ void *rrc_gnb_task(void *args_p) { AssertFatal(NODE_IS_CU(RC.nrrrc[instance]->node_type) || NODE_IS_MONOLITHIC(RC.nrrrc[instance]->node_type), "should not receive F1AP_INITIAL_UL_RRC_MESSAGE, need call by CU!\n"); rrc_gNB_process_initial_ul_rrc_message(msg_p->ittiMsgHeader.originInstance, &F1AP_INITIAL_UL_RRC_MESSAGE(msg_p)); + free_initial_ul_rrc_message_transfer(&F1AP_INITIAL_UL_RRC_MESSAGE(msg_p)); break; /* Messages from PDCP */ @@ -2515,6 +2512,12 @@ void *rrc_gnb_task(void *args_p) { rrc_gNB_process_f1_du_configuration_update(&F1AP_GNB_DU_CONFIGURATION_UPDATE(msg_p), msg_p->ittiMsgHeader.originInstance); break; + case F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE: + AssertFatal(!NODE_IS_DU(RC.nrrrc[instance]->node_type), + "should not receive F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE in DU!\n"); + LOG_E(NR_RRC, "Handling of F1AP_GNB_CU_CONFIGURATION_UPDATE_ACKNOWLEDGE not implemented\n"); + break; + /* Messages from X2AP */ case X2AP_ENDC_SGNB_ADDITION_REQ: LOG_I(NR_RRC, "Received ENDC sgNB addition request from X2AP \n"); diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 1ef1f8c808..6ffb8ad88e 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -248,11 +248,11 @@ static void fill_qos(NGAP_QosFlowSetupRequestList_t *qos, pdusession_t *session) AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx); if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = non_dynamic; + session->qos[qosIdx].fiveQI_type = NON_DYNAMIC; session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI; } else { AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = dynamic; + session->qos[qosIdx].fiveQI_type = DYNAMIC; session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI); } @@ -412,7 +412,7 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; qos_flow->qfi = qos_session->qfi; qos_char->qos_type = qos_session->fiveQI_type; - if (qos_char->qos_type == dynamic) { + if (qos_char->qos_type == DYNAMIC) { qos_char->dynamic.fiveqi = qos_session->fiveQI; qos_char->dynamic.qos_priority_level = qos_session->qos_priority; } else { @@ -861,11 +861,11 @@ static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *s AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx); if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) { AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = non_dynamic; + session->qos[qosIdx].fiveQI_type = NON_DYNAMIC; session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI; } else { AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n"); - session->qos[qosIdx].fiveQI_type = dynamic; + session->qos[qosIdx].fiveQI_type = DYNAMIC; session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI); } diff --git a/openair2/RRC/NR/rrc_gNB_du.c b/openair2/RRC/NR/rrc_gNB_du.c index e20121e8c2..e2806edf60 100644 --- a/openair2/RRC/NR/rrc_gNB_du.c +++ b/openair2/RRC/NR/rrc_gNB_du.c @@ -29,6 +29,7 @@ #include "executables/softmodem-common.h" #include "common/utils/ds/seq_arr.h" #include "common/utils/alg/foreach.h" +#include "lib/f1ap_interface_management.h" int get_dl_band(const struct f1ap_served_cell_info_t *cell_info) { @@ -261,6 +262,8 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) DevAssert(rrc); LOG_I(NR_RRC, "Received F1 Setup Request from gNB_DU %lu (%s) on assoc_id %d\n", req->gNB_DU_id, req->gNB_DU_name, assoc_id); + // pre-fill F1 Setup Failure message + f1ap_setup_failure_t fail = {.transaction_id = F1AP_get_next_transaction_identifier(0, 0)}; // check: // - it is one cell @@ -269,7 +272,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) // else reject if (req->num_cells_available != 1) { LOG_E(NR_RRC, "can only handle on DU cell, but gNB_DU %ld has %d\n", req->gNB_DU_id, req->num_cells_available); - f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_gNB_CU_Cell_Capacity_Exceeded}; + fail.cause = F1AP_CauseRadioNetwork_gNB_CU_Cell_Capacity_Exceeded; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); return; } @@ -283,7 +286,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) cell_info->plmn.mcc, cell_info->plmn.mnc_digit_length, cell_info->plmn.mnc); - f1ap_setup_failure_t fail = {.cause = F1AP_CauseRadioNetwork_plmn_not_served_by_the_gNB_CU}; + fail.cause = F1AP_CauseRadioNetwork_plmn_not_served_by_the_gNB_CU; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); return; } @@ -295,7 +298,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) it->setup_req->gNB_DU_name, it->assoc_id, it->setup_req->gNB_DU_id); - f1ap_setup_failure_t fail = {.cause = F1AP_CauseMisc_unspecified}; + fail.cause = F1AP_CauseMisc_unspecified; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); return; } @@ -312,7 +315,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) exist_info->nr_pci, new_info->nr_cellid, new_info->nr_pci); - f1ap_setup_failure_t fail = {.cause = F1AP_CauseMisc_unspecified}; + fail.cause = F1AP_CauseMisc_unspecified; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); return; } @@ -339,7 +342,7 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) if (sys_info != NULL && sys_info->mib != NULL && !(sys_info->sib1 == NULL && get_softmodem_params()->sa)) { if (!extract_sys_info(sys_info, &mib, &sib1)) { LOG_W(RRC, "rejecting DU ID %ld\n", req->gNB_DU_id); - f1ap_setup_failure_t fail = {.cause = F1AP_CauseProtocol_semantic_error}; + fail.cause = F1AP_CauseProtocol_semantic_error; rrc->mac_rrc.f1_setup_failure(assoc_id, &fail); ASN_STRUCT_FREE(asn_DEF_NR_MeasurementTimingConfiguration, mtc); return; @@ -358,7 +361,8 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) * allocate memory and copy it in */ du->setup_req = calloc(1,sizeof(*du->setup_req)); AssertFatal(du->setup_req, "out of memory\n"); - *du->setup_req = *req; + // Copy F1AP message + *du->setup_req = cp_f1ap_setup_request(req); // MIB can be null and configured later via DU Configuration Update du->mib = mib; du->sib1 = sib1; @@ -379,6 +383,8 @@ void rrc_gNB_process_f1_setup_req(f1ap_setup_req_t *req, sctp_assoc_t assoc_id) f1ap_setup_resp_t resp = {.transaction_id = req->transaction_id, .num_cells_to_activate = 1, .cells_to_activate[0] = cell}; + // free F1AP message after use + free_f1ap_setup_request(req); int num = read_version(TO_STRING(NR_RRC_VERSION), &resp.rrc_ver[0], &resp.rrc_ver[1], &resp.rrc_ver[2]); AssertFatal(num == 3, "could not read RRC version string %s\n", TO_STRING(NR_RRC_VERSION)); if (rrc->node_name != NULL) @@ -510,8 +516,9 @@ void rrc_gNB_process_f1_du_configuration_update(f1ap_gnb_du_configuration_update /* Send DU Configuration Acknowledgement */ f1ap_gnb_du_configuration_update_acknowledge_t ack = {.transaction_id = conf_up->transaction_id}; - rrc->mac_rrc.gnb_du_configuration_update_acknowledge(assoc_id, &ack); + /* free F1AP message after use */ + free_f1ap_du_configuration_update(conf_up); } void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id) diff --git a/openair3/SCTP/sctp_eNB_task.c b/openair3/SCTP/sctp_eNB_task.c index a6d3a11a39..530b3ea6b0 100644 --- a/openair3/SCTP/sctp_eNB_task.c +++ b/openair3/SCTP/sctp_eNB_task.c @@ -394,7 +394,7 @@ static void sctp_handle_new_association_req(const instance_t instance, struct addrinfo *serv; int status = getaddrinfo(local, NULL, &hints, &serv); - AssertFatal(status == 0, "getaddrinfo() failed: %s\n", gai_strerror(status)); + AssertFatal(status == 0, "getaddrinfo(%s) failed: %s\n", local, gai_strerror(status)); int sd; struct addrinfo *p = NULL;