diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index f2fd64252c..3d096c33e0 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -27,19 +27,19 @@ #include #include #include "common/ngran_types.h" -#include "f1ap_messages_types.h" -#include "ngap_messages_types.h" +#include "common/platform_types.h" +#include "common/5g_platform_types.h" +/* Definitions according to 3GPP TS 38.463 */ #define E1AP_MAX_NUM_TRANSAC_IDS 4 #define E1AP_MAX_NUM_PLMNS 4 #define E1AP_MAX_NUM_SLICES 1024 #define E1AP_MAX_NUM_CELL_GROUPS 4 -#define E1AP_MAX_NUM_QOS_FLOWS 4 -#define E1AP_MAX_NUM_NGRAN_DRB 4 +#define E1AP_MAX_NUM_QOS_FLOWS 64 #define E1AP_MAX_NUM_PDU_SESSIONS 4 -#define E1AP_MAX_NUM_DRBS 4 -#define E1AP_MAX_NUM_DRBS 4 +#define E1AP_MAX_NUM_DRBS 32 #define E1AP_MAX_NUM_UP_PARAM 4 +#define E1AP_SECURITY_KEY_SIZE 16 // keys have 128 bits length #define E1AP_REGISTER_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_register_req #define E1AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_req @@ -61,6 +61,17 @@ 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, +} cell_group_id_t; + typedef struct PLMN_ID_s { int mcc; int mnc; @@ -107,10 +118,6 @@ typedef struct e1ap_setup_fail_s { long transac_id; } e1ap_setup_fail_t; -typedef struct cell_group_s { - long id; -} cell_group_t; - typedef struct up_params_s { in_addr_t tlAddress; long teId; @@ -144,22 +151,27 @@ typedef struct drb_to_setup_s { in_addr_t tlAddress; long teId; int numCellGroups; - cell_group_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS]; + cell_group_id_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS]; } drb_to_setup_t; typedef struct qos_characteristics_s { union { struct { - long fiveqi; - long qos_priority_level; + uint16_t fiveqi; + uint8_t qos_priority_level; } non_dynamic; struct { - long fiveqi; // -1 -> optional - long qos_priority_level; - long packet_delay_budget; + // Range 5QI [0 - 255] + uint16_t fiveqi; + /* Range [0 - 15] + 15 = "no priority," 1-14 = decreasing priority (1 highest), 0 = logical error if received */ + uint8_t qos_priority_level; + // Range [0, 1023]: Upper bound for packet delay in 0.5ms units + uint16_t packet_delay_budget; struct { - long per_scalar; - long per_exponent; + // PER = Scalar x 10^-k (k: 0-9) + uint8_t per_scalar; + uint8_t per_exponent; } packet_error_rate; } dynamic; }; @@ -168,8 +180,10 @@ typedef struct qos_characteristics_s { typedef struct ngran_allocation_retention_priority_s { uint16_t priority_level; - long preemption_capability; - long preemption_vulnerability; + // Pre-emption capability on other QoS flows + uint8_t preemption_capability; + // Vulnerability of the QoS flow to pre-emption of other QoS flows + uint8_t preemption_vulnerability; } ngran_allocation_retention_priority_t; typedef struct qos_flow_level_qos_parameters_s { @@ -203,13 +217,31 @@ typedef struct DRB_nGRAN_to_setup_s { /* Cell Group Information (clause 9.3.1.11) */ int numCellGroups; - cell_group_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS]; + cell_group_id_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS]; /* DRB QoS Flows Parameters (clause 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; +typedef enum e1ap_indication_e { + SECURITY_REQUIRED = 0, + SECURITY_PREFERRED, + SECURITY_NOT_NEEDED +} e1ap_indication_t; + +typedef struct security_indication_s { + e1ap_indication_t integrityProtectionIndication; + e1ap_indication_t confidentialityProtectionIndication; + // Maximum Integrity Protected Data Rate + 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) @@ -218,18 +250,12 @@ typedef struct pdu_session_to_setup_s { long sessionId; long sessionType; e1ap_nssai_t nssai; - long integrityProtectionIndication; - long confidentialityProtectionIndication; - in_addr_t tlAddress; - in_addr_t tlAddress_dl; - int32_t teId; - int32_t teId_dl; - int tl_port; - int tl_port_dl; + security_indication_t securityIndication; + UP_TL_information_t UP_TL_information; long numDRB2Setup; - DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_NGRAN_DRB]; + DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; long numDRB2Modify; - DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_NGRAN_DRB]; + DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; } pdu_session_to_setup_t, pdu_session_to_mod_t; /** @@ -239,15 +265,15 @@ typedef struct pdu_session_to_setup_s { */ typedef struct e1ap_bearer_setup_req_s { uint32_t gNB_cu_cp_ue_id; - uint32_t gNB_cu_up_ue_id; + uint32_t gNB_cu_up_ue_id; // Bearer Context Modification Request only uint64_t cipheringAlgorithm; uint64_t integrityProtectionAlgorithm; - char encryptionKey[128]; - char integrityProtectionKey[128]; + char encryptionKey[E1AP_SECURITY_KEY_SIZE]; + char integrityProtectionKey[E1AP_SECURITY_KEY_SIZE]; long ueDlAggMaxBitRate; PLMN_ID_t servingPLMNid; BEARER_CONTEXT_STATUS_t bearerContextStatus; - long activityNotificationLevel; + activity_notification_level_t activityNotificationLevel; int numPDUSessions; pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; int numPDUSessionsMod; @@ -293,16 +319,16 @@ typedef struct pdu_session_setup_s { in_addr_t tlAddress; long teId; int numDRBSetup; - DRB_nGRAN_setup_t DRBnGRanList[E1AP_MAX_NUM_NGRAN_DRB]; + DRB_nGRAN_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; int numDRBFailed; - DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_NGRAN_DRB]; + DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_DRBS]; } pdu_session_setup_t; typedef struct pdu_session_modif_s { long id; // setup as part of PDU session modification not supported yet int numDRBModified; - DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_NGRAN_DRB]; + DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; } pdu_session_modif_t; typedef struct e1ap_bearer_setup_resp_s { diff --git a/openair2/COMMON/ngap_messages_types.h b/openair2/COMMON/ngap_messages_types.h index cdba1c5e2d..2ac5652a9f 100644 --- a/openair2/COMMON/ngap_messages_types.h +++ b/openair2/COMMON/ngap_messages_types.h @@ -29,6 +29,7 @@ #ifndef NGAP_MESSAGES_TYPES_H_ #define NGAP_MESSAGES_TYPES_H_ +#include "common/5g_platform_types.h" #include "common/platform_constants.h" #include "common/platform_types.h" #include "common/5g_platform_types.h" diff --git a/openair2/E1AP/CMakeLists.txt b/openair2/E1AP/CMakeLists.txt index c7657eed5a..5849a32fe5 100644 --- a/openair2/E1AP/CMakeLists.txt +++ b/openair2/E1AP/CMakeLists.txt @@ -1,7 +1,12 @@ add_subdirectory(MESSAGES) +add_subdirectory(lib) add_library(e1ap e1ap.c e1ap_common.c) target_link_libraries(e1ap - PUBLIC asn1_e1ap f1ap + PUBLIC asn1_e1ap e1ap_lib PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap UTIL e1_if) target_include_directories(e1ap PUBLIC ${CMAKE_CURRENT_DIR}) + +if(ENABLE_TESTS) + add_subdirectory(tests) +endif() diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 1e28ebd52a..79b326593b 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -33,6 +33,7 @@ #include "e1ap_default_values.h" #include "gtp_itf.h" #include "openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h" +#include "lib/e1ap_bearer_context_management.h" #define E1AP_NUM_MSG_HANDLERS 14 typedef int (*e1ap_message_processing_t)(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *message_p); @@ -572,296 +573,17 @@ int e1ap_handle_RELEASE_ACKNOWLEDGE(instance_t instance, sctp_assoc_t assoc_id, return -1; } -/* - BEARER CONTEXT SETUP REQUEST -*/ - -static int fill_BEARER_CONTEXT_SETUP_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) -{ - pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; - asn1cCalloc(pdu->choice.initiatingMessage, msg); - msg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup; - msg->criticality = E1AP_Criticality_reject; - msg->value.present = E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest; - E1AP_BearerContextSetupRequest_t *out = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest; - /* mandatory */ - /* c1. gNB-CU-UP UE E1AP ID */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC1); - ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; - ieC1->criticality = E1AP_Criticality_reject; - ieC1->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; - ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = bearerCxt->gNB_cu_cp_ue_id; - /* mandatory */ - /* c2. Security Information */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC2); - ieC2->id = E1AP_ProtocolIE_ID_id_SecurityInformation; - ieC2->criticality = E1AP_Criticality_reject; - ieC2->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation; - ieC2->value.choice.SecurityInformation.securityAlgorithm.cipheringAlgorithm = bearerCxt->cipheringAlgorithm; - OCTET_STRING_fromBuf(&ieC2->value.choice.SecurityInformation.uPSecuritykey.encryptionKey, - bearerCxt->encryptionKey, 16); - - asn1cCallocOne(ieC2->value.choice.SecurityInformation.securityAlgorithm.integrityProtectionAlgorithm, bearerCxt->integrityProtectionAlgorithm); - asn1cCalloc(ieC2->value.choice.SecurityInformation.uPSecuritykey.integrityProtectionKey, protKey); - OCTET_STRING_fromBuf(protKey, bearerCxt->integrityProtectionKey, 16); - /* mandatory */ - /* c3. UE DL Aggregate Maximum Bit Rate */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3); - ieC3->id = E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate; - ieC3->criticality = E1AP_Criticality_reject; - ieC3->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_BitRate; - asn_long2INTEGER(&ieC3->value.choice.BitRate, bearerCxt->ueDlAggMaxBitRate); - /* mandatory */ - /* c4. Serving PLMN */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC4); - ieC4->id = E1AP_ProtocolIE_ID_id_Serving_PLMN; - ieC4->criticality = E1AP_Criticality_ignore; - ieC4->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity; - PLMN_ID_t *servingPLMN = &bearerCxt->servingPLMNid; - MCC_MNC_TO_PLMNID(servingPLMN->mcc, servingPLMN->mnc, servingPLMN->mnc_digit_length, &ieC4->value.choice.PLMN_Identity); - /* mandatory */ - /* Activity Notification Level */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC5); - ieC5->id = E1AP_ProtocolIE_ID_id_ActivityNotificationLevel; - 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 */ - /* */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC6); - ieC6->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest; - ieC6->criticality = E1AP_Criticality_reject; - ieC6->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest; - ieC6->value.choice.System_BearerContextSetupRequest.present = E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest; - E1AP_ProtocolIE_Container_4932P19_t *msgNGRAN_list = calloc(1, sizeof(E1AP_ProtocolIE_Container_4932P19_t)); - ieC6->value.choice.System_BearerContextSetupRequest.choice.nG_RAN_BearerContextSetupRequest = (struct E1AP_ProtocolIE_Container *) msgNGRAN_list; - asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupRequest_t, msgNGRAN); - msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_List; - msgNGRAN->criticality = E1AP_Criticality_reject; - msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List; - E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List; - for (pdu_session_to_setup_t *i = bearerCxt->pduSession; i < bearerCxt->pduSession + bearerCxt->numPDUSessions; i++) { - asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Item_t, ieC6_1); - ieC6_1->pDU_Session_ID = i->sessionId; - ieC6_1->pDU_Session_Type = i->sessionType; - - INT8_TO_OCTET_STRING(i->nssai.sst, &ieC6_1->sNSSAI.sST); - if (i->nssai.sd != 0xffffff) { - ieC6_1->sNSSAI.sD = malloc(sizeof(*ieC6_1->sNSSAI.sD)); - AssertFatal(ieC6_1->sNSSAI.sD != NULL, "out of memory\n"); - INT24_TO_OCTET_STRING(i->nssai.sd, ieC6_1->sNSSAI.sD); - } - - ieC6_1->securityIndication.integrityProtectionIndication = i->integrityProtectionIndication; - ieC6_1->securityIndication.confidentialityProtectionIndication = i->confidentialityProtectionIndication; - - ieC6_1->nG_UL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(ieC6_1->nG_UL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID); - - for (DRB_nGRAN_to_setup_t *j = i->DRBnGRanList; j < i->DRBnGRanList + i->numDRB2Setup; j++) { - asn1cSequenceAdd(ieC6_1->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 */ - ieC6_1_1->sDAP_Configuration.defaultDRB = j->sdap_config.defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; - ieC6_1_1->sDAP_Configuration.sDAP_Header_UL = j->sdap_config.sDAP_Header_UL; - ieC6_1_1->sDAP_Configuration.sDAP_Header_DL = j->sdap_config.sDAP_Header_DL; - /* PDCP Config */ - ieC6_1_1->pDCP_Configuration.pDCP_SN_Size_UL = j->pdcp_config.pDCP_SN_Size_UL; - ieC6_1_1->pDCP_Configuration.pDCP_SN_Size_DL = j->pdcp_config.pDCP_SN_Size_DL; - asn1cCallocOne(ieC6_1_1->pDCP_Configuration.discardTimer, j->pdcp_config.discardTimer); - E1AP_T_ReorderingTimer_t *roTimer = calloc(1, sizeof(E1AP_T_ReorderingTimer_t)); - ieC6_1_1->pDCP_Configuration.t_ReorderingTimer = roTimer; - roTimer->t_Reordering = j->pdcp_config.reorderingTimer; - ieC6_1_1->pDCP_Configuration.rLC_Mode = j->pdcp_config.rLC_Mode; - /* Cell Group config */ - for (cell_group_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->id; - } - /* QoS Flows */ - for (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 */ - 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 */ - ngran_allocation_retention_priority_t *rent_priority_in = &k->qos_params.alloc_reten_priority; - ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel = rent_priority_in->priority_level; - ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability = - rent_priority_in->preemption_capability; - ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability = - rent_priority_in->preemption_vulnerability; - } - } - } - return 0; -} - void e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_bearer_setup_req_t *const bearerCxt) { - E1AP_E1AP_PDU_t pdu = {0}; - fill_BEARER_CONTEXT_SETUP_REQUEST(bearerCxt, &pdu); - e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__); -} - -static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *resp, E1AP_E1AP_PDU_t *pdu) -{ - /* Create */ - /* 0. pdu Type */ - pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome; - asn1cCalloc(pdu->choice.successfulOutcome, msg); - msg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup; - msg->criticality = E1AP_Criticality_reject; - msg->value.present = E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse; - E1AP_BearerContextSetupResponse_t *out = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse; - /* mandatory */ - /* c1. gNB-CU-CP UE E1AP ID */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC1); - ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; - ieC1->criticality = E1AP_Criticality_reject; - ieC1->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; - ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = resp->gNB_cu_cp_ue_id; - /* mandatory */ - /* c2. gNB-CU-UP UE E1AP ID */ - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC2); - ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID; - ieC2->criticality = E1AP_Criticality_reject; - ieC2->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; - ieC2->value.choice.GNB_CU_CP_UE_E1AP_ID = resp->gNB_cu_up_ue_id; - - asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC3); - ieC3->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse; - ieC3->criticality = E1AP_Criticality_reject; - ieC3->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse; - /*if (0) { // EUTRAN - ieC3->value.choice.System_BearerContextSetupResponse.present = - E1AP_System_BearerContextSetupResponse_PR_e_UTRAN_BearerContextSetupResponse; - E1AP_ProtocolIE_Container_4932P21_t *msgEUTRAN_list = calloc(1, - sizeof(E1AP_ProtocolIE_Container_4932P21_t)); - ieC3->value.choice.System_BearerContextSetupResponse.choice.e_UTRAN_BearerContextSetupResponse - = (struct E1AP_ProtocolIE_Container *) msgEUTRAN_list; - asn1cSequenceAdd(msgEUTRAN_list->list, - E1AP_EUTRAN_BearerContextSetupResponse_t, msgEUTRAN); msgEUTRAN->id = - E1AP_ProtocolIE_ID_id_DRB_Setup_List_EUTRAN; msgEUTRAN->criticality = - E1AP_Criticality_reject; msgEUTRAN->value.present = - E1AP_EUTRAN_BearerContextSetupResponse__value_PR_DRB_Setup_List_EUTRAN; - E1AP_DRB_Setup_List_EUTRAN_t *drbSetup = - &msgEUTRAN->value.choice.DRB_Setup_List_EUTRAN; - - for (drb_setup_t *i=resp->DRBList; i < resp->DRBList+resp->numDRBs; i++) { - asn1cSequenceAdd(drbSetup->list, E1AP_DRB_Setup_Item_EUTRAN_t, ieC3_1); - ieC3_1->dRB_ID = i->drbId; - - ieC3_1->s1_DL_UP_TNL_Information.present = - E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(ieC3_1->s1_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, - &gTPTunnel->transportLayerAddress); INT32_TO_OCTET_STRING(i->teId, - &gTPTunnel->gTP_TEID); - - for (up_params_t *j=i->UpParamList; j < i->UpParamList+i->numUpParam; j++) - { asn1cSequenceAdd(ieC3_1->uL_UP_Transport_Parameters.list, - E1AP_UP_Parameters_Item_t, ieC3_1_1); ieC3_1_1->uP_TNL_Information.present = - E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(ieC3_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(j->tlAddress, - &gTPTunnel->transportLayerAddress); INT32_TO_OCTET_STRING(j->teId, - &gTPTunnel->gTP_TEID); - } - } - } else */ - { - ieC3->value.choice.System_BearerContextSetupResponse.present = - E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse; - E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list = calloc(1, sizeof(E1AP_ProtocolIE_Container_4932P22_t)); - ieC3->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse = - (struct E1AP_ProtocolIE_Container *)msgNGRAN_list; - asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupResponse_t, msgNGRAN); - msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List; - msgNGRAN->criticality = E1AP_Criticality_reject; - msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List; - E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List; - - for (const pdu_session_setup_t *i = resp->pduSession; i < resp->pduSession + resp->numPDUSessions; i++) { - asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1); - ieC3_1->pDU_Session_ID = i->id; - - ieC3_1->nG_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(ieC3_1->nG_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID); - - for (const DRB_nGRAN_setup_t *j = i->DRBnGRanList; j < i->DRBnGRanList + i->numDRBSetup; j++) { - asn1cSequenceAdd(ieC3_1->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1); - ieC3_1_1->dRB_ID = j->id; - - 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->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); - } - - for (const qos_flow_setup_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; - } - } - - if (i->numDRBFailed > 0) - ieC3_1->dRB_Failed_List_NG_RAN = calloc(1, sizeof(E1AP_DRB_Failed_List_NG_RAN_t)); - - for (const DRB_nGRAN_failed_t *j = i->DRBnGRanFailedList; j < i->DRBnGRanFailedList + i->numDRBFailed; j++) { - asn1cSequenceAdd(ieC3_1->dRB_Failed_List_NG_RAN->list, E1AP_DRB_Failed_Item_NG_RAN_t, ieC3_1_1); - ieC3_1_1->dRB_ID = j->id; - - 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: - LOG_E(E1AP, "DRB setup failure cause out of expected range\n"); - break; - } - } - } - } + E1AP_E1AP_PDU_t *pdu = encode_E1_bearer_context_setup_request(bearerCxt); + e1ap_encode_send(CPtype, assoc_id, pdu, 0, __func__); } void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_bearer_setup_resp_t *resp) { - E1AP_E1AP_PDU_t pdu = {0}; - fill_BEARER_CONTEXT_SETUP_RESPONSE(resp, &pdu); - e1ap_encode_send(UPtype, assoc_id, &pdu, 0, __func__); + // Encode + E1AP_E1AP_PDU_t *pdu = encode_E1_bearer_context_setup_response(resp); + e1ap_encode_send(UPtype, assoc_id, pdu, 0, __func__); } int e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance) @@ -870,287 +592,27 @@ int e1apCUUP_send_BEARER_CONTEXT_SETUP_FAILURE(instance_t instance) return -1; } -static void extract_BEARER_CONTEXT_SETUP_REQUEST(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_req_t *bearerCxt) -{ - const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest; - E1AP_BearerContextSetupRequestIEs_t *ie; - - LOG_D(E1AP, "Bearer context setup number of IEs %d\n", in->protocolIEs.list.count); - - for (int i = 0; i < in->protocolIEs.list.count; i++) { - ie = in->protocolIEs.list.array[i]; - - switch(ie->id) { - case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID: - DevAssert(ie->criticality == E1AP_Criticality_reject); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID); - bearerCxt->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID; - break; - - case E1AP_ProtocolIE_ID_id_SecurityInformation: - DevAssert(ie->criticality == E1AP_Criticality_reject); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation); - bearerCxt->cipheringAlgorithm = ie->value.choice.SecurityInformation.securityAlgorithm.cipheringAlgorithm; - memcpy(bearerCxt->encryptionKey, - ie->value.choice.SecurityInformation.uPSecuritykey.encryptionKey.buf, - ie->value.choice.SecurityInformation.uPSecuritykey.encryptionKey.size); - if (ie->value.choice.SecurityInformation.securityAlgorithm.integrityProtectionAlgorithm) { - bearerCxt->integrityProtectionAlgorithm = *ie->value.choice.SecurityInformation.securityAlgorithm.integrityProtectionAlgorithm; - } - if (ie->value.choice.SecurityInformation.uPSecuritykey.integrityProtectionKey) { - memcpy(bearerCxt->integrityProtectionKey, - ie->value.choice.SecurityInformation.uPSecuritykey.integrityProtectionKey->buf, - ie->value.choice.SecurityInformation.uPSecuritykey.integrityProtectionKey->size); - } - break; - - case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: - DevAssert(ie->criticality == E1AP_Criticality_reject); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_BitRate); - asn_INTEGER2long(&ie->value.choice.BitRate, &bearerCxt->ueDlAggMaxBitRate); - break; - - case E1AP_ProtocolIE_ID_id_Serving_PLMN: - DevAssert(ie->criticality == E1AP_Criticality_ignore); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity); - PLMNID_TO_MCC_MNC(&ie->value.choice.PLMN_Identity, - bearerCxt->servingPLMNid.mcc, - bearerCxt->servingPLMNid.mnc, - bearerCxt->servingPLMNid.mnc_digit_length); - break; - - case E1AP_ProtocolIE_ID_id_ActivityNotificationLevel: - DevAssert(ie->criticality == E1AP_Criticality_reject); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel); - bearerCxt->activityNotificationLevel = ie->value.choice.ActivityNotificationLevel; - break; - - case E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest: - DevAssert(ie->criticality == E1AP_Criticality_reject); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest); - DevAssert(ie->value.choice.System_BearerContextSetupRequest.present == - E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest); - DevAssert(ie->value.choice.System_BearerContextSetupRequest.choice.nG_RAN_BearerContextSetupRequest); - E1AP_ProtocolIE_Container_4932P19_t *msgNGRAN_list = (E1AP_ProtocolIE_Container_4932P19_t *) ie->value.choice.System_BearerContextSetupRequest.choice.nG_RAN_BearerContextSetupRequest; - E1AP_NG_RAN_BearerContextSetupRequest_t *msgNGRAN = msgNGRAN_list->list.array[0]; - DevAssert(msgNGRAN_list->list.count == 1); - DevAssert(msgNGRAN->id == E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_List); - DevAssert(msgNGRAN->value.present == E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List); - - E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2SetupList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List; - bearerCxt->numPDUSessions = pdu2SetupList->list.count; - for (int i = 0; i < pdu2SetupList->list.count; i++) { - pdu_session_to_setup_t *pdu_session = bearerCxt->pduSession + i; - E1AP_PDU_Session_Resource_To_Setup_Item_t *pdu2Setup = pdu2SetupList->list.array[i]; - - pdu_session->sessionId = pdu2Setup->pDU_Session_ID; - pdu_session->sessionType = pdu2Setup->pDU_Session_Type; - - OCTET_STRING_TO_INT8(&pdu2Setup->sNSSAI.sST, pdu_session->nssai.sst); - pdu_session->nssai.sd = 0xffffff; - if (pdu2Setup->sNSSAI.sD != NULL) - OCTET_STRING_TO_INT24(pdu2Setup->sNSSAI.sD, pdu_session->nssai.sd); - - pdu_session->integrityProtectionIndication = pdu2Setup->securityIndication.integrityProtectionIndication; - pdu_session->confidentialityProtectionIndication = pdu2Setup->securityIndication.confidentialityProtectionIndication; - - if (pdu2Setup->nG_UL_UP_TNL_Information.choice.gTPTunnel) { // Optional IE - DevAssert(pdu2Setup->nG_UL_UP_TNL_Information.present == - E1AP_UP_TNL_Information_PR_gTPTunnel); - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&pdu2Setup->nG_UL_UP_TNL_Information.choice.gTPTunnel->transportLayerAddress, - pdu_session->tlAddress); - OCTET_STRING_TO_INT32(&pdu2Setup->nG_UL_UP_TNL_Information.choice.gTPTunnel->gTP_TEID, pdu_session->teId); - } - - E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &pdu2Setup->dRB_To_Setup_List_NG_RAN; - pdu_session->numDRB2Setup = drb2SetupList->list.count; - for (int j = 0; j < drb2SetupList->list.count; j++) { - DRB_nGRAN_to_setup_t *drb = pdu_session->DRBnGRanList + j; - E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j]; - - drb->id = drb2Setup->dRB_ID; - /* SDAP */ - drb->sdap_config.defaultDRB = drb2Setup->sDAP_Configuration.defaultDRB == E1AP_DefaultDRB_true; - drb->sdap_config.sDAP_Header_UL = drb2Setup->sDAP_Configuration.sDAP_Header_UL; - drb->sdap_config.sDAP_Header_DL = drb2Setup->sDAP_Configuration.sDAP_Header_DL; - /* PDCP */ - drb->pdcp_config.pDCP_SN_Size_UL = drb2Setup->pDCP_Configuration.pDCP_SN_Size_UL; - drb->pdcp_config.pDCP_SN_Size_DL = drb2Setup->pDCP_Configuration.pDCP_SN_Size_DL; - if (drb2Setup->pDCP_Configuration.discardTimer) { - drb->pdcp_config.discardTimer = *drb2Setup->pDCP_Configuration.discardTimer; - } - if (drb2Setup->pDCP_Configuration.t_ReorderingTimer) { - drb->pdcp_config.reorderingTimer = drb2Setup->pDCP_Configuration.t_ReorderingTimer->t_Reordering; - } - drb->pdcp_config.rLC_Mode = drb2Setup->pDCP_Configuration.rLC_Mode; - - E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information; - drb->numCellGroups = cellGroupList->list.count; - for (int k = 0; k < cellGroupList->list.count; k++) { - E1AP_Cell_Group_Information_Item_t *cg2Setup = cellGroupList->list.array[k]; - - drb->cellGroupList[k].id = cg2Setup->cell_Group_ID; - } - - 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->qfi = qos2Setup->qoS_Flow_Identifier; - - qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; - if (qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.present == E1AP_QoS_Characteristics_PR_non_Dynamic_5QI) { - qos_char->qos_type = NON_DYNAMIC; - qos_char->non_dynamic.fiveqi = - qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI->fiveQI; - } else { - E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qos2Setup->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI; - qos_char->qos_type = DYNAMIC; - qos_char->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; - } - - ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; - rent_priority->priority_level = qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.priorityLevel; - rent_priority->preemption_capability = - qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionCapability; - rent_priority->preemption_vulnerability = - qos2Setup->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority.pre_emptionVulnerability; - } - } - } - break; - - default: - LOG_E(E1AP, "Handle for this IE is not implemented (or) invalid IE detected\n"); - break; - } - } -} - int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu) { - DevAssert(pdu != NULL); - DevAssert(pdu->present == E1AP_E1AP_PDU_PR_initiatingMessage); - DevAssert(pdu->choice.initiatingMessage->procedureCode == E1AP_ProcedureCode_id_bearerContextSetup); - DevAssert(pdu->choice.initiatingMessage->criticality == E1AP_Criticality_reject); - DevAssert(pdu->choice.initiatingMessage->value.present == E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest); - + // Decode E1AP message e1ap_bearer_setup_req_t bearerCxt = {0}; - extract_BEARER_CONTEXT_SETUP_REQUEST(pdu, &bearerCxt); - + if (!decode_E1_bearer_context_setup_request(pdu, &bearerCxt)) { + LOG_E(E1AP, "Failed to decode E1 Bearer Context Setup Request\n"); + return -1; + } e1_bearer_context_setup(&bearerCxt); return 0; } -void extract_BEARER_CONTEXT_SETUP_RESPONSE(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_resp_t *bearerCxt) -{ - const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse; - E1AP_BearerContextSetupResponseIEs_t *ie; - - LOG_D(E1AP, "Bearer context setup response number of IEs %d\n", in->protocolIEs.list.count); - - for (int i = 0; i < in->protocolIEs.list.count; i++) { - ie = in->protocolIEs.list.array[i]; - - switch(ie->id) { - case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID: - DevAssert(ie->criticality == E1AP_Criticality_reject); - DevAssert(ie->value.present == E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID); - bearerCxt->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: - DevAssert(ie->criticality == E1AP_Criticality_reject); - DevAssert(ie->value.present == E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID); - bearerCxt->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID; - break; - - case E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse: - DevAssert(ie->criticality == E1AP_Criticality_reject); - DevAssert(ie->value.present == E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse); - DevAssert(ie->value.choice.System_BearerContextSetupResponse.present - == E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse); - E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list = - (E1AP_ProtocolIE_Container_4932P22_t *) - ie->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse; - DevAssert(msgNGRAN_list->list.count == 1); - E1AP_NG_RAN_BearerContextSetupResponse_t *msgNGRAN = msgNGRAN_list->list.array[0]; - DevAssert(msgNGRAN->id == E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List); - DevAssert(msgNGRAN->criticality == E1AP_Criticality_reject); - DevAssert(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; - bearerCxt->numPDUSessions = pduSetupList->list.count; - - for (int i = 0; i < pduSetupList->list.count; i++) { - pdu_session_setup_t *pduSetup = bearerCxt->pduSession + i; - E1AP_PDU_Session_Resource_Setup_Item_t *pdu_session = pduSetupList->list.array[i]; - pduSetup->id = pdu_session->pDU_Session_ID; - - if (pdu_session->nG_DL_UP_TNL_Information.choice.gTPTunnel) { - DevAssert(pdu_session->nG_DL_UP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel); - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4( - &pdu_session->nG_DL_UP_TNL_Information.choice.gTPTunnel->transportLayerAddress, - pduSetup->tlAddress); - OCTET_STRING_TO_INT32(&pdu_session->nG_DL_UP_TNL_Information.choice.gTPTunnel->gTP_TEID, pduSetup->teId); - } - - pduSetup->numDRBSetup = pdu_session->dRB_Setup_List_NG_RAN.list.count; - for (int j = 0; j < pdu_session->dRB_Setup_List_NG_RAN.list.count; j++) { - DRB_nGRAN_setup_t *drbSetup = pduSetup->DRBnGRanList + j; - E1AP_DRB_Setup_Item_NG_RAN_t *drb = pdu_session->dRB_Setup_List_NG_RAN.list.array[j]; - - drbSetup->id = drb->dRB_ID; - - 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; - E1AP_UP_Parameters_Item_t *in_UL_UP_param = drb->uL_UP_Transport_Parameters.list.array[k]; - - DevAssert(in_UL_UP_param->uP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel); - E1AP_GTPTunnel_t *gTPTunnel = in_UL_UP_param->uP_TNL_Information.choice.gTPTunnel; - 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); - } else { - AssertFatal(false, "gTPTunnel information in required\n"); - } - } - - // Qos Flow Information - 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]; - E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q]; - qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier; - } - } - } - break; - - // TODO: remaining IE handlers - - default: - LOG_E(E1AP, "Handle for this IE is not implemented (or) invalid IE detected\n"); - break; - } - } -} - int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu) { - DevAssert(pdu->present == E1AP_E1AP_PDU_PR_successfulOutcome); - DevAssert(pdu->choice.successfulOutcome->procedureCode == E1AP_ProcedureCode_id_bearerContextSetup); - DevAssert(pdu->choice.successfulOutcome->criticality == E1AP_Criticality_reject); - DevAssert(pdu->choice.successfulOutcome->value.present == E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse); - MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_RESP); + // Decode e1ap_bearer_setup_resp_t *bearerCxt = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg); - extract_BEARER_CONTEXT_SETUP_RESPONSE(pdu, bearerCxt); + if (!decode_E1_bearer_context_setup_response(pdu, bearerCxt)) { + LOG_E(E1AP, "Failed to decode Bearer Context Setup Response\n"); + return -1; + } msg->ittiMsgHeader.originInstance = assoc_id; // Fixme: instance is the NGAP instance, no good way to set it here instance_t instance = 0; @@ -1976,6 +1438,7 @@ void *E1AP_CUCP_task(void *arg) case E1AP_BEARER_CONTEXT_SETUP_REQ: e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(assoc_id, &E1AP_BEARER_CONTEXT_SETUP_REQ(msg)); + free_e1ap_context_setup_request(&E1AP_BEARER_CONTEXT_SETUP_REQ(msg)); break; case E1AP_BEARER_CONTEXT_MODIFICATION_REQ: @@ -2042,6 +1505,7 @@ void *E1AP_CUUP_task(void *arg) const e1ap_upcp_inst_t *inst = getCxtE1(myInstance); AssertFatal(inst, "no E1 instance found for instance %ld\n", myInstance); e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(inst->cuup.assoc_id, resp); + free_e1ap_context_setup_response(resp); } break; case E1AP_BEARER_CONTEXT_MODIFICATION_RESP: { diff --git a/openair2/E1AP/lib/CMakeLists.txt b/openair2/E1AP/lib/CMakeLists.txt new file mode 100644 index 0000000000..6e766581fa --- /dev/null +++ b/openair2/E1AP/lib/CMakeLists.txt @@ -0,0 +1,9 @@ +add_library(e1ap_lib OBJECT + e1ap_bearer_context_management.c +) + +target_link_libraries(e1ap_lib PRIVATE asn1_e1ap) +target_include_directories(e1ap_lib PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) + diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c new file mode 100644 index 0000000000..5e359512ed --- /dev/null +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -0,0 +1,971 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file e1ap_bearer_context_management.c + * \brief E1AP library for E1 Bearer Context Management + * \author Guido Casati + * \date 2024 + * \version 0.1 + */ + +#include + +#include "common/utils/assertions.h" +#include "openair3/UTILS/conversions.h" +#include "common/utils/oai_asn1.h" +#include "common/utils/utils.h" + +#include "e1ap_lib_common.h" +#include "e1ap_bearer_context_management.h" +#include "e1ap_lib_includes.h" + +/* ==================================== + * E1AP Bearer Context Setup Request + * ==================================== */ + +/** + * @brief Equality check for bearer_context_pdcp_config_t + */ +static bool eq_pdcp_config(const bearer_context_pdcp_config_t *a, const bearer_context_pdcp_config_t *b) +{ + _E1_EQ_CHECK_LONG(a->pDCP_SN_Size_UL, b->pDCP_SN_Size_UL); + _E1_EQ_CHECK_LONG(a->pDCP_SN_Size_DL, b->pDCP_SN_Size_DL); + _E1_EQ_CHECK_LONG(a->rLC_Mode, b->rLC_Mode); + _E1_EQ_CHECK_LONG(a->reorderingTimer, b->reorderingTimer); + _E1_EQ_CHECK_LONG(a->discardTimer, b->discardTimer); + _E1_EQ_CHECK_INT(a->pDCP_Reestablishment, b->pDCP_Reestablishment); + return true; +} + +/** + * @brief Equality check for bearer_context_sdap_config_t + */ +static bool eq_sdap_config(const bearer_context_sdap_config_t *a, const bearer_context_sdap_config_t *b) +{ + _E1_EQ_CHECK_LONG(a->defaultDRB, b->defaultDRB); + _E1_EQ_CHECK_LONG(a->sDAP_Header_UL, b->sDAP_Header_UL); + _E1_EQ_CHECK_LONG(a->sDAP_Header_DL, b->sDAP_Header_DL); + return true; +} + +/** + * @brief Equality check for qos_flow_to_setup_t + */ +static bool eq_qos_flow(const qos_flow_to_setup_t *a, const qos_flow_to_setup_t *b) +{ + _E1_EQ_CHECK_LONG(a->qfi, b->qfi); + const ngran_allocation_retention_priority_t *arp_a = &a->qos_params.alloc_reten_priority; + const ngran_allocation_retention_priority_t *arp_b = &b->qos_params.alloc_reten_priority; + _E1_EQ_CHECK_INT(arp_a->preemption_capability, arp_b->preemption_capability); + _E1_EQ_CHECK_INT(arp_a->preemption_vulnerability, arp_b->preemption_vulnerability); + _E1_EQ_CHECK_INT(arp_a->priority_level, arp_b->priority_level); + const qos_characteristics_t *qos_a = &a->qos_params.qos_characteristics; + const qos_characteristics_t *qos_b = &b->qos_params.qos_characteristics; + _E1_EQ_CHECK_INT(qos_a->qos_type, qos_b->qos_type); + _E1_EQ_CHECK_INT(qos_a->dynamic.fiveqi, qos_b->dynamic.fiveqi); + _E1_EQ_CHECK_INT(qos_a->dynamic.packet_delay_budget, qos_b->dynamic.packet_delay_budget); + _E1_EQ_CHECK_INT(qos_a->dynamic.packet_error_rate.per_exponent, qos_b->dynamic.packet_error_rate.per_exponent); + _E1_EQ_CHECK_INT(qos_a->dynamic.packet_error_rate.per_scalar, qos_b->dynamic.packet_error_rate.per_scalar); + _E1_EQ_CHECK_INT(qos_a->dynamic.qos_priority_level, qos_b->dynamic.qos_priority_level); + _E1_EQ_CHECK_INT(qos_a->non_dynamic.fiveqi, qos_b->non_dynamic.fiveqi); + _E1_EQ_CHECK_INT(qos_a->non_dynamic.qos_priority_level, qos_b->non_dynamic.qos_priority_level); + return true; +} + +/** + * @brief Equality check for DRB_nGRAN_to_setup_t + */ +static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_setup_t *b) +{ + 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]); + } + result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config); + result &= eq_sdap_config(&a->sdap_config, &b->sdap_config); + 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) +{ + 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; +} + +/* PDU Session To Setup Item */ + +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; + 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); + } + // 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 + 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 + 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; + } + } + return true; +} + +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) + 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); + /* 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; + } + } + /* 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; + if (!gTPTunnel) { + PRINT_ERROR("Missing mandatory IE item->nG_UL_UP_TNL_Information.choice.gTPTunnel\n"); + 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 ) + 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 + 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; + // 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 ) + 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++) { + 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) + 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; + } + } + return true; +} + +/** + * @brief Equality check for PDU session item to modify/setup + */ +static bool eq_pdu_session_item(const pdu_session_to_setup_t *a, const pdu_session_to_setup_t *b) +{ + _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); + _E1_EQ_CHECK_LONG(a->numDRB2Setup, b->numDRB2Setup); + if (a->numDRB2Setup != b->numDRB2Setup) + return false; + 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; + 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; +} + +/** + * @brief E1AP Bearer Context Setup Request encoding (9.2.2 of 3GPP TS 38.463) + */ +E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg) +{ + E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, initMsg); + initMsg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup; + initMsg->criticality = E1AP_Criticality_reject; + initMsg->value.present = E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest; + E1AP_BearerContextSetupRequest_t *out = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest; + /* mandatory */ + /* c1. gNB-CU-UP UE E1AP ID */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC1); + ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; + ieC1->criticality = E1AP_Criticality_reject; + ieC1->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; + ieC1->value.choice.GNB_CU_CP_UE_E1AP_ID = msg->gNB_cu_cp_ue_id; + /* mandatory */ + /* c2. Security Information */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC2); + 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); + /* mandatory */ + /* c3. UE DL Aggregate Maximum Bit Rate */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3); + ieC3->id = E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate; + ieC3->criticality = E1AP_Criticality_reject; + ieC3->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_BitRate; + asn_long2INTEGER(&ieC3->value.choice.BitRate, msg->ueDlAggMaxBitRate); + /* mandatory */ + /* c4. Serving PLMN */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC4); + ieC4->id = E1AP_ProtocolIE_ID_id_Serving_PLMN; + ieC4->criticality = E1AP_Criticality_ignore; + ieC4->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity; + const PLMN_ID_t *servingPLMN = &msg->servingPLMNid; + MCC_MNC_TO_PLMNID(servingPLMN->mcc, servingPLMN->mnc, servingPLMN->mnc_digit_length, &ieC4->value.choice.PLMN_Identity); + /* mandatory */ + /* Activity Notification Level */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC5); + ieC5->id = E1AP_ProtocolIE_ID_id_ActivityNotificationLevel; + 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 */ + /* */ + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC6); + ieC6->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest; + ieC6->criticality = E1AP_Criticality_reject; + ieC6->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest; + ieC6->value.choice.System_BearerContextSetupRequest.present = + E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest; + E1AP_ProtocolIE_Container_4932P19_t *msgNGRAN_list = calloc_or_fail(1, sizeof(*msgNGRAN_list)); + ieC6->value.choice.System_BearerContextSetupRequest.choice.nG_RAN_BearerContextSetupRequest = + (struct E1AP_ProtocolIE_Container *)msgNGRAN_list; + asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupRequest_t, msgNGRAN); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List; + E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List; + 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); + } + return pdu; +} + +/** + * @brief E1AP Bearer Context Setup Request memory management + */ +void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg) +{ + // Do nothing +} + +/** + * @brief E1AP Bearer Context Setup Request decoding + * gNB-CU-CP → gNB-CU-UP (9.2.2.1 of 3GPP TS 38.463) + */ +bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_req_t *out) +{ + DevAssert(pdu != NULL); + + // 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_INT(pdu->choice.initiatingMessage->value.present, E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest); + + const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest; + E1AP_BearerContextSetupRequestIEs_t *ie; + + // Check mandatory IEs first + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true); + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_SecurityInformation, true); + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate, true); + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Serving_PLMN, true); + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_ActivityNotificationLevel, true); + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest, true); + + // Loop over all IEs + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + AssertFatal(ie != NULL, "in->protocolIEs.list.array[i] shall not be null"); + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__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_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); + break; + + case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_BitRate); + asn_INTEGER2long(&ie->value.choice.BitRate, &out->ueDlAggMaxBitRate); + break; + + case E1AP_ProtocolIE_ID_id_Serving_PLMN: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_PLMN_Identity); + PLMNID_TO_MCC_MNC(&ie->value.choice.PLMN_Identity, + out->servingPLMNid.mcc, + out->servingPLMNid.mnc, + 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 = + &ie->value.choice.System_BearerContextSetupRequest; + switch (System_BearerContextSetupRequest->present) { + case E1AP_System_BearerContextSetupRequest_PR_NOTHING: + PRINT_ERROR("System Bearer Context Setup Request: no choice present\n"); + break; + case E1AP_System_BearerContextSetupRequest_PR_e_UTRAN_BearerContextSetupRequest: + AssertError(System_BearerContextSetupRequest->present == E1AP_System_BearerContextSetupRequest_PR_e_UTRAN_BearerContextSetupRequest, + return false, "E1AP_System_BearerContextSetupRequest_PR_e_UTRAN_BearerContextSetupRequest in E1 Setup Request not supported"); + break; + case E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest: + // Handle nG-RAN Bearer Context Setup Request + _E1_EQ_CHECK_INT(System_BearerContextSetupRequest->present, + E1AP_System_BearerContextSetupRequest_PR_nG_RAN_BearerContextSetupRequest); + AssertFatal(System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest != NULL, + "System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest shall not be null"); + break; + default: + PRINT_ERROR("System Bearer Context Setup Request: No valid choice present.\n"); + break; + } + + E1AP_ProtocolIE_Container_4932P19_t *msgNGRAN_list = + (E1AP_ProtocolIE_Container_4932P19_t *)System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest; + E1AP_NG_RAN_BearerContextSetupRequest_t *msgNGRAN = msgNGRAN_list->list.array[0]; + // NG-RAN + _E1_EQ_CHECK_INT(msgNGRAN_list->list.count, 1); // only one RAN is expected + _E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_List); + _E1_EQ_CHECK_INT(msgNGRAN->value.present, + E1AP_NG_RAN_BearerContextSetupRequest__value_PR_PDU_Session_Resource_To_Setup_List); + // PDU Session Resource To Setup List (9.3.3.2 of 3GPP TS 38.463) + E1AP_PDU_Session_Resource_To_Setup_List_t *pdu2SetupList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_List; + out->numPDUSessions = pdu2SetupList->list.count; + // Loop through all PDU sessions + 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; + } + } + break; + default: + PRINT_ERROR("Handle for this IE %ld is not implemented (or) invalid IE detected\n", ie->id); + break; + } + } + return true; +} + +/** + * @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)); + // Copy PDU Sessions + for (int i = 0; i < msg->numPDUSessions; i++) + cp_pdu_session_item(&cp.pduSession[i], &msg->pduSession[i]); + return cp; +} + +/** + * @brief E1AP Bearer Context Setup Request equality check + */ +bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1ap_bearer_setup_req_t *b) +{ + // 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->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 + _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); + // 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; + return true; +} + +/* ====================================== + * E1AP Bearer Context Setup Response + * ====================================== */ + +/* PDU Session Resource Setup Item */ + +/** + * @brief Decode an item of the E1 PDU Session Resource Setup List (9.3.3.5 of 3GPP TS 38.463) + */ +static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP_PDU_Session_Resource_Setup_Item_t *in) +{ + // PDU Session ID + 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->tlAddress); + OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->teId); + } + // 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; + E1AP_DRB_Setup_Item_NG_RAN_t *drb = in->dRB_Setup_List_NG_RAN.list.array[j]; + // 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->tlAddress); + OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UL_UP_param->teId); + } else { + } + // Cell Group ID (M) + UL_UP_param->cell_group_id = UL_UP_item->cell_Group_ID; + } + // 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]; + E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q]; + qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier; + } + } + return true; +} + +/** + * @brief Encode an item of the E1 PDU Session Resource Setup List (9.3.3.5 of 3GPP TS 38.463) + */ +static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Item_t *item, const pdu_session_setup_t *in) +{ + // 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->tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(in->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); + // 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->tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); + } + // Flow Setup List(M) + for (const qos_flow_setup_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; + } + } + // DRB Failed List (O) + if (in->numDRBFailed > 0) + item->dRB_Failed_List_NG_RAN = calloc_or_fail(1, sizeof(*item->dRB_Failed_List_NG_RAN)); + // DRB Failed Item + for (const DRB_nGRAN_failed_t *j = in->DRBnGRanFailedList; j < in->DRBnGRanFailedList + in->numDRBFailed; j++) { + asn1cSequenceAdd(item->dRB_Failed_List_NG_RAN->list, E1AP_DRB_Failed_Item_NG_RAN_t, ieC3_1_1); + // 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; + } + } + return true; +} + +/** + * @brief Encode E1 Bearer Context Setup Response (9.2.2.2 of 3GPP TS 38.463) + */ +E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *in) +{ + E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + // PDU Type + pdu->present = E1AP_E1AP_PDU_PR_successfulOutcome; + asn1cCalloc(pdu->choice.successfulOutcome, msg); + msg->procedureCode = E1AP_ProcedureCode_id_bearerContextSetup; + msg->criticality = E1AP_Criticality_reject; + msg->value.present = E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse; + E1AP_BearerContextSetupResponse_t *out = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse; + // gNB-CU-CP UE E1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC1); + ieC1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; + ieC1->criticality = E1AP_Criticality_reject; + ieC1->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; + ieC1->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_BearerContextSetupResponseIEs_t, ieC2); + ieC2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID; + ieC2->criticality = E1AP_Criticality_reject; + ieC2->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; + ieC2->value.choice.GNB_CU_CP_UE_E1AP_ID = in->gNB_cu_up_ue_id; + // Message Type (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupResponseIEs_t, ieC3); + ieC3->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse; + ieC3->criticality = E1AP_Criticality_reject; + ieC3->value.present = E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse; + // CHOICE System: default NG-RAN (M) + ieC3->value.choice.System_BearerContextSetupResponse.present = + E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse; + E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list = calloc_or_fail(1, sizeof(*msgNGRAN_list)); + ieC3->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse = + (struct E1AP_ProtocolIE_Container *)msgNGRAN_list; + asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextSetupResponse_t, msgNGRAN); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List; + 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); + } + return pdu; +} + +/** + * @brief Decode E1 Bearer Context Setup Response (9.2.2.2 of 3GPP TS 38.463) + */ +bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_setup_resp_t *out) +{ + // 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_INT(pdu->choice.successfulOutcome->value.present, E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse); + + const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse; + E1AP_BearerContextSetupResponseIEs_t *ie; + // Check mandatory IEs first + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true); + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID, true); + E1AP_LIB_FIND_IE(E1AP_BearerContextSetupResponseIEs_t, ie, in, E1AP_ProtocolIE_ID_id_System_BearerContextSetupResponse, true); + // Loop over all IEs + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupResponseIEs__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_BearerContextSetupResponseIEs__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_System_BearerContextSetupResponse: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupResponseIEs__value_PR_System_BearerContextSetupResponse); + switch (ie->value.choice.System_BearerContextSetupResponse.present) { + case E1AP_System_BearerContextSetupResponse_PR_nG_RAN_BearerContextSetupResponse: { + E1AP_ProtocolIE_Container_4932P22_t *msgNGRAN_list = + (E1AP_ProtocolIE_Container_4932P22_t *) + 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_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; + out->numPDUSessions = pduSetupList->list.count; + 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); + } + } break; + + case E1AP_System_BearerContextSetupResponse_PR_e_UTRAN_BearerContextSetupResponse: + PRINT_ERROR("DRB Setup List E-UTRAN not supported in E1 Setup Response\n"); + return false; + break; + + default: + PRINT_ERROR("Unknown DRB Setup List in E1 Setup Response\n"); + return false; + break; + } + break; + + default: + PRINT_ERROR("Handle for this IE is not implemented (or) invalid IE detected\n"); + return false; + break; + } + } + return true; +} + +/** + * @brief Deep copy function for E1 BEARER CONTEXT SETUP RESPONSE + */ +e1ap_bearer_setup_resp_t cp_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg) +{ + e1ap_bearer_setup_resp_t cp = {0}; + // Copy basic fields + cp = *msg; + // Copy PDU Sessions Setup + for (int i = 0; i < msg->numPDUSessions; i++) { + cp.pduSession[i] = msg->pduSession[i]; + // Copy DRB Setup + for (int j = 0; j < msg->pduSession[i].numDRBSetup; j++) { + cp.pduSession[i].DRBnGRanList[j] = msg->pduSession[i].DRBnGRanList[j]; + for (int k = 0; k < msg->pduSession[i].DRBnGRanList[j].numQosFlowSetup; k++) { + cp.pduSession[i].DRBnGRanList[j].qosFlows[k] = msg->pduSession[i].DRBnGRanList[j].qosFlows[k]; + } + } + cp.pduSession[i].numDRBFailed = msg->pduSession[i].numDRBFailed; + // Copy DRB Failed + for (int j = 0; j < msg->pduSession[i].numDRBFailed; j++) { + cp.pduSession[i].DRBnGRanFailedList[j] = msg->pduSession[i].DRBnGRanFailedList[j]; + } + } + return cp; +} + +/** + * @brief E1AP Bearer Context Setup Response equality check + */ +bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e1ap_bearer_setup_resp_t *b) +{ + // Check 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); + // Check PDU Sessions Setup + if (a->numPDUSessions != b->numPDUSessions) + return false; + for (int i = 0; i < a->numPDUSessions; i++) { + 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->numDRBSetup, ps_b->numDRBSetup); + _E1_EQ_CHECK_INT(ps_a->numDRBFailed, ps_b->numDRBFailed); + // Check DRB Setup + for (int j = 0; j < ps_a->numDRBSetup; j++) { + const DRB_nGRAN_setup_t *drb_a = &ps_a->DRBnGRanList[j]; + const DRB_nGRAN_setup_t *drb_b = &ps_b->DRBnGRanList[j]; + _E1_EQ_CHECK_LONG(drb_a->id, drb_b->id); + _E1_EQ_CHECK_INT(drb_a->numUpParam, drb_b->numUpParam); + _E1_EQ_CHECK_INT(drb_a->numQosFlowSetup, drb_b->numQosFlowSetup); + } + // Check DRB Failed + for (int j = 0; j < ps_a->numDRBFailed; j++) { + 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); + } + } + return true; +} + +/** + * @brief E1AP Bearer Context Setup Response memory management + */ +void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg) +{ + // Do nothing (no dynamic allocation) +} diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.h b/openair2/E1AP/lib/e1ap_bearer_context_management.h new file mode 100644 index 0000000000..95e4cb0e15 --- /dev/null +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.h @@ -0,0 +1,43 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef E1AP_BEARER_CONTEXT_MANAGEMENT_H_ +#define E1AP_BEARER_CONTEXT_MANAGEMENT_H_ + +#include +#include "openair2/COMMON/e1ap_messages_types.h" +#include "common/platform_types.h" + +struct E1AP_E1AP_PDU; + +struct E1AP_E1AP_PDU *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg); +bool decode_E1_bearer_context_setup_request(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_setup_req_t *out); +e1ap_bearer_setup_req_t cp_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg); +void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg); +bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1ap_bearer_setup_req_t *b); + +struct E1AP_E1AP_PDU *encode_E1_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg); +bool decode_E1_bearer_context_setup_response(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_setup_resp_t *out); +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); + +#endif /* E1AP_BEARER_CONTEXT_MANAGEMENT_H_ */ diff --git a/openair2/E1AP/lib/e1ap_lib_common.h b/openair2/E1AP/lib/e1ap_lib_common.h new file mode 100644 index 0000000000..f3c6b24da2 --- /dev/null +++ b/openair2/E1AP/lib/e1ap_lib_common.h @@ -0,0 +1,69 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef E1AP_LIB_COMMON_H_ +#define E1AP_LIB_COMMON_H_ + +#include +#include +#include +#include "openair3/UTILS/conversions.h" + +#ifdef ENABLE_TESTS +#define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__); +#else +#define PRINT_ERROR(...) // Do nothing +#endif + +#define _E1_EQ_CHECK_GENERIC(condition, fmt, ...) \ + do { \ + if (!(condition)) { \ + PRINT_ERROR("E1 Equality Check failure: %s:%d: Condition '%s' failed: " fmt " != " fmt "\n", \ + __FILE__, \ + __LINE__, \ + #condition, \ + ##__VA_ARGS__); \ + return false; \ + } \ + } while (0) + +#define _E1_EQ_CHECK_LONG(A, B) _E1_EQ_CHECK_GENERIC(A == B, "%ld", A, B); +#define _E1_EQ_CHECK_INT(A, B) _E1_EQ_CHECK_GENERIC(A == B, "%d", A, B); +#define _E1_EQ_CHECK_STR(A, B) _E1_EQ_CHECK_GENERIC(strcmp(A, B) == 0, "'%s'", A, B); + +// Macro to look up IE. If mandatory and not found, macro will log an error and return false. +#define E1AP_LIB_FIND_IE(IE_TYPE, ie, container, IE_ID, mandatory) \ + do { \ + ie = NULL; \ + for (int i = 0; i < (container)->protocolIEs.list.count; ++i) { \ + IE_TYPE *current_ie = (container)->protocolIEs.list.array[i]; \ + if (current_ie->id == (IE_ID)) { \ + ie = current_ie; \ + break; \ + } \ + } \ + if (mandatory && ie == NULL) { \ + fprintf(stderr, "%s(): Mandatory element not found: ID" #IE_ID " with type " #IE_TYPE "\n", __func__); \ + return false; \ + } \ + } while (0) + +#endif /* E1AP_LIB_COMMON_H_ */ diff --git a/openair2/E1AP/lib/e1ap_lib_includes.h b/openair2/E1AP/lib/e1ap_lib_includes.h new file mode 100644 index 0000000000..58da8f6c30 --- /dev/null +++ b/openair2/E1AP/lib/e1ap_lib_includes.h @@ -0,0 +1,57 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#ifndef E1AP_LIB_INCLUDES_H_ +#define E1AP_LIB_INCLUDES_H_ + +#include "E1AP_E1AP-PDU.h" +#include "E1AP_ProcedureCode.h" +#include "E1AP_SuccessfulOutcome.h" +#include "E1AP_InitiatingMessage.h" +#include "E1AP_ProtocolIE-ID.h" +#include "E1AP_ProtocolIE-Field.h" +#include "E1AP_UP-TNL-Information.h" +#include "E1AP_DefaultDRB.h" +#include "E1AP_QoS-Characteristics.h" +#include "E1AP_PDU-Session-Resource-To-Setup-Item.h" +#include "E1AP_GTPTunnel.h" +#include "E1AP_DRB-To-Setup-Item-NG-RAN.h" +#include "E1AP_T-ReorderingTimer.h" +#include "E1AP_QoS-Flow-QoS-Parameter-Item.h" +#include "E1AP_Cell-Group-Information-Item.h" +#include "E1AP_Dynamic5QIDescriptor.h" +#include "E1AP_Non-Dynamic5QIDescriptor.h" +// E1 Bearer Context Setup Request +#include "E1AP_BearerContextSetupRequest.h" +#include "E1AP_GNB-CU-CP-E1SetupRequest.h" +#include "E1AP_GNB-CU-UP-E1SetupRequest.h" +#include "E1AP_System-BearerContextSetupRequest.h" +#include "E1AP_MaximumIPdatarate.h" +#include "E1AP_PDU-Session-Type.h" +// E1 Bearer Context Setup Response +#include "E1AP_PDU-Session-Resource-Setup-Item.h" +#include "E1AP_DRB-Setup-Item-NG-RAN.h" +#include "E1AP_UP-Parameters-Item.h" +#include "E1AP_QoS-Flow-Item.h" +#include "E1AP_DRB-Failed-List-NG-RAN.h" +#include "E1AP_DRB-Failed-Item-NG-RAN.h" + +#endif /* E1AP_LIB_INCLUDES_H_ */ diff --git a/openair2/E1AP/tests/CMakeLists.txt b/openair2/E1AP/tests/CMakeLists.txt new file mode 100644 index 0000000000..fcec103f9c --- /dev/null +++ b/openair2/E1AP/tests/CMakeLists.txt @@ -0,0 +1,9 @@ +add_executable(e1ap_lib_test e1ap_lib_test.c) +add_dependencies(tests e1ap_lib_test) +add_test(NAME e1ap_lib_test COMMAND e1ap_lib_test) +target_link_libraries(e1ap_lib_test PRIVATE e1ap_lib) +target_link_libraries(e1ap_lib_test PRIVATE asn1_e1ap) +target_include_directories(e1ap_lib_test PRIVATE + ${CMAKE_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c new file mode 100644 index 0000000000..9e3a1035d8 --- /dev/null +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -0,0 +1,225 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +/*! \file e1ap_lib_test.c + * \brief Unit tests for E1AP libraries + * \author Guido Casati + * \date 2024 + * \version 0.1 + */ + +#include +#include +#include + +#include "E1AP/lib/e1ap_bearer_context_management.h" +#include "E1AP/lib/e1ap_lib_includes.h" +#include "common/utils/assertions.h" + +void exit_function(const char *file, const char *function, const int line, const char *s, const int assert) +{ + printf("detected error at %s:%d:%s: %s\n", file, line, function, s); + abort(); +} + +static E1AP_E1AP_PDU_t *e1ap_encode_decode(const E1AP_E1AP_PDU_t *enc_pdu) +{ + // xer_fprint(stdout, &asn_DEF_E1AP_E1AP_PDU, enc_pdu); + + DevAssert(enc_pdu != NULL); + char errbuf[2048]; + size_t errlen = sizeof(errbuf); + int ret = asn_check_constraints(&asn_DEF_E1AP_E1AP_PDU, enc_pdu, errbuf, &errlen); + AssertFatal(ret == 0, "asn_check_constraints() failed: %s\n", errbuf); + + uint8_t msgbuf[16384]; + asn_enc_rval_t enc = aper_encode_to_buffer(&asn_DEF_E1AP_E1AP_PDU, NULL, enc_pdu, msgbuf, sizeof(msgbuf)); + AssertFatal(enc.encoded > 0, "aper_encode_to_buffer() failed\n"); + + E1AP_E1AP_PDU_t *dec_pdu = NULL; + asn_codec_ctx_t st = {.max_stack_size = 100 * 1000}; + asn_dec_rval_t dec = aper_decode(&st, &asn_DEF_E1AP_E1AP_PDU, (void **)&dec_pdu, msgbuf, enc.encoded, 0, 0); + AssertFatal(dec.code == RC_OK, "aper_decode() failed\n"); + + // xer_fprint(stdout, &asn_DEF_E1AP_E1AP_PDU, dec_pdu); + return dec_pdu; +} + +static void e1ap_msg_free(E1AP_E1AP_PDU_t *pdu) +{ + ASN_STRUCT_FREE(asn_DEF_E1AP_E1AP_PDU, pdu); +} + +/** + * @brief Test E1AP Bearer Context Setup Request encoding/decoding + */ +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_SN_Size_DL = E1AP_PDCP_SN_Size_s_12, + .pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12, + .reorderingTimer = 10, + .rLC_Mode = E1AP_RLC_Mode_rlc_am, + }; + + bearer_context_sdap_config_t sdap = { + .defaultDRB = 1, + .sDAP_Header_DL = true, + .sDAP_Header_UL = true, + }; + + qos_flow_to_setup_t qos = { + .qfi = 1, + .qos_params.alloc_reten_priority.preemption_capability = E1AP_Pre_emptionCapability_shall_not_trigger_pre_emption, + .qos_params.alloc_reten_priority.preemption_vulnerability = E1AP_Pre_emptionVulnerability_not_pre_emptable, + .qos_params.alloc_reten_priority.priority_level = E1AP_PriorityLevel_highest, + .qos_params.qos_characteristics.non_dynamic.fiveqi = 9, + }; + + security_indication_t security = { + .confidentialityProtectionIndication = E1AP_ConfidentialityProtectionIndication_required, + .integrityProtectionIndication = E1AP_IntegrityProtectionIndication_required, + .maxIPrate = E1AP_MaxIPrate_max_UErate, + }; + + // 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, + .ueDlAggMaxBitRate = 1000000000, + .bearerContextStatus = 0, + .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, + .pduSession[0].nssai.sd = 0x01, + .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].DRBnGRanList[0].id = 1, + .pduSession[0].DRBnGRanList[0].sdap_config = sdap, + .pduSession[0].DRBnGRanList[0].pdcp_config = pdcp, + .pduSession[0].DRBnGRanList[0].id = 1, + .pduSession[0].DRBnGRanList[0].numCellGroups = 1, + .pduSession[0].DRBnGRanList[0].cellGroupList[0] = MCG, + .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)); + // E1AP encode the original message + E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_request(&orig); + // E1AP decode the encoded message + E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc); + // Free the E1AP encoded message + e1ap_msg_free(enc); + // E1 message decode + e1ap_bearer_setup_req_t decoded = {0}; + bool ret = decode_E1_bearer_context_setup_request(dec, &decoded); + AssertFatal(ret, "decode_E1_bearer_context_setup_request(): could not decode message\n"); + // Free the E1AP decoded message + e1ap_msg_free(dec); + // Equality check original/decoded + ret = eq_bearer_context_setup_request(&orig, &decoded); + AssertFatal(ret, "eq_bearer_context_setup_request(): decoded message doesn't match\n"); + // Free the memory for the decoded message + free_e1ap_context_setup_request(&decoded); + // Deep copy and equality check of the original message + e1ap_bearer_setup_req_t cp = cp_bearer_context_setup_request(&orig); + ret = eq_bearer_context_setup_request(&orig, &cp); + AssertFatal(ret, "eq_bearer_context_setup_request(): copied message doesn't match\n"); + // Free the copied message and original + free_e1ap_context_setup_request(&cp); + free_e1ap_context_setup_request(&orig); +} + +/** + * @brief Test E1AP Bearer Context Setup Response encoding/decoding + */ +static void test_bearer_context_setup_response(void) +{ + // Step 1: Initialize the E1AP Bearer Context Setup Response + e1ap_bearer_setup_resp_t orig = { + .gNB_cu_cp_ue_id = 1234, + .gNB_cu_up_ue_id = 5678, + .numPDUSessions = 1, + .pduSession[0].id = 1, + .pduSession[0].tlAddress = 167772161, + .pduSession[0].teId = 0x12345, + .pduSession[0].numDRBSetup = 1, + .pduSession[0].numDRBFailed = 0, + .pduSession[0].DRBnGRanList[0].id = 1, + .pduSession[0].DRBnGRanList[0].numUpParam = 1, + .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, + }; + // E1AP encode the original message + E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_response(&orig); + + // E1AP decode the encoded message + E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc); + + // Free the E1AP encoded message + e1ap_msg_free(enc); + + // E1 message decode + e1ap_bearer_setup_resp_t decoded = {0}; + bool ret = decode_E1_bearer_context_setup_response(dec, &decoded); + AssertFatal(ret, "decode_E1_bearer_context_setup_response(): could not decode message\n"); + + // Free the E1AP decoded message + e1ap_msg_free(dec); + + // Equality check original/decoded + ret = eq_bearer_context_setup_response(&orig, &decoded); + AssertFatal(ret, "eq_bearer_context_setup_response(): decoded message doesn't match\n"); + + // Free the memory for the decoded message + free_e1ap_context_setup_response(&decoded); + + // Deep copy and equality check of the original message + e1ap_bearer_setup_resp_t cp = cp_bearer_context_setup_response(&orig); + ret = eq_bearer_context_setup_response(&orig, &cp); + AssertFatal(ret, "eq_bearer_context_setup_response(): copied message doesn't match\n"); + + // Free the copied message and original + free_e1ap_context_setup_response(&cp); + free_e1ap_context_setup_response(&orig); +} + +int main() +{ + // E1 Bearer Context Setup + test_bearer_context_setup_request(); + test_bearer_context_setup_response(); + return 0; +} diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index ab2756c3cd..1d3394e788 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -88,11 +88,12 @@ static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, const pdcp_config->t_Reordering = calloc(1, sizeof(*pdcp_config->t_Reordering)); *pdcp_config->t_Reordering = drb->pdcp_config.reorderingTimer; pdcp_config->ext1 = NULL; - if (pdu->integrityProtectionIndication == 0 || // Required - pdu->integrityProtectionIndication == 1) { // Preferred - asn1cCallocOne(drbCfg->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled); + const security_indication_t *sec = &pdu->securityIndication; + if (sec->integrityProtectionIndication == SECURITY_REQUIRED || + sec->integrityProtectionIndication == SECURITY_PREFERRED) { + asn1cCallocOne(drbCfg->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled); } - if (pdu->confidentialityProtectionIndication == 2) { // Not Needed + if (sec->confidentialityProtectionIndication == SECURITY_NOT_NEEDED) { asn1cCalloc(pdcp_config->ext1, ext1); asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true); } @@ -188,8 +189,8 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) req_drb->id, req_pdu->sessionId, qfi, - req_pdu->tlAddress, - req_pdu->teId, + req_pdu->UP_TL_information.tlAddress, + req_pdu->UP_TL_information.teId, nr_pdcp_data_req_drb, sdap_data_req, &resp_n3); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index e94358f274..e8c7fcdc2c 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -94,6 +94,7 @@ #include "utils.h" #include "x2ap_messages_types.h" #include "xer_encoder.h" +#include "E1AP/lib/e1ap_bearer_context_management.h" #ifdef E2_AGENT #include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h" @@ -2595,6 +2596,7 @@ void *rrc_gnb_task(void *args_p) { case E1AP_BEARER_CONTEXT_SETUP_RESP: rrc_gNB_process_e1_bearer_context_setup_resp(&E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p), instance); + free_e1ap_context_setup_response(&E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p)); break; case E1AP_BEARER_CONTEXT_MODIFICATION_RESP: diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index c2a641db32..bf71357aed 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -349,11 +349,13 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession if (cuup_nssai.sst == 0) cuup_nssai = pdu->nssai; /* for CU-UP selection below */ - pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; - - pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; - pdu->teId = session->gtp_teid; - memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target + security_indication_t *sec = &pdu->securityIndication; + sec->integrityProtectionIndication = rrc->security.do_drb_integrity ? SECURITY_REQUIRED + : SECURITY_NOT_NEEDED; + sec->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? SECURITY_REQUIRED + : SECURITY_NOT_NEEDED; + pdu->UP_TL_information.teId = session->gtp_teid; + memcpy(&pdu->UP_TL_information.tlAddress, session->upf_addr.buffer, sizeof(in_addr_t)); /* we assume for the moment one DRB per PDU session. Activate the bearer, * and configure in RRC. */ @@ -380,9 +382,10 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession drb->numCellGroups = 1; // assume one cell group associated with a DRB + // Set all Cell Group IDs to MCG for (int k=0; k < drb->numCellGroups; k++) { - cell_group_t *cellGroup = drb->cellGroupList + k; - cellGroup->id = 0; // MCG + cell_group_id_t *cellGroup = drb->cellGroupList + k; + *cellGroup = MCG; } drb->numQosFlow2Setup = session->nb_qos; diff --git a/openair3/UTILS/conversions.h b/openair3/UTILS/conversions.h index 588edb1461..31a479cab6 100644 --- a/openair3/UTILS/conversions.h +++ b/openair3/UTILS/conversions.h @@ -31,7 +31,7 @@ ((x & 0x00FF0000) >> 8) | ((x & 0xFF000000) >> 24)) # define hton_int16(x) \ - (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8) + ((((x) & 0x00FF) << 8) | (((x) & 0xFF00) >> 8)) # define ntoh_int32_buf(bUF) \ ((*((uint8_t*)bUF)) << 24) | ((*((uint8_t*)bUF + 1)) << 16) | ((*((uint8_t*)bUF + 2)) << 8) \ @@ -285,19 +285,6 @@ do { \ BUFFER_TO_UINT32((aSN)->buf, x); \ } while (0) -#define BIT_STRING_TO_INT32(aSN, x) \ -do { \ - DevCheck((aSN)->bits_unused == 0, (aSN)->bits_unused, 0, 0); \ - OCTET_STRING_TO_INT32(aSN, x); \ -} while(0) - -#define BIT_STRING_TO_CELL_IDENTITY(aSN, vALUE) \ -do { \ - DevCheck((aSN)->bits_unused == 4, (aSN)->bits_unused, 4, 0); \ - vALUE = ((aSN)->buf[0] << 20) | ((aSN)->buf[1] << 12) | \ - ((aSN)->buf[2] << 4) | (aSN)->buf[3]; \ -} while(0) - #define BIT_STRING_TO_NR_CELL_IDENTITY(aSN, vALUE) \ do { \ DevCheck((aSN)->bits_unused == 4, (aSN)->bits_unused, 4, 0); \ @@ -315,14 +302,6 @@ do { \ #define MCC_MNC_DIGIT(vALUE) \ ((vALUE) % 10) -#define MCC_TO_BUFFER(mCC, bUFFER) \ -do { \ - DevAssert(bUFFER != NULL); \ - (bUFFER)[0] = MCC_HUNDREDS(mCC); \ - (bUFFER)[1] = MCC_MNC_DECIMAL(mCC); \ - (bUFFER)[2] = MCC_MNC_DIGIT(mCC); \ -} while(0) - #define MCC_MNC_TO_PLMNID(mCC, mNC, mNCdIGITlENGTH, oCTETsTRING) \ do { \ (oCTETsTRING)->buf = calloc(3, sizeof(uint8_t)); \ @@ -459,14 +438,6 @@ do { \ (bITsTRING)->bits_unused = 4; \ } while(0) -/* -#define INT16_TO_3_BYTE_BUFFER(x, buf) \ -do { \ - (buf)[0] = 0x00; \ - (buf)[1] = (x) >> 8; \ - (buf)[2] = (x); \ -} while(0) -*/ #define NR_FIVEGS_TAC_ID_TO_BIT_STRING(x, aSN) \ do { \ @@ -497,20 +468,6 @@ do { \ (bITsTRING)->bits_unused = 0; \ } while(0) -#define BIT_STRING_TO_MaskedIMEISV(bITsTRING, mACRO) \ -do { \ - DevCheck((bITsTRING)->size == 8, (bITsTRING)->size, 8, 0); \ - DevCheck((bITsTRING)->bits_unused == 0, (bITsTRING)->bits_unused, 0, 0); \ - mACRO = ((bITsTRING)->buf[0] << 56) + \ - ((bITsTRING)->buf[1] << 48) + \ - ((bITsTRING)->buf[2] << 40) + \ - ((bITsTRING)->buf[3] << 32) + \ - ((bITsTRING)->buf[4] << 24) + \ - ((bITsTRING)->buf[5] << 16) + \ - ((bITsTRING)->buf[6] << 8) + \ - ((bITsTRING)->buf[7]); \ -} while (0) - /* TS 36.413 v10.9.0 section 9.2.1.37: * Macro eNB ID: * Equal to the 20 leftmost bits of the Cell