diff --git a/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml b/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml index 6c3940d306..5a55ade3c8 100644 --- a/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml +++ b/ci-scripts/yaml_files/sa_e1_b200_gnb/docker-compose.yml @@ -9,6 +9,7 @@ services: environment: USE_ADDITIONAL_OPTIONS: --telnetsrv --telnetsrv.listenport 9090 --telnetsrv.shrmod ci --log_config.global_log_options level,nocolor,time,line_num,function + --security.drb_integrity yes volumes: - ../../conf_files/gnb-cucp.sa.f1.quectel.conf:/opt/oai-gnb/etc/gnb.conf # for performance reasons, we use host mode: in bridge mode, we have diff --git a/openair1/SIMULATION/NR_PHY/dlsim.c b/openair1/SIMULATION/NR_PHY/dlsim.c index e3321a93ad..ab3a044ac6 100644 --- a/openair1/SIMULATION/NR_PHY/dlsim.c +++ b/openair1/SIMULATION/NR_PHY/dlsim.c @@ -125,7 +125,7 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t int dummy_nr_ue_ul_indication(nr_uplink_indication_t *ul_info) { return(0); } void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); } +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); } int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) { diff --git a/openair1/SIMULATION/NR_PHY/psbchsim.c b/openair1/SIMULATION/NR_PHY/psbchsim.c index d1f7993346..23803e133f 100644 --- a/openair1/SIMULATION/NR_PHY/psbchsim.c +++ b/openair1/SIMULATION/NR_PHY/psbchsim.c @@ -51,7 +51,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } diff --git a/openair1/SIMULATION/NR_PHY/ulsim.c b/openair1/SIMULATION/NR_PHY/ulsim.c index 5688253b8d..4f07bbc7aa 100644 --- a/openair1/SIMULATION/NR_PHY/ulsim.c +++ b/openair1/SIMULATION/NR_PHY/ulsim.c @@ -126,7 +126,7 @@ void nr_derive_key_ng_ran_star(uint16_t pci, uint64_t nr_arfcn_dl, const uint8_t extern void fix_scd(NR_ServingCellConfig_t *scd);// forward declaration void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); } -void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req) { abort(); } +void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) { abort(); } void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd) { abort(); } int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) { diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index 7fed096971..2f59cb62d6 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -138,12 +138,6 @@ typedef enum BEARER_CONTEXT_STATUS_e { BEARER_RESUME, } BEARER_CONTEXT_STATUS_t; -typedef enum activity_notification_level_e { - ANL_DRB = 0, - ANL_PDU_SESSION, - ANL_UE, -} activity_notification_level_t; - typedef enum cell_group_id_e { MCG = 0, SCG, @@ -258,10 +252,16 @@ typedef struct e1ap_setup_fail_s { criticality_diagnostics_t *crit_diag; } e1ap_setup_fail_t; -typedef struct up_params_s { +typedef struct UP_TL_information_s { in_addr_t tlAddress; - long teId; - int cell_group_id; + int32_t teId; +} UP_TL_information_t; + +typedef struct up_params_s { + // Transport layer info + UP_TL_information_t tl_info; + // Cell Group ID (M) + cell_group_id_t cell_group_id; } up_params_t; /* IE SDAP Configuration (clause 9.3.1.39 of 3GPP TS 38.463) */ @@ -331,38 +331,63 @@ typedef struct qos_flow_level_qos_parameters_s { ngran_allocation_retention_priority_t alloc_reten_priority; // additional members should be added!! } qos_flow_level_qos_parameters_t; +// QoS Flow QoS Parameters List 9.3.1.25 typedef struct qos_flow_setup_e { long qfi; // qos flow identifier qos_flow_level_qos_parameters_t qos_params; } qos_flow_to_setup_t; -/* DRB To Setup List according to 3GPP TS 38.463 */ +// 9.3.1.60 QoS Flow Mapping Indication +typedef enum qos_flow_mapping_indication_e { + QF_UL = 0, + QF_DL, + QF_BOTH +} qos_flow_mapping_indication_t; + +typedef struct qos_flow_list_s { + long qfi; // qos flow identifier + qos_flow_mapping_indication_t *indication; +} qos_flow_list_t; + +/** + * DRB To Setup List according to 3GPP TS 38.463 + */ typedef struct DRB_nGRAN_to_setup_s { - /* DRB ID (clause 9.3.1.16) */ + // DRB ID (M) (clause 9.3.1.16) long id; - - /* SDAP Configuration (clause 9.3.1.39) */ + // SDAP Configuration (M) (clause 9.3.1.39) bearer_context_sdap_config_t sdap_config; - /* PDCP Configuration (clause 9.3.1.38) */ + // PDCP Configuration (M) (clause 9.3.1.38) bearer_context_pdcp_config_t pdcp_config; - - /* DRB Data Forwarding Information (clause 9.3.2.6) */ - /* Transport Layer Address (clause 9.3.2.4) */ - in_addr_t tlAddress; - /* GTP-TEID (clause 9.3.2.3) */ - int teId; - /* DL UP Transport Layer Information (clause 9.3.2.1) */ - int numDlUpParam; - up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM]; - - /* Cell Group Information (clause 9.3.1.11) */ + // DRB Inactivity Timer (O) + int *drb_inactivity_timer; + // Cell Group Information (M) (clause 9.3.1.11) int numCellGroups; cell_group_id_t cellGroupList[E1AP_MAX_NUM_CELL_GROUPS]; - - /* DRB QoS Flows Parameters (clause 9.3.1.26) */ + // QoS Flows Information To Be Setup (M) (clause 9.3.1.25, 9.3.1.26) int numQosFlow2Setup; qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; -} DRB_nGRAN_to_setup_t, DRB_nGRAN_to_mod_t; +} DRB_nGRAN_to_setup_t; + +/** + * DRB To Modify List according to 3GPP TS 38.463 + */ +typedef struct DRB_nGRAN_to_modify_s { + // DRB ID (M) (clause 9.3.1.16) + long id; + // SDAP Configuration (O) (clause 9.3.1.39) + bearer_context_sdap_config_t *sdap_config; + // PDCP Configuration (O) (clause 9.3.1.38) + bearer_context_pdcp_config_t *pdcp_config; + // PDCP SN Status Request (O) + bool pdcp_sn_status_requested; + // DL UP Transport Layer Information (O) (clause 9.3.1.13, 9.3.2.1) + int numDlUpParam; + up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM]; + // QoS Flows Information To Modify (O) (clause 9.3.1.25, 9.3.1.26) + int numQosFlow2Setup; + qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; +} DRB_nGRAN_to_mod_t; typedef enum e1ap_indication_e { SECURITY_REQUIRED = 0, @@ -377,48 +402,108 @@ typedef struct security_indication_s { long maxIPrate; } security_indication_t; -typedef struct UP_TL_information_s { - in_addr_t tlAddress; - int32_t teId; -} UP_TL_information_t; - -/** - * PDU Session Resource To Setup List (clause 9.3.3.10) - * PDU Session Resource To Modify List (clause 9.3.3.11) -*/ -typedef struct pdu_session_to_setup_s { - long sessionId; - long sessionType; - e1ap_nssai_t nssai; - security_indication_t securityIndication; - UP_TL_information_t UP_TL_information; - long numDRB2Setup; - DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; - long numDRB2Modify; - DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; -} pdu_session_to_setup_t, pdu_session_to_mod_t; - -/** - * Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463 - * out of simplicity, this same struct is used for clause 9.2.2.4 - * i.e. Bearer Context Modification Request message - */ -typedef struct e1ap_bearer_setup_req_s { - uint32_t gNB_cu_cp_ue_id; - uint32_t gNB_cu_up_ue_id; // Bearer Context Modification Request only +// Security Information (9.3.1.10) +typedef struct security_information_s { uint64_t cipheringAlgorithm; uint64_t integrityProtectionAlgorithm; char encryptionKey[E1AP_SECURITY_KEY_SIZE]; char integrityProtectionKey[E1AP_SECURITY_KEY_SIZE]; - long ueDlAggMaxBitRate; +} security_information_t; + +/** + * PDU Session Resource To Setup List (clause 9.3.3.10) + */ +typedef struct pdu_session_to_setup_s { + // PDU Session ID (M) + long sessionId; + // PDU Session Type (M) + long sessionType; + // S-NSSAI (M) + e1ap_nssai_t nssai; + // Security Indication (M) + security_indication_t securityIndication; + // PDU Session Resource DL Aggregate Maximum Bit Rate (O) + long *dlAggregateMaxBitRate; + // NG UL UP Transport Layer Information (M) + UP_TL_information_t UP_TL_information; + // PDU Session Inactivity Timer (O) + int *inactivityTimer; + // DRB To Setup List (M) + int numDRB2Setup; + // DRB To Setup Item (1..) + DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; +} pdu_session_to_setup_t; + +/** + * PDU Session Resource To Modify List (clause 9.3.3.11) + */ +typedef struct pdu_session_to_mod_s { + // PDU Session ID (M) + long sessionId; + // Security Indication (O) + security_indication_t *securityIndication; + // NG UL UP Transport Layer Information (O) + UP_TL_information_t *UP_TL_information; + // DRB To Setup List (0..1) + int numDRB2Setup; + // DRB To Setup Item (1..) + DRB_nGRAN_to_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; + // DRB To Modify List (0..1) + long numDRB2Modify; + // DRB To Modify Item (1..) + DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; +} pdu_session_to_mod_t; + +/** + * Bearer Context Setup Request message, clause 9.2.2.1 of 3GPP TS 38.463 + */ +typedef struct e1ap_bearer_setup_req_s { + // gNB-CU-CP UE E1AP ID (M) + uint32_t gNB_cu_cp_ue_id; + // Security Information (M) + security_information_t secInfo; + // UE DL Aggregate Maximum Bit Rate (M) + long ueDlAggMaxBitRate; + // UE DL Maximum Integrity Protected Data Rate (O) + long *ueDlMaxIPBitRate; + // Serving PLMN (M) PLMN_ID_t servingPLMNid; + // Bearer Context Status Change (O) BEARER_CONTEXT_STATUS_t bearerContextStatus; - activity_notification_level_t activityNotificationLevel; + // UE Inactivity Timer (O) + int *inactivityTimerUE; + // NG-RAN PDU Session Resource To Setup List (M) int numPDUSessions; pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; +} e1ap_bearer_setup_req_t; + +/** + * Bearer Context Modification Request, clause 9.2.2.4 of 3GPP TS 38.463 + */ +typedef struct e1ap_bearer_mod_req_s { + // gNB-CU-CP UE E1AP ID (M) + uint32_t gNB_cu_cp_ue_id; + // gNB-CU-UP UE E1AP ID (M) + uint32_t gNB_cu_up_ue_id; + // Security Information (O) + security_information_t *secInfo; + // UE DL Aggregate Maximum Bit Rate (O) + uint32_t *ueDlAggMaxBitRate; + // UE DL Maximum Integrity Protected Data Rate (O) + uint32_t *ueDlMaxIPBitRate; + // Bearer Context Status Change (O) + BEARER_CONTEXT_STATUS_t *bearerContextStatus; + // UE Inactivity Timer (O) + int *inactivityTimer; + // Data Discard Required (O) + bool dataDiscardRequired; + // NG-RAN PDU Session Resource To Setup List (O) + int numPDUSessions; + pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS]; + // NG-RAN PDU Session Resource To Modify List (O) int numPDUSessionsMod; pdu_session_to_mod_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS]; -} e1ap_bearer_setup_req_t, e1ap_bearer_mod_req_t; +} e1ap_bearer_mod_req_t; typedef struct e1ap_bearer_release_cmd_s { uint32_t gNB_cu_cp_ue_id; @@ -432,43 +517,61 @@ typedef struct e1ap_bearer_release_cplt_s { uint32_t gNB_cu_up_ue_id; } e1ap_bearer_release_cplt_t; -typedef struct qos_flow_setup_s { - long qfi; -} qos_flow_setup_t; - typedef struct DRB_nGRAN_setup_s { + // DRB ID (M) long id; int numUpParam; up_params_t UpParamList[E1AP_MAX_NUM_UP_PARAM]; + // Flow Setup List (M) int numQosFlowSetup; - qos_flow_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; + qos_flow_list_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; } DRB_nGRAN_setup_t; +/* DRB Modified Item */ typedef struct DRB_nGRAN_modified_s { + // DRB ID (M) long id; + // UL UP Parameters (O) + int numUpParam; + up_params_t ul_UP_Params[E1AP_MAX_NUM_UP_PARAM]; + // Flow Setup List (O) + int numQosFlowSetup; + qos_flow_list_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS]; + // Old QoS Flow List (O) + int numOldQosFlow; + qos_flow_list_t oldQosFlows[E1AP_MAX_NUM_QOS_FLOWS]; } DRB_nGRAN_modified_t; typedef struct DRB_nGRAN_failed_s { long id; - long cause_type; - long cause; + e1ap_cause_t cause; } DRB_nGRAN_failed_t; typedef struct pdu_session_setup_s { long id; - in_addr_t tlAddress; - long teId; + // Transport layer info + UP_TL_information_t tl_info; int numDRBSetup; DRB_nGRAN_setup_t DRBnGRanList[E1AP_MAX_NUM_DRBS]; int numDRBFailed; DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_DRBS]; } pdu_session_setup_t; +/* PDU Session Resource Modified List (9.3.3.17) */ typedef struct pdu_session_modif_s { + // PDU Session ID (M) long id; - // setup as part of PDU session modification not supported yet + // Security Result (O) + e1ap_indication_t *integrityProtectionIndication; + e1ap_indication_t *confidentialityProtectionIndication; + // NG DL UP Transport Layer Information (O) + UP_TL_information_t *ng_DL_UP_TL_info; + // DRB Modified List (O) int numDRBModified; DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_DRBS]; + // DRB Setup List (O) + int numDRBSetup; + DRB_nGRAN_setup_t DRBnGRanSetupList[E1AP_MAX_NUM_DRBS]; } pdu_session_modif_t; typedef struct e1ap_bearer_setup_resp_s { @@ -479,8 +582,11 @@ typedef struct e1ap_bearer_setup_resp_s { } e1ap_bearer_setup_resp_t; typedef struct e1ap_bearer_modif_resp_s { + // gNB-CU-CP UE E1AP ID (M) uint32_t gNB_cu_cp_ue_id; + // gNB-CU-UP UE E1AP ID (M) uint32_t gNB_cu_up_ue_id; + // NG-RAN PDU Session Resource Modified List (O) int numPDUSessionsMod; pdu_session_modif_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS]; } e1ap_bearer_modif_resp_t; diff --git a/openair2/E1AP/CMakeLists.txt b/openair2/E1AP/CMakeLists.txt index 5849a32fe5..eb3bd0f546 100644 --- a/openair2/E1AP/CMakeLists.txt +++ b/openair2/E1AP/CMakeLists.txt @@ -10,3 +10,7 @@ target_include_directories(e1ap PUBLIC ${CMAKE_CURRENT_DIR}) if(ENABLE_TESTS) add_subdirectory(tests) endif() + +if(ENABLE_TESTS) + target_compile_definitions(e1ap PRIVATE E1AP_LOG_ERRORS) +endif() diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index e085a9e9b9..0b5582ea39 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -431,7 +431,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upc BEARER CONTEXT MODIFICATION REQUEST */ -static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) +static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_mod_req_t *const bearerCxt, E1AP_E1AP_PDU_t *pdu) { pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; asn1cCalloc(pdu->choice.initiatingMessage, msg); @@ -453,6 +453,21 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con ieC2->criticality = E1AP_Criticality_reject; ieC2->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; ieC2->value.choice.GNB_CU_UP_UE_E1AP_ID = bearerCxt->gNB_cu_up_ue_id; + /* optional */ + /* Security Information */ + if (bearerCxt->secInfo) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie); + ie->id = E1AP_ProtocolIE_ID_id_SecurityInformation; + ie->criticality = E1AP_Criticality_reject; + ie->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation; + E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie->value.choice.SecurityInformation.securityAlgorithm; + E1AP_UPSecuritykey_t *uPSecuritykey = &ie->value.choice.SecurityInformation.uPSecuritykey; + securityAlgorithm->cipheringAlgorithm = bearerCxt->secInfo->cipheringAlgorithm; + OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, bearerCxt->secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE); + asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, bearerCxt->secInfo->integrityProtectionAlgorithm); + asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); + OCTET_STRING_fromBuf(protKey, bearerCxt->secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + } /* optional */ /* c3. E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest */ asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC3); @@ -475,7 +490,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod); drb2Mod->dRB_ID = j->id; asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration); - if (j->pdcp_config.pDCP_Reestablishment) { + if (j->pdcp_config && j->pdcp_config->pDCP_Reestablishment) { asn1cCallocOne(pDCP_Configuration->pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true); } if (j->numDlUpParam > 0) { @@ -484,8 +499,8 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param); DL_UP_Param->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; asn1cCalloc(DL_UP_Param->uP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tl_info.tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(k->tl_info.teId, &gTPTunnel->gTP_TEID); DL_UP_Param->cell_Group_ID = k->cell_group_id; } @@ -493,7 +508,7 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con } } /* c4. E1AP_ProtocolIE_ID_id_BearerContextStatusChange */ - if (bearerCxt->bearerContextStatus == BEARER_SUSPEND) { + if (bearerCxt->bearerContextStatus && *bearerCxt->bearerContextStatus == BEARER_SUSPEND) { asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ieC4); ieC4->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange; ieC4->criticality = E1AP_Criticality_reject; @@ -608,6 +623,26 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p bearerCxt->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID; break; + case E1AP_ProtocolIE_ID_id_SecurityInformation: { + DevAssert(ie->criticality == E1AP_Criticality_reject); + DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation); + E1AP_SecurityInformation_t *sec = &ie->value.choice.SecurityInformation; + DevAssert(sec->uPSecuritykey.encryptionKey.size == E1AP_SECURITY_KEY_SIZE); + DevAssert(sec->uPSecuritykey.integrityProtectionKey == NULL + || sec->uPSecuritykey.integrityProtectionKey->size == E1AP_SECURITY_KEY_SIZE); + bearerCxt->secInfo = malloc_or_fail(sizeof(*bearerCxt->secInfo)); + bearerCxt->secInfo->cipheringAlgorithm = sec->securityAlgorithm.cipheringAlgorithm; + bearerCxt->secInfo->integrityProtectionAlgorithm = sec->securityAlgorithm.integrityProtectionAlgorithm == NULL + ? 0 + : *sec->securityAlgorithm.integrityProtectionAlgorithm; + memcpy(bearerCxt->secInfo->encryptionKey, sec->uPSecuritykey.encryptionKey.buf, E1AP_SECURITY_KEY_SIZE); + if (sec->securityAlgorithm.integrityProtectionAlgorithm == NULL) + memset(bearerCxt->secInfo->integrityProtectionKey, 0, E1AP_SECURITY_KEY_SIZE); + else + memcpy(bearerCxt->secInfo->integrityProtectionKey, sec->uPSecuritykey.integrityProtectionKey->buf, E1AP_SECURITY_KEY_SIZE); + break; + } + case E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest: DevAssert(ie->criticality == E1AP_Criticality_reject); DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest); @@ -637,7 +672,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p if (drb2Mod->pDCP_Configuration != NULL && drb2Mod->pDCP_Configuration->pDCP_Reestablishment != NULL && *drb2Mod->pDCP_Configuration->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true) { - drb->pdcp_config.pDCP_Reestablishment = true; + drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config)); + drb->pdcp_config->pDCP_Reestablishment = true; } if (drb2Mod->dL_UP_Parameters) { /* Optional IE in the DRB To Modify Item */ E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; @@ -649,8 +685,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p DevAssert(dl_up_param_in->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel); BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4( &dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->transportLayerAddress, - dl_up_param->tlAddress); - OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->teId); + dl_up_param->tl_info.tlAddress); + OCTET_STRING_TO_INT32(&dl_up_param_in->uP_TNL_Information.choice.gTPTunnel->gTP_TEID, dl_up_param->tl_info.teId); } else { AssertFatal(false, "gTPTunnel IE is missing. It is mandatory at this point\n"); } @@ -665,7 +701,8 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p /* Bearer Context Status Change */ DevAssert(ie->criticality == E1AP_Criticality_reject); DevAssert(ie->value.present == E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange); - bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE; + bearerCxt->bearerContextStatus = malloc_or_fail(*bearerCxt->bearerContextStatus); + *bearerCxt->bearerContextStatus = (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) ? BEARER_SUSPEND : BEARER_ACTIVE; break; default: @@ -1131,7 +1168,7 @@ static void e1_task_handle_sctp_association_resp(E1_t type, if (getCxtE1(instance)->gtpInstF1U < 0) getCxtE1(instance)->gtpInstF1U = cuup_task_create_gtpu_instance_to_du(&IPaddr); if (getCxtE1(instance)->gtpInstF1U < 0) - LOG_E(E1AP, "Failed to create CUUP F1-U UDP listener"); + LOG_E(E1AP, "Failed to create CUUP F1-U UDP listener\n"); extern instance_t CUuniqInstance; CUuniqInstance = getCxtE1(instance)->gtpInstF1U; cuup_init_n3(instance); @@ -1154,7 +1191,7 @@ void cuup_init_n3(instance_t instance) legacyInstanceMapping = getCxtE1(instance)->gtpInstN3 = gtpv1Init(tmp); } if (getCxtE1(instance)->gtpInstN3 < 0) - LOG_E(E1AP, "Failed to create CUUP N3 UDP listener"); + LOG_E(E1AP, "Failed to create CUUP N3 UDP listener\n"); extern instance_t *N3GTPUInst; N3GTPUInst = &getCxtE1(instance)->gtpInstN3; } diff --git a/openair2/E1AP/lib/CMakeLists.txt b/openair2/E1AP/lib/CMakeLists.txt index 27bfbcc8a2..332986dffb 100644 --- a/openair2/E1AP/lib/CMakeLists.txt +++ b/openair2/E1AP/lib/CMakeLists.txt @@ -1,6 +1,7 @@ add_library(e1ap_lib OBJECT e1ap_bearer_context_management.c e1ap_interface_management.c + e1ap_lib_common.c ) target_link_libraries(e1ap_lib PRIVATE asn1_e1ap) diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index 5e359512ed..a8f68e70d6 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -37,9 +37,130 @@ #include "e1ap_bearer_context_management.h" #include "e1ap_lib_includes.h" -/* ==================================== - * E1AP Bearer Context Setup Request - * ==================================== */ +/** @brief Encode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */ +static E1AP_SecurityIndication_t e1_encode_security_indication(const security_indication_t *in) +{ + E1AP_SecurityIndication_t out = {0}; + out.integrityProtectionIndication = in->integrityProtectionIndication; + out.confidentialityProtectionIndication = in->confidentialityProtectionIndication; + if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) { + asn1cCalloc(out.maximumIPdatarate, ipDataRate); + ipDataRate->maxIPrate = in->maxIPrate; + } + return out; +} + +/** @brief Decode E1AP_SecurityIndication_t (3GPP TS 38.463 9.3.1.23) */ +static bool e1_decode_security_indication(security_indication_t *out, const E1AP_SecurityIndication_t *in) +{ + // Confidentiality Protection Indication (M) + out->confidentialityProtectionIndication = in->confidentialityProtectionIndication; + // Maximum Integrity Protected Data Rate (Conditional) + if (in->integrityProtectionIndication != SECURITY_NOT_NEEDED) { + if (in->maximumIPdatarate) + out->maxIPrate = in->maximumIPdatarate->maxIPrate; + else { + PRINT_ERROR("Received integrityProtectionIndication but maximumIPdatarate IE is missing\n"); + return false; + } + } + return true; +} + +/** + * @brief Encode E1AP_SecurityInformation_t + */ +static E1AP_SecurityInformation_t e1_encode_security_info(const security_information_t *secInfo) +{ + E1AP_SecurityInformation_t ie = {0}; + E1AP_SecurityAlgorithm_t *securityAlgorithm = &ie.securityAlgorithm; + E1AP_UPSecuritykey_t *uPSecuritykey = &ie.uPSecuritykey; + securityAlgorithm->cipheringAlgorithm = secInfo->cipheringAlgorithm; + OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, secInfo->encryptionKey, E1AP_SECURITY_KEY_SIZE); + asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, secInfo->integrityProtectionAlgorithm); + asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); + OCTET_STRING_fromBuf(protKey, secInfo->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + return ie; +} + +/** + * @brief Decode E1AP_SecurityInformation_t + */ +static bool e1_decode_security_info(security_information_t *out, const E1AP_SecurityInformation_t *in) +{ + out->cipheringAlgorithm = in->securityAlgorithm.cipheringAlgorithm; + memcpy(out->encryptionKey, in->uPSecuritykey.encryptionKey.buf, in->uPSecuritykey.encryptionKey.size); + if (in->securityAlgorithm.integrityProtectionAlgorithm) + out->integrityProtectionAlgorithm = *in->securityAlgorithm.integrityProtectionAlgorithm; + if (in->uPSecuritykey.integrityProtectionKey) { + E1AP_IntegrityProtectionKey_t *ipKey = in->uPSecuritykey.integrityProtectionKey; + memcpy(out->integrityProtectionKey, ipKey->buf, ipKey->size); + } + return true; +} + +/** + * @brief Encode E1AP_UP_TNL_Information_t + */ +static E1AP_UP_TNL_Information_t e1_encode_up_tnl_info(const UP_TL_information_t *in) +{ + E1AP_UP_TNL_Information_t out = {0}; + out.present = E1AP_UP_TNL_Information_PR_gTPTunnel; + asn1cCalloc(out.choice.gTPTunnel, gTPTunnel); + TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress); + INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID); + return out; +} + +/** + * @brief Decode E1AP_UP_TNL_Information_t + */ +static bool e1_decode_up_tnl_info(UP_TL_information_t *out, const E1AP_UP_TNL_Information_t *in) +{ + /* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */ + // GTP Tunnel + struct E1AP_GTPTunnel *gTPTunnel = in->choice.gTPTunnel; + AssertFatal(gTPTunnel != NULL, "item->nG_UL_UP_TNL_Information.choice.gTPTunnel is a mandatory IE"); + _E1_EQ_CHECK_INT(in->present, E1AP_UP_TNL_Information_PR_gTPTunnel); + BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, out->tlAddress); + // GTP-TEID + OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, out->teId); + return true; +} + +/** @brief Encode PDCP Configuration IE */ +static E1AP_PDCP_Configuration_t e1_encode_pdcp_config(const bearer_context_pdcp_config_t *in) +{ + E1AP_PDCP_Configuration_t out = {0}; + out.pDCP_SN_Size_UL = in->pDCP_SN_Size_UL; + out.pDCP_SN_Size_DL = in->pDCP_SN_Size_DL; + asn1cCallocOne(out.discardTimer, in->discardTimer); + E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer)); + out.t_ReorderingTimer = roTimer; + roTimer->t_Reordering = in->reorderingTimer; + out.rLC_Mode = in->rLC_Mode; + if (in->pDCP_Reestablishment) { + asn1cCallocOne(out.pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true); + } + return out; +} + +/** @brief Decode PDCP Configuration IE */ +static bool e1_decode_pdcp_config(bearer_context_pdcp_config_t *out, const E1AP_PDCP_Configuration_t *in) +{ + out->pDCP_SN_Size_UL = in->pDCP_SN_Size_UL; + out->pDCP_SN_Size_DL = in->pDCP_SN_Size_DL; + if (in->discardTimer) { + out->discardTimer = *in->discardTimer; + } + if (in->t_ReorderingTimer) { + out->reorderingTimer = in->t_ReorderingTimer->t_Reordering; + } + out->rLC_Mode = in->rLC_Mode; + if (in->pDCP_Reestablishment && *in->pDCP_Reestablishment == E1AP_PDCP_Reestablishment_true) + out->pDCP_Reestablishment = true; + return true; +} /** * @brief Equality check for bearer_context_pdcp_config_t @@ -55,6 +176,25 @@ static bool eq_pdcp_config(const bearer_context_pdcp_config_t *a, const bearer_c return true; } +/** @brief Encode SDAP Configuration IE */ +static E1AP_SDAP_Configuration_t e1_encode_sdap_config(const bearer_context_sdap_config_t *in) +{ + E1AP_SDAP_Configuration_t out = {0}; + out.defaultDRB = in->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + out.sDAP_Header_UL = in->sDAP_Header_UL; + out.sDAP_Header_DL = in->sDAP_Header_DL; + return out; +} + +/** @brief Decode SDAP Configuration IE */ +static bool e1_decode_sdap_config(bearer_context_sdap_config_t *out, const E1AP_SDAP_Configuration_t *in) +{ + out->defaultDRB = in->defaultDRB == E1AP_DefaultDRB_true; + out->sDAP_Header_UL = in->sDAP_Header_UL; + out->sDAP_Header_DL = in->sDAP_Header_DL; + return true; +} + /** * @brief Equality check for bearer_context_sdap_config_t */ @@ -66,6 +206,69 @@ static bool eq_sdap_config(const bearer_context_sdap_config_t *a, const bearer_c return true; } +static E1AP_QoS_Flow_QoS_Parameter_Item_t e1_encode_qos_flow_to_setup(const qos_flow_to_setup_t *in) +{ + E1AP_QoS_Flow_QoS_Parameter_Item_t out = {0}; + out.qoS_Flow_Identifier = in->qfi; + // QoS Characteristics + const qos_characteristics_t *qos_char_in = &in->qos_params.qos_characteristics; + if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI + out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI; + asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI); + non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi; + } else { // dynamic 5QI + out.qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI; + asn1cCalloc(out.qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI); + dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level; + dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget; + dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar; + dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent; + } + // QoS Retention Priority + const ngran_allocation_retention_priority_t *rent_priority_in = &in->qos_params.alloc_reten_priority; + E1AP_NGRANAllocationAndRetentionPriority_t *arp = &out.qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority; + arp->priorityLevel = rent_priority_in->priority_level; + arp->pre_emptionCapability = rent_priority_in->preemption_capability; + arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability; + return out; +} + +bool e1_decode_qos_flow_to_setup(qos_flow_to_setup_t *out, const E1AP_QoS_Flow_QoS_Parameter_Item_t *in) +{ + // QoS Flow Identifier (M) + out->qfi = in->qoS_Flow_Identifier; + qos_characteristics_t *qos_char = &out->qos_params.qos_characteristics; + // QoS Flow Level QoS Parameters (M) + const E1AP_QoSFlowLevelQoSParameters_t *qosParams = &in->qoSFlowLevelQoSParameters; + const E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics; + switch (qoS_Characteristics->present) { + case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI: + qos_char->qos_type = NON_DYNAMIC; + qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI; + break; + case E1AP_QoS_Characteristics_PR_dynamic_5QI: { + E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI; + qos_char->qos_type = DYNAMIC; + qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel; + qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget; + qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar; + qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent; + break; + } + default: + PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present); + return false; + break; + } + // NG-RAN Allocation and Retention Priority (M) + ngran_allocation_retention_priority_t *rent_priority = &out->qos_params.alloc_reten_priority; + const E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority; + rent_priority->priority_level = aRP->priorityLevel; + rent_priority->preemption_capability = aRP->pre_emptionCapability; + rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability; + return true; +} + /** * @brief Equality check for qos_flow_to_setup_t */ @@ -90,6 +293,62 @@ static bool eq_qos_flow(const qos_flow_to_setup_t *a, const qos_flow_to_setup_t return true; } +/** @brief S-NSSAI Encoding (3GPP TS 38.463 9.3.1.9) */ +static E1AP_SNSSAI_t e1_encode_snssai(const nssai_t *in) +{ + E1AP_SNSSAI_t out = {0}; + INT8_TO_OCTET_STRING(in->sst, &out.sST); + if (in->sd != 0xffffff) { + out.sD = malloc_or_fail(sizeof(*out.sD)); + INT24_TO_OCTET_STRING(in->sd, out.sD); + } + return out; +} + +/** @brief S-NSSAI Decoding (3GPP TS 38.463 9.3.1.9) */ +static bool e1_decode_snssai(e1ap_nssai_t *out, const E1AP_SNSSAI_t *in) +{ + // SST (M) + OCTET_STRING_TO_INT8(&in->sST, out->sst); + out->sd = 0xffffff; + // SD (O) + if (in->sD != NULL) + OCTET_STRING_TO_INT24(in->sD, out->sd); + return true; +} + +/** + * @brief Decode E1AP_UP_Parameters_t + */ +static int decode_dl_up_parameters(up_params_t *dl_up_param, const E1AP_UP_Parameters_t *dl_up_paramList) +{ + for (int k = 0; k < dl_up_paramList->list.count; k++) { + dl_up_param = dl_up_param + k; + E1AP_UP_Parameters_Item_t *dl_up_param_in = dl_up_paramList->list.array[k]; + // GTP tunnel + if (!e1_decode_up_tnl_info(&dl_up_param->tl_info, &dl_up_param_in->uP_TNL_Information)) { + PRINT_ERROR("GTP tunnel decoding failed\n"); + return -1; + } + // Cell group ID + dl_up_param->cell_group_id = dl_up_param_in->cell_Group_ID; + } + return dl_up_paramList->list.count; +} + +/** + * @brief Encode E1AP_UP_Parameters_t IE + */ +static E1AP_UP_Parameters_t encode_dl_up_parameters(const int numUpParam, const up_params_t *in) +{ + E1AP_UP_Parameters_t out = {0}; + for (const up_params_t *k = in; k < in + numUpParam; k++) { + asn1cSequenceAdd(out.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1); + ieC3_1_1_1->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); + } + return out; +} + /** * @brief Equality check for DRB_nGRAN_to_setup_t */ @@ -110,142 +369,58 @@ static bool eq_drb_to_setup(const DRB_nGRAN_to_setup_t *a, const DRB_nGRAN_to_se return result; } -/** - * @brief Equality check for DRB_nGRAN_to_mod_t - */ -static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b) +static void free_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg) { - bool result = true; - _E1_EQ_CHECK_LONG(a->id, b->id); - _E1_EQ_CHECK_INT(a->numCellGroups, b->numCellGroups); - for (int i = 0; i < a->numCellGroups; i++) { - _E1_EQ_CHECK_INT(a->cellGroupList[i], b->cellGroupList[i]); - } - _E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup); - for (int i = 0; i < a->numQosFlow2Setup; i++) { - result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); - } - _E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress); - _E1_EQ_CHECK_INT(a->teId, b->teId); - _E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam); - for (int i = 0; i < a->numDlUpParam; i++) { - _E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id); - _E1_EQ_CHECK_LONG(a->DlUpParamList[i].teId, b->DlUpParamList[i].teId); - _E1_EQ_CHECK_INT(a->DlUpParamList[i].tlAddress, b->DlUpParamList[i].tlAddress); - } - result &= eq_pdcp_config(&a->pdcp_config, &b->pdcp_config); - result &= eq_sdap_config(&a->sdap_config, &b->sdap_config); - return result; + free(msg->drb_inactivity_timer); } -/* PDU Session To Setup Item */ - +/** @brief Encode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */ static bool e1_encode_pdu_session_to_setup_item(E1AP_PDU_Session_Resource_To_Setup_Item_t *item, const pdu_session_to_setup_t *in) { + // PDU Session ID (M) item->pDU_Session_ID = in->sessionId; + // PDU Session Type (M) item->pDU_Session_Type = in->sessionType; - // SNSSAI - INT8_TO_OCTET_STRING(in->nssai.sst, &item->sNSSAI.sST); - if (in->nssai.sd != 0xffffff) { - item->sNSSAI.sD = malloc_or_fail(sizeof(*item->sNSSAI.sD)); - INT24_TO_OCTET_STRING(in->nssai.sd, item->sNSSAI.sD); - } - // 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 + // S-NSSAI (M) + item->sNSSAI = e1_encode_snssai(&in->nssai); + // Security Indication (M) + item->securityIndication = e1_encode_security_indication(&in->securityIndication); + // NG UL UP Transport Layer Information (M) + item->nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information); + // DRB To Setup List (M) for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) { asn1cSequenceAdd(item->dRB_To_Setup_List_NG_RAN.list, E1AP_DRB_To_Setup_Item_NG_RAN_t, ieC6_1_1); + // DRB ID (M) ieC6_1_1->dRB_ID = j->id; - // SDAP Config - E1AP_SDAP_Configuration_t *sdap = &ieC6_1_1->sDAP_Configuration; - sdap->defaultDRB = j->sdap_config.defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; - sdap->sDAP_Header_UL = j->sdap_config.sDAP_Header_UL; - sdap->sDAP_Header_DL = j->sdap_config.sDAP_Header_DL; - // PDCP Config - E1AP_PDCP_Configuration_t *pdcp = &ieC6_1_1->pDCP_Configuration; - pdcp->pDCP_SN_Size_UL = j->pdcp_config.pDCP_SN_Size_UL; - pdcp->pDCP_SN_Size_DL = j->pdcp_config.pDCP_SN_Size_DL; - asn1cCallocOne(pdcp->discardTimer, j->pdcp_config.discardTimer); - E1AP_T_ReorderingTimer_t *roTimer = calloc_or_fail(1, sizeof(*roTimer)); - pdcp->t_ReorderingTimer = roTimer; - roTimer->t_Reordering = j->pdcp_config.reorderingTimer; - pdcp->rLC_Mode = j->pdcp_config.rLC_Mode; - // Cell Group + // SDAP Configuration (M) + ieC6_1_1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config); + // PDCP Configuration (M) + ieC6_1_1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config); + // Cell Group Information (M) for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) { asn1cSequenceAdd(ieC6_1_1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ieC6_1_1_1); ieC6_1_1_1->cell_Group_ID = *k; } - // QoS Flows + // QoS Flows Information To Be Setup (M) for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { - asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_1); - ieC6_1_1_1->qoS_Flow_Identifier = k->qfi; - // QoS Characteristics - const qos_characteristics_t *qos_char_in = &k->qos_params.qos_characteristics; - if (qos_char_in->qos_type == NON_DYNAMIC) { // non Dynamic 5QI - ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_non_Dynamic_5QI; - asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.non_Dynamic_5QI, non_Dynamic_5QI); - non_Dynamic_5QI->fiveQI = qos_char_in->non_dynamic.fiveqi; - } else { // dynamic 5QI - ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.present = E1AP_QoS_Characteristics_PR_dynamic_5QI; - asn1cCalloc(ieC6_1_1_1->qoSFlowLevelQoSParameters.qoS_Characteristics.choice.dynamic_5QI, dynamic_5QI); - dynamic_5QI->qoSPriorityLevel = qos_char_in->dynamic.qos_priority_level; - dynamic_5QI->packetDelayBudget = qos_char_in->dynamic.packet_delay_budget; - dynamic_5QI->packetErrorRate.pER_Scalar = qos_char_in->dynamic.packet_error_rate.per_scalar; - dynamic_5QI->packetErrorRate.pER_Exponent = qos_char_in->dynamic.packet_error_rate.per_exponent; - } - // QoS Retention Priority - const ngran_allocation_retention_priority_t *rent_priority_in = &k->qos_params.alloc_reten_priority; - E1AP_NGRANAllocationAndRetentionPriority_t *arp = &ieC6_1_1_1->qoSFlowLevelQoSParameters.nGRANallocationRetentionPriority; - arp->priorityLevel = rent_priority_in->priority_level; - arp->pre_emptionCapability = rent_priority_in->preemption_capability; - arp->pre_emptionVulnerability = rent_priority_in->preemption_vulnerability; + asn1cSequenceAdd(ieC6_1_1->qos_flow_Information_To_Be_Setup.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ieC6_1_1_2); + *ieC6_1_1_2 = e1_encode_qos_flow_to_setup(k); } } return true; } +/** @brief Decode PDU Session Resource To Setup List Item (3GPP TS 38.463 9.3.3.2) */ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1AP_PDU_Session_Resource_To_Setup_Item_t *item) { // PDU Session ID (M) 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; - } - } + // S-NSSAI (M) + CHECK_E1AP_DEC(e1_decode_snssai(&out->nssai, &item->sNSSAI)); + // Security Indication (M) + CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication)); /* NG UL UP Transport Layer Information (M) (9.3.2.1 of 3GPP TS 38.463) */ // GTP Tunnel struct E1AP_GTPTunnel *gTPTunnel = item->nG_UL_UP_TNL_Information.choice.gTPTunnel; @@ -254,12 +429,8 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A return false; } _E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel); - // Transport Layer Address - UP_TL_information_t *UP_TL_information = &out->UP_TL_information; - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UP_TL_information->tlAddress); - // GTP-TEID - OCTET_STRING_TO_INT32(&gTPTunnel->gTP_TEID, UP_TL_information->teId); - // DRB To Setup List ( > 1 item ) + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information)); + /* DRB To Setup List ( > 1 item ) */ E1AP_DRB_To_Setup_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_List_NG_RAN; _E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0); out->numDRB2Setup = drb2SetupList->list.count; @@ -269,23 +440,11 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A E1AP_DRB_To_Setup_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j]; // DRB ID (M) drb->id = drb2Setup->dRB_ID; - // >SDAP Configuration (M) - E1AP_SDAP_Configuration_t *sdap = &drb2Setup->sDAP_Configuration; - drb->sdap_config.defaultDRB = sdap->defaultDRB == E1AP_DefaultDRB_true; - drb->sdap_config.sDAP_Header_UL = sdap->sDAP_Header_UL; - drb->sdap_config.sDAP_Header_DL = sdap->sDAP_Header_DL; + // SDAP Configuration (M) + CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration)); // PDCP Configuration (M) - E1AP_PDCP_Configuration_t *pdcp = &drb2Setup->pDCP_Configuration; - drb->pdcp_config.pDCP_SN_Size_UL = pdcp->pDCP_SN_Size_UL; - drb->pdcp_config.pDCP_SN_Size_DL = pdcp->pDCP_SN_Size_DL; - if (pdcp->discardTimer) { - drb->pdcp_config.discardTimer = *pdcp->discardTimer; - } - if (pdcp->t_ReorderingTimer) { - drb->pdcp_config.reorderingTimer = pdcp->t_ReorderingTimer->t_Reordering; - } - drb->pdcp_config.rLC_Mode = pdcp->rLC_Mode; - // Cell Group Information (M) ( > 1 item ) + CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration)); + // Cell Group Information (M) E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information; _E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0); drb->numCellGroups = cellGroupList->list.count; @@ -298,44 +457,50 @@ static bool e1_decode_pdu_session_to_setup_item(pdu_session_to_setup_t *out, E1A E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->qos_flow_Information_To_Be_Setup; drb->numQosFlow2Setup = qos2SetupList->list.count; for (int k = 0; k < qos2SetupList->list.count; k++) { - qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; - E1AP_QoS_Flow_QoS_Parameter_Item_t *qos2Setup = qos2SetupList->list.array[k]; - // QoS Flow Identifier (M) - qos_flow->qfi = qos2Setup->qoS_Flow_Identifier; - qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; - // QoS Flow Level QoS Parameters (M) - E1AP_QoSFlowLevelQoSParameters_t *qosParams = &qos2Setup->qoSFlowLevelQoSParameters; - E1AP_QoS_Characteristics_t *qoS_Characteristics = &qosParams->qoS_Characteristics; - switch (qoS_Characteristics->present) { - case E1AP_QoS_Characteristics_PR_non_Dynamic_5QI: - qos_char->qos_type = NON_DYNAMIC; - qos_char->non_dynamic.fiveqi = qoS_Characteristics->choice.non_Dynamic_5QI->fiveQI; - break; - case E1AP_QoS_Characteristics_PR_dynamic_5QI: { - E1AP_Dynamic5QIDescriptor_t *dynamic5QI = qoS_Characteristics->choice.dynamic_5QI; - qos_char->qos_type = DYNAMIC; - qos_char->dynamic.qos_priority_level = dynamic5QI->qoSPriorityLevel; - qos_char->dynamic.packet_delay_budget = dynamic5QI->packetDelayBudget; - qos_char->dynamic.packet_error_rate.per_scalar = dynamic5QI->packetErrorRate.pER_Scalar; - qos_char->dynamic.packet_error_rate.per_exponent = dynamic5QI->packetErrorRate.pER_Exponent; - break; - } - default: - PRINT_ERROR("Unexpected QoS Characteristics type: %d\n", qoS_Characteristics->present); - return false; - break; - } - // NG-RAN Allocation and Retention Priority (M) - ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; - E1AP_NGRANAllocationAndRetentionPriority_t *aRP = &qosParams->nGRANallocationRetentionPriority; - rent_priority->priority_level = aRP->priorityLevel; - rent_priority->preemption_capability = aRP->pre_emptionCapability; - rent_priority->preemption_vulnerability = aRP->pre_emptionVulnerability; + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); } } return true; } +/** @brief Deep copy DRB To Setup List Item (3GPP TS 38.463 9.3.3.2) */ +static DRB_nGRAN_to_setup_t cp_drb_to_setup_item(const DRB_nGRAN_to_setup_t *msg) +{ + DRB_nGRAN_to_setup_t cp = {0}; + cp.id = msg->id; + cp.sdap_config = msg->sdap_config; + cp.pdcp_config = msg->pdcp_config; + cp.numCellGroups = msg->numCellGroups; + // Cell Group List + for (int k = 0; k < msg->numCellGroups; k++) { + cp.cellGroupList[k] = msg->cellGroupList[k]; + } + cp.numQosFlow2Setup = msg->numQosFlow2Setup; + // QoS Flow To Setup List + for (int k = 0; k < msg->numQosFlow2Setup; k++) { + cp.qosFlows[k].qfi = msg->qosFlows[k].qfi; + cp.qosFlows[k].qos_params = msg->qosFlows[k].qos_params; + } + return cp; +} + +/** @brief Free PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */ +void free_pdu_session_to_setup_item(const pdu_session_to_setup_t *msg) +{ + free(msg->dlAggregateMaxBitRate); + free(msg->inactivityTimer); + for (int i = 0; i < msg->numDRB2Setup; i++) + free_drb_to_setup_item(&msg->DRBnGRanList[i]); +} + +/** @brief Equality check for UP Transport Layer Information (3GPP TS 38.463 9.3.2.1)*/ +static bool eq_up_tl_info(const UP_TL_information_t *a, const UP_TL_information_t *b) +{ + _E1_EQ_CHECK_INT(a->tlAddress, b->tlAddress); + _E1_EQ_CHECK_INT(a->teId, b->teId); + return true; +} + /** * @brief Equality check for PDU session item to modify/setup */ @@ -343,57 +508,21 @@ static bool eq_pdu_session_item(const pdu_session_to_setup_t *a, const pdu_sessi { _E1_EQ_CHECK_LONG(a->sessionId, b->sessionId); _E1_EQ_CHECK_LONG(a->sessionType, b->sessionType); - _E1_EQ_CHECK_INT(a->UP_TL_information.tlAddress, b->UP_TL_information.tlAddress); - _E1_EQ_CHECK_INT(a->UP_TL_information.teId, b->UP_TL_information.teId); - _E1_EQ_CHECK_LONG(a->numDRB2Setup, b->numDRB2Setup); - if (a->numDRB2Setup != b->numDRB2Setup) - return false; + eq_up_tl_info(&a->UP_TL_information, &b->UP_TL_information); + _E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup); for (int i = 0; i < a->numDRB2Setup; i++) if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i])) return false; - _E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify); - if (a->numDRB2Modify != b->numDRB2Modify) - return false; - for (int i = 0; i < a->numDRB2Modify; i++) - if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i])) - return false; + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer); + if (a->inactivityTimer && b->inactivityTimer) + _E1_EQ_CHECK_INT(a->inactivityTimer, b->inactivityTimer); + _E1_EQ_CHECK_OPTIONAL_IE(a, b, dlAggregateMaxBitRate, _E1_EQ_CHECK_LONG); return true; } -static bool cp_pdu_session_item(pdu_session_to_setup_t *cp, const pdu_session_to_setup_t *msg) -{ - // Copy basic fields - *cp = *msg; - // Copy DRB to Setup List - for (int j = 0; j < msg->numDRB2Setup; j++) { - cp->DRBnGRanList[j].id = msg->DRBnGRanList[j].id; - cp->DRBnGRanList[j].sdap_config = msg->DRBnGRanList[j].sdap_config; - cp->DRBnGRanList[j].pdcp_config = msg->DRBnGRanList[j].pdcp_config; - cp->DRBnGRanList[j].tlAddress = msg->DRBnGRanList[j].tlAddress; - cp->DRBnGRanList[j].teId = msg->DRBnGRanList[j].teId; - cp->DRBnGRanList[j].numDlUpParam = msg->DRBnGRanList[j].numDlUpParam; - // Copy DL UP Params List - for (int k = 0; k < msg->DRBnGRanList[j].numDlUpParam; k++) { - cp->DRBnGRanList[j].DlUpParamList[k] = msg->DRBnGRanList[j].DlUpParamList[k]; - } - cp->DRBnGRanList[j].numCellGroups = msg->DRBnGRanList[j].numCellGroups; - // Copy Cell Group List - for (int k = 0; k < msg->DRBnGRanList[j].numCellGroups; k++) { - cp->DRBnGRanList[j].cellGroupList[k] = msg->DRBnGRanList[j].cellGroupList[k]; - } - cp->DRBnGRanList[j].numQosFlow2Setup = msg->DRBnGRanList[j].numQosFlow2Setup; - // Copy QoS Flow To Setup List - for (int k = 0; k < msg->DRBnGRanList[j].numQosFlow2Setup; k++) { - cp->DRBnGRanList[j].qosFlows[k].qfi = msg->DRBnGRanList[j].qosFlows[k].qfi; - cp->DRBnGRanList[j].qosFlows[k].qos_params = msg->DRBnGRanList[j].qosFlows[k].qos_params; - } - } - // Copy DRB to Modify List - for (int j = 0; j < msg->numDRB2Modify; j++) { - cp->DRBnGRanModList[j] = msg->DRBnGRanModList[j]; - } - return true; -} +/* ==================================== + * E1AP Bearer Context Setup Request + * ==================================== */ /** * @brief E1AP Bearer Context Setup Request encoding (9.2.2 of 3GPP TS 38.463) @@ -421,13 +550,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ ieC2->id = E1AP_ProtocolIE_ID_id_SecurityInformation; ieC2->criticality = E1AP_Criticality_reject; ieC2->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation; - E1AP_SecurityAlgorithm_t *securityAlgorithm = &ieC2->value.choice.SecurityInformation.securityAlgorithm; - E1AP_UPSecuritykey_t *uPSecuritykey = &ieC2->value.choice.SecurityInformation.uPSecuritykey; - securityAlgorithm->cipheringAlgorithm = msg->cipheringAlgorithm; - OCTET_STRING_fromBuf(&uPSecuritykey->encryptionKey, msg->encryptionKey, E1AP_SECURITY_KEY_SIZE); - asn1cCallocOne(securityAlgorithm->integrityProtectionAlgorithm, msg->integrityProtectionAlgorithm); - asn1cCalloc(uPSecuritykey->integrityProtectionKey, protKey); - OCTET_STRING_fromBuf(protKey, msg->integrityProtectionKey, E1AP_SECURITY_KEY_SIZE); + ieC2->value.choice.SecurityInformation = e1_encode_security_info(&msg->secInfo); /* mandatory */ /* c3. UE DL Aggregate Maximum Bit Rate */ asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC3); @@ -450,8 +573,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ ieC5->criticality = E1AP_Criticality_reject; ieC5->value.present = E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel; ieC5->value.choice.ActivityNotificationLevel = E1AP_ActivityNotificationLevel_pdu_session; // TODO: Remove hard coding - /* mandatory */ - /* */ + // System (M) asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextSetupRequestIEs_t, ieC6); ieC6->id = E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest; ieC6->criticality = E1AP_Criticality_reject; @@ -469,7 +591,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ for (int i = 0; i < msg->numPDUSessions; i++) { const pdu_session_to_setup_t *pdu_session = &msg->pduSession[i]; asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Item_t, ieC6_1); - e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session); + CHECK_E1AP_DEC(e1_encode_pdu_session_to_setup_item(ieC6_1, pdu_session)); } return pdu; } @@ -479,7 +601,8 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_request(const e1ap_bearer_setup_ */ void free_e1ap_context_setup_request(e1ap_bearer_setup_req_t *msg) { - // Do nothing + free(msg->inactivityTimerUE); + free(msg->ueDlMaxIPBitRate); } /** @@ -492,8 +615,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea // Check message type _E1_EQ_CHECK_INT(pdu->present,E1AP_E1AP_PDU_PR_initiatingMessage); - _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); - _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->criticality, E1AP_Criticality_reject); + _E1_EQ_CHECK_LONG(pdu->choice.initiatingMessage->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); _E1_EQ_CHECK_INT(pdu->choice.initiatingMessage->value.present, E1AP_InitiatingMessage__value_PR_BearerContextSetupRequest); const E1AP_BearerContextSetupRequest_t *in = &pdu->choice.initiatingMessage->value.choice.BearerContextSetupRequest; @@ -519,17 +641,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea case E1AP_ProtocolIE_ID_id_SecurityInformation: _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_SecurityInformation); - 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); + CHECK_E1AP_DEC(e1_decode_security_info(&out->secInfo, &ie->value.choice.SecurityInformation)); break; case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: @@ -545,12 +657,6 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea out->servingPLMNid.mnc_digit_length); break; - case E1AP_ProtocolIE_ID_id_ActivityNotificationLevel: - _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel); - DevAssert(ie->value.present == E1AP_BearerContextSetupRequestIEs__value_PR_ActivityNotificationLevel); - out->activityNotificationLevel = ie->value.choice.ActivityNotificationLevel; - break; - case E1AP_ProtocolIE_ID_id_System_BearerContextSetupRequest: _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextSetupRequestIEs__value_PR_System_BearerContextSetupRequest); E1AP_System_BearerContextSetupRequest_t *System_BearerContextSetupRequest = @@ -590,10 +696,7 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea for (int i = 0; i < pdu2SetupList->list.count; i++) { pdu_session_to_setup_t *pdu_session = out->pduSession + i; E1AP_PDU_Session_Resource_To_Setup_Item_t *pdu2Setup = pdu2SetupList->list.array[i]; - if (!e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup)) { - PRINT_ERROR("Failed to decode PDU Session to setup item %d\n", i); - return false; - } + CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_item(pdu_session, pdu2Setup)); } break; default: @@ -604,19 +707,35 @@ bool decode_E1_bearer_context_setup_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bea return true; } -/** - * @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST - */ +/** @brief Deep copy PDU Session Resource To Setup List item (3GPP TS 38.463 9.3.3.2) */ +static pdu_session_to_setup_t cp_pdu_session_item(const pdu_session_to_setup_t *msg) +{ + pdu_session_to_setup_t cp = {0}; + // Copy basic fields + cp = *msg; + // Copy DRB to Setup List + for (int j = 0; j < msg->numDRB2Setup; j++) + cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]); + // Copy optional IEs + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer); + _E1_CP_OPTIONAL_IE(&cp, msg, dlAggregateMaxBitRate); + return cp; +} + +/** @brief Deep copy function for E1 BEARER CONTEXT SETUP REQUEST */ e1ap_bearer_setup_req_t cp_bearer_context_setup_request(const e1ap_bearer_setup_req_t *msg) { e1ap_bearer_setup_req_t cp = {0}; // Copy basi fields cp = *msg; - strncpy(cp.encryptionKey, msg->encryptionKey, sizeof(cp.encryptionKey)); - strncpy(cp.integrityProtectionKey, msg->integrityProtectionKey, sizeof(cp.integrityProtectionKey)); + strncpy(cp.secInfo.encryptionKey, msg->secInfo.encryptionKey, sizeof(cp.secInfo.encryptionKey)); + strncpy(cp.secInfo.integrityProtectionKey, msg->secInfo.integrityProtectionKey, sizeof(cp.secInfo.integrityProtectionKey)); // Copy PDU Sessions for (int i = 0; i < msg->numPDUSessions; i++) - cp_pdu_session_item(&cp.pduSession[i], &msg->pduSession[i]); + cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]); + // copy optional IEs + _E1_CP_OPTIONAL_IE(&cp, msg, ueDlMaxIPBitRate); + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimerUE); return cp; } @@ -627,30 +746,28 @@ bool eq_bearer_context_setup_request(const e1ap_bearer_setup_req_t *a, const e1a { // Primitive data types _E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id); - _E1_EQ_CHECK_LONG(a->cipheringAlgorithm, b->cipheringAlgorithm); - _E1_EQ_CHECK_LONG(a->integrityProtectionAlgorithm, b->integrityProtectionAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo.cipheringAlgorithm, b->secInfo.cipheringAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo.integrityProtectionAlgorithm, b->secInfo.integrityProtectionAlgorithm); _E1_EQ_CHECK_LONG(a->ueDlAggMaxBitRate, b->ueDlAggMaxBitRate); - _E1_EQ_CHECK_INT(a->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); + _E1_EQ_CHECK_STR(a->secInfo.encryptionKey, b->secInfo.encryptionKey); + _E1_EQ_CHECK_STR(a->secInfo.integrityProtectionKey, b->secInfo.integrityProtectionKey); // PDU Sessions if (a->numPDUSessions != b->numPDUSessions) return false; for (int i = 0; i < a->numPDUSessions; i++) if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i])) return false; - if (a->numPDUSessionsMod != b->numPDUSessionsMod) - return false; - for (int i = 0; i < a->numPDUSessionsMod; i++) - if (!eq_pdu_session_item(&a->pduSessionMod[i], &b->pduSessionMod[i])) - return false; + // Check optional IEs + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimerUE); + if (a->inactivityTimerUE && b->inactivityTimerUE) + _E1_EQ_CHECK_INT(a->inactivityTimerUE, b->inactivityTimerUE); + _E1_EQ_CHECK_OPTIONAL_IE(a, b, ueDlMaxIPBitRate, _E1_EQ_CHECK_LONG); return true; } @@ -669,12 +786,7 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP pduSetup->id = in->pDU_Session_ID; pduSetup->numDRBSetup = in->dRB_Setup_List_NG_RAN.list.count; // NG DL UP Transport Layer Information (M) - E1AP_UP_TNL_Information_t *DL_UP_TNL_Info = &in->nG_DL_UP_TNL_Information; - if (DL_UP_TNL_Info->choice.gTPTunnel) { - _E1_EQ_CHECK_INT(DL_UP_TNL_Info->present, E1AP_UP_TNL_Information_PR_gTPTunnel); - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&DL_UP_TNL_Info->choice.gTPTunnel->transportLayerAddress, pduSetup->tlAddress); - OCTET_STRING_TO_INT32(&DL_UP_TNL_Info->choice.gTPTunnel->gTP_TEID, pduSetup->teId); - } + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&pduSetup->tl_info, &in->nG_DL_UP_TNL_Information)); // DRB Setup List (1..) for (int j = 0; j < in->dRB_Setup_List_NG_RAN.list.count; j++) { DRB_nGRAN_setup_t *drbSetup = pduSetup->DRBnGRanList + j; @@ -682,32 +794,29 @@ static bool e1_decode_pdu_session_setup_item(pdu_session_setup_t *pduSetup, E1AP // DRB ID (M) drbSetup->id = drb->dRB_ID; // UL UP Parameters (M) - drbSetup->numUpParam = drb->uL_UP_Transport_Parameters.list.count; - for (int k = 0; k < drb->uL_UP_Transport_Parameters.list.count; k++) { - up_params_t *UL_UP_param = drbSetup->UpParamList + k; - // UP Parameters List (1..) - E1AP_UP_Parameters_Item_t *UL_UP_item = drb->uL_UP_Transport_Parameters.list.array[k]; - // UP Transport Layer Information (M) - DevAssert(UL_UP_item->uP_TNL_Information.present == E1AP_UP_TNL_Information_PR_gTPTunnel); - // GTP Tunnel (M) - E1AP_GTPTunnel_t *gTPTunnel = UL_UP_item->uP_TNL_Information.choice.gTPTunnel; - AssertError(gTPTunnel != NULL, return false, "gTPTunnel information in required in UP Transport Layer Information\n"); - if (gTPTunnel) { - BIT_STRING_TO_TRANSPORT_LAYER_ADDRESS_IPv4(&gTPTunnel->transportLayerAddress, UL_UP_param->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; + if ((drbSetup->numUpParam = decode_dl_up_parameters(drbSetup->UpParamList, &drb->uL_UP_Transport_Parameters)) < 0) { + PRINT_ERROR("UL UP Parameters decoding failed\n"); + return false; } // Flow Setup List (M) drbSetup->numQosFlowSetup = drb->flow_Setup_List.list.count; for (int q = 0; q < drb->flow_Setup_List.list.count; q++) { - qos_flow_setup_t *qosflowSetup = &drbSetup->qosFlows[q]; + qos_flow_list_t *qosflowSetup = &drbSetup->qosFlows[q]; E1AP_QoS_Flow_Item_t *in_qosflowSetup = drb->flow_Setup_List.list.array[q]; qosflowSetup->qfi = in_qosflowSetup->qoS_Flow_Identifier; } } + // DRB Failed to Setup List (O) + if (in->dRB_Failed_List_NG_RAN) { + for (int j = 0; j < in->dRB_Failed_List_NG_RAN->list.count; j++) { + DRB_nGRAN_failed_t *drbFailed = pduSetup->DRBnGRanFailedList + j; + E1AP_DRB_Failed_Item_NG_RAN_t *item = in->dRB_Failed_List_NG_RAN->list.array[j]; + // DRB ID (M) + drbFailed->id = item->dRB_ID; + // Cause (M) + drbFailed->cause = e1_decode_cause_ie(&item->cause); + } + } return true; } @@ -719,25 +828,16 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite // PDU Session ID (M) item->pDU_Session_ID = in->id; // NG DL UP Transport Layer Information (M) - item->nG_DL_UP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(item->nG_DL_UP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(in->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(in->teId, &gTPTunnel->gTP_TEID); + item->nG_DL_UP_TNL_Information = e1_encode_up_tnl_info(&in->tl_info); // DRB Setup List (1..) for (const DRB_nGRAN_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRBSetup; j++) { asn1cSequenceAdd(item->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1); // DRB ID (M) ieC3_1_1->dRB_ID = j->id; // UL UP Parameters (M) - for (const up_params_t *k = j->UpParamList; k < j->UpParamList + j->numUpParam; k++) { - asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1); - ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel; - asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel); - TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(k->tlAddress, &gTPTunnel->transportLayerAddress); - INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID); - } + ieC3_1_1->uL_UP_Transport_Parameters = encode_dl_up_parameters(j->numUpParam, j->UpParamList); // Flow Setup List(M) - for (const qos_flow_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) { + for (const qos_flow_list_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowSetup; k++) { asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1); ieC3_1_1_1->qoS_Flow_Identifier = k->qfi; } @@ -751,24 +851,7 @@ static bool e1_encode_pdu_session_setup_item(E1AP_PDU_Session_Resource_Setup_Ite // DRB ID (M) ieC3_1_1->dRB_ID = j->id; // Cause (M) - ieC3_1_1->cause.present = j->cause_type; - switch (ieC3_1_1->cause.present) { - case E1AP_Cause_PR_radioNetwork: - ieC3_1_1->cause.choice.radioNetwork = j->cause; - break; - case E1AP_Cause_PR_transport: - ieC3_1_1->cause.choice.transport = j->cause; - break; - case E1AP_Cause_PR_protocol: - ieC3_1_1->cause.choice.protocol = j->cause; - break; - case E1AP_Cause_PR_misc: - ieC3_1_1->cause.choice.misc = j->cause; - break; - default: - PRINT_ERROR("DRB setup failure cause out of expected range\n"); - break; - } + ieC3_1_1->cause = e1_encode_cause_ie(&j->cause); } return true; } @@ -816,7 +899,7 @@ E1AP_E1AP_PDU_t *encode_E1_bearer_context_setup_response(const e1ap_bearer_setup E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List; for (const pdu_session_setup_t *i = in->pduSession; i < in->pduSession + in->numPDUSessions; i++) { asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1); - e1_encode_pdu_session_setup_item(ieC3_1, i); + CHECK_E1AP_DEC(e1_encode_pdu_session_setup_item(ieC3_1, i)); } return pdu; } @@ -828,8 +911,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be { // Check message type _E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_successfulOutcome); - _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); - _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->criticality, E1AP_Criticality_reject); + _E1_EQ_CHECK_LONG(pdu->choice.successfulOutcome->procedureCode, E1AP_ProcedureCode_id_bearerContextSetup); _E1_EQ_CHECK_INT(pdu->choice.successfulOutcome->value.present, E1AP_SuccessfulOutcome__value_PR_BearerContextSetupResponse); const E1AP_BearerContextSetupResponse_t *in = &pdu->choice.successfulOutcome->value.choice.BearerContextSetupResponse; @@ -862,7 +944,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be ie->value.choice.System_BearerContextSetupResponse.choice.nG_RAN_BearerContextSetupResponse; _E1_EQ_CHECK_INT(msgNGRAN_list->list.count, 1); E1AP_NG_RAN_BearerContextSetupResponse_t *msgNGRAN = msgNGRAN_list->list.array[0]; - _E1_EQ_CHECK_INT(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List); + _E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_Setup_List); _E1_EQ_CHECK_INT(msgNGRAN->value.present, E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List); E1AP_PDU_Session_Resource_Setup_List_t *pduSetupList = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List; @@ -870,7 +952,7 @@ bool decode_E1_bearer_context_setup_response(const E1AP_E1AP_PDU_t *pdu, e1ap_be for (int i = 0; i < pduSetupList->list.count; i++) { pdu_session_setup_t *pduSetup = out->pduSession + i; E1AP_PDU_Session_Resource_Setup_Item_t *pdu_session = pduSetupList->list.array[i]; - e1_decode_pdu_session_setup_item(pduSetup, pdu_session); + CHECK_E1AP_DEC(e1_decode_pdu_session_setup_item(pduSetup, pdu_session)); } } break; @@ -938,8 +1020,7 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e const pdu_session_setup_t *ps_a = &a->pduSession[i]; const pdu_session_setup_t *ps_b = &b->pduSession[i]; _E1_EQ_CHECK_LONG(ps_a->id, ps_b->id); - _E1_EQ_CHECK_INT(ps_a->tlAddress, ps_b->tlAddress); - _E1_EQ_CHECK_LONG(ps_a->teId, ps_b->teId); + eq_up_tl_info(&ps_a->tl_info, &ps_b->tl_info); _E1_EQ_CHECK_INT(ps_a->numDRBSetup, ps_b->numDRBSetup); _E1_EQ_CHECK_INT(ps_a->numDRBFailed, ps_b->numDRBFailed); // Check DRB Setup @@ -955,8 +1036,8 @@ bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e const DRB_nGRAN_failed_t *drbf_a = &ps_a->DRBnGRanFailedList[j]; const DRB_nGRAN_failed_t *drbf_b = &ps_b->DRBnGRanFailedList[j]; _E1_EQ_CHECK_LONG(drbf_a->id, drbf_b->id); - _E1_EQ_CHECK_LONG(drbf_a->cause_type, drbf_b->cause_type); - _E1_EQ_CHECK_LONG(drbf_a->cause, drbf_b->cause); + _E1_EQ_CHECK_LONG(drbf_a->cause.type, drbf_b->cause.type); + _E1_EQ_CHECK_LONG(drbf_a->cause.value, drbf_b->cause.value); } } return true; @@ -969,3 +1050,633 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg) { // Do nothing (no dynamic allocation) } + +/* ============================================ + * E1AP Bearer Context Modification Request + * ============================================ */ + +/** @brief Encode PDU Session Item to modify */ +static E1AP_PDU_Session_Resource_To_Modify_Item_t e1_encode_pdu_session_to_mod_item(const pdu_session_to_mod_t *in) +{ + E1AP_PDU_Session_Resource_To_Modify_Item_t out = {0}; + out.pDU_Session_ID = in->sessionId; + for (const DRB_nGRAN_to_mod_t *j = in->DRBnGRanModList; j < in->DRBnGRanModList + in->numDRB2Modify; j++) { + asn1cCalloc(out.dRB_To_Modify_List_NG_RAN, drb2Mod_List); + asn1cSequenceAdd(drb2Mod_List->list, E1AP_DRB_To_Modify_Item_NG_RAN_t, drb2Mod); + drb2Mod->dRB_ID = j->id; + // PDCP Config (O) + if (j->pdcp_config) { + asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration); + *pDCP_Configuration = e1_encode_pdcp_config(j->pdcp_config); + } + // SDAP Config (O) + if (j->sdap_config) { + asn1cCalloc(drb2Mod->sDAP_Configuration, sDAP_Configuration); + *sDAP_Configuration = e1_encode_sdap_config(j->sdap_config); + } + // PDCP SN Status Request (O) + if (j->pdcp_sn_status_requested) { + asn1cCalloc(drb2Mod->pDCP_SN_Status_Request, pDCP_SN_Status_Request); + *pDCP_SN_Status_Request = E1AP_PDCP_SN_Status_Request_requested; + } + // DL UP TNL parameters (O) + if (j->numDlUpParam > 0) { + asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List); + for (const up_params_t *k = j->DlUpParamList; k < j->DlUpParamList + j->numDlUpParam; k++) { + asn1cSequenceAdd(DL_UP_Param_List->list, E1AP_UP_Parameters_Item_t, DL_UP_Param); + DL_UP_Param->uP_TNL_Information = e1_encode_up_tnl_info(&k->tl_info); + DL_UP_Param->cell_Group_ID = k->cell_group_id; + } + } + // QoS Flows to setup (O) + for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { + asn1cCalloc(drb2Mod->flow_Mapping_Information, flow_Mapping_Information); + asn1cSequenceAdd(flow_Mapping_Information->list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2); + *ie1_2 = e1_encode_qos_flow_to_setup(k); + } + } + return out; +} + +/** @brief Common encoding for the NG-RAN System IE */ +static E1AP_NG_RAN_BearerContextModificationRequest_t *encode_ng_ran_to_mod(E1AP_BearerContextModificationRequestIEs_t *ie) +{ + ie->id = E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest; + ie->criticality = E1AP_Criticality_reject; + ie->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest; + E1AP_System_BearerContextModificationRequest_t *reqIE = &ie->value.choice.System_BearerContextModificationRequest; + reqIE->present = E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest; + E1AP_ProtocolIE_Container_4932P26_t *msgNGRAN_list = calloc_or_fail(1, sizeof(*msgNGRAN_list)); + reqIE->choice.nG_RAN_BearerContextModificationRequest = (struct E1AP_ProtocolIE_Container *)msgNGRAN_list; + asn1cSequenceAdd(msgNGRAN_list->list, E1AP_NG_RAN_BearerContextModificationRequest_t, msgNGRAN); + return msgNGRAN; +} + +/** @brief Encode PDU Session Resource To Setup Modification List item */ +static E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t e1_encode_pdu_session_to_setup_mod_item(const pdu_session_to_setup_t *in) +{ + E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t item = {0}; + // PDU Session ID (M) + item.pDU_Session_ID = in->sessionId; + // PDU Session Type (M) + item.pDU_Session_Type = in->sessionType; + // SNSSAI (M) + item.sNSSAI = e1_encode_snssai(&in->nssai); + // Security indication (M) + item.securityIndication = e1_encode_security_indication(&in->securityIndication); + // NG UL UP Transport Layer Information (M) + item.nG_UL_UP_TNL_Information = e1_encode_up_tnl_info(&in->UP_TL_information); + // DRB to setup + for (const DRB_nGRAN_to_setup_t *j = in->DRBnGRanList; j < in->DRBnGRanList + in->numDRB2Setup; j++) { + asn1cSequenceAdd(item.dRB_To_Setup_Mod_List_NG_RAN.list, E1AP_DRB_To_Setup_Mod_Item_NG_RAN_t, ie1); + // DRB ID (M) + ie1->dRB_ID = j->id; + // SDAP Config (M) + ie1->sDAP_Configuration = e1_encode_sdap_config(&j->sdap_config); + // PDCP Config (M) + ie1->pDCP_Configuration = e1_encode_pdcp_config(&j->pdcp_config); + // Cell Group Information (M) + for (const cell_group_id_t *k = j->cellGroupList; k < j->cellGroupList + j->numCellGroups; k++) { + asn1cSequenceAdd(ie1->cell_Group_Information.list, E1AP_Cell_Group_Information_Item_t, ie1_1); + ie1_1->cell_Group_ID = *k; + } + // QoS Flows Information To Be Setup (M) + for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) { + asn1cSequenceAdd(ie1->flow_Mapping_Information.list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2); + *ie1_2 = e1_encode_qos_flow_to_setup(k); + } + } + return item; +} + +/** + * @brief Encodes the E1 Bearer Modification Request message + */ +E1AP_E1AP_PDU_t *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *in) +{ + E1AP_E1AP_PDU_t *pdu = calloc_or_fail(1, sizeof(*pdu)); + + // PDU Type + pdu->present = E1AP_E1AP_PDU_PR_initiatingMessage; + asn1cCalloc(pdu->choice.initiatingMessage, msg); + msg->procedureCode = E1AP_ProcedureCode_id_bearerContextModification; + msg->criticality = E1AP_Criticality_reject; + msg->value.present = E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest; + + E1AP_BearerContextModificationRequest_t *out = &msg->value.choice.BearerContextModificationRequest; + + // gNB-CU-CP UE E1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie1); + ie1->id = E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID; + ie1->criticality = E1AP_Criticality_reject; + ie1->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID; + ie1->value.choice.GNB_CU_CP_UE_E1AP_ID = in->gNB_cu_cp_ue_id; + + // gNB-CU-UP UE E1AP ID (M) + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie2); + ie2->id = E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID; + ie2->criticality = E1AP_Criticality_reject; + ie2->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID; + ie2->value.choice.GNB_CU_UP_UE_E1AP_ID = in->gNB_cu_up_ue_id; + + // Security Information (O) + if (in->secInfo) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie3); + ie3->id = E1AP_ProtocolIE_ID_id_SecurityInformation; + ie3->criticality = E1AP_Criticality_reject; + ie3->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_SecurityInformation; + ie3->value.choice.SecurityInformation = e1_encode_security_info(in->secInfo); + } + + // UE DL Aggregate Maximum Bit Rate (O) + if (in->ueDlAggMaxBitRate) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie4); + ie4->id = E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate; + ie4->criticality = E1AP_Criticality_reject; + ie4->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BitRate; + INT32_TO_OCTET_STRING(*in->ueDlAggMaxBitRate, &ie4->value.choice.BitRate); + } + + // UE DL Maximum Integrity Protected Data Rate (O) + if (in->ueDlMaxIPBitRate) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie5); + ie5->id = E1AP_ProtocolIE_ID_id_UEDLMaximumIntegrityProtectedDataRate; + ie5->criticality = E1AP_Criticality_ignore; + ie5->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BitRate; + INT32_TO_OCTET_STRING(*in->ueDlMaxIPBitRate, &ie5->value.choice.BitRate); + } + + // Bearer Context Status Change (O) + if (in->bearerContextStatus && *in->bearerContextStatus == BEARER_SUSPEND) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie6); + ie6->id = E1AP_ProtocolIE_ID_id_BearerContextStatusChange; + ie6->criticality = E1AP_Criticality_reject; + ie6->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange; + ie6->value.choice.BearerContextStatusChange = E1AP_BearerContextStatusChange_suspend; + } + + // UE Inactivity Timer (O) + if (in->inactivityTimer) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie7); + ie7->id = E1AP_ProtocolIE_ID_id_UE_Inactivity_Timer; + ie7->criticality = E1AP_Criticality_ignore; + ie7->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_Inactivity_Timer; + ie7->value.choice.Inactivity_Timer = *in->inactivityTimer; + } + + // Data Discard Required (O) + if (in->dataDiscardRequired) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, ie9); + ie9->id = E1AP_ProtocolIE_ID_id_DataDiscardRequired; + ie9->criticality = E1AP_Criticality_ignore; + ie9->value.present = E1AP_BearerContextModificationRequestIEs__value_PR_DataDiscardRequired; + ie9->value.choice.DataDiscardRequired = in->dataDiscardRequired; + } + + // NG-RAN PDU Session Resource To Setup List (O) + if (in->numPDUSessions) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, setupList); + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(setupList); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Setup_Mod_List; + E1AP_PDU_Session_Resource_To_Setup_Mod_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_Mod_List; + for (int i = 0; i < in->numPDUSessions; i++) { + const pdu_session_to_setup_t *pdu_session = &in->pduSession[i]; + asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t, item); + *item = e1_encode_pdu_session_to_setup_mod_item(pdu_session); + } + } + + // NG-RAN PDU Session Resource To Modify List (O) + if (in->numPDUSessionsMod) { + asn1cSequenceAdd(out->protocolIEs.list, E1AP_BearerContextModificationRequestIEs_t, modList); + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = encode_ng_ran_to_mod(modList); + msgNGRAN->id = E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List; + msgNGRAN->criticality = E1AP_Criticality_reject; + msgNGRAN->value.present = E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List; + E1AP_PDU_Session_Resource_To_Modify_List_t *pdu2Setup = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List; + for (const pdu_session_to_mod_t *i = in->pduSessionMod; i < in->pduSessionMod + in->numPDUSessionsMod; i++) { + asn1cSequenceAdd(pdu2Setup->list, E1AP_PDU_Session_Resource_To_Modify_Item_t, ieC3_1); + *ieC3_1 = e1_encode_pdu_session_to_mod_item(i); + } + } + return pdu; +} + +/** @brief Decode PDU Session Item to Setup (Bearer Context Modification Request) */ +static bool e1_decode_pdu_session_to_setup_mod_item(pdu_session_to_setup_t *out, + const E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t *item) +{ + // PDU Session ID (M) + out->sessionId = item->pDU_Session_ID; + // PDU Session Type (M) + out->sessionType = item->pDU_Session_Type; + // S-NSSAI (M) + CHECK_E1AP_DEC(e1_decode_snssai(&out->nssai, &item->sNSSAI)); + // Security Indication (M) + CHECK_E1AP_DEC(e1_decode_security_indication(&out->securityIndication, &item->securityIndication)); + /* NG UL UP Transport Layer Information (M) */ + _E1_EQ_CHECK_INT(item->nG_UL_UP_TNL_Information.present, E1AP_UP_TNL_Information_PR_gTPTunnel); + CHECK_E1AP_DEC(e1_decode_up_tnl_info(&out->UP_TL_information, &item->nG_UL_UP_TNL_Information)); + /* DRB To Setup List ( > 1 item ) */ + const E1AP_DRB_To_Setup_Mod_List_NG_RAN_t *drb2SetupList = &item->dRB_To_Setup_Mod_List_NG_RAN; + _E1_EQ_CHECK_GENERIC(drb2SetupList->list.count > 0, "%d", drb2SetupList->list.count, 0); + out->numDRB2Setup = drb2SetupList->list.count; + _E1_EQ_CHECK_INT(out->numDRB2Setup, 1); // can only handle one DRB per PDU session + for (int j = 0; j < drb2SetupList->list.count; j++) { + DRB_nGRAN_to_setup_t *drb = out->DRBnGRanList + j; + const E1AP_DRB_To_Setup_Mod_Item_NG_RAN_t *drb2Setup = drb2SetupList->list.array[j]; + // DRB ID (M) + drb->id = drb2Setup->dRB_ID; + // SDAP Configuration (M) + CHECK_E1AP_DEC(e1_decode_sdap_config(&drb->sdap_config, &drb2Setup->sDAP_Configuration)); + // PDCP Configuration (M) + CHECK_E1AP_DEC(e1_decode_pdcp_config(&drb->pdcp_config, &drb2Setup->pDCP_Configuration)); + // Cell Group Information (M) + const E1AP_Cell_Group_Information_t *cellGroupList = &drb2Setup->cell_Group_Information; + _E1_EQ_CHECK_GENERIC(cellGroupList->list.count > 0, "%d", cellGroupList->list.count, 0); + drb->numCellGroups = cellGroupList->list.count; + for (int k = 0; k < cellGroupList->list.count; k++) { + const E1AP_Cell_Group_Information_Item_t *cg2Setup = cellGroupList->list.array[k]; + // Cell Group ID + drb->cellGroupList[k] = cg2Setup->cell_Group_ID; + } + // QoS Flows Information To Be Setup (M) + const E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = &drb2Setup->flow_Mapping_Information; + drb->numQosFlow2Setup = qos2SetupList->list.count; + for (int k = 0; k < qos2SetupList->list.count; k++) { + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); + } + } + return true; +} + + +/** @brief Decode PDU Session Item to modify (Bearer Context Modification Request) */ +static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E1AP_PDU_Session_Resource_To_Modify_Item_t *in) +{ + // PDU Session ID + out->sessionId = in->pDU_Session_ID; + // DRB to modify list + E1AP_DRB_To_Modify_List_NG_RAN_t *drb2ModList = in->dRB_To_Modify_List_NG_RAN; + out->numDRB2Modify = drb2ModList->list.count; + for (int j = 0; j < drb2ModList->list.count; j++) { + DRB_nGRAN_to_mod_t *drb = out->DRBnGRanModList + j; + // DRB to modify item + E1AP_DRB_To_Modify_Item_NG_RAN_t *drb2Mod = drb2ModList->list.array[j]; + drb->id = drb2Mod->dRB_ID; + // PDCP Config (O) + if (drb2Mod->pDCP_Configuration) { + drb->pdcp_config = malloc_or_fail(sizeof(*drb->pdcp_config)); + CHECK_E1AP_DEC(e1_decode_pdcp_config(drb->pdcp_config, drb2Mod->pDCP_Configuration)); + } + // SDAP Config (O) + if (drb2Mod->sDAP_Configuration) { + drb->sdap_config = malloc_or_fail(sizeof(*drb->sdap_config)); + CHECK_E1AP_DEC(e1_decode_sdap_config(drb->sdap_config, drb2Mod->sDAP_Configuration)); + } + // PDCP SN Status Request (O) + if (drb2Mod->pDCP_SN_Status_Request) { + drb->pdcp_sn_status_requested = true; + } + // DL UP TNL parameters (O) + if (drb2Mod->dL_UP_Parameters) { + E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; + if((drb->numDlUpParam = decode_dl_up_parameters(drb->DlUpParamList, dl_up_paramList)) < 0) { + PRINT_ERROR("Failed to decode DL UP TNL parameters\n"); + return false; + } + } + // QoS Flows Information To Be Setup (O) + E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = drb2Mod->flow_Mapping_Information; + drb->numQosFlow2Setup = qos2SetupList->list.count; + for (int k = 0; k < qos2SetupList->list.count; k++) { + CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k])); + } + } + return true; +} + + +/** + * @brief E1 Bearer Modification Request message decoding + */ +bool decode_E1_bearer_context_mod_request(const E1AP_E1AP_PDU_t *pdu, e1ap_bearer_mod_req_t *out) +{ + DevAssert(pdu != NULL); + // Validate message type + _E1_EQ_CHECK_INT(pdu->present, E1AP_E1AP_PDU_PR_initiatingMessage); + const E1AP_InitiatingMessage_t *im = pdu->choice.initiatingMessage; + _E1_EQ_CHECK_LONG(im->procedureCode, E1AP_ProcedureCode_id_bearerContextModification); + _E1_EQ_CHECK_INT(im->value.present, E1AP_InitiatingMessage__value_PR_BearerContextModificationRequest); + + const E1AP_BearerContextModificationRequest_t *in = &im->value.choice.BearerContextModificationRequest; + E1AP_BearerContextModificationRequestIEs_t *ie = NULL; + + // Mandatory IEs + // gNB-CU-CP UE E1AP ID (M) + E1AP_LIB_FIND_IE(E1AP_BearerContextModificationRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID, true); + // gNB-CU-UP UE E1AP ID (M) + E1AP_LIB_FIND_IE(E1AP_BearerContextModificationRequestIEs_t, ie, in, E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID, true); + + // Loop through all IEs and extract + for (int i = 0; i < in->protocolIEs.list.count; i++) { + ie = in->protocolIEs.list.array[i]; + + switch (ie->id) { + case E1AP_ProtocolIE_ID_id_gNB_CU_CP_UE_E1AP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_CP_UE_E1AP_ID); + out->gNB_cu_cp_ue_id = ie->value.choice.GNB_CU_CP_UE_E1AP_ID; + break; + + case E1AP_ProtocolIE_ID_id_gNB_CU_UP_UE_E1AP_ID: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_GNB_CU_UP_UE_E1AP_ID); + out->gNB_cu_up_ue_id = ie->value.choice.GNB_CU_UP_UE_E1AP_ID; + break; + + case E1AP_ProtocolIE_ID_id_SecurityInformation: + out->secInfo = malloc_or_fail(sizeof(*out->secInfo)); + CHECK_E1AP_DEC(e1_decode_security_info(out->secInfo, &ie->value.choice.SecurityInformation)); + break; + + case E1AP_ProtocolIE_ID_id_UEDLAggregateMaximumBitRate: + out->ueDlAggMaxBitRate = malloc_or_fail(sizeof(*out->ueDlAggMaxBitRate)); + OCTET_STRING_TO_UINT32(&ie->value.choice.BitRate, *out->ueDlAggMaxBitRate); + break; + + case E1AP_ProtocolIE_ID_id_UEDLMaximumIntegrityProtectedDataRate: + out->ueDlMaxIPBitRate = malloc_or_fail(sizeof(*out->ueDlMaxIPBitRate)); + OCTET_STRING_TO_UINT32(&ie->value.choice.BitRate, *out->ueDlMaxIPBitRate); + break; + + case E1AP_ProtocolIE_ID_id_BearerContextStatusChange: + _E1_EQ_CHECK_INT(ie->value.present, E1AP_BearerContextModificationRequestIEs__value_PR_BearerContextStatusChange); + if (ie->value.choice.BearerContextStatusChange == E1AP_BearerContextStatusChange_suspend) { + out->bearerContextStatus = malloc_or_fail(sizeof(*out->bearerContextStatus)); + *out->bearerContextStatus = BEARER_SUSPEND; + } + break; + + case E1AP_ProtocolIE_ID_id_UE_Inactivity_Timer: + out->inactivityTimer = malloc_or_fail(sizeof(*out->inactivityTimer)); + *out->inactivityTimer = ie->value.choice.Inactivity_Timer; + break; + + case E1AP_ProtocolIE_ID_id_DataDiscardRequired: + out->dataDiscardRequired = ie->value.choice.DataDiscardRequired; + break; + + case E1AP_ProtocolIE_ID_id_System_BearerContextModificationRequest: { + _E1_EQ_CHECK_INT(ie->value.present, + E1AP_BearerContextModificationRequestIEs__value_PR_System_BearerContextModificationRequest); + E1AP_System_BearerContextModificationRequest_t *modReq = &ie->value.choice.System_BearerContextModificationRequest; + DevAssert(ie->value.choice.System_BearerContextModificationRequest.choice.nG_RAN_BearerContextModificationRequest != NULL); + // System IE can contain either UTRAN or NG-RAN + switch (modReq->present) { + case E1AP_System_BearerContextModificationRequest_PR_NOTHING: + PRINT_ERROR("System Bearer Context Setup Request: no choice present\n"); + break; + case E1AP_System_BearerContextModificationRequest_PR_e_UTRAN_BearerContextModificationRequest: + PRINT_ERROR("UTRAN in E1 Setup Modification Request not supported\n"); + return false; + break; + case E1AP_System_BearerContextModificationRequest_PR_nG_RAN_BearerContextModificationRequest: + // NG-RAN + AssertFatal(modReq->choice.nG_RAN_BearerContextModificationRequest != NULL, + "System_BearerContextSetupRequest->choice.nG_RAN_BearerContextSetupRequest shall not be null"); + E1AP_ProtocolIE_Container_4932P26_t *msgNGRAN_list = + (E1AP_ProtocolIE_Container_4932P26_t *)modReq->choice.nG_RAN_BearerContextModificationRequest; + // loop through all items in the NG-RAN list (to setup, to modify, etc) + for (int i = 0; i < msgNGRAN_list->list.count; i++) { + E1AP_NG_RAN_BearerContextModificationRequest_t *msgNGRAN = msgNGRAN_list->list.array[i]; + switch (msgNGRAN->id) { + case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List: + _E1_EQ_CHECK_LONG(msgNGRAN->id, E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Setup_Mod_List); + _E1_EQ_CHECK_INT(msgNGRAN->value.present, + E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Setup_Mod_List); + E1AP_PDU_Session_Resource_To_Setup_Mod_List_t *setupList = + &msgNGRAN->value.choice.PDU_Session_Resource_To_Setup_Mod_List; + // PDU Session Resource To Modify List + out->numPDUSessions = setupList->list.count; + // Loop through all PDU sessions + for (int i = 0; i < setupList->list.count; i++) { + pdu_session_to_setup_t *pdu_session = out->pduSession + i; + E1AP_PDU_Session_Resource_To_Setup_Mod_Item_t *pdu2Setup = setupList->list.array[i]; + CHECK_E1AP_DEC(e1_decode_pdu_session_to_setup_mod_item(pdu_session, pdu2Setup)); + } + break; + case E1AP_ProtocolIE_ID_id_PDU_Session_Resource_To_Modify_List: + /* PDU Session Resource To Modify List (see 9.3.3.11 of TS 38.463) */ + _E1_EQ_CHECK_INT(msgNGRAN->value.present, + E1AP_NG_RAN_BearerContextModificationRequest__value_PR_PDU_Session_Resource_To_Modify_List); + E1AP_PDU_Session_Resource_To_Modify_List_t *modList = &msgNGRAN->value.choice.PDU_Session_Resource_To_Modify_List; + out->numPDUSessionsMod = modList->list.count; + // Loop through all PDU sessions + for (int i = 0; i < modList->list.count; i++) { + CHECK_E1AP_DEC(e1_decode_pdu_session_to_mod_item(out->pduSessionMod + i, modList->list.array[i])); + } + break; + default: + PRINT_ERROR("Unknown msgNGRAN->id in E1 Setup Modification Request\n"); + return false; + break; + } + } + + break; + default: + PRINT_ERROR("System Bearer Context Modification Request: No valid choice present.\n"); + break; + } + + break; + } + + default: + PRINT_ERROR("System Bearer Context Modification Request: this IE is not implemented (or) invalid IE detected\n"); + return false; + break; + } + } + + return true; +} + +/** @brief Deep copy for DRB Item to modify */ +static DRB_nGRAN_to_mod_t cp_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) +{ + DRB_nGRAN_to_mod_t cp = {0}; + // shallow copy + cp = *msg; + _E1_CP_OPTIONAL_IE(&cp, msg, sdap_config); + _E1_CP_OPTIONAL_IE(&cp, msg, pdcp_config); + return cp; +} + +/** @brief Deep copy for PDU Session Item to modify */ +static pdu_session_to_mod_t cp_pdu_session_to_mod_item(const pdu_session_to_mod_t *msg) +{ + pdu_session_to_mod_t cp = {0}; + // shallow copy + cp = *msg; + // DRB to setup list + for (int j = 0; j < msg->numDRB2Setup; j++) + cp.DRBnGRanList[j] = cp_drb_to_setup_item(&msg->DRBnGRanList[j]); + // DRB to modify list + for (int j = 0; j < msg->numDRB2Modify; j++) + cp.DRBnGRanModList[j] = cp_drb_to_mod_item(&msg->DRBnGRanModList[j]); + _E1_CP_OPTIONAL_IE(&cp, msg, securityIndication); + _E1_CP_OPTIONAL_IE(&cp, msg, UP_TL_information); + return cp; +} + +/** @brief Deep copy for Bearer Context Modification Request */ +e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg) +{ + e1ap_bearer_mod_req_t cp = {0}; + // Shallow copy + cp = *msg; + // Deep copy for optional fields + _E1_CP_OPTIONAL_IE(&cp, msg, secInfo); + _E1_CP_OPTIONAL_IE(&cp, msg, bearerContextStatus); + _E1_CP_OPTIONAL_IE(&cp, msg, inactivityTimer); + // Deep copy PDU sessions + for (int i = 0; i < msg->numPDUSessions; i++) + cp.pduSession[i] = cp_pdu_session_item(&msg->pduSession[i]); + for (int i = 0; i < msg->numPDUSessionsMod; i++) + cp.pduSessionMod[i] = cp_pdu_session_to_mod_item(&msg->pduSessionMod[i]); + return cp; +} + +/** @brief Equality check for Security Indication IE (3GPP TS 38.463 9.3.1.23) */ +static bool eq_security_ind(security_indication_t *a, security_indication_t *b) +{ + _E1_EQ_CHECK_INT(a->confidentialityProtectionIndication, b->confidentialityProtectionIndication); + _E1_EQ_CHECK_INT(a->integrityProtectionIndication, b->integrityProtectionIndication); + _E1_EQ_CHECK_LONG(a->maxIPrate, b->maxIPrate); + return true; +} + +/** + * @brief Equality check for DRB_nGRAN_to_mod_t + */ +static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b) +{ + bool result = true; + _E1_EQ_CHECK_LONG(a->id, b->id); + _E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup); + for (int i = 0; i < a->numQosFlow2Setup; i++) { + result &= eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]); + } + _E1_EQ_CHECK_INT(a->numDlUpParam, b->numDlUpParam); + for (int i = 0; i < a->numDlUpParam; i++) { + _E1_EQ_CHECK_INT(a->DlUpParamList[i].cell_group_id, b->DlUpParamList[i].cell_group_id); + eq_up_tl_info(&a->DlUpParamList[i].tl_info, &b->DlUpParamList[i].tl_info); + } + if (a->pdcp_config && b->pdcp_config) + result &= eq_pdcp_config(a->pdcp_config, b->pdcp_config); + if (a->sdap_config && b->sdap_config) + result &= eq_sdap_config(a->sdap_config, b->sdap_config); + return result; +} + +/** @brief Equality check for PDU session item to modify */ +static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_session_to_mod_t *b) +{ + _E1_EQ_CHECK_LONG(a->sessionId, b->sessionId); + if (a->UP_TL_information && a->UP_TL_information) { + if (!eq_up_tl_info(a->UP_TL_information, b->UP_TL_information)) + return false; + } + _E1_EQ_CHECK_INT(a->numDRB2Setup, b->numDRB2Setup); + for (int i = 0; i < a->numDRB2Setup; i++) { + if (!eq_drb_to_setup(&a->DRBnGRanList[i], &b->DRBnGRanList[i])) + return false; + } + _E1_EQ_CHECK_LONG(a->numDRB2Modify, b->numDRB2Modify); + for (int i = 0; i < a->numDRB2Modify; i++) { + if (!eq_drb_to_mod(&a->DRBnGRanModList[i], &b->DRBnGRanModList[i])) + return false; + } + if (a->securityIndication && b->securityIndication) { + eq_security_ind(a->securityIndication, b->securityIndication); + } + return true; +} + +/** + * @brief E1AP Bearer Modification Request equality check + */ +bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_bearer_mod_req_t *b) +{ + // basic members + _E1_EQ_CHECK_INT(a->gNB_cu_cp_ue_id, b->gNB_cu_cp_ue_id); + _E1_EQ_CHECK_INT(a->gNB_cu_up_ue_id, b->gNB_cu_up_ue_id); + _E1_EQ_CHECK_INT(a->numPDUSessions, b->numPDUSessions); + _E1_EQ_CHECK_INT(a->numPDUSessionsMod, b->numPDUSessionsMod); + // Security Info + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, secInfo); + if (a->secInfo && b->secInfo) { + _E1_EQ_CHECK_LONG(a->secInfo->cipheringAlgorithm, b->secInfo->cipheringAlgorithm); + _E1_EQ_CHECK_LONG(a->secInfo->integrityProtectionAlgorithm, b->secInfo->integrityProtectionAlgorithm); + _E1_EQ_CHECK_STR(a->secInfo->encryptionKey, b->secInfo->encryptionKey); + _E1_EQ_CHECK_STR(a->secInfo->integrityProtectionKey, b->secInfo->integrityProtectionKey); + } + // Bearer Context Status (O) + _E1_EQ_CHECK_OPTIONAL_IE(a, b, bearerContextStatus, _E1_EQ_CHECK_INT); + // Inactivity Timer (O) + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, inactivityTimer); + if (a->inactivityTimer && b->inactivityTimer) + _E1_EQ_CHECK_INT(*a->inactivityTimer, *b->inactivityTimer); + // Activity Notification Level (O) + // PDU Sessions + if (a->numPDUSessions != b->numPDUSessions) + return false; + for (int i = 0; i < a->numPDUSessions; i++) { + if (!eq_pdu_session_item(&a->pduSession[i], &b->pduSession[i])) + return false; + } + // Modified PDU Sessions + if (a->numPDUSessionsMod != b->numPDUSessionsMod) + return false; + for (int i = 0; i < a->numPDUSessionsMod; i++) { + if (!eq_pdu_session_to_mod_item(&a->pduSessionMod[i], &b->pduSessionMod[i])) + return false; + } + return true; +} + +/* Free DRB to modify item */ +static void free_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) +{ + free(msg->pdcp_config); + free(msg->sdap_config); +} + +/* Free PDU Session to modify item */ +void free_pdu_session_to_mod_item(const pdu_session_to_mod_t *msg) +{ + free(msg->securityIndication); + free(msg->UP_TL_information); + for (int i = 0; i < msg->numDRB2Modify; i++) + free_drb_to_mod_item(&msg->DRBnGRanModList[i]); + for (int i = 0; i < msg->numDRB2Setup; i++) + free_drb_to_setup_item(&msg->DRBnGRanList[i]); +} + +/** + * @brief E1AP Bearer Context Modification Request memory management + */ +void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg) +{ + free(msg->secInfo); + free(msg->ueDlAggMaxBitRate); + free(msg->ueDlMaxIPBitRate); + free(msg->bearerContextStatus); + free(msg->inactivityTimer); + for (int i = 0; i < msg->numPDUSessions; i++) + free_pdu_session_to_setup_item(&msg->pduSession[i]); + for (int i = 0; i < msg->numPDUSessionsMod; i++) + free_pdu_session_to_mod_item(&msg->pduSessionMod[i]); +} diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.h b/openair2/E1AP/lib/e1ap_bearer_context_management.h index 95e4cb0e15..132c1857e1 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.h +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.h @@ -40,4 +40,10 @@ void free_e1ap_context_setup_response(const e1ap_bearer_setup_resp_t *msg); e1ap_bearer_setup_resp_t cp_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *msg); bool eq_bearer_context_setup_response(const e1ap_bearer_setup_resp_t *a, const e1ap_bearer_setup_resp_t *b); +struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg); +bool decode_E1_bearer_context_mod_request(const struct E1AP_E1AP_PDU *pdu, e1ap_bearer_mod_req_t *out); +void free_e1ap_context_mod_request(const e1ap_bearer_mod_req_t *msg); +e1ap_bearer_mod_req_t cp_bearer_context_mod_request(const e1ap_bearer_mod_req_t *msg); +bool eq_bearer_context_mod_request(const e1ap_bearer_mod_req_t *a, const e1ap_bearer_mod_req_t *b); + #endif /* E1AP_BEARER_CONTEXT_MANAGEMENT_H_ */ diff --git a/openair2/E1AP/lib/e1ap_interface_management.c b/openair2/E1AP/lib/e1ap_interface_management.c index 8f29ba07c5..681942f58b 100644 --- a/openair2/E1AP/lib/e1ap_interface_management.c +++ b/openair2/E1AP/lib/e1ap_interface_management.c @@ -508,61 +508,6 @@ bool eq_e1ap_cuup_setup_response(const e1ap_setup_resp_t *a, const e1ap_setup_re * GNB-CU-UP E1 SETUP FAILURE * ==================================== */ -static E1AP_Cause_t encode_e1ap_cause_ie(const e1ap_cause_t *cause) -{ - E1AP_Cause_t ie; - switch (cause->type) { - case E1AP_CAUSE_RADIO_NETWORK: - ie.present = E1AP_Cause_PR_radioNetwork; - ie.choice.radioNetwork = cause->value; - break; - case E1AP_CAUSE_TRANSPORT: - ie.present = E1AP_Cause_PR_transport; - ie.choice.transport = cause->value; - break; - case E1AP_CAUSE_PROTOCOL: - ie.present = E1AP_Cause_PR_protocol; - ie.choice.protocol = cause->value; - break; - case E1AP_CAUSE_MISC: - ie.present = E1AP_Cause_PR_misc; - ie.choice.misc = cause->value; - break; - default: - ie.present = E1AP_Cause_PR_NOTHING; - break; - } - return ie; -} - -static e1ap_cause_t decode_e1ap_cause_ie(const E1AP_Cause_t *ie) -{ - e1ap_cause_t cause; - // Decode the 'choice' field based on the 'present' value - switch (ie->present) { - case E1AP_Cause_PR_radioNetwork: - cause.value = ie->choice.radioNetwork; - cause.type = E1AP_CAUSE_RADIO_NETWORK; - break; - case E1AP_Cause_PR_transport: - cause.value = ie->choice.transport; - cause.type = E1AP_CAUSE_TRANSPORT; - break; - case E1AP_Cause_PR_protocol: - cause.value = ie->choice.protocol; - cause.type = E1AP_CAUSE_PROTOCOL; - break; - case E1AP_Cause_PR_misc: - cause.value = ie->choice.misc; - cause.type = E1AP_CAUSE_MISC; - break; - default: - cause.type = E1AP_CAUSE_NOTHING; - break; - } - return cause; -} - /** * @brief Encoder for GNB-CU-UP E1 Setup Failure * @ref 9.2.1.6 GNB-CU-UP E1 SETUP FAILURE of 3GPP TS 38.463 @@ -588,7 +533,7 @@ E1AP_E1AP_PDU_t *encode_e1ap_cuup_setup_failure(const e1ap_setup_fail_t *msg) ie2->id = E1AP_ProtocolIE_ID_id_Cause; ie2->criticality = E1AP_Criticality_ignore; ie2->value.present = E1AP_GNB_CU_UP_E1SetupFailureIEs__value_PR_Cause; - ie2->value.choice.Cause = encode_e1ap_cause_ie(&msg->cause); + ie2->value.choice.Cause = e1_encode_cause_ie(&msg->cause); // Time To Wait (O) if (msg->time_to_wait) { asn1cSequenceAdd(out->protocolIEs.list, E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie3); @@ -630,7 +575,7 @@ bool decode_e1ap_cuup_setup_failure(const E1AP_E1AP_PDU_t *pdu, e1ap_setup_fail_ case E1AP_ProtocolIE_ID_id_Cause: // Cause E1AP_LIB_FIND_IE(E1AP_GNB_CU_UP_E1SetupFailureIEs_t, ie, in, E1AP_ProtocolIE_ID_id_Cause, true); - out->cause = decode_e1ap_cause_ie(&ie->value.choice.Cause); + out->cause = e1_decode_cause_ie(&ie->value.choice.Cause); break; case E1AP_ProtocolIE_ID_id_Transport_Layer_Address_Info: // Time To Wait (O) diff --git a/openair2/E1AP/lib/e1ap_lib_common.c b/openair2/E1AP/lib/e1ap_lib_common.c new file mode 100644 index 0000000000..02923b7cf7 --- /dev/null +++ b/openair2/E1AP/lib/e1ap_lib_common.c @@ -0,0 +1,81 @@ +/* + * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The OpenAirInterface Software Alliance licenses this file to You under + * the OAI Public License, Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.openairinterface.org/?page_id=698 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *------------------------------------------------------------------------------- + * For more information about the OpenAirInterface (OAI) Software Alliance: + * contact@openairinterface.org + */ + +#include "e1ap_lib_common.h" +#include "e1ap_lib_includes.h" +#include "e1ap_messages_types.h" + +E1AP_Cause_t e1_encode_cause_ie(const e1ap_cause_t *cause) +{ + E1AP_Cause_t ie; + switch (cause->type) { + case E1AP_CAUSE_RADIO_NETWORK: + ie.present = E1AP_Cause_PR_radioNetwork; + ie.choice.radioNetwork = cause->value; + break; + case E1AP_CAUSE_TRANSPORT: + ie.present = E1AP_Cause_PR_transport; + ie.choice.transport = cause->value; + break; + case E1AP_CAUSE_PROTOCOL: + ie.present = E1AP_Cause_PR_protocol; + ie.choice.protocol = cause->value; + break; + case E1AP_CAUSE_MISC: + ie.present = E1AP_Cause_PR_misc; + ie.choice.misc = cause->value; + break; + default: + ie.present = E1AP_Cause_PR_NOTHING; + PRINT_ERROR("encode_e1ap_cause_ie: no cause value provided\n"); + break; + } + return ie; +} + +e1ap_cause_t e1_decode_cause_ie(const E1AP_Cause_t *ie) +{ + e1ap_cause_t cause; + // Decode the 'choice' field based on the 'present' value + switch (ie->present) { + case E1AP_Cause_PR_radioNetwork: + cause.value = ie->choice.radioNetwork; + cause.type = E1AP_CAUSE_RADIO_NETWORK; + break; + case E1AP_Cause_PR_transport: + cause.value = ie->choice.transport; + cause.type = E1AP_CAUSE_TRANSPORT; + break; + case E1AP_Cause_PR_protocol: + cause.value = ie->choice.protocol; + cause.type = E1AP_CAUSE_PROTOCOL; + break; + case E1AP_Cause_PR_misc: + cause.value = ie->choice.misc; + cause.type = E1AP_CAUSE_MISC; + break; + default: + cause.type = E1AP_CAUSE_NOTHING; + PRINT_ERROR("decode_e1ap_cause_ie: no cause value provided\n"); + break; + } + return cause; +} diff --git a/openair2/E1AP/lib/e1ap_lib_common.h b/openair2/E1AP/lib/e1ap_lib_common.h index f3c6b24da2..6fda2cd8ca 100644 --- a/openair2/E1AP/lib/e1ap_lib_common.h +++ b/openair2/E1AP/lib/e1ap_lib_common.h @@ -26,13 +26,22 @@ #include #include #include "openair3/UTILS/conversions.h" +#include "e1ap_messages_types.h" -#ifdef ENABLE_TESTS +#ifdef E1AP_LOG_ERRORS #define PRINT_ERROR(...) fprintf(stderr, ##__VA_ARGS__); #else #define PRINT_ERROR(...) // Do nothing #endif +#define CHECK_E1AP_DEC(exp) \ + do { \ + if (!(exp)) { \ + PRINT_ERROR("Failed executing " #exp " in %s() line %d\n", __func__, __LINE__); \ + return false; \ + } \ + } while (0) + #define _E1_EQ_CHECK_GENERIC(condition, fmt, ...) \ do { \ if (!(condition)) { \ @@ -66,4 +75,40 @@ } \ } while (0) +/* deep copy of optional E1AP IE */ +#define _E1_CP_OPTIONAL_IE(dest, src, field) \ + do { \ + if ((src)->field) { \ + (dest)->field = malloc_or_fail(sizeof(*(dest)->field)); \ + *(dest)->field = *(src)->field; \ + } \ + } while (0) + +#define _E1_EQ_CHECK_OPTIONAL_IE(a, b, field, EQ_MACRO) \ + do { \ + if (((a)->field && !(b)->field) || (!(a)->field && (b)->field)) { \ + return false; /* One of the two is not allocated */ \ + } \ + if ((a)->field && (b)->field) { \ + EQ_MACRO(*(a)->field, *(b)->field) \ + } \ + } while (0) + +#define _E1_EQ_CHECK_OPTIONAL_PTR(a, b, field) \ + do { \ + if (((a)->field && !(b)->field) || (!(a)->field && (b)->field)) { \ + PRINT_ERROR("%s:%d: optional IE '%s' not allocated: %p, %p\n", \ + __FILE__, \ + __LINE__, \ + #field, \ + (void *)(a)->field, \ + (void *)(b)->field); \ + return false; /* One of the two is not allocated */ \ + } \ + } while (0) + +struct E1AP_Cause; +struct E1AP_Cause e1_encode_cause_ie(const e1ap_cause_t *cause); +e1ap_cause_t e1_decode_cause_ie(const struct E1AP_Cause *ie); + #endif /* E1AP_LIB_COMMON_H_ */ diff --git a/openair2/E1AP/lib/e1ap_lib_includes.h b/openair2/E1AP/lib/e1ap_lib_includes.h index 443d59e19e..46d09f5aa9 100644 --- a/openair2/E1AP/lib/e1ap_lib_includes.h +++ b/openair2/E1AP/lib/e1ap_lib_includes.h @@ -48,6 +48,7 @@ #include "E1AP_System-BearerContextSetupRequest.h" #include "E1AP_MaximumIPdatarate.h" #include "E1AP_PDU-Session-Type.h" +#include "E1AP_Data-Forwarding-Information.h" // E1 Bearer Context Setup Response #include "E1AP_PDU-Session-Resource-Setup-Item.h" #include "E1AP_DRB-Setup-Item-NG-RAN.h" @@ -66,5 +67,11 @@ #include "E1AP_Transport-UP-Layer-Addresses-Info-To-Remove-Item.h" #include "E1AP_GTPTLAs.h" #include "E1AP_GTPTLA-Item.h" +// E1 Bearer Context Modification Request +#include "E1AP_PDU-Session-Resource-To-Modify-Item.h" +#include "E1AP_DRB-To-Modify-List-NG-RAN.h" +#include "E1AP_DRB-To-Modify-Item-NG-RAN.h" +#include "E1AP_PDU-Session-Resource-To-Setup-Mod-Item.h" +#include "E1AP_DRB-To-Setup-Mod-Item-NG-RAN.h" #endif /* E1AP_LIB_INCLUDES_H_ */ diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index 91eab080a9..59e6f08e66 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -70,6 +70,14 @@ static void e1ap_msg_free(E1AP_E1AP_PDU_t *pdu) ASN_STRUCT_FREE(asn_DEF_E1AP_E1AP_PDU, pdu); } +static UP_TL_information_t create_up_tl_info(void) +{ + UP_TL_information_t tl_info; + tl_info.tlAddress = htonl(0xC0A90001); // 192.169.0.1 + tl_info.teId = 0x2345; + return tl_info; +} + /** * @brief Test E1AP Bearer Context Setup Request encoding/decoding */ @@ -77,7 +85,7 @@ static void test_bearer_context_setup_request(void) { bearer_context_pdcp_config_t pdcp = { .discardTimer = E1AP_DiscardTimer_ms10, - .pDCP_Reestablishment = E1AP_PDCP_Reestablishment_true, + .pDCP_Reestablishment = true, .pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12, .pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12, .reorderingTimer = 10, @@ -107,14 +115,13 @@ static void test_bearer_context_setup_request(void) // Step 1: Initialize the E1AP Bearer Context Setup Request e1ap_bearer_setup_req_t orig = { .gNB_cu_cp_ue_id = 1234, - .cipheringAlgorithm = 0x01, - .integrityProtectionAlgorithm = 0x01, + .secInfo.cipheringAlgorithm = 0x01, + .secInfo.integrityProtectionAlgorithm = 0x01, .ueDlAggMaxBitRate = 1000000000, .bearerContextStatus = 0, .servingPLMNid.mcc = 001, .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, @@ -122,8 +129,7 @@ static void test_bearer_context_setup_request(void) .pduSession[0].nssai.sst = 0x01, .pduSession[0].securityIndication = security, .pduSession[0].numDRB2Setup = 1, - .pduSession[0].UP_TL_information.tlAddress = 167772161, - .pduSession[0].UP_TL_information.teId = 0x12345, + .pduSession[0].UP_TL_information = create_up_tl_info(), .pduSession[0].DRBnGRanList[0].id = 1, .pduSession[0].DRBnGRanList[0].sdap_config = sdap, .pduSession[0].DRBnGRanList[0].pdcp_config = pdcp, @@ -133,8 +139,8 @@ static void test_bearer_context_setup_request(void) .pduSession[0].DRBnGRanList[0].numQosFlow2Setup = 1, .pduSession[0].DRBnGRanList[0].qosFlows[0] = qos, }; - memset(orig.encryptionKey, 0xAB, sizeof(orig.encryptionKey)); - memset(orig.integrityProtectionKey, 0xCD, sizeof(orig.integrityProtectionKey)); + memset(orig.secInfo.encryptionKey, 0xAB, sizeof(orig.secInfo.encryptionKey)); + memset(orig.secInfo.integrityProtectionKey, 0xCD, sizeof(orig.secInfo.integrityProtectionKey)); // E1AP encode the original message E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_request(&orig); // E1AP decode the encoded message @@ -172,8 +178,7 @@ static void test_bearer_context_setup_response(void) .gNB_cu_up_ue_id = 5678, .numPDUSessions = 1, .pduSession[0].id = 1, - .pduSession[0].tlAddress = 167772161, - .pduSession[0].teId = 0x12345, + .pduSession[0].tl_info = create_up_tl_info(), .pduSession[0].numDRBSetup = 1, .pduSession[0].numDRBFailed = 0, .pduSession[0].DRBnGRanList[0].id = 1, @@ -181,8 +186,7 @@ static void test_bearer_context_setup_response(void) .pduSession[0].DRBnGRanList[0].numQosFlowSetup = 1, .pduSession[0].DRBnGRanList[0].qosFlows[0].qfi = 1, .pduSession[0].DRBnGRanList[0].UpParamList[0].cell_group_id = MCG, - .pduSession[0].DRBnGRanList[0].UpParamList[0].teId = 0x34345, - .pduSession[0].DRBnGRanList[0].UpParamList[0].tlAddress = 167772161, + .pduSession[0].DRBnGRanList[0].UpParamList[0].tl_info = create_up_tl_info(), }; // E1AP encode the original message E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_setup_response(&orig); @@ -335,6 +339,120 @@ static void test_e1_cuup_setup_failure(void) free_e1ap_cuup_setup_failure(&orig); } +/** + * @brief Test E1AP Bearer Context Modification Request encoding/decoding + */ +static void test_bearer_context_modification_request(void) +{ + const bearer_context_sdap_config_t dummy_sdap_config = { + .defaultDRB = 0, + .sDAP_Header_DL = false, + .sDAP_Header_UL = false, + }; + + const bearer_context_pdcp_config_t dummy_pdcp_config = { + .discardTimer = E1AP_DiscardTimer_ms100, + .pDCP_Reestablishment = true, + .pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_12, + .pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_12, + .reorderingTimer = 5, + .rLC_Mode = E1AP_RLC_Mode_rlc_um_bidirectional, + }; + + const qos_flow_to_setup_t dummy_qos_flows = { + .qfi = 9, + .qos_params.alloc_reten_priority.preemption_capability = E1AP_Pre_emptionCapability_may_trigger_pre_emption, + .qos_params.alloc_reten_priority.preemption_vulnerability = E1AP_Pre_emptionVulnerability_pre_emptable, + .qos_params.alloc_reten_priority.priority_level = E1AP_PriorityLevel_no_priority, + .qos_params.qos_characteristics.non_dynamic.fiveqi = 9, + }; + + DRB_nGRAN_to_mod_t drb_to_mod = { + .numDlUpParam = 1, + .DlUpParamList[0].cell_group_id = MCG, + .DlUpParamList[0].tl_info = create_up_tl_info(), + .id = 1, + .pdcp_config = malloc_or_fail(sizeof(*drb_to_mod.pdcp_config)), + .pdcp_sn_status_requested = true, + .numQosFlow2Setup = 1, + .qosFlows[0] = dummy_qos_flows, + }; + *drb_to_mod.pdcp_config = dummy_pdcp_config; + + pdu_session_to_mod_t pdusession_mod_item = { + .sessionId = 1, + .numDRB2Modify = 1, + .DRBnGRanModList[0] = drb_to_mod, + }; + + DRB_nGRAN_to_setup_t drb_to_setup = { + .id = 1, + .cellGroupList[0] = MCG, + .numCellGroups = 1, + .pdcp_config = dummy_pdcp_config, + .sdap_config = dummy_sdap_config, + .numQosFlow2Setup = 1, + .qosFlows[0] = dummy_qos_flows, + .drb_inactivity_timer = malloc_or_fail(sizeof(*drb_to_setup.drb_inactivity_timer)), + }; + *drb_to_setup.drb_inactivity_timer = 500; + + pdu_session_to_setup_t pdusession_setup_item = { + .numDRB2Setup = 1, + .nssai.sd = 0x01, + .nssai.sst = 0x01, + .UP_TL_information.teId = 0x12345, + .UP_TL_information.tlAddress = 167772161, + .DRBnGRanList[0] = drb_to_setup, + }; + + // Initialize the Bearer Context Modification Request + e1ap_bearer_mod_req_t orig = { + .gNB_cu_cp_ue_id = 0x1234, + .gNB_cu_up_ue_id = 0x5678, + .bearerContextStatus = malloc_or_fail(sizeof(*orig.bearerContextStatus)), + .inactivityTimer = malloc_or_fail(sizeof(*orig.inactivityTimer)), + .numPDUSessions = 1, + .pduSession[0] = pdusession_setup_item, + .numPDUSessionsMod = 1, + .pduSessionMod[0] = pdusession_mod_item, + }; + *orig.bearerContextStatus = BEARER_SUSPEND; + *orig.inactivityTimer = 1000; + + // Encode the original message + E1AP_E1AP_PDU_t *enc = encode_E1_bearer_context_mod_request(&orig); + + // Decode the encoded message + E1AP_E1AP_PDU_t *dec = e1ap_encode_decode(enc); + + // Free the encoded message + e1ap_msg_free(enc); + + // Decode the message into a new struct + e1ap_bearer_mod_req_t decoded = {0}; + AssertFatal(decode_E1_bearer_context_mod_request(dec, &decoded), "decode_E1_bearer_context_mod_request(): could not decode message\n"); + + // Free the decoded E1AP message + e1ap_msg_free(dec); + + // Compare the original and decoded structs + AssertFatal(eq_bearer_context_mod_request(&orig, &decoded), "eq_bearer_context_mod_request(): decoded message doesn't match\n"); + + // Free the memory for the decoded message + free_e1ap_context_mod_request(&decoded); + + // Deep copy the original message + e1ap_bearer_mod_req_t cp = cp_bearer_context_mod_request(&orig); + + // Verify the deep copy matches the original + AssertFatal(eq_bearer_context_mod_request(&orig, &cp), "eq_bearer_context_mod_request(): copied message doesn't match\n"); + + // Free the copied and original message + free_e1ap_context_mod_request(&cp); + free_e1ap_context_mod_request(&orig); +} + int main() { // E1 Bearer Context Setup @@ -344,5 +462,7 @@ int main() test_e1_cuup_setup_request(); test_e1_cuup_setup_response(); test_e1_cuup_setup_failure(); + // E1 Bearer Context Modification Request + test_bearer_context_modification_request(); return 0; } diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index dd281fb77d..96701dbb83 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -168,7 +168,6 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) const pdu_session_to_setup_t *req_pdu = req->pduSession + i; resp_pdu->id = req_pdu->sessionId; - AssertFatal(req_pdu->numDRB2Modify == 0, "DRB modification not implemented\n"); AssertFatal(req_pdu->numDRB2Setup == 1, "can only handle one DRB per PDU session\n"); resp_pdu->numDRBSetup = req_pdu->numDRB2Setup; const DRB_nGRAN_to_setup_t *req_drb = &req_pdu->DRBnGRanList[0]; @@ -178,7 +177,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup; for (int k = 0; k < resp_drb->numQosFlowSetup; k++) { const qos_flow_to_setup_t *qosflow2Setup = &req_drb->qosFlows[k]; - qos_flow_setup_t *qosflowSetup = &resp_drb->qosFlows[k]; + qos_flow_list_t *qosflowSetup = &resp_drb->qosFlows[k]; qosflowSetup->qfi = qosflow2Setup->qfi; } @@ -197,17 +196,17 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) &resp_n3); AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n"); AssertFatal(resp_n3.num_tunnels == req_pdu->numDRB2Setup, "could not create all tunnels\n"); - resp_pdu->teId = resp_n3.gnb_NGu_teid[0]; - memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4); + resp_pdu->tl_info.teId = resp_n3.gnb_NGu_teid[0]; + memcpy(&resp_pdu->tl_info.tlAddress, &resp_n3.gnb_addr.buffer, 4); // create PDCP bearers. This will also create SDAP bearers NR_DRB_ToAddModList_t DRB_configList = {0}; fill_DRB_configList_e1(&DRB_configList, req_pdu); nr_pdcp_entity_security_keys_and_algos_t security_parameters; - security_parameters.ciphering_algorithm = req->cipheringAlgorithm; - security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm; - memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE); - memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE); + security_parameters.ciphering_algorithm = req->secInfo.cipheringAlgorithm; + security_parameters.integrity_algorithm = req->secInfo.integrityProtectionAlgorithm; + memcpy(security_parameters.ciphering_key, req->secInfo.encryptionKey, NR_K_KEY_SIZE); + memcpy(security_parameters.integrity_key, req->secInfo.integrityProtectionKey, NR_K_KEY_SIZE); nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE cu_up_ue_id, &DRB_configList, @@ -230,8 +229,8 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) &resp_f1); resp_drb->numUpParam = 1; AssertFatal(ret >= 0, "Unable to create GTP Tunnel for F1-U\n"); - memcpy(&resp_drb->UpParamList[0].tlAddress, &resp_f1.gnb_addr.buffer, 4); - resp_drb->UpParamList[0].teId = resp_f1.gnb_NGu_teid[0]; + memcpy(&resp_drb->UpParamList[0].tl_info.tlAddress, &resp_f1.gnb_addr.buffer, 4); + resp_drb->UpParamList[0].tl_info.teId = resp_f1.gnb_NGu_teid[0]; } // We assume all DRBs to setup have been setup successfully, so we always @@ -273,12 +272,18 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) DRB_nGRAN_modified_t *modified = &modif.pduSessionMod[i].DRBnGRanModList[j]; modified->id = to_modif->id; - if (to_modif->pdcp_config.pDCP_Reestablishment) { + if (to_modif->pdcp_config && to_modif->pdcp_config->pDCP_Reestablishment) { nr_pdcp_entity_security_keys_and_algos_t security_parameters; - security_parameters.ciphering_algorithm = req->cipheringAlgorithm; - security_parameters.integrity_algorithm = req->integrityProtectionAlgorithm; - memcpy(security_parameters.ciphering_key, req->encryptionKey, NR_K_KEY_SIZE); - memcpy(security_parameters.integrity_key, req->integrityProtectionKey, NR_K_KEY_SIZE); + if (req->secInfo) { + security_parameters.ciphering_algorithm = req->secInfo->cipheringAlgorithm; + security_parameters.integrity_algorithm = req->secInfo->integrityProtectionAlgorithm; + memcpy(security_parameters.ciphering_key, req->secInfo->encryptionKey, NR_K_KEY_SIZE); + memcpy(security_parameters.integrity_key, req->secInfo->integrityProtectionKey, NR_K_KEY_SIZE); + } else { + /* don't change security settings if not present in the Bearer Context Modification Request */ + security_parameters.ciphering_algorithm = -1; + security_parameters.integrity_algorithm = -1; + } nr_pdcp_reestablishment(req->gNB_cu_up_ue_id, to_modif->id, false, @@ -291,8 +296,8 @@ void e1_bearer_context_modif(const e1ap_bearer_mod_req_t *req) /* Loop through DL UP Transport Layer params list * and update GTP tunnel outgoing addr and TEID */ for (int k = 0; k < to_modif->numDlUpParam; k++) { - in_addr_t addr = to_modif->DlUpParamList[k].tlAddress; - GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].teId); + in_addr_t addr = to_modif->DlUpParamList[k].tl_info.tlAddress; + GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[k].tl_info.teId); } } } diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h index 521a33ea99..c74623da7d 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h @@ -27,9 +27,10 @@ void nr_pdcp_e1_if_init(bool uses_e1); struct e1ap_bearer_setup_req_s; +struct e1ap_bearer_mod_req_s; struct e1ap_bearer_release_cmd_s; void e1_bearer_context_setup(const struct e1ap_bearer_setup_req_s *req); -void e1_bearer_context_modif(const struct e1ap_bearer_setup_req_s *req); +void e1_bearer_context_modif(const struct e1ap_bearer_mod_req_s *req); void e1_bearer_release_cmd(const struct e1ap_bearer_release_cmd_s *cmd); void e1_reset(void); diff --git a/openair2/RRC/NR/cucp_cuup_e1ap.c b/openair2/RRC/NR/cucp_cuup_e1ap.c index 69cb92f50a..538cd3f524 100644 --- a/openair2/RRC/NR/cucp_cuup_e1ap.c +++ b/openair2/RRC/NR/cucp_cuup_e1ap.c @@ -26,6 +26,7 @@ #include "e1ap_messages_types.h" #include "intertask_interface.h" #include "nr_rrc_defs.h" +#include "E1AP/lib/e1ap_bearer_context_management.h" static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req) { @@ -33,8 +34,7 @@ static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1a MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_REQ); msg_p->ittiMsgHeader.originInstance = assoc_id; e1ap_bearer_setup_req_t *bearer_req = &E1AP_BEARER_CONTEXT_SETUP_REQ(msg_p); - memcpy(bearer_req, req, sizeof(e1ap_bearer_setup_req_t)); - + *bearer_req = cp_bearer_context_setup_request(req); itti_send_msg_to_task (TASK_CUCP_E1, 0, msg_p); } diff --git a/openair2/RRC/NR/cucp_cuup_if.h b/openair2/RRC/NR/cucp_cuup_if.h index 86b3a2435e..418e1f362e 100644 --- a/openair2/RRC/NR/cucp_cuup_if.h +++ b/openair2/RRC/NR/cucp_cuup_if.h @@ -29,9 +29,11 @@ #include "common/platform_types.h" struct e1ap_bearer_setup_req_s; +struct e1ap_bearer_mod_req_s; struct e1ap_bearer_setup_resp_s; struct e1ap_bearer_release_cmd_s; typedef void (*cucp_cuup_bearer_context_setup_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_setup_req_s *req); +typedef void (*cucp_cuup_bearer_context_mod_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_mod_req_s *req); typedef void (*cucp_cuup_bearer_context_release_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_release_cmd_s *cmd); struct gNB_RRC_INST_s; diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 7ed9bf322e..7c02ad4f9f 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -343,7 +343,7 @@ typedef struct nr_mac_rrc_dl_if_s { typedef struct cucp_cuup_if_s { cucp_cuup_bearer_context_setup_func_t bearer_context_setup; - cucp_cuup_bearer_context_setup_func_t bearer_context_mod; + cucp_cuup_bearer_context_mod_func_t bearer_context_mod; cucp_cuup_bearer_context_release_func_t bearer_context_release; } cucp_cuup_if_t; diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 358b5af653..281af514fa 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -736,6 +736,14 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc, nr_rrc_transfer_protected_rrc_message(rrc, ue_p, DL_SCH_LCID_DCCH, buffer, size); } +static void fill_security_info(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, security_information_t *secInfo) +{ + secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; + secInfo->integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; + nr_derive_key(UP_ENC_ALG, secInfo->cipheringAlgorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey); + nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); +} + /* \brief find existing PDU session inside E1AP Bearer Modif message, or * point to new one. * \param bearer_modif E1AP Bearer Modification Message @@ -793,20 +801,27 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; drb_e1->id = drb_id; drb_e1->numDlUpParam = 1; - memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); - drb_e1->DlUpParamList[0].teId = drb->du_tunnel_config.teid; + memcpy(&drb_e1->DlUpParamList[0].tl_info.tlAddress, &drb->du_tunnel_config.addr.buffer, sizeof(uint8_t) * 4); + drb_e1->DlUpParamList[0].tl_info.teId = drb->du_tunnel_config.teid; /* PDCP configuration */ - bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config; + if (!drb_e1->pdcp_config) + drb_e1->pdcp_config = malloc_or_fail(sizeof(*drb_e1->pdcp_config)); + bearer_context_pdcp_config_t *pdcp_config = drb_e1->pdcp_config; set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb); pdcp_config->pDCP_Reestablishment = true; /* increase DRB to modify counter */ pdu_e1->numDRB2Modify += 1; } - req.cipheringAlgorithm = rrc->security.do_drb_ciphering ? ue_p->ciphering_algorithm : 0; - req.integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? ue_p->integrity_algorithm : 0; - nr_derive_key(UP_ENC_ALG, req.cipheringAlgorithm, ue_p->kgnb, (uint8_t *)req.encryptionKey); - nr_derive_key(UP_INT_ALG, req.integrityProtectionAlgorithm, ue_p->kgnb, (uint8_t *)req.integrityProtectionKey); +#if 0 + /* According to current understanding of E1 specifications, it is not needed + * to send security information because this does not change. + * But let's keep the code here in case it's needed. + */ + // Always send security information + req.secInfo = malloc_or_fail(sizeof(*req.secInfo)); + fill_security_info(rrc, ue_p, req.secInfo); +#endif /* Send E1 Bearer Context Modification Request (3GPP TS 38.463) */ sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue_p); @@ -1855,12 +1870,12 @@ void rrc_gNB_process_dc_overall_timeout(const module_id_t gnb_mod_idP, x2ap_ENDC /* \brief fill E1 bearer modification's DRB from F1 DRB * \param drb_e1 pointer to a DRB inside an E1 bearer modification message * \param drb_f1 pointer to a DRB inside an F1 UE Ctxt modification Response */ -static void fill_e1_bearer_modif(DRB_nGRAN_to_setup_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) +static void fill_e1_bearer_modif(DRB_nGRAN_to_mod_t *drb_e1, const f1ap_drb_to_be_setup_t *drb_f1) { drb_e1->id = drb_f1->drb_id; drb_e1->numDlUpParam = drb_f1->up_dl_tnl_length; - drb_e1->DlUpParamList[0].tlAddress = drb_f1->up_dl_tnl[0].tl_address; - drb_e1->DlUpParamList[0].teId = drb_f1->up_dl_tnl[0].teid; + drb_e1->DlUpParamList[0].tl_info.tlAddress = drb_f1->up_dl_tnl[0].tl_address; + drb_e1->DlUpParamList[0].tl_info.teId = drb_f1->up_dl_tnl[0].teid; } /** @@ -1892,8 +1907,8 @@ static void store_du_f1u_tunnel(const f1ap_drb_to_be_setup_t *drbs, int n, gNB_R */ static void f1u_ul_gtp_update(f1u_tunnel_t *f1u, const up_params_t *p) { - f1u->teid = p->teId; - memcpy(&f1u->addr.buffer, &p->tlAddress, sizeof(uint8_t) * 4); + f1u->teid = p->tl_info.teId; + memcpy(&f1u->addr.buffer, &p->tl_info.tlAddress, sizeof(uint8_t) * 4); f1u->addr.length = sizeof(in_addr_t); } @@ -1919,10 +1934,10 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f LOG_E(RRC, "UE %d: UE Context Modif Response: no PDU session for DRB ID %ld\n", UE->rrc_ue_id, drb_f1->drb_id); continue; } - pdu_session_to_setup_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); + pdu_session_to_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); DevAssert(pdu_e1 != NULL); pdu_e1->sessionId = pdu_ue->param.pdusession_id; - DRB_nGRAN_to_setup_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; + DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; /* Fill E1 bearer context modification */ fill_e1_bearer_modif(drb_e1, drb_f1); pdu_e1->numDRB2Modify += 1; @@ -1930,10 +1945,9 @@ static void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f DevAssert(req.numPDUSessionsMod > 0); DevAssert(req.numPDUSessions == 0); - req.cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; - req.integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; - nr_derive_key(UP_ENC_ALG, req.cipheringAlgorithm, UE->kgnb, (uint8_t *)req.encryptionKey); - nr_derive_key(UP_INT_ALG, req.integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)req.integrityProtectionKey); + // Always send security information + req.secInfo = malloc_or_fail(sizeof(*req.secInfo)); + fill_security_info(rrc, UE, req.secInfo); // send the E1 bearer modification request message to update F1-U tunnel info sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE); @@ -2270,9 +2284,9 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, f1ap_drb_to_be_setup_t *drb = &drbs[nb_drb]; drb->drb_id = pduSession[p].DRBnGRanList[i].id; drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM; - drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tlAddress; + drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tl_info.tlAddress; drb->up_ul_tnl[0].port = rrc->eth_params_s.my_portd; - drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].teId; + drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].tl_info.teId; drb->up_ul_tnl_length = 1; /* pass QoS info to MAC */ @@ -2323,8 +2337,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id); continue; } - rrc_pdu->param.gNB_teid_N3 = e1_pdu->teId; - memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tlAddress, sizeof(uint8_t) * 4); + rrc_pdu->param.gNB_teid_N3 = e1_pdu->tl_info.teId; + memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tl_info.tlAddress, sizeof(uint8_t) * 4); rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t); // save the tunnel address for the DRBs diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 12ef7ec2f4..c1715c438c 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -353,10 +353,11 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession session->nssai = sessions[i].nssai; decodePDUSessionResourceSetup(session); bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; - bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; - bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; - nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); - nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); + security_information_t *secInfo = &bearer_req.secInfo; + secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0; + secInfo->integrityProtectionAlgorithm = rrc->security.do_drb_integrity ? UE->integrity_algorithm : 0; + nr_derive_key(UP_ENC_ALG, secInfo->cipheringAlgorithm, UE->kgnb, (uint8_t *)secInfo->encryptionKey); + nr_derive_key(UP_INT_ALG, secInfo->integrityProtectionAlgorithm, UE->kgnb, (uint8_t *)secInfo->integrityProtectionKey); bearer_req.ueDlAggMaxBitRate = ueAggMaxBitRateDownlink; pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; bearer_req.numPDUSessions++;