From bf3b8b19efa0ca8203d0666d3214eb8f4d015748 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Fri, 20 Dec 2024 09:38:28 +0100 Subject: [PATCH 01/18] Fix missing line break in e1ap.c --- openair2/E1AP/e1ap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 95046cb652..e9aa7f54df 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -1129,7 +1129,7 @@ static void e1_task_handle_sctp_association_resp(E1_t type, if (getCxtE1(instance)->gtpInstF1U < 0) getCxtE1(instance)->gtpInstF1U = cuup_task_create_gtpu_instance_to_du(&IPaddr); if (getCxtE1(instance)->gtpInstF1U < 0) - LOG_E(E1AP, "Failed to create CUUP F1-U UDP listener"); + LOG_E(E1AP, "Failed to create CUUP F1-U UDP listener\n"); extern instance_t CUuniqInstance; CUuniqInstance = getCxtE1(instance)->gtpInstF1U; cuup_init_n3(instance); @@ -1152,7 +1152,7 @@ void cuup_init_n3(instance_t instance) legacyInstanceMapping = getCxtE1(instance)->gtpInstN3 = gtpv1Init(tmp); } if (getCxtE1(instance)->gtpInstN3 < 0) - LOG_E(E1AP, "Failed to create CUUP N3 UDP listener"); + LOG_E(E1AP, "Failed to create CUUP N3 UDP listener\n"); extern instance_t *N3GTPUInst; N3GTPUInst = &getCxtE1(instance)->gtpInstN3; } From a0da09635154a74d59f298705c2f00bf924300b9 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 4 Dec 2024 11:55:33 +0100 Subject: [PATCH 02/18] Fix equality check types in Bearer Context Setup Request/Response --- openair2/E1AP/lib/e1ap_bearer_context_management.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index 5e359512ed..a67d4b5b08 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -263,7 +263,7 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_List_NG_RAN; _E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0); out->numDRB2Setup = drb2SetupList->list.count; - _E1_EQ_CHECK_INT(out->numDRB2Setup, 1); // can only handle one DRB per PDU session + _E1_EQ_CHECK_LONG(out->numDRB2Setup, 1UL); // can only handle one DRB per PDU session for (int j = 0; j < drb2SetupList->list.count; j++) { DRB_nGRAN_to_setup_t *drb = out->DRBnGRanList + j; E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j]; @@ -492,8 +492,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea // Check message type _E1_EQ_CHECK_INT(pdu->present,E1AP_E1AP_PDU_PR_initiatingMessage); - _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); - _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->criticality, E1AP_Criticality_reject); + _E1_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest); const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest; @@ -828,8 +827,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be { // Check message type _E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_successfulOutcome); - _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); - _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->criticality, E1AP_Criticality_reject); + _E1_EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse); const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse; @@ -862,7 +860,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be ie->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse; _E1_EQ_CHECK_INT(msgNGRAN_list->list.count, 1); E1AP_NG_RAN_BearerContextSetupResponse_t *msgNGRAN = msgNGRAN_list->list.array[0]; - _E1_EQ_CHECK_INT(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List); + _E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List); _E1_EQ_CHECK_INT(msgNGRAN->value.present, E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List); E1AP_PDU_Session_Resource_Setup_List_t *pduSetupList = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List; From e9ff62884422725fbe92d2e7f84a71f43bb4bcb0 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 19 Nov 2024 18:55:29 +0100 Subject: [PATCH 03/18] Add macros to deep copy and compare optional E1 IEs --- openair2/E1AP/lib/e1ap_lib_common.h | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/openair2/E1AP/lib/e1ap_lib_common.h b/openair2/E1AP/lib/e1ap_lib_common.h index f3c6b24da2..eceddb263f 100644 --- a/openair2/E1AP/lib/e1ap_lib_common.h +++ b/openair2/E1AP/lib/e1ap_lib_common.h @@ -66,4 +66,36 @@ } \ } while (0) +/* deep copy of optional E1AP IE */ +#define _E1_CP_OPTIONAL_IE(dest, src, field) \ + do { \ + if ((src)->field) { \ + (dest)->field = malloc_or_fail(sizeof(*(dest)->field)); \ + *(dest)->field = *(src)->field; \ + } \ + } while (0) + +#define _E1_EQ_CHECK_OPTIONAL_IE(a, b, field, EQ_MACRO) \ + do { \ + if (((a)->field && !(b)->field) || (!(a)->field && (b)->field)) { \ + return false; /* One of the two is not allocated */ \ + } \ + if ((a)->field && (b)->field) { \ + EQ_MACRO(*(a)->field, *(b)->field) \ + } \ + } while (0) + +#define _E1_EQ_CHECK_OPTIONAL_PTR(a, b, field) \ + do { \ + if (((a)->field && !(b)->field) || (!(a)->field && (b)->field)) { \ + PRINT_ERROR("%s:%d: optional IE '%s' not allocated: %p, %p\n", \ + __FILE__, \ + __LINE__, \ + #field, \ + (void *)(a)->field, \ + (void *)(b)->field); \ + return false; /* One of the two is not allocated */ \ + } \ + } while (0) + #endif /* E1AP_LIB_COMMON_H_ */ From 212fe8d2f35f94267a5c0cde3ed92bf9f326eed3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 3 Feb 2025 15:58:04 +0100 Subject: [PATCH 04/18] Add common enc/dec E1AP libs to e1ap_lib_common.c * these functions are used in both interface management and bearer context management libraries --- openair2/E1AP/lib/CMakeLists.txt | 1 + openair2/E1AP/lib/e1ap_interface_management.c | 59 +------------- openair2/E1AP/lib/e1ap_lib_common.c | 81 +++++++++++++++++++ openair2/E1AP/lib/e1ap_lib_common.h | 5 ++ 4 files changed, 89 insertions(+), 57 deletions(-) create mode 100644 openair2/E1AP/lib/e1ap_lib_common.c diff --git a/openair2/E1AP/lib/CMakeLists.txt b/openair2/E1AP/lib/CMakeLists.txt index 27bfbcc8a2..332986dffb 100644 --- a/openair2/E1AP/lib/CMakeLists.txt +++ b/openair2/E1AP/lib/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(e1ap_lib OBJECT e1ap_bearer_context_management.c e1ap_interface_management.c + e1ap_lib_common.c ) target_link_libraries(e1ap_lib PRIVATE asn1_e1ap) diff --git a/openair2/E1AP/lib/e1ap_interface_management.c b/openair2/E1AP/lib/e1ap_interface_management.c index 8f29ba07c5..681942f58b 100644 --- a/openair2/E1AP/lib/e1ap_interface_management.c +++ b/openair2/E1AP/lib/e1ap_interface_management.c @@ -508,61 +508,6 @@ bool eq_e1ap_cuup_setup_response(const e1ap_setup_resp_t *a, const e1ap_setup_re * GNB-CU-UP E1 SETUP FAILURE * ==================================== */ -static E1AP_Cause_t encode_e1ap_cause_ie(const e1ap_cause_t *cause) -{ - E1AP_Cause_t ie; - switch (cause->type) { - case E1AP_CAUSE_RADIO_NETWORK: - ie.present = E1AP_Cause_PR_radioNetwork; - ie.choice.radioNetwork = cause->value; - break; - case E1AP_CAUSE_TRANSPORT: - ie.present = E1AP_Cause_PR_transport; - ie.choice.transport = cause->value; - break; - case E1AP_CAUSE_PROTOCOL: - ie.present = E1AP_Cause_PR_protocol; - ie.choice.protocol = cause->value; - break; - case E1AP_CAUSE_MISC: - ie.present = E1AP_Cause_PR_misc; - ie.choice.misc = cause->value; - break; - default: - ie.present = E1AP_Cause_PR_NOTHING; - break; - } - return ie; -} - -static e1ap_cause_t decode_e1ap_cause_ie(const E1AP_Cause_t *ie) -{ - e1ap_cause_t cause; - // Decode the 'choice' field based on the 'present' value - switch (ie->present) { - case E1AP_Cause_PR_radioNetwork: - cause.value = ie->choice.radioNetwork; - cause.type = E1AP_CAUSE_RADIO_NETWORK; - break; - case E1AP_Cause_PR_transport: - cause.value = ie->choice.transport; - cause.type = E1AP_CAUSE_TRANSPORT; - break; - case E1AP_Cause_PR_protocol: - cause.value = ie->choice.protocol; - cause.type = E1AP_CAUSE_PROTOCOL; - break; - case E1AP_Cause_PR_misc: - cause.value = ie->choice.misc; - cause.type = E1AP_CAUSE_MISC; - break; - default: - cause.type = E1AP_CAUSE_NOTHING; - break; - } - return cause; -} - /** * @brief Encoder for GNB-CU-UP E1 Setup Failure * @ref 9.2.1.6 GNB-CU-UP E1 SETUP FAILURE of 3GPP TS 38.463 @@ -588,7 +533,7 @@ E1AP_E1AP_PDU_t *encode_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *msg) ie2->id = E1AP_ProtocolIE_ID_id_Cause; ie2->criticality = E1AP_Criticality_ignore; ie2->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_Cause; - ie2->value.choice.Cause = encode_e1ap_cause_ie(&msg->cause); + ie2->value.choice.Cause = e1_encode_cause_ie(&msg->cause); // Time To Wait (O) if (msg->time_to_wait) { asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie3); @@ -630,7 +575,7 @@ bool decode_e1ap_cuup_setup_failure(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_fail_ case E1AP_ProtocolIE_ID_id_Cause: // Cause E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Cause, true); - out->cause = decode_e1ap_cause_ie(&ie->value.choice.Cause); + out->cause = e1_decode_cause_ie(&ie->value.choice.Cause); break; case E1AP_ProtocolIE_ID_id_Transport_Layer_Address_Info: // Time To Wait (O) diff --git a/openair2/E1AP/lib/e1ap_lib_common.c b/openair2/E1AP/lib/e1ap_lib_common.c new file mode 100644 index 0000000000..02923b7cf7 --- /dev/null +++ b/openair2/E1AP/lib/e1ap_lib_common.c @@ -0,0 +1,81 @@ +/* + * 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 "e1ap_lib_common.h" +#include "e1ap_lib_includes.h" +#include "e1ap_messages_types.h" + +E1AP_Cause_t e1_encode_cause_ie(const e1ap_cause_t *cause) +{ + E1AP_Cause_t ie; + switch (cause->type) { + case E1AP_CAUSE_RADIO_NETWORK: + ie.present = E1AP_Cause_PR_radioNetwork; + ie.choice.radioNetwork = cause->value; + break; + case E1AP_CAUSE_TRANSPORT: + ie.present = E1AP_Cause_PR_transport; + ie.choice.transport = cause->value; + break; + case E1AP_CAUSE_PROTOCOL: + ie.present = E1AP_Cause_PR_protocol; + ie.choice.protocol = cause->value; + break; + case E1AP_CAUSE_MISC: + ie.present = E1AP_Cause_PR_misc; + ie.choice.misc = cause->value; + break; + default: + ie.present = E1AP_Cause_PR_NOTHING; + PRINT_ERROR("encode_e1ap_cause_ie: no cause value provided\n"); + break; + } + return ie; +} + +e1ap_cause_t e1_decode_cause_ie(const E1AP_Cause_t *ie) +{ + e1ap_cause_t cause; + // Decode the 'choice' field based on the 'present' value + switch (ie->present) { + case E1AP_Cause_PR_radioNetwork: + cause.value = ie->choice.radioNetwork; + cause.type = E1AP_CAUSE_RADIO_NETWORK; + break; + case E1AP_Cause_PR_transport: + cause.value = ie->choice.transport; + cause.type = E1AP_CAUSE_TRANSPORT; + break; + case E1AP_Cause_PR_protocol: + cause.value = ie->choice.protocol; + cause.type = E1AP_CAUSE_PROTOCOL; + break; + case E1AP_Cause_PR_misc: + cause.value = ie->choice.misc; + cause.type = E1AP_CAUSE_MISC; + break; + default: + cause.type = E1AP_CAUSE_NOTHING; + PRINT_ERROR("decode_e1ap_cause_ie: no cause value provided\n"); + break; + } + return cause; +} diff --git a/openair2/E1AP/lib/e1ap_lib_common.h b/openair2/E1AP/lib/e1ap_lib_common.h index eceddb263f..be11100d90 100644 --- a/openair2/E1AP/lib/e1ap_lib_common.h +++ b/openair2/E1AP/lib/e1ap_lib_common.h @@ -26,6 +26,7 @@ #include #include #include "openair3/UTILS/conversions.h" +#include "e1ap_messages_types.h" #ifdef ENABLE_TESTS #define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__); @@ -98,4 +99,8 @@ } \ } while (0) +struct E1AP_Cause; +struct E1AP_Cause e1_encode_cause_ie(const e1ap_cause_t *cause); +e1ap_cause_t e1_decode_cause_ie(const struct E1AP_Cause *ie); + #endif /* E1AP_LIB_COMMON_H_ */ From b862963a95060c0b9d7277b7b2dc1386a8dbd6cf Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 4 Feb 2025 11:14:59 +0100 Subject: [PATCH 05/18] Add macro to check result of dec lib functions and return with a failure --- openair2/E1AP/lib/e1ap_lib_common.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openair2/E1AP/lib/e1ap_lib_common.h b/openair2/E1AP/lib/e1ap_lib_common.h index be11100d90..39e3d64448 100644 --- a/openair2/E1AP/lib/e1ap_lib_common.h +++ b/openair2/E1AP/lib/e1ap_lib_common.h @@ -34,6 +34,14 @@ #define PRINT_ERROR(...) // Do nothing #endif +#define CHECK_E1AP_DEC(exp) \ + do { \ + if (!(exp)) { \ + PRINT_ERROR("Failed executing " #exp " in %s() line %d\n", __func__, __LINE__); \ + return false; \ + } \ + } while (0) + #define _E1_EQ_CHECK_GENERIC(condition, fmt, ...) \ do { \ if (!(condition)) { \ From 4f613ab2af372f48126be268e2f8001d3dac1c3e Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 4 Feb 2025 11:31:33 +0100 Subject: [PATCH 06/18] Remove incomplete activityNotificationLevel handling --- openair2/COMMON/e1ap_messages_types.h | 7 ------- openair2/E1AP/lib/e1ap_bearer_context_management.c | 7 ------- openair2/E1AP/tests/e1ap_lib_test.c | 1 - 3 files changed, 15 deletions(-) diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index 7fed096971..458cfc1f46 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -138,12 +138,6 @@ typedef enum BEARER_CONTEXT_STATUS_e { BEARER_RESUME, } BEARER_CONTEXT_STATUS_t; -typedef enum activity_notification_level_e { - ANL_DRB = 0, - ANL_PDU_SESSION, - ANL_UE, -} activity_notification_level_t; - typedef enum cell_group_id_e { MCG = 0, SCG, @@ -413,7 +407,6 @@ typedef struct e1ap_bearer_setup_req_s { long ueDlAggMaxBitRate; PLMN_ID_t servingPLMNid; BEARER_CONTEXT_STATUS_t bearerContextStatus; - activity_notification_level_t activityNotificationLevel; int numPDUSessions; pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; int numPDUSessionsMod; diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index a67d4b5b08..2552e478ba 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -544,12 +544,6 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea out->servingPLMNid.mnc_digit_length); break; - case E1AP_ProtocolIE_ID_id_ActivityNotificationLevel: - _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel); - out->activityNotificationLevel = ie->value.choice.ActivityNotificationLevel; - break; - case E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest: _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest); E1AP_System_BearerContextSetupRequest_t *System_BearerContextSetupRequest = @@ -629,7 +623,6 @@ bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1a _E1_EQ_CHECK_LONG(a->cipheringAlgorithm, b->cipheringAlgorithm); _E1_EQ_CHECK_LONG(a->integrityProtectionAlgorithm, b->integrityProtectionAlgorithm); _E1_EQ_CHECK_LONG(a->ueDlAggMaxBitRate, b->ueDlAggMaxBitRate); - _E1_EQ_CHECK_INT(a->activityNotificationLevel, b->activityNotificationLevel); _E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions); _E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod); // PLMN diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index 91eab080a9..9a53e8074d 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -114,7 +114,6 @@ static void test_bearer_context_setup_request(void) .servingPLMNid.mcc = 001, .servingPLMNid.mnc = 01, .servingPLMNid.mnc_digit_length = 0x02, - .activityNotificationLevel = ANL_PDU_SESSION, .numPDUSessions = 1, .pduSession[0].sessionId = 1, .pduSession[0].sessionType = E1AP_PDU_Session_Type_ipv4, From 2146f29c44e77f81615c7c089c65d6f32e32a784 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 4 Feb 2025 11:56:40 +0100 Subject: [PATCH 07/18] Refactor E1 Bearer Context Management structs Bearer context setup request and modification request messages differ in various IEs according to 9.2.2 of 3GPP TS 38.463, e.g. the Bearer context setup request does not contain a list of DRBs to modify and does not contain an UP TL configuration. Thus, the goal of this commit is to split the setup request message and the modification request into two different structs: * adopt e1ap_bearer_mod_req_t where necessary (e.g. fill_e1_bearer_modif) Also, reorganized existing struct members according to specs: * remove irrelevant struct members from the setup request * group members from the same IEs into structs * set optional struct members IEs as pointers * add and adopt enc/dec/cp/eq lib functions for single IEs * add UP_TL_information_t struct with TEID and TL address info and adopt in stack * use int instead of long for count types * update the relevant copy/equality check utility functions Extra: * add a function to handle Security Information in RRC in the process * add create_up_tl_info and adopt in unit tests --- openair1/SIMULATION/NR_PHY/dlsim.c | 2 +- openair1/SIMULATION/NR_PHY/psbchsim.c | 2 +- openair1/SIMULATION/NR_PHY/ulsim.c | 2 +- openair2/COMMON/e1ap_messages_types.h | 239 +++++-- openair2/E1AP/e1ap.c | 20 +- .../E1AP/lib/e1ap_bearer_context_management.c | 590 ++++++++++-------- openair2/E1AP/lib/e1ap_lib_includes.h | 1 + openair2/E1AP/tests/e1ap_lib_test.c | 25 +- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 35 +- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h | 3 +- openair2/RRC/NR/cucp_cuup_if.h | 2 + openair2/RRC/NR/nr_rrc_defs.h | 2 +- openair2/RRC/NR/rrc_gNB.c | 54 +- openair2/RRC/NR/rrc_gNB_NGAP.c | 9 +- 14 files changed, 585 insertions(+), 401 deletions(-) diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index 236913d3f8..67da0bb428 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -125,7 +125,7 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); } void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); } +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); } int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) { diff --git a/openair1/SIMULATION/NR_PHY/psbchsim.c b/openair1/SIMULATION/NR_PHY/psbchsim.c index 972605fc96..f5b0f88ab2 100644 --- a/openair1/SIMULATION/NR_PHY/psbchsim.c +++ b/openair1/SIMULATION/NR_PHY/psbchsim.c @@ -51,7 +51,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 301beb19f5..5f2b7ce6c9 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -126,7 +126,7 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); } +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); } int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) { diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index 458cfc1f46..2f59cb62d6 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -252,10 +252,16 @@ typedef struct e1ap_setup_fail_s { criticality_diagnostics_t *crit_diag; } e1ap_setup_fail_t; -typedef struct up_params_s { +typedef struct UP_TL_information_s { in_addr_t tlAddress; - long teId; - int cell_group_id; + int32_t teId; +} UP_TL_information_t; + +typedef struct up_params_s { + // Transport layer info + UP_TL_information_t tl_info; + // Cell Group ID (M) + cell_group_id_t cell_group_id; } up_params_t; /* IE SDAP Configuration (clause 9.3.1.39 of 3GPP TS 38.463) */ @@ -325,38 +331,63 @@ typedef struct qos_flow_level_qos_parameters_s { ngran_allocation_retention_priority_t alloc_reten_priority; // additional members should be added!! } qos_flow_level_qos_parameters_t; +// QoS Flow QoS Parameters List 9.3.1.25 typedef struct qos_flow_setup_e { long qfi; // qos flow identifier qos_flow_level_qos_parameters_t qos_params; } qos_flow_to_setup_t; -/* DRB To Setup List according to 3GPP TS 38.463 */ +// 9.3.1.60 QoS Flow Mapping Indication +typedef enum qos_flow_mapping_indication_e { + QF_UL = 0, + QF_DL, + QF_BOTH +} qos_flow_mapping_indication_t; + +typedef struct qos_flow_list_s { + long qfi; // qos flow identifier + qos_flow_mapping_indication_t *indication; +} qos_flow_list_t; + +/** + * DRB To Setup List according to 3GPP TS 38.463 + */ typedef struct DRB_nGRAN_to_setup_s { - /* DRB ID (clause 9.3.1.16) */ + // DRB ID (M) (clause 9.3.1.16) long id; - - /* SDAP Configuration (clause 9.3.1.39) */ + // SDAP Configuration (M) (clause 9.3.1.39) bearer_context_sdap_config_t sdap_config; - /* PDCP Configuration (clause 9.3.1.38) */ + // PDCP Configuration (M) (clause 9.3.1.38) bearer_context_pdcp_config_t pdcp_config; - - /* DRB Data Forwarding Information (clause 9.3.2.6) */ - /* Transport Layer Address (clause 9.3.2.4) */ - in_addr_t tlAddress; - /* GTP-TEID (clause 9.3.2.3) */ - int teId; - /* DL UP Transport Layer Information (clause 9.3.2.1) */ - int numDlUpParam; - up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM]; - - /* Cell Group Information (clause 9.3.1.11) */ + // DRB Inactivity Timer (O) + int *drb_inactivity_timer; + // Cell Group Information (M) (clause 9.3.1.11) int numCellGroups; cell_group_id_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS]; - - /* DRB QoS Flows Parameters (clause 9.3.1.26) */ + // QoS Flows Information To Be Setup (M) (clause 9.3.1.25, 9.3.1.26) int numQosFlow2Setup; qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; -} DRB_nGRAN_to_setup_t, DRB_nGRAN_to_mod_t; +} DRB_nGRAN_to_setup_t; + +/** + * DRB To Modify List according to 3GPP TS 38.463 + */ +typedef struct DRB_nGRAN_to_modify_s { + // DRB ID (M) (clause 9.3.1.16) + long id; + // SDAP Configuration (O) (clause 9.3.1.39) + bearer_context_sdap_config_t *sdap_config; + // PDCP Configuration (O) (clause 9.3.1.38) + bearer_context_pdcp_config_t *pdcp_config; + // PDCP SN Status Request (O) + bool pdcp_sn_status_requested; + // DL UP Transport Layer Information (O) (clause 9.3.1.13, 9.3.2.1) + int numDlUpParam; + up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM]; + // QoS Flows Information To Modify (O) (clause 9.3.1.25, 9.3.1.26) + int numQosFlow2Setup; + qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; +} DRB_nGRAN_to_mod_t; typedef enum e1ap_indication_e { SECURITY_REQUIRED = 0, @@ -371,47 +402,108 @@ typedef struct security_indication_s { long maxIPrate; } security_indication_t; -typedef struct UP_TL_information_s { - in_addr_t tlAddress; - int32_t teId; -} UP_TL_information_t; - -/** - * PDU Session Resource To Setup List (clause 9.3.3.10) - * PDU Session Resource To Modify List (clause 9.3.3.11) -*/ -typedef struct pdu_session_to_setup_s { - long sessionId; - long sessionType; - e1ap_nssai_t nssai; - security_indication_t securityIndication; - UP_TL_information_t UP_TL_information; - long numDRB2Setup; - DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; - long numDRB2Modify; - DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; -} pdu_session_to_setup_t, pdu_session_to_mod_t; - -/** - * Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463 - * out of simplicity, this same struct is used for clause 9.2.2.4 - * i.e. Bearer Context Modification Request message - */ -typedef struct e1ap_bearer_setup_req_s { - uint32_t gNB_cu_cp_ue_id; - uint32_t gNB_cu_up_ue_id; // Bearer Context Modification Request only +// Security Information (9.3.1.10) +typedef struct security_information_s { uint64_t cipheringAlgorithm; uint64_t integrityProtectionAlgorithm; char encryptionKey[E1AP_SECURITY_KEY_SIZE]; char integrityProtectionKey[E1AP_SECURITY_KEY_SIZE]; - long ueDlAggMaxBitRate; +} security_information_t; + +/** + * PDU Session Resource To Setup List (clause 9.3.3.10) + */ +typedef struct pdu_session_to_setup_s { + // PDU Session ID (M) + long sessionId; + // PDU Session Type (M) + long sessionType; + // S-NSSAI (M) + e1ap_nssai_t nssai; + // Security Indication (M) + security_indication_t securityIndication; + // PDU Session Resource DL Aggregate Maximum Bit Rate (O) + long *dlAggregateMaxBitRate; + // NG UL UP Transport Layer Information (M) + UP_TL_information_t UP_TL_information; + // PDU Session Inactivity Timer (O) + int *inactivityTimer; + // DRB To Setup List (M) + int numDRB2Setup; + // DRB To Setup Item (1..) + DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; +} pdu_session_to_setup_t; + +/** + * PDU Session Resource To Modify List (clause 9.3.3.11) + */ +typedef struct pdu_session_to_mod_s { + // PDU Session ID (M) + long sessionId; + // Security Indication (O) + security_indication_t *securityIndication; + // NG UL UP Transport Layer Information (O) + UP_TL_information_t *UP_TL_information; + // DRB To Setup List (0..1) + int numDRB2Setup; + // DRB To Setup Item (1..) + DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; + // DRB To Modify List (0..1) + long numDRB2Modify; + // DRB To Modify Item (1..) + DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; +} pdu_session_to_mod_t; + +/** + * Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463 + */ +typedef struct e1ap_bearer_setup_req_s { + // gNB-CU-CP UE E1AP ID (M) + uint32_t gNB_cu_cp_ue_id; + // Security Information (M) + security_information_t secInfo; + // UE DL Aggregate Maximum Bit Rate (M) + long ueDlAggMaxBitRate; + // UE DL Maximum Integrity Protected Data Rate (O) + long *ueDlMaxIPBitRate; + // Serving PLMN (M) PLMN_ID_t servingPLMNid; + // Bearer Context Status Change (O) BEARER_CONTEXT_STATUS_t bearerContextStatus; + // UE Inactivity Timer (O) + int *inactivityTimerUE; + // NG-RAN PDU Session Resource To Setup List (M) int numPDUSessions; pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; +} e1ap_bearer_setup_req_t; + +/** + * Bearer Context Modification Request, clause 9.2.2.4 of 3GPP TS 38.463 + */ +typedef struct e1ap_bearer_mod_req_s { + // gNB-CU-CP UE E1AP ID (M) + uint32_t gNB_cu_cp_ue_id; + // gNB-CU-UP UE E1AP ID (M) + uint32_t gNB_cu_up_ue_id; + // Security Information (O) + security_information_t *secInfo; + // UE DL Aggregate Maximum Bit Rate (O) + uint32_t *ueDlAggMaxBitRate; + // UE DL Maximum Integrity Protected Data Rate (O) + uint32_t *ueDlMaxIPBitRate; + // Bearer Context Status Change (O) + BEARER_CONTEXT_STATUS_t *bearerContextStatus; + // UE Inactivity Timer (O) + int *inactivityTimer; + // Data Discard Required (O) + bool dataDiscardRequired; + // NG-RAN PDU Session Resource To Setup List (O) + int numPDUSessions; + pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; + // NG-RAN PDU Session Resource To Modify List (O) int numPDUSessionsMod; pdu_session_to_mod_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS]; -} e1ap_bearer_setup_req_t, e1ap_bearer_mod_req_t; +} e1ap_bearer_mod_req_t; typedef struct e1ap_bearer_release_cmd_s { uint32_t gNB_cu_cp_ue_id; @@ -425,43 +517,61 @@ typedef struct e1ap_bearer_release_cplt_s { uint32_t gNB_cu_up_ue_id; } e1ap_bearer_release_cplt_t; -typedef struct qos_flow_setup_s { - long qfi; -} qos_flow_setup_t; - typedef struct DRB_nGRAN_setup_s { + // DRB ID (M) long id; int numUpParam; up_params_t UpParamList[E1AP_MAX_NUM_UP_PARAM]; + // Flow Setup List (M) int numQosFlowSetup; - qos_flow_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; + qos_flow_list_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; } DRB_nGRAN_setup_t; +/* DRB Modified Item */ typedef struct DRB_nGRAN_modified_s { + // DRB ID (M) long id; + // UL UP Parameters (O) + int numUpParam; + up_params_t ul_UP_Params[E1AP_MAX_NUM_UP_PARAM]; + // Flow Setup List (O) + int numQosFlowSetup; + qos_flow_list_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; + // Old QoS Flow List (O) + int numOldQosFlow; + qos_flow_list_t oldQosFlows[E1AP_MAX_NUM_QOS_FLOWS]; } DRB_nGRAN_modified_t; typedef struct DRB_nGRAN_failed_s { long id; - long cause_type; - long cause; + e1ap_cause_t cause; } DRB_nGRAN_failed_t; typedef struct pdu_session_setup_s { long id; - in_addr_t tlAddress; - long teId; + // Transport layer info + UP_TL_information_t tl_info; int numDRBSetup; DRB_nGRAN_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; int numDRBFailed; DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_DRBS]; } pdu_session_setup_t; +/* PDU Session Resource Modified List (9.3.3.17) */ typedef struct pdu_session_modif_s { + // PDU Session ID (M) long id; - // setup as part of PDU session modification not supported yet + // Security Result (O) + e1ap_indication_t *integrityProtectionIndication; + e1ap_indication_t *confidentialityProtectionIndication; + // NG DL UP Transport Layer Information (O) + UP_TL_information_t *ng_DL_UP_TL_info; + // DRB Modified List (O) int numDRBModified; DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; + // DRB Setup List (O) + int numDRBSetup; + DRB_nGRAN_setup_t DRBnGRanSetupList[E1AP_MAX_NUM_DRBS]; } pdu_session_modif_t; typedef struct e1ap_bearer_setup_resp_s { @@ -472,8 +582,11 @@ typedef struct e1ap_bearer_setup_resp_s { } e1ap_bearer_setup_resp_t; typedef struct e1ap_bearer_modif_resp_s { + // gNB-CU-CP UE E1AP ID (M) uint32_t gNB_cu_cp_ue_id; + // gNB-CU-UP UE E1AP ID (M) uint32_t gNB_cu_up_ue_id; + // NG-RAN PDU Session Resource Modified List (O) int numPDUSessionsMod; pdu_session_modif_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS]; } e1ap_bearer_modif_resp_t; diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index e9aa7f54df..72eff658cb 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -429,7 +429,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upc BEARER CONTEXT MODIFICATION REQUEST */ -static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) +static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_mod_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) { pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; asn1cCalloc(pdu->choice.initiatingMessage, msg); @@ -473,7 +473,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod); drb2Mod->dRB_ID = j->id; asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration); - if (j->pdcp_config.pDCP_Reestablishment) { + if (j->pdcp_config && j->pdcp_config->pDCP_Reestablishment) { asn1cCallocOne(pDCP_Configuration->pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true); } if (j->numDlUpParam > 0) { @@ -482,8 +482,8 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param); DL_UP_Param->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; asn1cCalloc(DL_UP_Param->uP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tl_info.tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(k->tl_info.teId, &gTPTunnel->gTP_TEID); DL_UP_Param->cell_Group_ID = k->cell_group_id; } @@ -491,7 +491,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con } } /* c4. E1AP_ProtocolIE_ID_id_BearerContextStatusChange */ - if (bearerCxt->bearerContextStatus == BEARER_SUSPEND) { + if (bearerCxt->bearerContextStatus && *bearerCxt->bearerContextStatus == BEARER_SUSPEND) { asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC4); ieC4->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange; ieC4->criticality = E1AP_Criticality_reject; @@ -635,7 +635,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p if (drb2Mod->pDCP_Configuration != NULL && drb2Mod->pDCP_Configuration->pDCP_Reestablishment != NULL && *drb2Mod->pDCP_Configuration->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true) { - drb->pdcp_config.pDCP_Reestablishment = true; + drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config)); + drb->pdcp_config->pDCP_Reestablishment = true; } if (drb2Mod->dL_UP_Parameters) { /* Optional IE in the DRB To Modify Item */ E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; @@ -647,8 +648,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p DevAssert(dl_up_param_in->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel); BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4( &dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->transportLayerAddress, - dl_up_param->tlAddress); - OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->teId); + dl_up_param->tl_info.tlAddress); + OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->tl_info.teId); } else { AssertFatal(false, "gTPTunnel IE is missing. It is mandatory at this point\n"); } @@ -663,7 +664,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p /* Bearer Context Status Change */ DevAssert(ie->criticality == E1AP_Criticality_reject); DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange); - bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE; + bearerCxt->bearerContextStatus = malloc_or_fail(*bearerCxt->bearerContextStatus); + *bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE; break; default: diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index 2552e478ba..d73a3bddd7 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -37,9 +37,130 @@ #include "e1ap_bearer_context_management.h" #include "e1ap_lib_includes.h" -/* ==================================== - * E1AP Bearer Context Setup Request - * ==================================== */ +/** @brief Encode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */ +static E1AP_SecurityIndication_t e1_encode_security_indication(const security_indication_t *in) +{ + E1AP_SecurityIndication_t out = {0}; + out.integrityProtectionIndication = in->integrityProtectionIndication; + out.confidentialityProtectionIndication = in->confidentialityProtectionIndication; + if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) { + asn1cCalloc(out.maximumIPdatarate, ipDataRate); + ipDataRate->maxIPrate = in->maxIPrate; + } + return out; +} + +/** @brief Decode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */ +static bool e1_decode_security_indication(security_indication_t *out, const E1AP_SecurityIndication_t *in) +{ + // Confidentiality Protection Indication (M) + out->confidentialityProtectionIndication = in->confidentialityProtectionIndication; + // Maximum Integrity Protected Data Rate (Conditional) + if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) { + if (in->maximumIPdatarate) + out->maxIPrate = in->maximumIPdatarate->maxIPrate; + else { + PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n"); + return false; + } + } + return true; +} + +/** + * @brief Encode E1AP_SecurityInformation_t + */ +static E1AP_SecurityInformation_t e1_encode_security_info(const security_information_t *secInfo) +{ + E1AP_SecurityInformation_t ie = {0}; + E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie.securityAlgorithm; + E1AP_UPSecuritykey_t *uPSecuritykey = &ie.uPSecuritykey; + securityAlgorithm->cipheringAlgorithm = secInfo->cipheringAlgorithm; + OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE); + asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, secInfo->integrityProtectionAlgorithm); + asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); + OCTET_STRING_fromBuf(protKey, secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + return ie; +} + +/** + * @brief Decode E1AP_SecurityInformation_t + */ +static bool e1_decode_security_info(security_information_t *out, const E1AP_SecurityInformation_t *in) +{ + out->cipheringAlgorithm = in->securityAlgorithm.cipheringAlgorithm; + memcpy(out->encryptionKey, in->uPSecuritykey.encryptionKey.buf, in->uPSecuritykey.encryptionKey.size); + if (in->securityAlgorithm.integrityProtectionAlgorithm) + out->integrityProtectionAlgorithm = *in->securityAlgorithm.integrityProtectionAlgorithm; + if (in->uPSecuritykey.integrityProtectionKey) { + E1AP_IntegrityProtectionKey_t *ipKey = in->uPSecuritykey.integrityProtectionKey; + memcpy(out->integrityProtectionKey, ipKey->buf, ipKey->size); + } + return true; +} + +/** + * @brief Encode E1AP_UP_TNL_Information_t + */ +static E1AP_UP_TNL_Information_t e1_encode_up_tnl_info(const UP_TL_information_t *in) +{ + E1AP_UP_TNL_Information_t out = {0}; + out.present = E1AP_UP_TNL_Information_PR_gTPTunnel; + asn1cCalloc(out.choice.gTPTunnel, gTPTunnel); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID); + return out; +} + +/** + * @brief Decode E1AP_UP_TNL_Information_t + */ +static bool e1_decode_up_tnl_info(UP_TL_information_t *out, const E1AP_UP_TNL_Information_t *in) +{ + /* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */ + // GTP Tunnel + struct E1AP_GTPTunnel *gTPTunnel = in->choice.gTPTunnel; + AssertFatal(gTPTunnel != NULL, "item->nG_UL_UP_TNL_Information.choice.gTPTunnel is a mandatory IE"); + _E1_EQ_CHECK_INT(in->present, E1AP_UP_TNL_Information_PR_gTPTunnel); + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, out->tlAddress); + // GTP-TEID + OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, out->teId); + return true; +} + +/** @brief Encode PDCP Configuration IE */ +static E1AP_PDCP_Configuration_t e1_encode_pdcp_config(const bearer_context_pdcp_config_t *in) +{ + E1AP_PDCP_Configuration_t out = {0}; + out.pDCP_SN_Size_UL = in->pDCP_SN_Size_UL; + out.pDCP_SN_Size_DL = in->pDCP_SN_Size_DL; + asn1cCallocOne(out.discardTimer, in->discardTimer); + E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer)); + out.t_ReorderingTimer = roTimer; + roTimer->t_Reordering = in->reorderingTimer; + out.rLC_Mode = in->rLC_Mode; + if (in->pDCP_Reestablishment) { + asn1cCallocOne(out.pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true); + } + return out; +} + +/** @brief Decode PDCP Configuration IE */ +static bool e1_decode_pdcp_config(bearer_context_pdcp_config_t *out, const E1AP_PDCP_Configuration_t *in) +{ + out->pDCP_SN_Size_UL = in->pDCP_SN_Size_UL; + out->pDCP_SN_Size_DL = in->pDCP_SN_Size_DL; + if (in->discardTimer) { + out->discardTimer = *in->discardTimer; + } + if (in->t_ReorderingTimer) { + out->reorderingTimer = in->t_ReorderingTimer->t_Reordering; + } + out->rLC_Mode = in->rLC_Mode; + if (in->pDCP_Reestablishment && *in->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true) + out->pDCP_Reestablishment = true; + return true; +} /** * @brief Equality check for bearer_context_pdcp_config_t @@ -55,6 +176,25 @@ static bool eq_pdcp_config(const bearer_context_pdcp_config_t *a, const bearer_c return true; } +/** @brief Encode SDAP Configuration IE */ +static E1AP_SDAP_Configuration_t e1_encode_sdap_config(const bearer_context_sdap_config_t *in) +{ + E1AP_SDAP_Configuration_t out; + out.defaultDRB = in->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + out.sDAP_Header_UL = in->sDAP_Header_UL; + out.sDAP_Header_DL = in->sDAP_Header_DL; + return out; +} + +/** @brief Decode SDAP Configuration IE */ +static bool e1_decode_sdap_config(bearer_context_sdap_config_t *out, const E1AP_SDAP_Configuration_t *in) +{ + out->defaultDRB = in->defaultDRB == E1AP_DefaultDRB_true; + out->sDAP_Header_UL = in->sDAP_Header_UL; + out->sDAP_Header_DL = in->sDAP_Header_DL; + return true; +} + /** * @brief Equality check for bearer_context_sdap_config_t */ @@ -66,6 +206,69 @@ static bool eq_sdap_config(const bearer_context_sdap_config_t *a, const bearer_c return true; } +static E1AP_QoS_Flow_QoS_Parameter_Item_t e1_encode_qos_flow_to_setup(const qos_flow_to_setup_t *in) +{ + E1AP_QoS_Flow_QoS_Parameter_Item_t out = {0}; + out.qoS_Flow_Identifier = in->qfi; + // QoS Characteristics + const qos_characteristics_t *qos_char_in = &in->qos_params.qos_characteristics; + if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI + out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI); + non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi; + } else { // dynamic 5QI + out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI); + dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level; + dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget; + dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar; + dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent; + } + // QoS Retention Priority + const ngran_allocation_retention_priority_t *rent_priority_in = &in->qos_params.alloc_reten_priority; + E1AP_NGRANAllocationAndRetentionPriority_t *arp = &out.qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority; + arp->priorityLevel = rent_priority_in->priority_level; + arp->pre_emptionCapability = rent_priority_in->preemption_capability; + arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability; + return out; +} + +bool e1_decode_qos_flow_to_setup(qos_flow_to_setup_t *out, const E1AP_QoS_Flow_QoS_Parameter_Item_t *in) +{ + // QoS Flow Identifier (M) + out->qfi = in->qoS_Flow_Identifier; + qos_characteristics_t *qos_char = &out->qos_params.qos_characteristics; + // QoS Flow Level QoS Parameters (M) + const E1AP_QoSFlowLevelQoSParameters_t *qosParams = &in->qoSFlowLevelQoSParameters; + const E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics; + switch (qoS_Characteristics->present) { + case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI: + qos_char->qos_type = NON_DYNAMIC; + qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI; + break; + case E1AP_QoS_Characteristics_PR_dynamic_5QI: { + E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI; + 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; + qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent; + break; + } + default: + PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present); + return false; + break; + } + // NG-RAN Allocation and Retention Priority (M) + ngran_allocation_retention_priority_t *rent_priority = &out->qos_params.alloc_reten_priority; + const E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority; + rent_priority->priority_level = aRP->priorityLevel; + rent_priority->preemption_capability = aRP->pre_emptionCapability; + rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability; + return true; +} + /** * @brief Equality check for qos_flow_to_setup_t */ @@ -110,36 +313,12 @@ static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_se return result; } -/** - * @brief Equality check for DRB_nGRAN_to_mod_t - */ -static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b) +static void free_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg) { - bool result = true; - _E1_EQ_CHECK_LONG(a->id, b->id); - _E1_EQ_CHECK_INT(a->numCellGroups, b->numCellGroups); - for (int i = 0; i < a->numCellGroups; i++) { - _E1_EQ_CHECK_INT(a->cellGroupList[i], b->cellGroupList[i]); - } - _E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup); - for (int i = 0; i < a->numQosFlow2Setup; i++) { - result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); - } - _E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress); - _E1_EQ_CHECK_INT(a->teId, b->teId); - _E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam); - for (int i = 0; i < a->numDlUpParam; i++) { - _E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id); - _E1_EQ_CHECK_LONG(a->DlUpParamList[i].teId, b->DlUpParamList[i].teId); - _E1_EQ_CHECK_INT(a->DlUpParamList[i].tlAddress, b->DlUpParamList[i].tlAddress); - } - result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config); - result &= eq_sdap_config(&a->sdap_config, &b->sdap_config); - return result; + free(msg->drb_inactivity_timer); } -/* PDU Session To Setup Item */ - +/** @brief Encode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */ static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Setup_Item_t *item, const pdu_session_to_setup_t *in) { item->pDU_Session_ID = in->sessionId; @@ -150,73 +329,33 @@ static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Set item->sNSSAI.sD = malloc_or_fail(sizeof(*item->sNSSAI.sD)); INT24_TO_OCTET_STRING(in->nssai.sd, item->sNSSAI.sD); } - // Security Indication - E1AP_SecurityIndication_t *siOut = &item->securityIndication; - const security_indication_t *siIn = &in->securityIndication; - siOut->integrityProtectionIndication = siIn->integrityProtectionIndication; - siOut->confidentialityProtectionIndication = siIn->confidentialityProtectionIndication; - if (siIn->integrityProtectionIndication != SECURITY_NOT_NEEDED) { - asn1cCalloc(siOut->maximumIPdatarate, ipDataRate); - ipDataRate->maxIPrate = siIn->maxIPrate; - } - // TNL Information - item->nG_UL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(item->nG_UL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - const UP_TL_information_t *UP_TL_information = &in->UP_TL_information; - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(UP_TL_information->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(UP_TL_information->teId, &gTPTunnel->gTP_TEID); - // DRB to setup + // Security Indication (M) + item->securityIndication = e1_encode_security_indication(&in->securityIndication); + // NG UL UP Transport Layer Information (M) + item->nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information); + // DRB To Setup List (M) for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) { asn1cSequenceAdd(item->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1); ieC6_1_1->dRB_ID = j->id; - // SDAP Config - E1AP_SDAP_Configuration_t *sdap = &ieC6_1_1->sDAP_Configuration; - sdap->defaultDRB = j->sdap_config.defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; - sdap->sDAP_Header_UL = j->sdap_config.sDAP_Header_UL; - sdap->sDAP_Header_DL = j->sdap_config.sDAP_Header_DL; - // PDCP Config - E1AP_PDCP_Configuration_t *pdcp = &ieC6_1_1->pDCP_Configuration; - pdcp->pDCP_SN_Size_UL = j->pdcp_config.pDCP_SN_Size_UL; - pdcp->pDCP_SN_Size_DL = j->pdcp_config.pDCP_SN_Size_DL; - asn1cCallocOne(pdcp->discardTimer, j->pdcp_config.discardTimer); - E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer)); - pdcp->t_ReorderingTimer = roTimer; - roTimer->t_Reordering = j->pdcp_config.reorderingTimer; - pdcp->rLC_Mode = j->pdcp_config.rLC_Mode; - // Cell Group + // SDAP Configuration (M) + ieC6_1_1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config); + // PDCP Configuration (M) + ieC6_1_1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config); + // Cell Group Information (M) for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) { asn1cSequenceAdd(ieC6_1_1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ieC6_1_1_1); ieC6_1_1_1->cell_Group_ID = *k; } // QoS Flows for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { - asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_1); - ieC6_1_1_1->qoS_Flow_Identifier = k->qfi; - // QoS Characteristics - const qos_characteristics_t *qos_char_in = &k->qos_params.qos_characteristics; - 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; - } else { // dynamic 5QI - ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI); - dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level; - dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget; - dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar; - dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent; - } - // QoS Retention Priority - const ngran_allocation_retention_priority_t *rent_priority_in = &k->qos_params.alloc_reten_priority; - E1AP_NGRANAllocationAndRetentionPriority_t *arp = &ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority; - arp->priorityLevel = rent_priority_in->priority_level; - arp->pre_emptionCapability = rent_priority_in->preemption_capability; - arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability; + asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_2); + *ieC6_1_1_2 = e1_encode_qos_flow_to_setup(k); } } return true; } +/** @brief Decode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1AP_PDU_Session_Resource_To_Setup_Item_t *item) { // PDU Session ID (M) @@ -230,22 +369,8 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A // SD (O) if (item->sNSSAI.sD != NULL) OCTET_STRING_TO_INT24(item->sNSSAI.sD, out->nssai.sd); - /* Security Indication (M) */ - E1AP_SecurityIndication_t *securityIndication = &item->securityIndication; - // Integrity Protection Indication (M) - security_indication_t *sec = &out->securityIndication; - sec->integrityProtectionIndication = securityIndication->integrityProtectionIndication; - // Confidentiality Protection Indication (M) - sec->confidentialityProtectionIndication = securityIndication->confidentialityProtectionIndication; - // Maximum Integrity Protected Data Rate (Conditional) - if (sec->integrityProtectionIndication != SECURITY_NOT_NEEDED) { - if (securityIndication->maximumIPdatarate) - sec->maxIPrate = securityIndication->maximumIPdatarate->maxIPrate; - else { - PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n"); - return false; - } - } + // Security Indication (M) + CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication)); /* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */ // GTP Tunnel struct E1AP_GTPTunnel *gTPTunnel = item->nG_UL_UP_TNL_Information.choice.gTPTunnel; @@ -254,38 +379,22 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A return false; } _E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel); - // Transport Layer Address - UP_TL_information_t *UP_TL_information = &out->UP_TL_information; - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UP_TL_information->tlAddress); - // GTP-TEID - OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UP_TL_information->teId); - // DRB To Setup List ( > 1 item ) + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information)); + /* DRB To Setup List ( > 1 item ) */ E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_List_NG_RAN; _E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0); out->numDRB2Setup = drb2SetupList->list.count; - _E1_EQ_CHECK_LONG(out->numDRB2Setup, 1UL); // can only handle one DRB per PDU session + _E1_EQ_CHECK_INT(out->numDRB2Setup, 1); // can only handle one DRB per PDU session for (int j = 0; j < drb2SetupList->list.count; j++) { DRB_nGRAN_to_setup_t *drb = out->DRBnGRanList + j; E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j]; // DRB ID (M) drb->id = drb2Setup->dRB_ID; - // >SDAP Configuration (M) - E1AP_SDAP_Configuration_t *sdap = &drb2Setup->sDAP_Configuration; - drb->sdap_config.defaultDRB = sdap->defaultDRB == E1AP_DefaultDRB_true; - drb->sdap_config.sDAP_Header_UL = sdap->sDAP_Header_UL; - drb->sdap_config.sDAP_Header_DL = sdap->sDAP_Header_DL; + // SDAP Configuration (M) + CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration)); // PDCP Configuration (M) - E1AP_PDCP_Configuration_t *pdcp = &drb2Setup->pDCP_Configuration; - drb->pdcp_config.pDCP_SN_Size_UL = pdcp->pDCP_SN_Size_UL; - drb->pdcp_config.pDCP_SN_Size_DL = pdcp->pDCP_SN_Size_DL; - if (pdcp->discardTimer) { - drb->pdcp_config.discardTimer = *pdcp->discardTimer; - } - if (pdcp->t_ReorderingTimer) { - drb->pdcp_config.reorderingTimer = pdcp->t_ReorderingTimer->t_Reordering; - } - drb->pdcp_config.rLC_Mode = pdcp->rLC_Mode; - // Cell Group Information (M) ( > 1 item ) + CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration)); + // Cell Group Information (M) E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information; _E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0); drb->numCellGroups = cellGroupList->list.count; @@ -298,44 +407,42 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->qos_flow_Information_To_Be_Setup; drb->numQosFlow2Setup = qos2SetupList->list.count; for (int k = 0; k < qos2SetupList->list.count; k++) { - qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; - E1AP_QoS_Flow_QoS_Parameter_Item_t *qos2Setup = qos2SetupList->list.array[k]; - // QoS Flow Identifier (M) - qos_flow->qfi = qos2Setup->qoS_Flow_Identifier; - qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; - // QoS Flow Level QoS Parameters (M) - E1AP_QoSFlowLevelQoSParameters_t *qosParams = &qos2Setup->qoSFlowLevelQoSParameters; - E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics; - switch (qoS_Characteristics->present) { - case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI: - qos_char->qos_type = NON_DYNAMIC; - qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI; - break; - case E1AP_QoS_Characteristics_PR_dynamic_5QI: { - E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI; - 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; - qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent; - break; - } - default: - PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present); - return false; - break; - } - // NG-RAN Allocation and Retention Priority (M) - ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; - E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority; - rent_priority->priority_level = aRP->priorityLevel; - rent_priority->preemption_capability = aRP->pre_emptionCapability; - rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability; + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); } } return true; } +/** @brief Deep copy DRB To Setup List Item (3GPP TS 38.463 9.3.3.2) */ +static DRB_nGRAN_to_setup_t cp_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg) +{ + DRB_nGRAN_to_setup_t cp = {0}; + cp.id = msg->id; + cp.sdap_config = msg->sdap_config; + cp.pdcp_config = msg->pdcp_config; + cp.numCellGroups = msg->numCellGroups; + // Cell Group List + for (int k = 0; k < msg->numCellGroups; k++) { + cp.cellGroupList[k] = msg->cellGroupList[k]; + } + cp.numQosFlow2Setup = msg->numQosFlow2Setup; + // QoS Flow To Setup List + for (int k = 0; k < msg->numQosFlow2Setup; k++) { + cp.qosFlows[k].qfi = msg->qosFlows[k].qfi; + cp.qosFlows[k].qos_params = msg->qosFlows[k].qos_params; + } + return cp; +} + +/** @brief Free PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */ +void free_pdu_session_to_setup_item(const pdu_session_to_setup_t *msg) +{ + free(msg->dlAggregateMaxBitRate); + free(msg->inactivityTimer); + for (int i = 0; i < msg->numDRB2Setup; i++) + free_drb_to_setup_item(&msg->DRBnGRanList[i]); +} + /** * @brief Equality check for PDU session item to modify/setup */ @@ -345,55 +452,20 @@ static bool eq_pdu_session_item(const pdu_session_to_setup_t *a, const pdu_sessi _E1_EQ_CHECK_LONG(a->sessionType, b->sessionType); _E1_EQ_CHECK_INT(a->UP_TL_information.tlAddress, b->UP_TL_information.tlAddress); _E1_EQ_CHECK_INT(a->UP_TL_information.teId, b->UP_TL_information.teId); - _E1_EQ_CHECK_LONG(a->numDRB2Setup, b->numDRB2Setup); - if (a->numDRB2Setup != b->numDRB2Setup) - return false; + _E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup); for (int i = 0; i < a->numDRB2Setup; i++) if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i])) return false; - _E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify); - if (a->numDRB2Modify != b->numDRB2Modify) - return false; - for (int i = 0; i < a->numDRB2Modify; i++) - if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i])) - return false; + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer); + if (a->inactivityTimer && b->inactivityTimer) + _E1_EQ_CHECK_INT(a->inactivityTimer, b->inactivityTimer); + _E1_EQ_CHECK_OPTIONAL_IE(a, b, dlAggregateMaxBitRate, _E1_EQ_CHECK_LONG); return true; } -static bool cp_pdu_session_item(pdu_session_to_setup_t *cp, const pdu_session_to_setup_t *msg) -{ - // Copy basic fields - *cp = *msg; - // Copy DRB to Setup List - for (int j = 0; j < msg->numDRB2Setup; j++) { - cp->DRBnGRanList[j].id = msg->DRBnGRanList[j].id; - cp->DRBnGRanList[j].sdap_config = msg->DRBnGRanList[j].sdap_config; - cp->DRBnGRanList[j].pdcp_config = msg->DRBnGRanList[j].pdcp_config; - cp->DRBnGRanList[j].tlAddress = msg->DRBnGRanList[j].tlAddress; - cp->DRBnGRanList[j].teId = msg->DRBnGRanList[j].teId; - cp->DRBnGRanList[j].numDlUpParam = msg->DRBnGRanList[j].numDlUpParam; - // Copy DL UP Params List - for (int k = 0; k < msg->DRBnGRanList[j].numDlUpParam; k++) { - cp->DRBnGRanList[j].DlUpParamList[k] = msg->DRBnGRanList[j].DlUpParamList[k]; - } - cp->DRBnGRanList[j].numCellGroups = msg->DRBnGRanList[j].numCellGroups; - // Copy Cell Group List - for (int k = 0; k < msg->DRBnGRanList[j].numCellGroups; k++) { - cp->DRBnGRanList[j].cellGroupList[k] = msg->DRBnGRanList[j].cellGroupList[k]; - } - cp->DRBnGRanList[j].numQosFlow2Setup = msg->DRBnGRanList[j].numQosFlow2Setup; - // Copy QoS Flow To Setup List - for (int k = 0; k < msg->DRBnGRanList[j].numQosFlow2Setup; k++) { - cp->DRBnGRanList[j].qosFlows[k].qfi = msg->DRBnGRanList[j].qosFlows[k].qfi; - cp->DRBnGRanList[j].qosFlows[k].qos_params = msg->DRBnGRanList[j].qosFlows[k].qos_params; - } - } - // Copy DRB to Modify List - for (int j = 0; j < msg->numDRB2Modify; j++) { - cp->DRBnGRanModList[j] = msg->DRBnGRanModList[j]; - } - return true; -} +/* ==================================== + * E1AP Bearer Context Setup Request + * ==================================== */ /** * @brief E1AP Bearer Context Setup Request encoding (9.2.2 of 3GPP TS 38.463) @@ -421,13 +493,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ ieC2->id = E1AP_ProtocolIE_ID_id_SecurityInformation; ieC2->criticality = E1AP_Criticality_reject; ieC2->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation; - E1AP_SecurityAlgorithm_t *securityAlgorithm = &ieC2->value.choice.SecurityInformation.securityAlgorithm; - E1AP_UPSecuritykey_t *uPSecuritykey = &ieC2->value.choice.SecurityInformation.uPSecuritykey; - securityAlgorithm->cipheringAlgorithm = msg->cipheringAlgorithm; - OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, msg->encryptionKey, E1AP_SECURITY_KEY_SIZE); - asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, msg->integrityProtectionAlgorithm); - asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); - OCTET_STRING_fromBuf(protKey, msg->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + ieC2->value.choice.SecurityInformation = e1_encode_security_info(&msg->secInfo); /* mandatory */ /* c3. UE DL Aggregate Maximum Bit Rate */ asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3); @@ -479,7 +545,8 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ */ void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg) { - // Do nothing + free(msg->inactivityTimerUE); + free(msg->ueDlMaxIPBitRate); } /** @@ -518,17 +585,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea case E1AP_ProtocolIE_ID_id_SecurityInformation: _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation); - E1AP_SecurityInformation_t *SecurityInformation = &ie->value.choice.SecurityInformation; - E1AP_SecurityAlgorithm_t *securityAlgorithm = &SecurityInformation->securityAlgorithm; - E1AP_EncryptionKey_t *encryptionKey = &SecurityInformation->uPSecuritykey.encryptionKey; - E1AP_IntegrityProtectionKey_t *integrityProtectionKey = SecurityInformation->uPSecuritykey.integrityProtectionKey; - - out->cipheringAlgorithm = securityAlgorithm->cipheringAlgorithm; - memcpy(out->encryptionKey, encryptionKey->buf, encryptionKey->size); - if (securityAlgorithm->integrityProtectionAlgorithm) - out->integrityProtectionAlgorithm = *securityAlgorithm->integrityProtectionAlgorithm; - if (integrityProtectionKey) - memcpy(out->integrityProtectionKey, integrityProtectionKey->buf, integrityProtectionKey->size); + e1_decode_security_info(&out->secInfo, &ie->value.choice.SecurityInformation); break; case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: @@ -583,10 +640,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea for (int i = 0; i < pdu2SetupList->list.count; i++) { pdu_session_to_setup_t *pdu_session = out->pduSession + i; E1AP_PDU_Session_Resource_To_Setup_Item_t *pdu2Setup = pdu2SetupList->list.array[i]; - if (!e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup)) { - PRINT_ERROR("Failed to decode PDU Session to setup item %d\n", i); - return false; - } + CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup)); } break; default: @@ -597,19 +651,35 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea return true; } -/** - * @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST - */ +/** @brief Deep copy PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */ +static pdu_session_to_setup_t cp_pdu_session_item(const pdu_session_to_setup_t *msg) +{ + pdu_session_to_setup_t cp = {0}; + // Copy basic fields + cp = *msg; + // Copy DRB to Setup List + for (int j = 0; j < msg->numDRB2Setup; j++) + cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]); + // Copy optional IEs + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer); + _E1_CP_OPTIONAL_IE(&cp, msg, dlAggregateMaxBitRate); + return cp; +} + +/** @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST */ e1ap_bearer_setup_req_t cp_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg) { e1ap_bearer_setup_req_t cp = {0}; // Copy basi fields cp = *msg; - strncpy(cp.encryptionKey, msg->encryptionKey, sizeof(cp.encryptionKey)); - strncpy(cp.integrityProtectionKey, msg->integrityProtectionKey, sizeof(cp.integrityProtectionKey)); + strncpy(cp.secInfo.encryptionKey, msg->secInfo.encryptionKey, sizeof(cp.secInfo.encryptionKey)); + strncpy(cp.secInfo.integrityProtectionKey, msg->secInfo.integrityProtectionKey, sizeof(cp.secInfo.integrityProtectionKey)); // Copy PDU Sessions for (int i = 0; i < msg->numPDUSessions; i++) - cp_pdu_session_item(&cp.pduSession[i], &msg->pduSession[i]); + cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]); + // copy optional IEs + _E1_CP_OPTIONAL_IE(&cp, msg, ueDlMaxIPBitRate); + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimerUE); return cp; } @@ -620,29 +690,28 @@ bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1a { // Primitive data types _E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id); - _E1_EQ_CHECK_LONG(a->cipheringAlgorithm, b->cipheringAlgorithm); - _E1_EQ_CHECK_LONG(a->integrityProtectionAlgorithm, b->integrityProtectionAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo.cipheringAlgorithm, b->secInfo.cipheringAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo.integrityProtectionAlgorithm, b->secInfo.integrityProtectionAlgorithm); _E1_EQ_CHECK_LONG(a->ueDlAggMaxBitRate, b->ueDlAggMaxBitRate); _E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions); - _E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod); // PLMN _E1_EQ_CHECK_INT(a->servingPLMNid.mcc, b->servingPLMNid.mcc); _E1_EQ_CHECK_INT(a->servingPLMNid.mnc, b->servingPLMNid.mnc); _E1_EQ_CHECK_INT(a->servingPLMNid.mnc_digit_length, b->servingPLMNid.mnc_digit_length); // Security Keys - _E1_EQ_CHECK_STR(a->encryptionKey, b->encryptionKey); - _E1_EQ_CHECK_STR(a->integrityProtectionKey, b->integrityProtectionKey); + _E1_EQ_CHECK_STR(a->secInfo.encryptionKey, b->secInfo.encryptionKey); + _E1_EQ_CHECK_STR(a->secInfo.integrityProtectionKey, b->secInfo.integrityProtectionKey); // PDU Sessions if (a->numPDUSessions != b->numPDUSessions) return false; for (int i = 0; i < a->numPDUSessions; i++) if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i])) return false; - if (a->numPDUSessionsMod != b->numPDUSessionsMod) - return false; - for (int i = 0; i < a->numPDUSessionsMod; i++) - if (!eq_pdu_session_item(&a->pduSessionMod[i], &b->pduSessionMod[i])) - return false; + // Check optional IEs + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimerUE); + if (a->inactivityTimerUE && b->inactivityTimerUE) + _E1_EQ_CHECK_INT(a->inactivityTimerUE, b->inactivityTimerUE); + _E1_EQ_CHECK_OPTIONAL_IE(a, b, ueDlMaxIPBitRate, _E1_EQ_CHECK_LONG); return true; } @@ -664,8 +733,8 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP E1AP_UP_TNL_Information_t *DL_UP_TNL_Info = &in->nG_DL_UP_TNL_Information; if (DL_UP_TNL_Info->choice.gTPTunnel) { _E1_EQ_CHECK_INT(DL_UP_TNL_Info->present, E1AP_UP_TNL_Information_PR_gTPTunnel); - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&DL_UP_TNL_Info->choice.gTPTunnel->transportLayerAddress, pduSetup->tlAddress); - OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->teId); + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&DL_UP_TNL_Info->choice.gTPTunnel->transportLayerAddress, pduSetup->tl_info.tlAddress); + OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->tl_info.teId); } // DRB Setup List (1..) for (int j = 0; j < in->dRB_Setup_List_NG_RAN.list.count; j++) { @@ -685,8 +754,8 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP E1AP_GTPTunnel_t *gTPTunnel = UL_UP_item->uP_TNL_Information.choice.gTPTunnel; AssertError(gTPTunnel != NULL, return false, "gTPTunnel information in required in UP Transport Layer Information\n"); if (gTPTunnel) { - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->tlAddress); - OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->teId); + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->tl_info.tlAddress); + OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->tl_info.teId); } else { } // Cell Group ID (M) @@ -695,7 +764,7 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP // Flow Setup List (M) drbSetup->numQosFlowSetup = drb->flow_Setup_List.list.count; for (int q = 0; q < drb->flow_Setup_List.list.count; q++) { - qos_flow_setup_t *qosflowSetup = &drbSetup->qosFlows[q]; + qos_flow_list_t *qosflowSetup = &drbSetup->qosFlows[q]; E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q]; qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier; } @@ -713,8 +782,8 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite // NG DL UP Transport Layer Information (M) item->nG_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; asn1cCalloc(item->nG_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tl_info.tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(in->tl_info.teId, &gTPTunnel->gTP_TEID); // DRB Setup List (1..) for (const DRB_nGRAN_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRBSetup; j++) { asn1cSequenceAdd(item->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1); @@ -725,11 +794,11 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1); ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tl_info.tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(k->tl_info.teId, &gTPTunnel->gTP_TEID); } // Flow Setup List(M) - for (const qos_flow_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) { + for (const qos_flow_list_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) { asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1); ieC3_1_1_1->qoS_Flow_Identifier = k->qfi; } @@ -743,24 +812,7 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite // DRB ID (M) ieC3_1_1->dRB_ID = j->id; // Cause (M) - ieC3_1_1->cause.present = j->cause_type; - switch (ieC3_1_1->cause.present) { - case E1AP_Cause_PR_radioNetwork: - ieC3_1_1->cause.choice.radioNetwork = j->cause; - break; - case E1AP_Cause_PR_transport: - ieC3_1_1->cause.choice.transport = j->cause; - break; - case E1AP_Cause_PR_protocol: - ieC3_1_1->cause.choice.protocol = j->cause; - break; - case E1AP_Cause_PR_misc: - ieC3_1_1->cause.choice.misc = j->cause; - break; - default: - PRINT_ERROR("DRB setup failure cause out of expected range\n"); - break; - } + ieC3_1_1->cause = e1_encode_cause_ie(&j->cause); } return true; } @@ -929,8 +981,8 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e const pdu_session_setup_t *ps_a = &a->pduSession[i]; const pdu_session_setup_t *ps_b = &b->pduSession[i]; _E1_EQ_CHECK_LONG(ps_a->id, ps_b->id); - _E1_EQ_CHECK_INT(ps_a->tlAddress, ps_b->tlAddress); - _E1_EQ_CHECK_LONG(ps_a->teId, ps_b->teId); + _E1_EQ_CHECK_INT(ps_a->tl_info.tlAddress, ps_b->tl_info.tlAddress); + _E1_EQ_CHECK_LONG(ps_a->tl_info.teId, ps_b->tl_info.teId); _E1_EQ_CHECK_INT(ps_a->numDRBSetup, ps_b->numDRBSetup); _E1_EQ_CHECK_INT(ps_a->numDRBFailed, ps_b->numDRBFailed); // Check DRB Setup @@ -946,8 +998,8 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e const DRB_nGRAN_failed_t *drbf_a = &ps_a->DRBnGRanFailedList[j]; const DRB_nGRAN_failed_t *drbf_b = &ps_b->DRBnGRanFailedList[j]; _E1_EQ_CHECK_LONG(drbf_a->id, drbf_b->id); - _E1_EQ_CHECK_LONG(drbf_a->cause_type, drbf_b->cause_type); - _E1_EQ_CHECK_LONG(drbf_a->cause, drbf_b->cause); + _E1_EQ_CHECK_LONG(drbf_a->cause.type, drbf_b->cause.type); + _E1_EQ_CHECK_LONG(drbf_a->cause.value, drbf_b->cause.value); } } return true; diff --git a/openair2/E1AP/lib/e1ap_lib_includes.h b/openair2/E1AP/lib/e1ap_lib_includes.h index 443d59e19e..785fd9d09c 100644 --- a/openair2/E1AP/lib/e1ap_lib_includes.h +++ b/openair2/E1AP/lib/e1ap_lib_includes.h @@ -48,6 +48,7 @@ #include "E1AP_System-BearerContextSetupRequest.h" #include "E1AP_MaximumIPdatarate.h" #include "E1AP_PDU-Session-Type.h" +#include "E1AP_Data-Forwarding-Information.h" // E1 Bearer Context Setup Response #include "E1AP_PDU-Session-Resource-Setup-Item.h" #include "E1AP_DRB-Setup-Item-NG-RAN.h" diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index 9a53e8074d..bc670486cd 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -70,6 +70,14 @@ static void e1ap_msg_free(E1AP_E1AP_PDU_t *pdu) ASN_STRUCT_FREE(asn_DEF_E1AP_E1AP_PDU, pdu); } +static UP_TL_information_t create_up_tl_info(void) +{ + UP_TL_information_t tl_info; + tl_info.tlAddress = htonl(0xC0A90001); // 192.169.0.1 + tl_info.teId = 0x2345; + return tl_info; +} + /** * @brief Test E1AP Bearer Context Setup Request encoding/decoding */ @@ -107,8 +115,8 @@ static void test_bearer_context_setup_request(void) // Step 1: Initialize the E1AP Bearer Context Setup Request e1ap_bearer_setup_req_t orig = { .gNB_cu_cp_ue_id = 1234, - .cipheringAlgorithm = 0x01, - .integrityProtectionAlgorithm = 0x01, + .secInfo.cipheringAlgorithm = 0x01, + .secInfo.integrityProtectionAlgorithm = 0x01, .ueDlAggMaxBitRate = 1000000000, .bearerContextStatus = 0, .servingPLMNid.mcc = 001, @@ -121,8 +129,7 @@ static void test_bearer_context_setup_request(void) .pduSession[0].nssai.sst = 0x01, .pduSession[0].securityIndication = security, .pduSession[0].numDRB2Setup = 1, - .pduSession[0].UP_TL_information.tlAddress = 167772161, - .pduSession[0].UP_TL_information.teId = 0x12345, + .pduSession[0].UP_TL_information = create_up_tl_info(), .pduSession[0].DRBnGRanList[0].id = 1, .pduSession[0].DRBnGRanList[0].sdap_config = sdap, .pduSession[0].DRBnGRanList[0].pdcp_config = pdcp, @@ -132,8 +139,8 @@ static void test_bearer_context_setup_request(void) .pduSession[0].DRBnGRanList[0].numQosFlow2Setup = 1, .pduSession[0].DRBnGRanList[0].qosFlows[0] = qos, }; - memset(orig.encryptionKey, 0xAB, sizeof(orig.encryptionKey)); - memset(orig.integrityProtectionKey, 0xCD, sizeof(orig.integrityProtectionKey)); + memset(orig.secInfo.encryptionKey, 0xAB, sizeof(orig.secInfo.encryptionKey)); + memset(orig.secInfo.integrityProtectionKey, 0xCD, sizeof(orig.secInfo.integrityProtectionKey)); // E1AP encode the original message E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_request(&orig); // E1AP decode the encoded message @@ -171,8 +178,7 @@ static void test_bearer_context_setup_response(void) .gNB_cu_up_ue_id = 5678, .numPDUSessions = 1, .pduSession[0].id = 1, - .pduSession[0].tlAddress = 167772161, - .pduSession[0].teId = 0x12345, + .pduSession[0].tl_info = create_up_tl_info(), .pduSession[0].numDRBSetup = 1, .pduSession[0].numDRBFailed = 0, .pduSession[0].DRBnGRanList[0].id = 1, @@ -180,8 +186,7 @@ static void test_bearer_context_setup_response(void) .pduSession[0].DRBnGRanList[0].numQosFlowSetup = 1, .pduSession[0].DRBnGRanList[0].qosFlows[0].qfi = 1, .pduSession[0].DRBnGRanList[0].UpParamList[0].cell_group_id = MCG, - .pduSession[0].DRBnGRanList[0].UpParamList[0].teId = 0x34345, - .pduSession[0].DRBnGRanList[0].UpParamList[0].tlAddress = 167772161, + .pduSession[0].DRBnGRanList[0].UpParamList[0].tl_info = create_up_tl_info(), }; // E1AP encode the original message E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_response(&orig); diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 380ae1f60a..ed39dbeff0 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -168,7 +168,6 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) const pdu_session_to_setup_t *req_pdu = req->pduSession + i; resp_pdu->id = req_pdu->sessionId; - AssertFatal(req_pdu->numDRB2Modify == 0, "DRB modification not implemented\n"); AssertFatal(req_pdu->numDRB2Setup == 1, "can only handle one DRB per PDU session\n"); resp_pdu->numDRBSetup = req_pdu->numDRB2Setup; const DRB_nGRAN_to_setup_t *req_drb = &req_pdu->DRBnGRanList[0]; @@ -178,7 +177,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup; for (int k = 0; k < resp_drb->numQosFlowSetup; k++) { const qos_flow_to_setup_t *qosflow2Setup = &req_drb->qosFlows[k]; - qos_flow_setup_t *qosflowSetup = &resp_drb->qosFlows[k]; + qos_flow_list_t *qosflowSetup = &resp_drb->qosFlows[k]; qosflowSetup->qfi = qosflow2Setup->qfi; } @@ -197,17 +196,17 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) &resp_n3); AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n"); AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n"); - resp_pdu->teId = resp_n3.gnb_NGu_teid[0]; - memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4); + resp_pdu->tl_info.teId = resp_n3.gnb_NGu_teid[0]; + memcpy(&resp_pdu->tl_info.tlAddress, &resp_n3.gnb_addr.buffer, 4); // create PDCP bearers. This will also create SDAP bearers NR_DRB_ToAddModList_t DRB_configList = {0}; fill_DRB_configList_e1(&DRB_configList, req_pdu); nr_pdcp_entity_security_keys_and_algos_t security_parameters; - security_parameters.ciphering_algorithm = req->cipheringAlgorithm; - security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm; - memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE); - memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE); + security_parameters.ciphering_algorithm = req->secInfo.cipheringAlgorithm; + security_parameters.integrity_algorithm = req->secInfo.integrityProtectionAlgorithm; + memcpy(security_parameters.ciphering_key, req->secInfo.encryptionKey, NR_K_KEY_SIZE); + memcpy(security_parameters.integrity_key, req->secInfo.integrityProtectionKey, NR_K_KEY_SIZE); nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE cu_up_ue_id, &DRB_configList, @@ -230,8 +229,8 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) &resp_f1); resp_drb->numUpParam = 1; AssertFatal(ret >= 0, "Unable to create GTP Tunnel for F1-U\n"); - memcpy(&resp_drb->UpParamList[0].tlAddress, &resp_f1.gnb_addr.buffer, 4); - resp_drb->UpParamList[0].teId = resp_f1.gnb_NGu_teid[0]; + memcpy(&resp_drb->UpParamList[0].tl_info.tlAddress, &resp_f1.gnb_addr.buffer, 4); + resp_drb->UpParamList[0].tl_info.teId = resp_f1.gnb_NGu_teid[0]; } // We assume all DRBs to setup have been setup successfully, so we always @@ -273,12 +272,14 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) DRB_nGRAN_modified_t *modified = &modif.pduSessionMod[i].DRBnGRanModList[j]; modified->id = to_modif->id; - if (to_modif->pdcp_config.pDCP_Reestablishment) { + if (to_modif->pdcp_config && to_modif->pdcp_config->pDCP_Reestablishment) { nr_pdcp_entity_security_keys_and_algos_t security_parameters; - security_parameters.ciphering_algorithm = req->cipheringAlgorithm; - security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm; - memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE); - memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE); + if (req->secInfo) { + security_parameters.ciphering_algorithm = req->secInfo->cipheringAlgorithm; + security_parameters.integrity_algorithm = req->secInfo->integrityProtectionAlgorithm; + memcpy(security_parameters.ciphering_key, req->secInfo->encryptionKey, NR_K_KEY_SIZE); + memcpy(security_parameters.integrity_key, req->secInfo->integrityProtectionKey, NR_K_KEY_SIZE); + } nr_pdcp_reestablishment(req->gNB_cu_up_ue_id, to_modif->id, false, @@ -291,8 +292,8 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) /* Loop through DL UP Transport Layer params list * and update GTP tunnel outgoing addr and TEID */ for (int k = 0; k < to_modif->numDlUpParam; k++) { - in_addr_t addr = to_modif->DlUpParamList[k].tlAddress; - GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].teId); + in_addr_t addr = to_modif->DlUpParamList[k].tl_info.tlAddress; + GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].tl_info.teId); } } } diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h index 7290043371..5d6860f2a7 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h @@ -27,9 +27,10 @@ void nr_pdcp_e1_if_init(bool uses_e1); struct e1ap_bearer_setup_req_s; +struct e1ap_bearer_mod_req_s; struct e1ap_bearer_release_cmd_s; void e1_bearer_context_setup(const struct e1ap_bearer_setup_req_s *req); -void e1_bearer_context_modif(const struct e1ap_bearer_setup_req_s *req); +void e1_bearer_context_modif(const struct e1ap_bearer_mod_req_s *req); void e1_bearer_release_cmd(const struct e1ap_bearer_release_cmd_s *cmd); #endif /* CUCP_CUUP_HANDLER_H */ diff --git a/openair2/RRC/NR/cucp_cuup_if.h b/openair2/RRC/NR/cucp_cuup_if.h index 86b3a2435e..418e1f362e 100644 --- a/openair2/RRC/NR/cucp_cuup_if.h +++ b/openair2/RRC/NR/cucp_cuup_if.h @@ -29,9 +29,11 @@ #include "common/platform_types.h" struct e1ap_bearer_setup_req_s; +struct e1ap_bearer_mod_req_s; struct e1ap_bearer_setup_resp_s; struct e1ap_bearer_release_cmd_s; typedef void (*cucp_cuup_bearer_context_setup_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_setup_req_s *req); +typedef void (*cucp_cuup_bearer_context_mod_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_mod_req_s *req); typedef void (*cucp_cuup_bearer_context_release_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_release_cmd_s *cmd); struct gNB_RRC_INST_s; diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 953f723853..0861ebedb2 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -345,7 +345,7 @@ typedef struct nr_mac_rrc_dl_if_s { typedef struct cucp_cuup_if_s { cucp_cuup_bearer_context_setup_func_t bearer_context_setup; - cucp_cuup_bearer_context_setup_func_t bearer_context_mod; + cucp_cuup_bearer_context_mod_func_t bearer_context_mod; cucp_cuup_bearer_context_release_func_t bearer_context_release; } cucp_cuup_if_t; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index b4d33b16f0..6cfb0047af 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -740,6 +740,14 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, buffer, size); } +static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo) +{ + secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; + secInfo->integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; + nr_derive_key(UP_ENC_ALG, secInfo->cipheringAlgorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey); + nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); +} + /* \brief find existing PDU session inside E1AP Bearer Modif message, or * point to new one. * \param bearer_modif E1AP Bearer Modification Message @@ -797,21 +805,20 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; drb_e1->id = drb_id; drb_e1->numDlUpParam = 1; - memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb_e1->DlUpParamList[0].teId = drb->du_tunnel_config.teid; + memcpy(&drb_e1->DlUpParamList[0].tl_info.tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb_e1->DlUpParamList[0].tl_info.teId = drb->du_tunnel_config.teid; /* PDCP configuration */ - bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config; + if (!drb_e1->pdcp_config) + drb_e1->pdcp_config = malloc_or_fail(sizeof(*drb_e1->pdcp_config)); + bearer_context_pdcp_config_t *pdcp_config = drb_e1->pdcp_config; set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb); pdcp_config->pDCP_Reestablishment = true; /* increase DRB to modify counter */ pdu_e1->numDRB2Modify += 1; } - - req.cipheringAlgorithm = rrc->security.do_drb_ciphering ? ue_p->ciphering_algorithm : 0; - req.integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? ue_p->integrity_algorithm : 0; - nr_derive_key(UP_ENC_ALG, req.cipheringAlgorithm, ue_p->kgnb, (uint8_t *)req.encryptionKey); - nr_derive_key(UP_INT_ALG, req.integrityProtectionAlgorithm, ue_p->kgnb, (uint8_t *)req.integrityProtectionKey); - + // Always send security information + req.secInfo = malloc_or_fail(sizeof(*req.secInfo)); + fill_security_info(rrc, ue_p, req.secInfo); /* Send E1 Bearer Context Modification Request (3GPP TS 38.463) */ sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue_p); rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); @@ -1859,12 +1866,12 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC /* \brief fill E1 bearer modification's DRB from F1 DRB * \param drb_e1 pointer to a DRB inside an E1 bearer modification message * \param drb_f1 pointer to a DRB inside an F1 UE Ctxt modification Response */ -static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) +static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) { drb_e1->id = drb_f1->drb_id; drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length; - drb_e1->DlUpParamList[0].tlAddress = drb_f1->up_dl_tnl[0].tl_address; - drb_e1->DlUpParamList[0].teId = drb_f1->up_dl_tnl[0].teid; + drb_e1->DlUpParamList[0].tl_info.tlAddress = drb_f1->up_dl_tnl[0].tl_address; + drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid; } /** @@ -1896,8 +1903,8 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R */ static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p) { - f1u->teid = p->teId; - memcpy(&f1u->addr.buffer, &p->tlAddress, sizeof(uint8_t) * 4); + f1u->teid = p->tl_info.teId; + memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4); f1u->addr.length = sizeof(in_addr_t); } @@ -1923,10 +1930,10 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f LOG_E(RRC, "UE %d: UE Context Modif Response: no PDU session for DRB ID %ld\n", UE->rrc_ue_id, drb_f1->drb_id); continue; } - pdu_session_to_setup_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); + pdu_session_to_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); DevAssert(pdu_e1 != NULL); pdu_e1->sessionId = pdu_ue->param.pdusession_id; - DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; + DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; /* Fill E1 bearer context modification */ fill_e1_bearer_modif(drb_e1, drb_f1); pdu_e1->numDRB2Modify += 1; @@ -1934,10 +1941,9 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f DevAssert(req.numPDUSessionsMod > 0); DevAssert(req.numPDUSessions == 0); - req.cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; - req.integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; - nr_derive_key(UP_ENC_ALG, req.cipheringAlgorithm, UE->kgnb, (uint8_t *)req.encryptionKey); - nr_derive_key(UP_INT_ALG, req.integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)req.integrityProtectionKey); + // Always send security information + req.secInfo = malloc_or_fail(sizeof(*req.secInfo)); + fill_security_info(rrc, UE, req.secInfo); // send the E1 bearer modification request message to update F1-U tunnel info sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); @@ -2275,9 +2281,9 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, 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 ? 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].tl_address = drb_config->UpParamList[0].tl_info.tlAddress; drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; + drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].tl_info.teId; drb->up_ul_tnl_length = 1; /* pass QoS info to MAC */ @@ -2328,8 +2334,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id); continue; } - rrc_pdu->param.gNB_teid_N3 = e1_pdu->teId; - memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tlAddress, sizeof(uint8_t) * 4); + rrc_pdu->param.gNB_teid_N3 = e1_pdu->tl_info.teId; + memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4); rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t); // save the tunnel address for the DRBs diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 08f83ea5c8..7f17baea4a 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -355,10 +355,11 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession session->nssai = sessions[i].nssai; decodePDUSessionResourceSetup(session); bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; - bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; - bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; - nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); - nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); + security_information_t *secInfo = &bearer_req.secInfo; + secInfo->cipheringAlgorithm = UE->ciphering_algorithm; + secInfo->integrityProtectionAlgorithm = UE->integrity_algorithm; + nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey); + nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); bearer_req.ueDlAggMaxBitRate = ueAggMaxBitRateDownlink; pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; bearer_req.numPDUSessions++; From 1ef24796f91be77930b6fe6ad05a7aa0a3f1f9c0 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 4 Feb 2025 12:03:01 +0100 Subject: [PATCH 08/18] Add compile definitions E1AP_LOG_ERRORS * this is necessary to enable the error logs in the E1 libs * also, updated the define name in the E1AP lib --- openair2/E1AP/CMakeLists.txt | 4 ++++ openair2/E1AP/lib/e1ap_lib_common.h | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/openair2/E1AP/CMakeLists.txt b/openair2/E1AP/CMakeLists.txt index 5849a32fe5..eb3bd0f546 100644 --- a/openair2/E1AP/CMakeLists.txt +++ b/openair2/E1AP/CMakeLists.txt @@ -10,3 +10,7 @@ target_include_directories(e1ap PUBLIC ${CMAKE_CURRENT_DIR}) if(ENABLE_TESTS) add_subdirectory(tests) endif() + +if(ENABLE_TESTS) + target_compile_definitions(e1ap PRIVATE E1AP_LOG_ERRORS) +endif() diff --git a/openair2/E1AP/lib/e1ap_lib_common.h b/openair2/E1AP/lib/e1ap_lib_common.h index 39e3d64448..6fda2cd8ca 100644 --- a/openair2/E1AP/lib/e1ap_lib_common.h +++ b/openair2/E1AP/lib/e1ap_lib_common.h @@ -28,7 +28,7 @@ #include "openair3/UTILS/conversions.h" #include "e1ap_messages_types.h" -#ifdef ENABLE_TESTS +#ifdef E1AP_LOG_ERRORS #define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__); #else #define PRINT_ERROR(...) // Do nothing From cd7218c9765ec8275e28e274763a65984f4c9ba4 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 4 Feb 2025 12:21:26 +0100 Subject: [PATCH 09/18] Improvements to E1 Bearer Context Setup Request/Response * Add enc/dec/cp/eq sub-functions to E1 library and adopt in stack * eq_drb_to_mod * encode_dl_up_parameters * decode_dl_up_parameters * e1_decode_snssai * e1_encode_snssai * eq_security_ind * Check result of enc/dec functions in Bearer Context Setup enc/dec libs --- .../E1AP/lib/e1ap_bearer_context_management.c | 154 +++++++++++------- 1 file changed, 96 insertions(+), 58 deletions(-) diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index d73a3bddd7..e58fcbf145 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -293,6 +293,62 @@ static bool eq_qos_flow(const qos_flow_to_setup_t *a, const qos_flow_to_setup_t return true; } +/** @brief S-NSSAI Encoding (3GPP TS 38.463 9.3.1.9) */ +static E1AP_SNSSAI_t e1_encode_snssai(const nssai_t *in) +{ + E1AP_SNSSAI_t out = {0}; + INT8_TO_OCTET_STRING(in->sst, &out.sST); + if (in->sd != 0xffffff) { + out.sD = malloc_or_fail(sizeof(*out.sD)); + INT24_TO_OCTET_STRING(in->sd, out.sD); + } + return out; +} + +/** @brief S-NSSAI Decoding (3GPP TS 38.463 9.3.1.9) */ +static bool e1_decode_snssai(e1ap_nssai_t *out, const E1AP_SNSSAI_t *in) +{ + // SST (M) + OCTET_STRING_TO_INT8(&in->sST, out->sst); + out->sd = 0xffffff; + // SD (O) + if (in->sD != NULL) + OCTET_STRING_TO_INT24(in->sD, out->sd); + return true; +} + +/** + * @brief Decode E1AP_UP_Parameters_t + */ +static int decode_dl_up_parameters(up_params_t *dl_up_param, const E1AP_UP_Parameters_t *dl_up_paramList) +{ + for (int k = 0; k < dl_up_paramList->list.count; k++) { + dl_up_param = dl_up_param + k; + E1AP_UP_Parameters_Item_t *dl_up_param_in = dl_up_paramList->list.array[k]; + // GTP tunnel + if (!e1_decode_up_tnl_info(&dl_up_param->tl_info, &dl_up_param_in->uP_TNL_Information)) { + PRINT_ERROR("GTP tunnel decoding failed\n"); + return -1; + } + // Cell group ID + dl_up_param->cell_group_id = dl_up_param_in->cell_Group_ID; + } + return dl_up_paramList->list.count; +} + +/** + * @brief Encode E1AP_UP_Parameters_t IE + */ +static E1AP_UP_Parameters_t encode_dl_up_parameters(const int numUpParam, const up_params_t *in) +{ + E1AP_UP_Parameters_t out = {0}; + for (const up_params_t *k = in; k < in + numUpParam; k++) { + asn1cSequenceAdd(out.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1); + ieC3_1_1_1->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); + } + return out; +} + /** * @brief Equality check for DRB_nGRAN_to_setup_t */ @@ -321,14 +377,12 @@ static void free_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg) /** @brief Encode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */ static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Setup_Item_t *item, const pdu_session_to_setup_t *in) { + // PDU Session ID (M) item->pDU_Session_ID = in->sessionId; + // PDU Session Type (M) item->pDU_Session_Type = in->sessionType; - // SNSSAI - INT8_TO_OCTET_STRING(in->nssai.sst, &item->sNSSAI.sST); - if (in->nssai.sd != 0xffffff) { - item->sNSSAI.sD = malloc_or_fail(sizeof(*item->sNSSAI.sD)); - INT24_TO_OCTET_STRING(in->nssai.sd, item->sNSSAI.sD); - } + // S-NSSAI (M) + item->sNSSAI = e1_encode_snssai(&in->nssai); // Security Indication (M) item->securityIndication = e1_encode_security_indication(&in->securityIndication); // NG UL UP Transport Layer Information (M) @@ -336,6 +390,7 @@ static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Set // DRB To Setup List (M) for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) { asn1cSequenceAdd(item->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1); + // DRB ID (M) ieC6_1_1->dRB_ID = j->id; // SDAP Configuration (M) ieC6_1_1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config); @@ -346,7 +401,7 @@ static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Set asn1cSequenceAdd(ieC6_1_1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ieC6_1_1_1); ieC6_1_1_1->cell_Group_ID = *k; } - // QoS Flows + // QoS Flows Information To Be Setup (M) for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_2); *ieC6_1_1_2 = e1_encode_qos_flow_to_setup(k); @@ -362,13 +417,8 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A out->sessionId = item->pDU_Session_ID; // PDU Session Type (M) out->sessionType = item->pDU_Session_Type; - /* S-NSSAI (M) */ - // SST (M) - OCTET_STRING_TO_INT8(&item->sNSSAI.sST, out->nssai.sst); - out->nssai.sd = 0xffffff; - // SD (O) - if (item->sNSSAI.sD != NULL) - OCTET_STRING_TO_INT24(item->sNSSAI.sD, out->nssai.sd); + // S-NSSAI (M) + CHECK_E1AP_DEC(e1_decode_snssai(&out->nssai, &item->sNSSAI)); // Security Indication (M) CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication)); /* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */ @@ -443,6 +493,14 @@ void free_pdu_session_to_setup_item(const pdu_session_to_setup_t *msg) free_drb_to_setup_item(&msg->DRBnGRanList[i]); } +/** @brief Equality check for UP Transport Layer Information (3GPP TS 38.463 9.3.2.1)*/ +static bool eq_up_tl_info(const UP_TL_information_t *a, const UP_TL_information_t *b) +{ + _E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress); + _E1_EQ_CHECK_INT(a->teId, b->teId); + return true; +} + /** * @brief Equality check for PDU session item to modify/setup */ @@ -450,8 +508,7 @@ static bool eq_pdu_session_item(const pdu_session_to_setup_t *a, const pdu_sessi { _E1_EQ_CHECK_LONG(a->sessionId, b->sessionId); _E1_EQ_CHECK_LONG(a->sessionType, b->sessionType); - _E1_EQ_CHECK_INT(a->UP_TL_information.tlAddress, b->UP_TL_information.tlAddress); - _E1_EQ_CHECK_INT(a->UP_TL_information.teId, b->UP_TL_information.teId); + eq_up_tl_info(&a->UP_TL_information, &b->UP_TL_information); _E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup); for (int i = 0; i < a->numDRB2Setup; i++) if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i])) @@ -516,8 +573,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ ieC5->criticality = E1AP_Criticality_reject; ieC5->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel; ieC5->value.choice.ActivityNotificationLevel = E1AP_ActivityNotificationLevel_pdu_session; // TODO: Remove hard coding - /* mandatory */ - /* */ + // System (M) asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC6); ieC6->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest; ieC6->criticality = E1AP_Criticality_reject; @@ -535,7 +591,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ for (int i = 0; i < msg->numPDUSessions; i++) { const pdu_session_to_setup_t *pdu_session = &msg->pduSession[i]; asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Item_t, ieC6_1); - e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session); + CHECK_E1AP_DEC(e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session)); } return pdu; } @@ -585,7 +641,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea case E1AP_ProtocolIE_ID_id_SecurityInformation: _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation); - e1_decode_security_info(&out->secInfo, &ie->value.choice.SecurityInformation); + CHECK_E1AP_DEC(e1_decode_security_info(&out->secInfo, &ie->value.choice.SecurityInformation)); break; case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: @@ -730,12 +786,7 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP pduSetup->id = in->pDU_Session_ID; pduSetup->numDRBSetup = in->dRB_Setup_List_NG_RAN.list.count; // NG DL UP Transport Layer Information (M) - E1AP_UP_TNL_Information_t *DL_UP_TNL_Info = &in->nG_DL_UP_TNL_Information; - if (DL_UP_TNL_Info->choice.gTPTunnel) { - _E1_EQ_CHECK_INT(DL_UP_TNL_Info->present, E1AP_UP_TNL_Information_PR_gTPTunnel); - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&DL_UP_TNL_Info->choice.gTPTunnel->transportLayerAddress, pduSetup->tl_info.tlAddress); - OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->tl_info.teId); - } + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&pduSetup->tl_info, &in->nG_DL_UP_TNL_Information)); // DRB Setup List (1..) for (int j = 0; j < in->dRB_Setup_List_NG_RAN.list.count; j++) { DRB_nGRAN_setup_t *drbSetup = pduSetup->DRBnGRanList + j; @@ -743,23 +794,9 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP // DRB ID (M) drbSetup->id = drb->dRB_ID; // UL UP Parameters (M) - drbSetup->numUpParam = drb->uL_UP_Transport_Parameters.list.count; - for (int k = 0; k < drb->uL_UP_Transport_Parameters.list.count; k++) { - up_params_t *UL_UP_param = drbSetup->UpParamList + k; - // UP Parameters List (1..) - E1AP_UP_Parameters_Item_t *UL_UP_item = drb->uL_UP_Transport_Parameters.list.array[k]; - // UP Transport Layer Information (M) - DevAssert(UL_UP_item->uP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel); - // GTP Tunnel (M) - E1AP_GTPTunnel_t *gTPTunnel = UL_UP_item->uP_TNL_Information.choice.gTPTunnel; - AssertError(gTPTunnel != NULL, return false, "gTPTunnel information in required in UP Transport Layer Information\n"); - if (gTPTunnel) { - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->tl_info.tlAddress); - OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->tl_info.teId); - } else { - } - // Cell Group ID (M) - UL_UP_param->cell_group_id = UL_UP_item->cell_Group_ID; + if ((drbSetup->numUpParam = decode_dl_up_parameters(drbSetup->UpParamList, &drb->uL_UP_Transport_Parameters)) < 0) { + PRINT_ERROR("UL UP Parameters decoding failed\n"); + return false; } // Flow Setup List (M) drbSetup->numQosFlowSetup = drb->flow_Setup_List.list.count; @@ -769,6 +806,17 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier; } } + // DRB Failed to Setup List (O) + if (in->dRB_Failed_List_NG_RAN) { + for (int j = 0; j < in->dRB_Failed_List_NG_RAN->list.count; j++) { + DRB_nGRAN_failed_t *drbFailed = pduSetup->DRBnGRanFailedList + j; + E1AP_DRB_Failed_Item_NG_RAN_t *item = in->dRB_Failed_List_NG_RAN->list.array[j]; + // DRB ID (M) + drbFailed->id = item->dRB_ID; + // Cause (M) + drbFailed->cause = e1_decode_cause_ie(&item->cause); + } + } return true; } @@ -780,23 +828,14 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite // PDU Session ID (M) item->pDU_Session_ID = in->id; // NG DL UP Transport Layer Information (M) - item->nG_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(item->nG_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tl_info.tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(in->tl_info.teId, &gTPTunnel->gTP_TEID); + item->nG_DL_UP_TNL_Information = e1_encode_up_tnl_info(&in->tl_info); // DRB Setup List (1..) for (const DRB_nGRAN_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRBSetup; j++) { asn1cSequenceAdd(item->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1); // DRB ID (M) ieC3_1_1->dRB_ID = j->id; // UL UP Parameters (M) - for (const up_params_t *k = j->UpParamList; k < j->UpParamList + j->numUpParam; k++) { - asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1); - ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tl_info.tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(k->tl_info.teId, &gTPTunnel->gTP_TEID); - } + ieC3_1_1->uL_UP_Transport_Parameters = encode_dl_up_parameters(j->numUpParam, j->UpParamList); // Flow Setup List(M) for (const qos_flow_list_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) { asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1); @@ -860,7 +899,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_response(const e1ap_bearer_setup E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List; for (const pdu_session_setup_t *i = in->pduSession; i < in->pduSession + in->numPDUSessions; i++) { asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1); - e1_encode_pdu_session_setup_item(ieC3_1, i); + CHECK_E1AP_DEC(e1_encode_pdu_session_setup_item(ieC3_1, i)); } return pdu; } @@ -913,7 +952,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be for (int i = 0; i < pduSetupList->list.count; i++) { pdu_session_setup_t *pduSetup = out->pduSession + i; E1AP_PDU_Session_Resource_Setup_Item_t *pdu_session = pduSetupList->list.array[i]; - e1_decode_pdu_session_setup_item(pduSetup, pdu_session); + CHECK_E1AP_DEC(e1_decode_pdu_session_setup_item(pduSetup, pdu_session)); } } break; @@ -981,8 +1020,7 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e const pdu_session_setup_t *ps_a = &a->pduSession[i]; const pdu_session_setup_t *ps_b = &b->pduSession[i]; _E1_EQ_CHECK_LONG(ps_a->id, ps_b->id); - _E1_EQ_CHECK_INT(ps_a->tl_info.tlAddress, ps_b->tl_info.tlAddress); - _E1_EQ_CHECK_LONG(ps_a->tl_info.teId, ps_b->tl_info.teId); + eq_up_tl_info(&ps_a->tl_info, &ps_b->tl_info); _E1_EQ_CHECK_INT(ps_a->numDRBSetup, ps_b->numDRBSetup); _E1_EQ_CHECK_INT(ps_a->numDRBFailed, ps_b->numDRBFailed); // Check DRB Setup From f2b80ae31cfdcc34c2e18256f213fd3f20733327 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Mon, 20 Jan 2025 17:36:16 +0100 Subject: [PATCH 10/18] Use cp_bearer_context_setup_request in cucp_cuup_e1ap.c --- openair2/RRC/NR/cucp_cuup_e1ap.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openair2/RRC/NR/cucp_cuup_e1ap.c b/openair2/RRC/NR/cucp_cuup_e1ap.c index 69cb92f50a..538cd3f524 100644 --- a/openair2/RRC/NR/cucp_cuup_e1ap.c +++ b/openair2/RRC/NR/cucp_cuup_e1ap.c @@ -26,6 +26,7 @@ #include "e1ap_messages_types.h" #include "intertask_interface.h" #include "nr_rrc_defs.h" +#include "E1AP/lib/e1ap_bearer_context_management.h" static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req) { @@ -33,8 +34,7 @@ static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1a MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_REQ); msg_p->ittiMsgHeader.originInstance = assoc_id; e1ap_bearer_setup_req_t *bearer_req = &E1AP_BEARER_CONTEXT_SETUP_REQ(msg_p); - memcpy(bearer_req, req, sizeof(e1ap_bearer_setup_req_t)); - + *bearer_req = cp_bearer_context_setup_request(req); itti_send_msg_to_task (TASK_CUCP_E1, 0, msg_p); } From b061b5769855bf1566b2bf0a0d3c7bee7500e7c3 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 4 Feb 2025 11:14:23 +0100 Subject: [PATCH 11/18] Add Bearer Context Modification Request enc/dec lib --- .../E1AP/lib/e1ap_bearer_context_management.c | 632 +++++++++++++++++- .../E1AP/lib/e1ap_bearer_context_management.h | 6 + openair2/E1AP/lib/e1ap_lib_includes.h | 6 + 3 files changed, 643 insertions(+), 1 deletion(-) diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index e58fcbf145..a8f68e70d6 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -179,7 +179,7 @@ static bool eq_pdcp_config(const bearer_context_pdcp_config_t *a, const bearer_c /** @brief Encode SDAP Configuration IE */ static E1AP_SDAP_Configuration_t e1_encode_sdap_config(const bearer_context_sdap_config_t *in) { - E1AP_SDAP_Configuration_t out; + E1AP_SDAP_Configuration_t out = {0}; out.defaultDRB = in->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; out.sDAP_Header_UL = in->sDAP_Header_UL; out.sDAP_Header_DL = in->sDAP_Header_DL; @@ -1050,3 +1050,633 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg) { // Do nothing (no dynamic allocation) } + +/* ============================================ + * E1AP Bearer Context Modification Request + * ============================================ */ + +/** @brief Encode PDU Session Item to modify */ +static E1AP_PDU_Session_Resource_To_Modify_Item_t e1_encode_pdu_session_to_mod_item(const pdu_session_to_mod_t *in) +{ + E1AP_PDU_Session_Resource_To_Modify_Item_t out = {0}; + out.pDU_Session_ID = in->sessionId; + for (const DRB_nGRAN_to_mod_t *j = in->DRBnGRanModList; j < in->DRBnGRanModList + in->numDRB2Modify; j++) { + asn1cCalloc(out.dRB_To_Modify_List_NG_RAN, drb2Mod_List); + asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod); + drb2Mod->dRB_ID = j->id; + // PDCP Config (O) + if (j->pdcp_config) { + asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration); + *pDCP_Configuration = e1_encode_pdcp_config(j->pdcp_config); + } + // SDAP Config (O) + if (j->sdap_config) { + asn1cCalloc(drb2Mod->sDAP_Configuration, sDAP_Configuration); + *sDAP_Configuration = e1_encode_sdap_config(j->sdap_config); + } + // PDCP SN Status Request (O) + if (j->pdcp_sn_status_requested) { + asn1cCalloc(drb2Mod->pDCP_SN_Status_Request, pDCP_SN_Status_Request); + *pDCP_SN_Status_Request = E1AP_PDCP_SN_Status_Request_requested; + } + // DL UP TNL parameters (O) + if (j->numDlUpParam > 0) { + asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List); + for (const up_params_t *k = j->DlUpParamList; k < j->DlUpParamList + j->numDlUpParam; k++) { + asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param); + DL_UP_Param->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); + DL_UP_Param->cell_Group_ID = k->cell_group_id; + } + } + // QoS Flows to setup (O) + for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { + asn1cCalloc(drb2Mod->flow_Mapping_Information, flow_Mapping_Information); + asn1cSequenceAdd(flow_Mapping_Information->list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2); + *ie1_2 = e1_encode_qos_flow_to_setup(k); + } + } + return out; +} + +/** @brief Common encoding for the NG-RAN System IE */ +static E1AP_NG_RAN_BearerContextModificationRequest_t *encode_ng_ran_to_mod(E1AP_BearerContextModificationRequestIEs_t *ie) +{ + ie->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest; + ie->criticality = E1AP_Criticality_reject; + ie->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest; + E1AP_System_BearerContextModificationRequest_t *reqIE = &ie->value.choice.System_BearerContextModificationRequest; + reqIE->present = E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest; + E1AP_ProtocolIE_Container_4932P26_t *msgNGRAN_list = calloc_or_fail(1, sizeof(*msgNGRAN_list)); + reqIE->choice.nG_RAN_BearerContextModificationRequest = (struct E1AP_ProtocolIE_Container *)msgNGRAN_list; + asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextModificationRequest_t, msgNGRAN); + return msgNGRAN; +} + +/** @brief Encode PDU Session Resource To Setup Modification List item */ +static E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t e1_encode_pdu_session_to_setup_mod_item(const pdu_session_to_setup_t *in) +{ + E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t item = {0}; + // PDU Session ID (M) + item.pDU_Session_ID = in->sessionId; + // PDU Session Type (M) + item.pDU_Session_Type = in->sessionType; + // SNSSAI (M) + item.sNSSAI = e1_encode_snssai(&in->nssai); + // Security indication (M) + item.securityIndication = e1_encode_security_indication(&in->securityIndication); + // NG UL UP Transport Layer Information (M) + item.nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information); + // DRB to setup + for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) { + asn1cSequenceAdd(item.dRB_To_Setup_Mod_List_NG_RAN.list, E1AP_DRB_To_Setup_Mod_Item_NG_RAN_t, ie1); + // DRB ID (M) + ie1->dRB_ID = j->id; + // SDAP Config (M) + ie1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config); + // PDCP Config (M) + ie1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config); + // Cell Group Information (M) + for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) { + asn1cSequenceAdd(ie1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ie1_1); + ie1_1->cell_Group_ID = *k; + } + // QoS Flows Information To Be Setup (M) + for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { + asn1cSequenceAdd(ie1->flow_Mapping_Information.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2); + *ie1_2 = e1_encode_qos_flow_to_setup(k); + } + } + return item; +} + +/** + * @brief Encodes the E1 Bearer Modification Request message + */ +E1AP_E1AP_PDU_t *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *in) +{ + E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + // PDU Type + pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, msg); + msg->procedureCode = E1AP_ProcedureCode_id_bearerContextModification; + msg->criticality = E1AP_Criticality_reject; + msg->value.present = E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest; + + E1AP_BearerContextModificationRequest_t *out = &msg->value.choice.BearerContextModificationRequest; + + // gNB-CU-CP UE E1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie1); + ie1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; + ie1->criticality = E1AP_Criticality_reject; + ie1->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; + ie1->value.choice.GNB_CU_CP_UE_E1AP_ID = in->gNB_cu_cp_ue_id; + + // gNB-CU-UP UE E1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie2); + ie2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID; + ie2->criticality = E1AP_Criticality_reject; + ie2->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; + ie2->value.choice.GNB_CU_UP_UE_E1AP_ID = in->gNB_cu_up_ue_id; + + // Security Information (O) + if (in->secInfo) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie3); + ie3->id = E1AP_ProtocolIE_ID_id_SecurityInformation; + ie3->criticality = E1AP_Criticality_reject; + ie3->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation; + ie3->value.choice.SecurityInformation = e1_encode_security_info(in->secInfo); + } + + // UE DL Aggregate Maximum Bit Rate (O) + if (in->ueDlAggMaxBitRate) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie4); + ie4->id = E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate; + ie4->criticality = E1AP_Criticality_reject; + ie4->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BitRate; + INT32_TO_OCTET_STRING(*in->ueDlAggMaxBitRate, &ie4->value.choice.BitRate); + } + + // UE DL Maximum Integrity Protected Data Rate (O) + if (in->ueDlMaxIPBitRate) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie5); + ie5->id = E1AP_ProtocolIE_ID_id_UEDLMaximumIntegrityProtectedDataRate; + ie5->criticality = E1AP_Criticality_ignore; + ie5->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BitRate; + INT32_TO_OCTET_STRING(*in->ueDlMaxIPBitRate, &ie5->value.choice.BitRate); + } + + // Bearer Context Status Change (O) + if (in->bearerContextStatus && *in->bearerContextStatus == BEARER_SUSPEND) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie6); + ie6->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange; + ie6->criticality = E1AP_Criticality_reject; + ie6->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange; + ie6->value.choice.BearerContextStatusChange = E1AP_BearerContextStatusChange_suspend; + } + + // UE Inactivity Timer (O) + if (in->inactivityTimer) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie7); + ie7->id = E1AP_ProtocolIE_ID_id_UE_Inactivity_Timer; + ie7->criticality = E1AP_Criticality_ignore; + ie7->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_Inactivity_Timer; + ie7->value.choice.Inactivity_Timer = *in->inactivityTimer; + } + + // Data Discard Required (O) + if (in->dataDiscardRequired) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie9); + ie9->id = E1AP_ProtocolIE_ID_id_DataDiscardRequired; + ie9->criticality = E1AP_Criticality_ignore; + ie9->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_DataDiscardRequired; + ie9->value.choice.DataDiscardRequired = in->dataDiscardRequired; + } + + // NG-RAN PDU Session Resource To Setup List (O) + if (in->numPDUSessions) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, setupList); + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(setupList); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Setup_Mod_List; + E1AP_PDU_Session_Resource_To_Setup_Mod_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_Mod_List; + for (int i = 0; i < in->numPDUSessions; i++) { + const pdu_session_to_setup_t *pdu_session = &in->pduSession[i]; + asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t, item); + *item = e1_encode_pdu_session_to_setup_mod_item(pdu_session); + } + } + + // NG-RAN PDU Session Resource To Modify List (O) + if (in->numPDUSessionsMod) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, modList); + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(modList); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List; + E1AP_PDU_Session_Resource_To_Modify_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List; + for (const pdu_session_to_mod_t *i = in->pduSessionMod; i < in->pduSessionMod + in->numPDUSessionsMod; i++) { + asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Modify_Item_t, ieC3_1); + *ieC3_1 = e1_encode_pdu_session_to_mod_item(i); + } + } + return pdu; +} + +/** @brief Decode PDU Session Item to Setup (Bearer Context Modification Request) */ +static bool e1_decode_pdu_session_to_setup_mod_item(pdu_session_to_setup_t *out, + const E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t *item) +{ + // PDU Session ID (M) + out->sessionId = item->pDU_Session_ID; + // PDU Session Type (M) + out->sessionType = item->pDU_Session_Type; + // S-NSSAI (M) + CHECK_E1AP_DEC(e1_decode_snssai(&out->nssai, &item->sNSSAI)); + // Security Indication (M) + CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication)); + /* NG UL UP Transport Layer Information (M) */ + _E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel); + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information)); + /* DRB To Setup List ( > 1 item ) */ + const E1AP_DRB_To_Setup_Mod_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_Mod_List_NG_RAN; + _E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0); + out->numDRB2Setup = drb2SetupList->list.count; + _E1_EQ_CHECK_INT(out->numDRB2Setup, 1); // can only handle one DRB per PDU session + for (int j = 0; j < drb2SetupList->list.count; j++) { + DRB_nGRAN_to_setup_t *drb = out->DRBnGRanList + j; + const E1AP_DRB_To_Setup_Mod_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j]; + // DRB ID (M) + drb->id = drb2Setup->dRB_ID; + // SDAP Configuration (M) + CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration)); + // PDCP Configuration (M) + CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration)); + // Cell Group Information (M) + const E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information; + _E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0); + drb->numCellGroups = cellGroupList->list.count; + for (int k = 0; k < cellGroupList->list.count; k++) { + const E1AP_Cell_Group_Information_Item_t *cg2Setup = cellGroupList->list.array[k]; + // Cell Group ID + drb->cellGroupList[k] = cg2Setup->cell_Group_ID; + } + // QoS Flows Information To Be Setup (M) + const E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->flow_Mapping_Information; + drb->numQosFlow2Setup = qos2SetupList->list.count; + for (int k = 0; k < qos2SetupList->list.count; k++) { + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); + } + } + return true; +} + + +/** @brief Decode PDU Session Item to modify (Bearer Context Modification Request) */ +static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E1AP_PDU_Session_Resource_To_Modify_Item_t *in) +{ + // PDU Session ID + out->sessionId = in->pDU_Session_ID; + // DRB to modify list + E1AP_DRB_To_Modify_List_NG_RAN_t *drb2ModList = in->dRB_To_Modify_List_NG_RAN; + out->numDRB2Modify = drb2ModList->list.count; + for (int j = 0; j < drb2ModList->list.count; j++) { + DRB_nGRAN_to_mod_t *drb = out->DRBnGRanModList + j; + // DRB to modify item + E1AP_DRB_To_Modify_Item_NG_RAN_t *drb2Mod = drb2ModList->list.array[j]; + drb->id = drb2Mod->dRB_ID; + // PDCP Config (O) + if (drb2Mod->pDCP_Configuration) { + drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config)); + CHECK_E1AP_DEC(e1_decode_pdcp_config(drb->pdcp_config, drb2Mod->pDCP_Configuration)); + } + // SDAP Config (O) + if (drb2Mod->sDAP_Configuration) { + drb->sdap_config = malloc_or_fail(sizeof(*drb->sdap_config)); + CHECK_E1AP_DEC(e1_decode_sdap_config(drb->sdap_config, drb2Mod->sDAP_Configuration)); + } + // PDCP SN Status Request (O) + if (drb2Mod->pDCP_SN_Status_Request) { + drb->pdcp_sn_status_requested = true; + } + // DL UP TNL parameters (O) + if (drb2Mod->dL_UP_Parameters) { + E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; + if((drb->numDlUpParam = decode_dl_up_parameters(drb->DlUpParamList, dl_up_paramList)) < 0) { + PRINT_ERROR("Failed to decode DL UP TNL parameters\n"); + return false; + } + } + // QoS Flows Information To Be Setup (O) + E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = drb2Mod->flow_Mapping_Information; + drb->numQosFlow2Setup = qos2SetupList->list.count; + for (int k = 0; k < qos2SetupList->list.count; k++) { + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); + } + } + return true; +} + + +/** + * @brief E1 Bearer Modification Request message decoding + */ +bool decode_E1_bearer_context_mod_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_mod_req_t *out) +{ + DevAssert(pdu != NULL); + // Validate message type + _E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_initiatingMessage); + const E1AP_InitiatingMessage_t *im = pdu->choice.initiatingMessage; + _E1_EQ_CHECK_LONG(im->procedureCode, E1AP_ProcedureCode_id_bearerContextModification); + _E1_EQ_CHECK_INT(im->value.present, E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest); + + const E1AP_BearerContextModificationRequest_t *in = &im->value.choice.BearerContextModificationRequest; + E1AP_BearerContextModificationRequestIEs_t *ie = NULL; + + // Mandatory IEs + // gNB-CU-CP UE E1AP ID (M) + E1AP_LIB_FIND_IE(E1AP_BearerContextModificationRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true); + // gNB-CU-UP UE E1AP ID (M) + E1AP_LIB_FIND_IE(E1AP_BearerContextModificationRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID, true); + + // Loop through all IEs and extract + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID); + out->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID; + break; + + case E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID); + out->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID; + break; + + case E1AP_ProtocolIE_ID_id_SecurityInformation: + out->secInfo = malloc_or_fail(sizeof(*out->secInfo)); + CHECK_E1AP_DEC(e1_decode_security_info(out->secInfo, &ie->value.choice.SecurityInformation)); + break; + + case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: + out->ueDlAggMaxBitRate = malloc_or_fail(sizeof(*out->ueDlAggMaxBitRate)); + OCTET_STRING_TO_UINT32(&ie->value.choice.BitRate, *out->ueDlAggMaxBitRate); + break; + + case E1AP_ProtocolIE_ID_id_UEDLMaximumIntegrityProtectedDataRate: + out->ueDlMaxIPBitRate = malloc_or_fail(sizeof(*out->ueDlMaxIPBitRate)); + OCTET_STRING_TO_UINT32(&ie->value.choice.BitRate, *out->ueDlMaxIPBitRate); + break; + + case E1AP_ProtocolIE_ID_id_BearerContextStatusChange: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange); + if (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) { + out->bearerContextStatus = malloc_or_fail(sizeof(*out->bearerContextStatus)); + *out->bearerContextStatus = BEARER_SUSPEND; + } + break; + + case E1AP_ProtocolIE_ID_id_UE_Inactivity_Timer: + out->inactivityTimer = malloc_or_fail(sizeof(*out->inactivityTimer)); + *out->inactivityTimer = ie->value.choice.Inactivity_Timer; + break; + + case E1AP_ProtocolIE_ID_id_DataDiscardRequired: + out->dataDiscardRequired = ie->value.choice.DataDiscardRequired; + break; + + case E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest: { + _E1_EQ_CHECK_INT(ie->value.present, + E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest); + E1AP_System_BearerContextModificationRequest_t *modReq = &ie->value.choice.System_BearerContextModificationRequest; + DevAssert(ie->value.choice.System_BearerContextModificationRequest.choice.nG_RAN_BearerContextModificationRequest != NULL); + // System IE can contain either UTRAN or NG-RAN + switch (modReq->present) { + case E1AP_System_BearerContextModificationRequest_PR_NOTHING: + PRINT_ERROR("System Bearer Context Setup Request: no choice present\n"); + break; + case E1AP_System_BearerContextModificationRequest_PR_e_UTRAN_BearerContextModificationRequest: + PRINT_ERROR("UTRAN in E1 Setup Modification Request not supported\n"); + return false; + break; + case E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest: + // NG-RAN + AssertFatal(modReq->choice.nG_RAN_BearerContextModificationRequest != NULL, + "System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest shall not be null"); + E1AP_ProtocolIE_Container_4932P26_t *msgNGRAN_list = + (E1AP_ProtocolIE_Container_4932P26_t *)modReq->choice.nG_RAN_BearerContextModificationRequest; + // loop through all items in the NG-RAN list (to setup, to modify, etc) + for (int i = 0; i < msgNGRAN_list->list.count; i++) { + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = msgNGRAN_list->list.array[i]; + switch (msgNGRAN->id) { + case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List: + _E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List); + _E1_EQ_CHECK_INT(msgNGRAN->value.present, + E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Setup_Mod_List); + E1AP_PDU_Session_Resource_To_Setup_Mod_List_t *setupList = + &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_Mod_List; + // PDU Session Resource To Modify List + out->numPDUSessions = setupList->list.count; + // Loop through all PDU sessions + for (int i = 0; i < setupList->list.count; i++) { + pdu_session_to_setup_t *pdu_session = out->pduSession + i; + E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t *pdu2Setup = setupList->list.array[i]; + CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_mod_item(pdu_session, pdu2Setup)); + } + break; + case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List: + /* PDU Session Resource To Modify List (see 9.3.3.11 of TS 38.463) */ + _E1_EQ_CHECK_INT(msgNGRAN->value.present, + E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List); + E1AP_PDU_Session_Resource_To_Modify_List_t *modList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List; + out->numPDUSessionsMod = modList->list.count; + // Loop through all PDU sessions + for (int i = 0; i < modList->list.count; i++) { + CHECK_E1AP_DEC(e1_decode_pdu_session_to_mod_item(out->pduSessionMod + i, modList->list.array[i])); + } + break; + default: + PRINT_ERROR("Unknown msgNGRAN->id in E1 Setup Modification Request\n"); + return false; + break; + } + } + + break; + default: + PRINT_ERROR("System Bearer Context Modification Request: No valid choice present.\n"); + break; + } + + break; + } + + default: + PRINT_ERROR("System Bearer Context Modification Request: this IE is not implemented (or) invalid IE detected\n"); + return false; + break; + } + } + + return true; +} + +/** @brief Deep copy for DRB Item to modify */ +static DRB_nGRAN_to_mod_t cp_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) +{ + DRB_nGRAN_to_mod_t cp = {0}; + // shallow copy + cp = *msg; + _E1_CP_OPTIONAL_IE(&cp, msg, sdap_config); + _E1_CP_OPTIONAL_IE(&cp, msg, pdcp_config); + return cp; +} + +/** @brief Deep copy for PDU Session Item to modify */ +static pdu_session_to_mod_t cp_pdu_session_to_mod_item(const pdu_session_to_mod_t *msg) +{ + pdu_session_to_mod_t cp = {0}; + // shallow copy + cp = *msg; + // DRB to setup list + for (int j = 0; j < msg->numDRB2Setup; j++) + cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]); + // DRB to modify list + for (int j = 0; j < msg->numDRB2Modify; j++) + cp.DRBnGRanModList[j] = cp_drb_to_mod_item(&msg->DRBnGRanModList[j]); + _E1_CP_OPTIONAL_IE(&cp, msg, securityIndication); + _E1_CP_OPTIONAL_IE(&cp, msg, UP_TL_information); + return cp; +} + +/** @brief Deep copy for Bearer Context Modification Request */ +e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg) +{ + e1ap_bearer_mod_req_t cp = {0}; + // Shallow copy + cp = *msg; + // Deep copy for optional fields + _E1_CP_OPTIONAL_IE(&cp, msg, secInfo); + _E1_CP_OPTIONAL_IE(&cp, msg, bearerContextStatus); + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer); + // Deep copy PDU sessions + for (int i = 0; i < msg->numPDUSessions; i++) + cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]); + for (int i = 0; i < msg->numPDUSessionsMod; i++) + cp.pduSessionMod[i] = cp_pdu_session_to_mod_item(&msg->pduSessionMod[i]); + return cp; +} + +/** @brief Equality check for Security Indication IE (3GPP TS 38.463 9.3.1.23) */ +static bool eq_security_ind(security_indication_t *a, security_indication_t *b) +{ + _E1_EQ_CHECK_INT(a->confidentialityProtectionIndication, b->confidentialityProtectionIndication); + _E1_EQ_CHECK_INT(a->integrityProtectionIndication, b->integrityProtectionIndication); + _E1_EQ_CHECK_LONG(a->maxIPrate, b->maxIPrate); + return true; +} + +/** + * @brief Equality check for DRB_nGRAN_to_mod_t + */ +static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b) +{ + bool result = true; + _E1_EQ_CHECK_LONG(a->id, b->id); + _E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup); + for (int i = 0; i < a->numQosFlow2Setup; i++) { + result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); + } + _E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam); + for (int i = 0; i < a->numDlUpParam; i++) { + _E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id); + eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info); + } + if (a->pdcp_config && b->pdcp_config) + result &= eq_pdcp_config(a->pdcp_config, b->pdcp_config); + if (a->sdap_config && b->sdap_config) + result &= eq_sdap_config(a->sdap_config, b->sdap_config); + return result; +} + +/** @brief Equality check for PDU session item to modify */ +static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_session_to_mod_t *b) +{ + _E1_EQ_CHECK_LONG(a->sessionId, b->sessionId); + if (a->UP_TL_information && a->UP_TL_information) { + if (!eq_up_tl_info(a->UP_TL_information, b->UP_TL_information)) + return false; + } + _E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup); + for (int i = 0; i < a->numDRB2Setup; i++) { + if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i])) + return false; + } + _E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify); + for (int i = 0; i < a->numDRB2Modify; i++) { + if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i])) + return false; + } + if (a->securityIndication && b->securityIndication) { + eq_security_ind(a->securityIndication, b->securityIndication); + } + return true; +} + +/** + * @brief E1AP Bearer Modification Request equality check + */ +bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_bearer_mod_req_t *b) +{ + // basic members + _E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id); + _E1_EQ_CHECK_INT(a->gNB_cu_up_ue_id, b->gNB_cu_up_ue_id); + _E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions); + _E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod); + // Security Info + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, secInfo); + if (a->secInfo && b->secInfo) { + _E1_EQ_CHECK_LONG(a->secInfo->cipheringAlgorithm, b->secInfo->cipheringAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo->integrityProtectionAlgorithm, b->secInfo->integrityProtectionAlgorithm); + _E1_EQ_CHECK_STR(a->secInfo->encryptionKey, b->secInfo->encryptionKey); + _E1_EQ_CHECK_STR(a->secInfo->integrityProtectionKey, b->secInfo->integrityProtectionKey); + } + // Bearer Context Status (O) + _E1_EQ_CHECK_OPTIONAL_IE(a, b, bearerContextStatus, _E1_EQ_CHECK_INT); + // Inactivity Timer (O) + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer); + if (a->inactivityTimer && b->inactivityTimer) + _E1_EQ_CHECK_INT(*a->inactivityTimer, *b->inactivityTimer); + // Activity Notification Level (O) + // PDU Sessions + if (a->numPDUSessions != b->numPDUSessions) + return false; + for (int i = 0; i < a->numPDUSessions; i++) { + if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i])) + return false; + } + // Modified PDU Sessions + if (a->numPDUSessionsMod != b->numPDUSessionsMod) + return false; + for (int i = 0; i < a->numPDUSessionsMod; i++) { + if (!eq_pdu_session_to_mod_item(&a->pduSessionMod[i], &b->pduSessionMod[i])) + return false; + } + return true; +} + +/* Free DRB to modify item */ +static void free_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) +{ + free(msg->pdcp_config); + free(msg->sdap_config); +} + +/* Free PDU Session to modify item */ +void free_pdu_session_to_mod_item(const pdu_session_to_mod_t *msg) +{ + free(msg->securityIndication); + free(msg->UP_TL_information); + for (int i = 0; i < msg->numDRB2Modify; i++) + free_drb_to_mod_item(&msg->DRBnGRanModList[i]); + for (int i = 0; i < msg->numDRB2Setup; i++) + free_drb_to_setup_item(&msg->DRBnGRanList[i]); +} + +/** + * @brief E1AP Bearer Context Modification Request memory management + */ +void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg) +{ + free(msg->secInfo); + free(msg->ueDlAggMaxBitRate); + free(msg->ueDlMaxIPBitRate); + free(msg->bearerContextStatus); + free(msg->inactivityTimer); + for (int i = 0; i < msg->numPDUSessions; i++) + free_pdu_session_to_setup_item(&msg->pduSession[i]); + for (int i = 0; i < msg->numPDUSessionsMod; i++) + free_pdu_session_to_mod_item(&msg->pduSessionMod[i]); +} diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.h b/openair2/E1AP/lib/e1ap_bearer_context_management.h index 95e4cb0e15..132c1857e1 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.h +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.h @@ -40,4 +40,10 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg); e1ap_bearer_setup_resp_t cp_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg); bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e1ap_bearer_setup_resp_t *b); +struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg); +bool decode_E1_bearer_context_mod_request(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_mod_req_t *out); +void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg); +e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg); +bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_bearer_mod_req_t *b); + #endif /* E1AP_BEARER_CONTEXT_MANAGEMENT_H_ */ diff --git a/openair2/E1AP/lib/e1ap_lib_includes.h b/openair2/E1AP/lib/e1ap_lib_includes.h index 785fd9d09c..46d09f5aa9 100644 --- a/openair2/E1AP/lib/e1ap_lib_includes.h +++ b/openair2/E1AP/lib/e1ap_lib_includes.h @@ -67,5 +67,11 @@ #include "E1AP_Transport-UP-Layer-Addresses-Info-To-Remove-Item.h" #include "E1AP_GTPTLAs.h" #include "E1AP_GTPTLA-Item.h" +// E1 Bearer Context Modification Request +#include "E1AP_PDU-Session-Resource-To-Modify-Item.h" +#include "E1AP_DRB-To-Modify-List-NG-RAN.h" +#include "E1AP_DRB-To-Modify-Item-NG-RAN.h" +#include "E1AP_PDU-Session-Resource-To-Setup-Mod-Item.h" +#include "E1AP_DRB-To-Setup-Mod-Item-NG-RAN.h" #endif /* E1AP_LIB_INCLUDES_H_ */ From b854f971306f4c780b6d5aff228c4938ebcf8b89 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 11 Feb 2025 13:15:01 +0100 Subject: [PATCH 12/18] Enable pDCP_Reestablishment in test_bearer_context_setup_request --- openair2/E1AP/tests/e1ap_lib_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index bc670486cd..368698a517 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -85,7 +85,7 @@ static void test_bearer_context_setup_request(void) { bearer_context_pdcp_config_t pdcp = { .discardTimer = E1AP_DiscardTimer_ms10, - .pDCP_Reestablishment = E1AP_PDCP_Reestablishment_true, + .pDCP_Reestablishment = true, .pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12, .pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12, .reorderingTimer = 10, From 627f8171ec6b963eea4ca1727d1f12346de1f886 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 11 Feb 2025 14:04:19 +0100 Subject: [PATCH 13/18] Add test for Bearer Context Modification Request --- openair2/E1AP/tests/e1ap_lib_test.c | 116 ++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index 368698a517..59e6f08e66 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -339,6 +339,120 @@ static void test_e1_cuup_setup_failure(void) free_e1ap_cuup_setup_failure(&orig); } +/** + * @brief Test E1AP Bearer Context Modification Request encoding/decoding + */ +static void test_bearer_context_modification_request(void) +{ + const bearer_context_sdap_config_t dummy_sdap_config = { + .defaultDRB = 0, + .sDAP_Header_DL = false, + .sDAP_Header_UL = false, + }; + + const bearer_context_pdcp_config_t dummy_pdcp_config = { + .discardTimer = E1AP_DiscardTimer_ms100, + .pDCP_Reestablishment = true, + .pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12, + .pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12, + .reorderingTimer = 5, + .rLC_Mode = E1AP_RLC_Mode_rlc_um_bidirectional, + }; + + const qos_flow_to_setup_t dummy_qos_flows = { + .qfi = 9, + .qos_params.alloc_reten_priority.preemption_capability = E1AP_Pre_emptionCapability_may_trigger_pre_emption, + .qos_params.alloc_reten_priority.preemption_vulnerability = E1AP_Pre_emptionVulnerability_pre_emptable, + .qos_params.alloc_reten_priority.priority_level = E1AP_PriorityLevel_no_priority, + .qos_params.qos_characteristics.non_dynamic.fiveqi = 9, + }; + + DRB_nGRAN_to_mod_t drb_to_mod = { + .numDlUpParam = 1, + .DlUpParamList[0].cell_group_id = MCG, + .DlUpParamList[0].tl_info = create_up_tl_info(), + .id = 1, + .pdcp_config = malloc_or_fail(sizeof(*drb_to_mod.pdcp_config)), + .pdcp_sn_status_requested = true, + .numQosFlow2Setup = 1, + .qosFlows[0] = dummy_qos_flows, + }; + *drb_to_mod.pdcp_config = dummy_pdcp_config; + + pdu_session_to_mod_t pdusession_mod_item = { + .sessionId = 1, + .numDRB2Modify = 1, + .DRBnGRanModList[0] = drb_to_mod, + }; + + DRB_nGRAN_to_setup_t drb_to_setup = { + .id = 1, + .cellGroupList[0] = MCG, + .numCellGroups = 1, + .pdcp_config = dummy_pdcp_config, + .sdap_config = dummy_sdap_config, + .numQosFlow2Setup = 1, + .qosFlows[0] = dummy_qos_flows, + .drb_inactivity_timer = malloc_or_fail(sizeof(*drb_to_setup.drb_inactivity_timer)), + }; + *drb_to_setup.drb_inactivity_timer = 500; + + pdu_session_to_setup_t pdusession_setup_item = { + .numDRB2Setup = 1, + .nssai.sd = 0x01, + .nssai.sst = 0x01, + .UP_TL_information.teId = 0x12345, + .UP_TL_information.tlAddress = 167772161, + .DRBnGRanList[0] = drb_to_setup, + }; + + // Initialize the Bearer Context Modification Request + e1ap_bearer_mod_req_t orig = { + .gNB_cu_cp_ue_id = 0x1234, + .gNB_cu_up_ue_id = 0x5678, + .bearerContextStatus = malloc_or_fail(sizeof(*orig.bearerContextStatus)), + .inactivityTimer = malloc_or_fail(sizeof(*orig.inactivityTimer)), + .numPDUSessions = 1, + .pduSession[0] = pdusession_setup_item, + .numPDUSessionsMod = 1, + .pduSessionMod[0] = pdusession_mod_item, + }; + *orig.bearerContextStatus = BEARER_SUSPEND; + *orig.inactivityTimer = 1000; + + // Encode the original message + E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_mod_request(&orig); + + // Decode the encoded message + E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc); + + // Free the encoded message + e1ap_msg_free(enc); + + // Decode the message into a new struct + e1ap_bearer_mod_req_t decoded = {0}; + AssertFatal(decode_E1_bearer_context_mod_request(dec, &decoded), "decode_E1_bearer_context_mod_request(): could not decode message\n"); + + // Free the decoded E1AP message + e1ap_msg_free(dec); + + // Compare the original and decoded structs + AssertFatal(eq_bearer_context_mod_request(&orig, &decoded), "eq_bearer_context_mod_request(): decoded message doesn't match\n"); + + // Free the memory for the decoded message + free_e1ap_context_mod_request(&decoded); + + // Deep copy the original message + e1ap_bearer_mod_req_t cp = cp_bearer_context_mod_request(&orig); + + // Verify the deep copy matches the original + AssertFatal(eq_bearer_context_mod_request(&orig, &cp), "eq_bearer_context_mod_request(): copied message doesn't match\n"); + + // Free the copied and original message + free_e1ap_context_mod_request(&cp); + free_e1ap_context_mod_request(&orig); +} + int main() { // E1 Bearer Context Setup @@ -348,5 +462,7 @@ int main() test_e1_cuup_setup_request(); test_e1_cuup_setup_response(); test_e1_cuup_setup_failure(); + // E1 Bearer Context Modification Request + test_bearer_context_modification_request(); return 0; } From a1eb8f35fbbf0d2959d49c7c683607cc1adad22e Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 Jan 2025 16:00:34 +0100 Subject: [PATCH 14/18] bugfix: use correct algorithm and derive keys accordingly This was not a big problem, but we were advertising wrong algorithm and deriving keys using this wrong algorithm in case DRB ciphering and/or integrity was not active. (Say SRBs are configured with NIA2 but DRBs are configured without integrity, we would advertise NIA2 and send the integrity key derived for NIA2, instead of NIA0 for both.) It was not a problem because in the PDU Session Resource To Setup item, there is "securityIndication" which we use to effectively activate/deactivate the ciphering and/or integrity. But it did not look clean to see a SecurityInformation with incorrect data when inspecting the message in wireshark. So let's use the correct values. We could also not include the SecurityInformation if both ciphering and integrity are not used, and only include ciphering if integrity is not used (because integrity settings are optional). But then if only integrity is used, we still need to include ciphering, setting algorithm to NEA0 (no ciphering), because the ciphering settings are always included. This logic is too complex, let's use the simple one to always include SecurityInformation with NEA0 and/or NIA0 if ciphering and/or integrity is not activated. --- openair2/RRC/NR/rrc_gNB_NGAP.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 7f17baea4a..87ee2623eb 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -356,10 +356,10 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession decodePDUSessionResourceSetup(session); bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; security_information_t *secInfo = &bearer_req.secInfo; - secInfo->cipheringAlgorithm = UE->ciphering_algorithm; - secInfo->integrityProtectionAlgorithm = UE->integrity_algorithm; - nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey); - nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); + secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; + secInfo->integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; + nr_derive_key(UP_ENC_ALG, secInfo->cipheringAlgorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey); + nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); bearer_req.ueDlAggMaxBitRate = ueAggMaxBitRateDownlink; pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; bearer_req.numPDUSessions++; From 182b05bd5c6493ec5d7b2ac40ed59ac33bcc4142 Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 Jan 2025 16:06:36 +0100 Subject: [PATCH 15/18] e1: security information is optional in bearer modification Check if the IE is memory allocated to deal with presence/absence of this information element in Bearer Context Modification Request and add encoding/decoding in the code. Note that for decoding the integrity settings may be absent, in which case we consider NIA0 to be used (no integrity protection). To be refined if needed. And for encoding, we always encode integrity settings, even if it's NIA0. May also be refined if needed. --- openair2/E1AP/e1ap.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 72eff658cb..c17f54be11 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -451,6 +451,21 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_mod_req_t *const ieC2->criticality = E1AP_Criticality_reject; ieC2->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; ieC2->value.choice.GNB_CU_UP_UE_E1AP_ID = bearerCxt->gNB_cu_up_ue_id; + /* optional */ + /* Security Information */ + if (bearerCxt->secInfo) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie); + ie->id = E1AP_ProtocolIE_ID_id_SecurityInformation; + ie->criticality = E1AP_Criticality_reject; + ie->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation; + E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie->value.choice.SecurityInformation.securityAlgorithm; + E1AP_UPSecuritykey_t *uPSecuritykey = &ie->value.choice.SecurityInformation.uPSecuritykey; + securityAlgorithm->cipheringAlgorithm = bearerCxt->secInfo->cipheringAlgorithm; + OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, bearerCxt->secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE); + asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, bearerCxt->secInfo->integrityProtectionAlgorithm); + asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); + OCTET_STRING_fromBuf(protKey, bearerCxt->secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + } /* optional */ /* c3. E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest */ asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC3); @@ -606,6 +621,26 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p bearerCxt->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID; break; + case E1AP_ProtocolIE_ID_id_SecurityInformation: { + DevAssert(ie->criticality == E1AP_Criticality_reject); + DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation); + E1AP_SecurityInformation_t *sec = &ie->value.choice.SecurityInformation; + DevAssert(sec->uPSecuritykey.encryptionKey.size == E1AP_SECURITY_KEY_SIZE); + DevAssert(sec->uPSecuritykey.integrityProtectionKey == NULL + || sec->uPSecuritykey.integrityProtectionKey->size == E1AP_SECURITY_KEY_SIZE); + bearerCxt->secInfo = malloc_or_fail(sizeof(*bearerCxt->secInfo)); + bearerCxt->secInfo->cipheringAlgorithm = sec->securityAlgorithm.cipheringAlgorithm; + bearerCxt->secInfo->integrityProtectionAlgorithm = sec->securityAlgorithm.integrityProtectionAlgorithm == NULL + ? 0 + : *sec->securityAlgorithm.integrityProtectionAlgorithm; + memcpy(bearerCxt->secInfo->encryptionKey, sec->uPSecuritykey.encryptionKey.buf, E1AP_SECURITY_KEY_SIZE); + if (sec->securityAlgorithm.integrityProtectionAlgorithm == NULL) + memset(bearerCxt->secInfo->integrityProtectionKey, 0, E1AP_SECURITY_KEY_SIZE); + else + memcpy(bearerCxt->secInfo->integrityProtectionKey, sec->uPSecuritykey.integrityProtectionKey->buf, E1AP_SECURITY_KEY_SIZE); + break; + } + case E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest: DevAssert(ie->criticality == E1AP_Criticality_reject); DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest); From 1273446804ca70d0307220863d04f90bf45b4dfc Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 Jan 2025 16:11:00 +0100 Subject: [PATCH 16/18] e1: change security settings only if parameters present If the Bearer Context Modification Request does not contain security information, the PDCP entity shall keep the currently configured security settings. Passing -1 for ciphering_algorithm and integrity_algorithm is the way to implement this logic. --- openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index ed39dbeff0..3417940051 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -279,6 +279,10 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) security_parameters.integrity_algorithm = req->secInfo->integrityProtectionAlgorithm; memcpy(security_parameters.ciphering_key, req->secInfo->encryptionKey, NR_K_KEY_SIZE); memcpy(security_parameters.integrity_key, req->secInfo->integrityProtectionKey, NR_K_KEY_SIZE); + } else { + /* don't change security settings if not present in the Bearer Context Modification Request */ + security_parameters.ciphering_algorithm = -1; + security_parameters.integrity_algorithm = -1; } nr_pdcp_reestablishment(req->gNB_cu_up_ue_id, to_modif->id, From 410446cbe9132474343cf943ae655b75cbb188bb Mon Sep 17 00:00:00 2001 From: Cedric Roux Date: Wed, 22 Jan 2025 16:15:04 +0100 Subject: [PATCH 17/18] e1: no need to pass security information since it does not change In Bearer Context Modification Request, the security information field is needed only if we change the PDCP algorithms/keys. Since we don't, no need to pass it. Let's keep the old code, maybe the current understanding of the specifications is wrong. --- openair2/RRC/NR/rrc_gNB.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 6cfb0047af..d9e83bb4c2 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -816,9 +816,17 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) /* increase DRB to modify counter */ pdu_e1->numDRB2Modify += 1; } + +#if 0 + /* According to current understanding of E1 specifications, it is not needed + * to send security information because this does not change. + * But let's keep the code here in case it's needed. + */ // Always send security information req.secInfo = malloc_or_fail(sizeof(*req.secInfo)); fill_security_info(rrc, ue_p, req.secInfo); +#endif + /* Send E1 Bearer Context Modification Request (3GPP TS 38.463) */ sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue_p); rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); From ac6b1b189445e9c576eafa0170baef85ca553ec4 Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Tue, 4 Feb 2025 12:56:33 +0100 Subject: [PATCH 18/18] Enable integrity in E1 SABOX CI test --- ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml index 6c3940d306..5a55ade3c8 100644 --- a/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml @@ -9,6 +9,7 @@ services: environment: USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.listenport 9090 --telnetsrv.shrmod ci --log_config.global_log_options level,nocolor,time,line_num,function + --security.drb_integrity yes volumes: - ../../conf_files/gnb-cucp.sa.f1.quectel.conf:/opt/oai-gnb/etc/gnb.conf # for performance reasons, we use host mode: in bridge mode, we have