diff --git a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c index 5dcc631776..99c427cc17 100644 --- a/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c +++ b/openair2/LAYER2/nr_pdcp/cucp_cuup_handler.c @@ -148,7 +148,7 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) /* mirror the CU-CP UE ID for CU-UP */ uint32_t cu_up_ue_id = req->gNB_cu_cp_ue_id; f1_ue_data_t ued = {.secondary_ue = req->gNB_cu_cp_ue_id}; - if (need_ue_id_mgmt) { + if (need_ue_id_mgmt && !cu_exists_f1_ue_data(cu_up_ue_id)) { bool success = cu_add_f1_ue_data(cu_up_ue_id, &ued); DevAssert(success); LOG_I(E1AP, "adding UE with CU-CP UE ID %d and CU-UP UE ID %d\n", req->gNB_cu_cp_ue_id, cu_up_ue_id); @@ -163,8 +163,10 @@ void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) }; resp.numPDUSessions = req->numPDUSessions; for (int i = 0; i < resp.numPDUSessions; ++i) { - pdu_session_setup_t *resp_pdu = resp.pduSession + i; const pdu_session_to_setup_t *req_pdu = req->pduSession + i; + LOG_I(E1AP, "UE %d: add PDU session ID %ld (%d bearers)\n", cu_up_ue_id, req_pdu->sessionId, req_pdu->numDRB2Setup); + + pdu_session_setup_t *resp_pdu = resp.pduSession + i; resp_pdu->id = req_pdu->sessionId; AssertFatal(req_pdu->numDRB2Setup == 1, "can only handle one DRB per PDU session\n"); diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 7c02ad4f9f..c30f8856bc 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -255,6 +255,10 @@ typedef struct gNB_RRC_UE_s { /* Nas Pdu */ ngap_pdu_t nas_pdu; + /* hack, see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() for more info */ + int max_delays_pdu_session; + bool ongoing_pdusession_setup_request; + } gNB_RRC_UE_t; typedef struct rrc_gNB_ue_context_s { diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 01db036e22..b5d682fb44 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -1666,6 +1666,10 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U LOG_E(RRC, "UE %d: Received unexpected transaction type %d for xid %d\n", UE->rrc_ue_id, UE->xids[xid], xid); break; } + + if (UE->xids[xid] == RRC_PDUSESSION_ESTABLISH) + UE->ongoing_pdusession_setup_request = false; + UE->xids[xid] = RRC_ACTION_NONE; for (int i = 0; i < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++i) { if (UE->xids[i] != RRC_ACTION_NONE) { @@ -2554,9 +2558,10 @@ void *rrc_gnb_task(void *args_p) { break; case TIMER_HAS_EXPIRED: - /* only this one handled for now */ - DevAssert(TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id); - write_rrc_stats(RC.nrrrc[0]); + if (TIMER_HAS_EXPIRED(msg_p).timer_id == stats_timer_id) + write_rrc_stats(RC.nrrrc[0]); + else + itti_send_msg_to_task(TASK_RRC_GNB, 0, TIMER_HAS_EXPIRED(msg_p).arg); /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */ break; case F1AP_INITIAL_UL_RRC_MESSAGE: diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index fa6d6e03bc..e8f5fea61e 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -815,6 +815,29 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE return; } +/* \brief checks if any transaction is ongoing for any xid of this UE */ +static bool transaction_ongoing(const gNB_RRC_UE_t *UE) +{ + for (int xid = 0; xid < NR_RRC_TRANSACTION_IDENTIFIER_NUMBER; ++xid) { + if (UE->xids[xid] != RRC_ACTION_NONE) + return true; + } + return false; +} + +/* \brief delays the ongoing transaction (in msg_p) by setting a timer to wait + * 10ms; upon expiry, delivers to RRC, which sends the message to itself */ +static void delay_transaction(MessageDef *msg_p, int wait_us) +{ + MessageDef *new = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQ); + ngap_pdusession_setup_req_t *n = &NGAP_PDUSESSION_SETUP_REQ(new); + *n = NGAP_PDUSESSION_SETUP_REQ(msg_p); + + int instance = msg_p->ittiMsgHeader.originInstance; + long timer_id; + timer_setup(0, wait_us, TASK_RRC_GNB, instance, TIMER_ONE_SHOT, new, &timer_id); +} + /** * @brief Fill PDU Session Resource Setup Response with a list of PDU Session Resources Failed to Setup * and send ITTI message to TASK_NGAP @@ -871,17 +894,52 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return; } + // Reject PDU session if at least one exists already with that ID. + // At least one because marking one as existing, and setting up another, that + // might be more work than is worth it. See 8.2.1.4 in 38.413 + for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) { + const pdusession_t *p = &msg->pdusession_setup_params[i]; + rrc_pdu_session_param_t *exist = find_pduSession(UE, p->pdusession_id, false /* don't create */); + if (exist) { + LOG_E(NR_RRC, "UE %d: already has existing PDU session %d rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id, p->pdusession_id); + ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_PDU_SESSION_ID_INSTANCES}; + send_ngap_pdu_session_setup_resp_fail(instance, msg, cause); + rrc_forward_ue_nas_message(rrc, UE); + return; + } + } + UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; + /* This is a hack. We observed that with some UEs, PDU session requests might + * come in quick succession, faster than the RRC reconfiguration for the PDU + * session requests can be carried out (UE is doing reconfig, and second PDU + * session request arrives). We don't have currently the means to "queue up" + * these transactions, which would probably involve some rework of the RRC. + * To still allow these requests to come in and succeed, we below check and delay transactions + * for 10ms. However, to not accidentally end up in infinite loops, the + * maximum number is capped on a per-UE basis as indicated in variable + * max_delays_pdu_session. */ + if (!UE->ongoing_pdusession_setup_request) + UE->max_delays_pdu_session = 100; + + if (UE->max_delays_pdu_session > 0 && (transaction_ongoing(UE) || UE->ongoing_pdusession_setup_request)) { + int wait_us = 10000; + LOG_I(RRC, "UE %d: delay PDU session setup by %d us, pending %d retries\n", UE->rrc_ue_id, wait_us, UE->max_delays_pdu_session); + delay_transaction(msg_p, wait_us); + UE->max_delays_pdu_session--; + return; + } + if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink)) { // Reject PDU Session Resource setup if there's no CU-UP associated LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE}; send_ngap_pdu_session_setup_resp_fail(instance, msg, cause); rrc_forward_ue_nas_message(rrc, UE); + } else { + UE->ongoing_pdusession_setup_request = true; } - - return; } static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *session) diff --git a/openair2/RRC/NR/rrc_gNB_UE_context.c b/openair2/RRC/NR/rrc_gNB_UE_context.c index 9b02eaa1f4..b39abd9a30 100644 --- a/openair2/RRC/NR/rrc_gNB_UE_context.c +++ b/openair2/RRC/NR/rrc_gNB_UE_context.c @@ -206,6 +206,8 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id, ue->rrc_ue_id); bool success = cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data); DevAssert(success); + ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */ + ue->ongoing_pdusession_setup_request = false; RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p); LOG_UE_EVENT(ue,