diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index f4e9090f66..788236ca05 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -283,6 +283,22 @@ typedef struct bearer_context_pdcp_config_s { bool pDCP_Reestablishment; } bearer_context_pdcp_config_t; +/* 9.3.1.35 3GPP TS 38.463 */ +typedef struct { + // PDCP SN + uint32_t sn; + // HFN + uint32_t hfn; +} e1_pdcp_count_t; + +/* 9.3.1.58 3GPP TS 38.463 */ +typedef struct { + // UL Count Value + e1_pdcp_count_t ul_count; + // DL Count Value + e1_pdcp_count_t dl_count; +} e1_pdcp_status_info_t; + typedef struct drb_to_setup_s { long drbId; bearer_context_pdcp_config_t pdcp_config; @@ -384,6 +400,8 @@ typedef struct DRB_nGRAN_to_modify_s { bearer_context_pdcp_config_t *pdcp_config; // PDCP SN Status Request (O) bool pdcp_sn_status_requested; + // PDCP SN Status Information + e1_pdcp_status_info_t *pdcp_status; // 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]; @@ -561,9 +579,8 @@ typedef struct DRB_nGRAN_modified_s { // Flow Failed List (O) int numQosFlowFailed; qos_flow_failed_t qosFlowsFailed[E1AP_MAX_NUM_QOS_FLOWS]; - // Old QoS Flow List (O) - int numOldQosFlow; - qos_flow_list_t oldQosFlows[E1AP_MAX_NUM_QOS_FLOWS]; + // PDCP SN Status Information (0) + e1_pdcp_status_info_t *pdcp_status; } DRB_nGRAN_modified_t; typedef struct DRB_nGRAN_failed_s { diff --git a/openair2/E1AP/lib/e1ap_bearer_context_management.c b/openair2/E1AP/lib/e1ap_bearer_context_management.c index f9afa06f69..0f2e5972e2 100644 --- a/openair2/E1AP/lib/e1ap_bearer_context_management.c +++ b/openair2/E1AP/lib/e1ap_bearer_context_management.c @@ -360,6 +360,39 @@ static E1AP_UP_Parameters_t encode_dl_up_parameters(const int numUpParam, const return out; } +/** @brief PDCP SN Status Information (9.3.1.58 3GPP TS 38.463) */ +static E1AP_PDCP_SN_Status_Information_t encode_pdcp_status_info(const e1_pdcp_status_info_t *in) +{ + E1AP_PDCP_SN_Status_Information_t pdcp = {0}; + pdcp.pdcpStatusTransfer_DL.hFN = in->dl_count.hfn; + pdcp.pdcpStatusTransfer_DL.pDCP_SN = in->dl_count.sn; + pdcp.pdcpStatusTransfer_UL.countValue.hFN = in->ul_count.hfn; + pdcp.pdcpStatusTransfer_UL.countValue.pDCP_SN = in->ul_count.sn; + return pdcp; +} + +/** @brief PDCP SN Status Information (9.3.1.58 3GPP TS 38.463) */ +static e1_pdcp_status_info_t decode_pdcp_status_info(const E1AP_PDCP_SN_Status_Information_t* in) +{ + e1_pdcp_status_info_t out = {0}; + const E1AP_PDCP_Count_t *dl = &in->pdcpStatusTransfer_DL; + const E1AP_PDCP_Count_t *ul = &in->pdcpStatusTransfer_UL.countValue; + out.dl_count.hfn = dl->hFN; + out.dl_count.sn = dl->pDCP_SN; + out.ul_count.hfn = ul->hFN; + out.ul_count.sn = ul->pDCP_SN; + return out; +} + +static bool eq_pdcp_info(const e1_pdcp_status_info_t *a, const e1_pdcp_status_info_t *b) +{ + _E1_EQ_CHECK_INT(a->dl_count.hfn, b->dl_count.hfn); + _E1_EQ_CHECK_INT(a->dl_count.sn, b->dl_count.sn); + _E1_EQ_CHECK_INT(a->ul_count.hfn, b->ul_count.hfn); + _E1_EQ_CHECK_INT(a->ul_count.sn, b->ul_count.sn); + return true; +} + /** * @brief Equality check for DRB_nGRAN_to_setup_t */ @@ -1409,6 +1442,11 @@ static E1AP_PDU_Session_Resource_To_Modify_Item_t e1_encode_pdu_session_to_mod_i asn1cCalloc(drb2Mod->pDCP_SN_Status_Request, pDCP_SN_Status_Request); *pDCP_SN_Status_Request = E1AP_PDCP_SN_Status_Request_requested; } + // PDCP Status Information (O) + if (j->pdcp_status) { + asn1cCalloc(drb2Mod->pdcp_SN_Status_Information, pdcp); + *pdcp = encode_pdcp_status_info(j->pdcp_status); + } // DL UP TNL parameters (O) if (j->numDlUpParam > 0) { asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List); @@ -1667,9 +1705,14 @@ static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E CHECK_E1AP_DEC(e1_decode_sdap_config(drb->sdap_config, drb2Mod->sDAP_Configuration)); } // PDCP SN Status Request (O) - if (drb2Mod->pDCP_SN_Status_Request) { + if (drb2Mod->pDCP_SN_Status_Request && *drb2Mod->pDCP_SN_Status_Request == E1AP_PDCP_SN_Status_Request_requested) { drb->pdcp_sn_status_requested = true; } + // PDCP SN Status Information (O) + if (drb2Mod->pdcp_SN_Status_Information) { + drb->pdcp_status = malloc_or_fail(sizeof(*drb->pdcp_status)); + *drb->pdcp_status = decode_pdcp_status_info(drb2Mod->pdcp_SN_Status_Information); + } // DL UP TNL parameters (O) if (drb2Mod->dL_UP_Parameters) { E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; @@ -1843,6 +1886,7 @@ static DRB_nGRAN_to_mod_t cp_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) cp = *msg; _E1_CP_OPTIONAL_IE(&cp, msg, sdap_config); _E1_CP_OPTIONAL_IE(&cp, msg, pdcp_config); + _E1_CP_OPTIONAL_IE(&cp, msg, pdcp_status); return cp; } @@ -1904,12 +1948,15 @@ static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t _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); + result &= 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); + _E1_EQ_CHECK_OPTIONAL_PTR(a, b, pdcp_status); + if (a->pdcp_status && b->pdcp_status) + result &= eq_pdcp_info(a->pdcp_status, b->pdcp_status); return result; } @@ -1984,6 +2031,7 @@ static void free_drb_to_mod_item(const DRB_nGRAN_to_mod_t *msg) { free(msg->pdcp_config); free(msg->sdap_config); + free(msg->pdcp_status); } /* Free PDU Session to modify item */ @@ -2111,6 +2159,13 @@ struct E1AP_E1AP_PDU *encode_E1_bearer_context_mod_response(const e1ap_bearer_mo asn1cSequenceAdd(drb_mod->flow_Failed_List->list, E1AP_QoS_Flow_Failed_Item_t, fail); encode_qos_flow_failed_item(fail, &drb->qosFlowsFailed[q]); } + + // PDCP Status Information (O) + if (drb->pdcp_status) { + asn1cCalloc(drb_mod->pDCP_SN_Status_Information, pdcp); + *pdcp = encode_pdcp_status_info(drb->pdcp_status); + } + // UL UP Parameters (O) if (drb->numUpParam) drb_mod->uL_UP_Transport_Parameters = calloc_or_fail(1, sizeof(*drb_mod->uL_UP_Transport_Parameters)); @@ -2310,6 +2365,11 @@ bool decode_E1_bearer_context_mod_response(e1ap_bearer_modif_resp_t *out, const drbMod->qosFlowsFailed[i] = decode_qos_flow_failed_item(drbIE->flow_Failed_List->list.array[i]); } } + // PDCP Status Info (O) + if (drbIE->pDCP_SN_Status_Information) { + drbMod->pdcp_status = malloc_or_fail(sizeof(*drbMod->pdcp_status)); + *drbMod->pdcp_status = decode_pdcp_status_info(drbIE->pDCP_SN_Status_Information); + } } } // DRB Failed to Mod list @@ -2347,8 +2407,12 @@ e1ap_bearer_modif_resp_t cp_bearer_context_mod_response(const e1ap_bearer_modif_ // Shallow copy cp = *msg; // Deep copy PDU sessions modified items - for (int i = 0; i < msg->numPDUSessionsMod; i++) + for (int i = 0; i < msg->numPDUSessionsMod; i++) { cp.pduSessionMod[i] = cp_pdu_session_mod_item(&msg->pduSessionMod[i]); + for (int j = 0; j < msg->pduSessionMod[i].numDRBModified; j++) { + _E1_CP_OPTIONAL_IE(&cp.pduSessionMod[i].DRBnGRanModList[j], &msg->pduSessionMod[i].DRBnGRanModList[j], pdcp_status); + } + } return cp; } @@ -2359,6 +2423,8 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a { if (!a || !b) return false; // Null-check both inputs + bool result = true; + // 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); @@ -2375,7 +2441,7 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a _E1_EQ_CHECK_OPTIONAL_PTR(pduA, pduB, ng_DL_UP_TL_info); if (pduA->ng_DL_UP_TL_info && pduB->ng_DL_UP_TL_info) - eq_up_tl_info(pduA->ng_DL_UP_TL_info, pduB->ng_DL_UP_TL_info); + result &= eq_up_tl_info(pduA->ng_DL_UP_TL_info, pduB->ng_DL_UP_TL_info); // DRB Modified List _E1_EQ_CHECK_INT(pduA->numDRBModified, pduB->numDRBModified); @@ -2387,6 +2453,10 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a for (int j = 0; j < drbModA->numQosFlowSetup; j++) { _E1_EQ_CHECK_LONG(drbModA->qosFlows[j].qfi, drbModB->qosFlows[j].qfi); } + _E1_EQ_CHECK_OPTIONAL_PTR(drbModA, drbModB, pdcp_status); + if (drbModA->pdcp_status && drbModB->pdcp_status) { + result &= eq_pdcp_info(drbModA->pdcp_status, drbModA->pdcp_status); + } } // DRB Failed to Modify List @@ -2420,7 +2490,7 @@ bool eq_bearer_context_mod_response(const e1ap_bearer_modif_resp_t *a, const e1a } - return true; + return result; } /** @@ -2432,6 +2502,9 @@ void free_e1ap_context_mod_response(const e1ap_bearer_modif_resp_t *msg) free(msg->pduSessionMod[i].confidentialityProtectionIndication); free(msg->pduSessionMod[i].integrityProtectionIndication); free(msg->pduSessionMod[i].ng_DL_UP_TL_info); + for (int j = 0; j < msg->pduSessionMod[i].numDRBModified; j++) { + free(msg->pduSessionMod[i].DRBnGRanModList[j].pdcp_status); + } } } diff --git a/openair2/E1AP/tests/e1ap_lib_test.c b/openair2/E1AP/tests/e1ap_lib_test.c index a9fd7aa390..b168ff9e82 100644 --- a/openair2/E1AP/tests/e1ap_lib_test.c +++ b/openair2/E1AP/tests/e1ap_lib_test.c @@ -490,6 +490,13 @@ static void test_bearer_context_modification_request(void) .qos_params.qos_characteristics.non_dynamic.fiveqi = 9, }; + const e1_pdcp_status_info_t dummy_pdcp_status = { + .dl_count.hfn = 12, + .dl_count.sn = 34, + .ul_count.hfn = 56, + .ul_count.sn = 78, + }; + DRB_nGRAN_to_mod_t drb_to_mod = { .numDlUpParam = 1, .DlUpParamList[0].cell_group_id = MCG, @@ -497,10 +504,12 @@ static void test_bearer_context_modification_request(void) .id = 1, .pdcp_config = malloc_or_fail(sizeof(*drb_to_mod.pdcp_config)), .pdcp_sn_status_requested = true, + .pdcp_status = malloc_or_fail(sizeof(*drb_to_mod.pdcp_status)), .numQosFlow2Setup = 1, .qosFlows[0] = dummy_qos_flows, }; *drb_to_mod.pdcp_config = dummy_pdcp_config; + *drb_to_mod.pdcp_status = dummy_pdcp_status; pdu_session_to_mod_t pdusession_mod_item = { .sessionId = 1, @@ -592,12 +601,21 @@ const DRB_nGRAN_failed_t dummy_drb_failed = { */ static void test_bearer_context_modification_response(void) { + const e1_pdcp_status_info_t dummy_pdcp_status = { + .dl_count.hfn = 12, + .dl_count.sn = 2, + .ul_count.hfn = 12, + .ul_count.sn = 3, + }; + // DRB Modified List DRB_nGRAN_modified_t drb_mod = { .id = 1, .numQosFlowSetup = 1, .qosFlows[0].qfi = 1, + .pdcp_status = malloc_or_fail(sizeof(*drb_mod.pdcp_status)), }; + *drb_mod.pdcp_status = dummy_pdcp_status; // DRB Setup List DRB_nGRAN_setup_t setup = {