diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 4bfe0b7747..7e6cd00097 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -2600,10 +2600,23 @@ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t return; } - // there is not really anything to do here as of now + int n_drb_mod = 0; + e1_pdcp_status_info_t pdcp_status[MAX_DRBS_PER_UE] = {0}; for (int i = 0; i < resp->numPDUSessionsMod; ++i) { const pdu_session_modif_t *pdu = &resp->pduSessionMod[i]; LOG_I(RRC, "UE %d: PDU session ID %ld modified %d bearers\n", resp->gNB_cu_cp_ue_id, pdu->id, pdu->numDRBModified); + for (int j = 0; j < pdu->numDRBModified; j++) { + // Trigger UL RAN Status Transfer + if (pdu->DRBnGRanModList[j].pdcp_status) { + pdcp_status[n_drb_mod++] = *pdu->DRBnGRanModList[j].pdcp_status; + } + } + } + if (n_drb_mod) { + LOG_I(NR_RRC, "UE %d: received PDU Status Info - send UL RAN Status Transfer\n", resp->gNB_cu_cp_ue_id); + gNB_RRC_UE_t *ue = &ue_context_p->ue_context; + if (ue->ho_context && ue->ho_context->source) + ue->ho_context->source->ho_status_transfer(rrc, ue, n_drb_mod, pdcp_status); } } diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index 961191d171..e845369951 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -1165,6 +1165,52 @@ void rrc_gNB_free_Handover_Request(ngap_handover_request_t *msg) free(msg->mobility_restriction); } +/** @brief Send NG Uplink RAN Status Transfer message (8.4.6 3GPP TS 38.413) + * Direction: source NG-RAN node -> AMF */ +int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const int n_to_mod, const e1_pdcp_status_info_t *pdcp_status) +{ + AssertFatal(UE != NULL, "UE context is NULL\n"); + + LOG_I(NR_RRC, + "Sending NGAP Uplink RAN Status Transfer (AMF_UE_NGAP_ID=%" PRIu64 ", GNB_UE_NGAP_ID=%u)\n", + UE->amf_ue_ngap_id, + UE->rrc_ue_id); + + ngap_ran_status_transfer_t msg = { + .amf_ue_ngap_id = UE->amf_ue_ngap_id, + .gnb_ue_ngap_id = UE->rrc_ue_id, + }; + + // Loop through DRBs and extract COUNT values + for (int i = 0; i < n_to_mod; ++i) { + drb_t *drb = &UE->established_drbs[i]; + if (!drb->status) + continue; + + bool sn_length_18 = rrc->pdcp_config.drb.sn_size == 18; + + ngap_drb_status_t *item = &msg.ran_status.drb_status_list[msg.ran_status.nb_drb++]; + item->drb_id = drb->drb_id; + + const e1_pdcp_count_t *ul_pdcp = &pdcp_status[i].ul_count; + const e1_pdcp_count_t *dl_pdcp = &pdcp_status[i].dl_count; + + item->ul_count.pdcp_sn = ul_pdcp->sn; + item->ul_count.hfn = ul_pdcp->hfn; + item->ul_count.sn_len = sn_length_18 ? NGAP_SN_LENGTH_18 : NGAP_SN_LENGTH_12; + + item->dl_count.pdcp_sn = dl_pdcp->sn; + item->dl_count.hfn = dl_pdcp->hfn; + item->dl_count.sn_len = sn_length_18 ? NGAP_SN_LENGTH_18 : NGAP_SN_LENGTH_12; + } + + MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UL_RAN_STATUS_TRANSFER); + NGAP_UL_RAN_STATUS_TRANSFER(msg_p) = msg; + itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p); + + return 0; +} + /** @brief Process NG Handover Command on Source gNB */ void rrc_gNB_process_HandoverCommand(gNB_RRC_INST *rrc, const ngap_handover_command_t *msg) { diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.h b/openair2/RRC/NR/rrc_gNB_NGAP.h index 4d44b7197c..babd82cb01 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.h +++ b/openair2/RRC/NR/rrc_gNB_NGAP.h @@ -106,4 +106,6 @@ void rrc_gNB_free_Handover_Command(ngap_handover_command_t *msg); void rrc_gNB_send_NGAP_HANDOVER_NOTIFY(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE); +int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const int n_to_mod, const e1_pdcp_status_info_t *pdcp_status); + #endif diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 42214ecc55..614c27e242 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -545,6 +545,7 @@ void nr_rrc_trigger_n2_ho(gNB_RRC_INST *rrc, ue->ho_context = alloc_ho_ctx(HO_CTX_SOURCE); ue->ho_context->source->du = get_du_for_ue(rrc, ue->rrc_ue_id); + ue->ho_context->source->ho_status_transfer = rrc_gNB_send_NGAP_ul_ran_status_transfer; rrc_gNB_send_NGAP_HANDOVER_REQUIRED(rrc, ue, neighbour_config, hoPrepInfo); free_byte_array(hoPrepInfo); diff --git a/openair2/RRC/NR/rrc_gNB_mobility.h b/openair2/RRC/NR/rrc_gNB_mobility.h index db0645c5e3..40072abb2d 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.h +++ b/openair2/RRC/NR/rrc_gNB_mobility.h @@ -33,6 +33,8 @@ typedef struct nr_rrc_du_container_t nr_rrc_du_container_t; typedef struct NR_CellGroupConfig NR_CellGroupConfig_t; typedef void (*ho_cancel_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue); +typedef int (*ho_status_transfer_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const int n_to_mod, const e1_pdcp_status_info_t *pdcp_status); + typedef struct nr_ho_source_cu { /// pointer to the (source) DU structure const nr_rrc_du_container_t *du; @@ -48,6 +50,8 @@ typedef struct nr_ho_source_cu { /// function pointer to announce the handover cancellation, e.g., /// reestablishment ho_cancel_t ho_cancel; + /// status transfer + ho_status_transfer_t ho_status_transfer; } nr_ho_source_cu_t; /* acknowledgement of handover request. buf+len is the RRC Reconfiguration */