diff --git a/openair2/COMMON/e1ap_messages_types.h b/openair2/COMMON/e1ap_messages_types.h index 486f4d3ecd..5b727a3818 100644 --- a/openair2/COMMON/e1ap_messages_types.h +++ b/openair2/COMMON/e1ap_messages_types.h @@ -125,7 +125,7 @@ typedef struct bearer_context_pdcp_config_s { long rLC_Mode; long reorderingTimer; long discardTimer; - long pDCP_Reestablishment; + bool pDCP_Reestablishment; } bearer_context_pdcp_config_t; typedef struct drb_to_setup_s { diff --git a/openair2/E1AP/e1ap.c b/openair2/E1AP/e1ap.c index 8acc43a689..ca1a7e179e 100644 --- a/openair2/E1AP/e1ap.c +++ b/openair2/E1AP/e1ap.c @@ -1214,7 +1214,10 @@ static int fill_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_bearer_setup_req_t *con asn1cCalloc(ieC3_1->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; - + asn1cCalloc(drb2Mod->pDCP_Configuration, pDCP_Configuration); + if (j->pdcp_config.pDCP_Reestablishment) { + asn1cCallocOne(pDCP_Configuration->pDCP_Reestablishment, E1AP_PDCP_Reestablishment_true); + } if (j->numDlUpParam > 0) { asn1cCalloc(drb2Mod->dL_UP_Parameters, DL_UP_Param_List); for (up_params_t *k = j->DlUpParamList; k < j->DlUpParamList + j->numDlUpParam; k++) { @@ -1360,21 +1363,28 @@ static void extract_BEARER_CONTEXT_MODIFICATION_REQUEST(const E1AP_E1AP_PDU_t *p DRB_nGRAN_to_mod_t *drb = pdu_session->DRBnGRanModList + j; E1AP_DRB_To_Modify_Item_NG_RAN_t *drb2Mod = drb2ModList->list.array[j]; drb->id = drb2Mod->dRB_ID; - - E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; - drb->numDlUpParam = dl_up_paramList->list.count; - for (int k = 0; k < dl_up_paramList->list.count; k++) { - up_params_t *dl_up_param = drb->DlUpParamList + k; - E1AP_UP_Parameters_Item_t *dl_up_param_in = dl_up_paramList->list.array[k]; - if (dl_up_param_in->uP_TNL_Information.choice.gTPTunnel) { // Optional IE - 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); - } else { - AssertFatal(false, "gTPTunnel IE is missing. It is mandatory at this point\n"); + 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; + } + if (drb2Mod->dL_UP_Parameters) { /* Optional IE in the DRB To Modify Item */ + E1AP_UP_Parameters_t *dl_up_paramList = drb2Mod->dL_UP_Parameters; + drb->numDlUpParam = dl_up_paramList->list.count; + for (int k = 0; k < dl_up_paramList->list.count; k++) { + up_params_t *dl_up_param = drb->DlUpParamList + k; + E1AP_UP_Parameters_Item_t *dl_up_param_in = dl_up_paramList->list.array[k]; + if (dl_up_param_in->uP_TNL_Information.choice.gTPTunnel) { // Optional IE + 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); + } else { + AssertFatal(false, "gTPTunnel IE is missing. It is mandatory at this point\n"); + } + dl_up_param->cell_group_id = dl_up_param_in->cell_Group_ID; } - dl_up_param->cell_group_id = dl_up_param_in->cell_Group_ID; } } } diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 8118af7e0b..7faf9a5b5e 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -249,6 +249,10 @@ 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) { + nr_pdcp_reestablishment(req->gNB_cu_up_ue_id, to_modif->id, false); + } + if (f1inst < 0) // no F1-U? continue; // nothing to do diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c index 0bbd294c53..381152b5c5 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_entity.c @@ -409,6 +409,10 @@ static void free_rx_list(nr_pdcp_entity_t *entity) entity->rx_size = 0; } +/** + * @brief PDCP entity re-establishment according to 5.1.2 of 3GPP TS 38.323 + * @todo deal with ciphering/integrity algos and keys for transmitting/receiving entity procedures +*/ static void nr_pdcp_entity_reestablish_drb_am(nr_pdcp_entity_t *entity) { /* transmitting entity procedures */ diff --git a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c index 73e015976d..db78c4108b 100644 --- a/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c +++ b/openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.c @@ -1210,9 +1210,10 @@ void nr_pdcp_reestablishment(ue_id_t ue_id, int rb_id, bool srb_flag) rb = nr_pdcp_get_rb(ue, rb_id, srb_flag); if (rb != NULL) { + LOG_D(PDCP, "UE %4.4lx re-establishment of %sRB %d\n", ue_id, srb_flag ? "S" : "D", rb_id); rb->reestablish_entity(rb); } else { - LOG_W(PDCP, "UE %4.4lx cannot re-establish RB %d (is_srb %d), RB not found\n", ue_id, rb_id, srb_flag); + LOG_W(PDCP, "UE %4.4lx cannot re-establish %sRB %d, RB not found\n", ue_id, srb_flag ? "S" : "D", rb_id); } nr_pdcp_manager_unlock(nr_pdcp_ue_manager); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 4e7505bcd0..6f91b98bb2 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -902,7 +902,60 @@ static pdu_session_to_mod_t *find_or_next_pdu_session(e1ap_bearer_mod_req_t *bea return &bearer_modif->pduSessionMod[bearer_modif->numPDUSessionsMod - 1]; } -//----------------------------------------------------------------------------- +/** + * @brief Notify E1 re-establishment to CU-UP + */ +static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p) +{ + e1ap_bearer_mod_req_t req = { + .gNB_cu_cp_ue_id = ue_p->rrc_ue_id, + .gNB_cu_up_ue_id = ue_p->rrc_ue_id, + }; + if (!ue_associated_to_cuup(rrc, ue_p)) + return; + /* loop through active DRBs */ + for (int drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) { + if (ue_p->established_drbs[drb_id - 1].status == DRB_INACTIVE) + continue; + /* fetch an existing PDU session for this DRB */ + rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue_p, drb_id); + if (pdu == NULL) { + LOG_E(RRC, "UE %d: E1 Bearer Context Modification: no PDU session for DRB ID %d\n", ue_p->rrc_ue_id, drb_id); + continue; + } + /* Get pointer to existing (or new one) PDU session to modify in E1 */ + pdu_session_to_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu->param.pdusession_id); + AssertError(pdu != NULL, + continue, + "UE %d: E1 Bearer Context Modification: PDU session %d to setup is null\n", + ue_p->rrc_ue_id, + pdu->param.pdusession_id); + /* Prepare PDU for E1 Bearear Context Modification Request */ + pdu_e1->sessionId = pdu->param.pdusession_id; + /* Fill DRB to setup with ID, DL TL and DL TEID */ + DRB_nGRAN_to_mod_t *drb_e1 = &pdu_e1->DRBnGRanModList[pdu_e1->numDRB2Modify]; + drb_e1->id = drb_id; + drb_e1->numDlUpParam = 1; + drb_t *drbs = &ue_p->established_drbs[drb_id]; + memcpy(&drb_e1->DlUpParamList[0].tlAddress, &drbs->f1u_tunnel_config.cuup_addr_f1u.buffer, sizeof(uint8_t) * 4); + drb_e1->DlUpParamList[0].teId = drbs->f1u_tunnel_config.cuup_teid_f1u; + /* PDCP configuration */ + bearer_context_pdcp_config_t *pdcp_config = &drb_e1->pdcp_config; + drb_t *rrc_drb = get_drb(ue_p, drb_id); + set_bearer_context_pdcp_config(pdcp_config, rrc_drb, rrc->configuration.um_on_default_drb); + pdcp_config->pDCP_Reestablishment = true; + /* increase DRB to modify counter */ + pdu_e1->numDRB2Modify += 1; + } + /* Send E1 Bearer Context Modification Request (3GPP TS 38.463) */ + sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue_p); + rrc->cucp_cuup.bearer_context_mod(assoc_id, &req); +} + +/** + * @brief RRCReestablishment message + * Direction: Network to UE + */ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context_pP, const uint8_t *masterCellGroup_from_DU, const rnti_t old_rnti, @@ -941,17 +994,12 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context for (int srb_id = 1; srb_id < NR_NUM_SRB; srb_id++) { if (ue_p->Srb[srb_id].Active) { nr_pdcp_config_set_security(ue_p->rrc_ue_id, srb_id, security_mode, kRRCenc, kRRCint, kUPenc); - // TODO: should send E1 UE Bearer Modification with PDCP Reestablishment flag nr_pdcp_reestablishment(ue_p->rrc_ue_id, srb_id, true); } } - - // TODO: should send E1 UE Bearer Modification with PDCP Reestablishment flag - for (int drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) { - if (ue_p->established_drbs[drb_id - 1].status != DRB_INACTIVE) - nr_pdcp_reestablishment(ue_p->rrc_ue_id, drb_id, false); - } - + /* PDCP Reestablishment over E1 */ + cuup_notify_reestablishment(rrc, ue_p); + /* F1AP DL RRC Message Transfer */ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); RETURN_IF_INVALID_ASSOC_ID(ue_data); uint32_t old_gNB_DU_ue_id = old_rnti; @@ -1788,7 +1836,7 @@ 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_mod_t *pdu_e1 = find_or_next_pdu_session(&req, pdu_ue->param.pdusession_id); + pdu_session_to_setup_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];