Handle PDU Session Resource to Setup Failure in (PDU Session Resource/Initial Context) Setup Response

* add function to check whether cu-up is connected
* add functions to send the relevant response messages with the failed list
  e.g. to fill PDU Session Resource Failed to Setup items
* set return value of trigger_bearer_setup to bool and handle the
  failure by sending setup response messages with list of PDU sessions failed to setup
  i.e. send failed list of items when no CU-UP is associated to the CU-CP
  note: it considers all PDU Sessions as failed to setup in the considered failure scenarios
* e.g. send a list of failed PDU session resources in the response message to reject
  PDU Session Resource Setup in rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ
* the Initial Context Setup has a Failure message, but for the considered failure scenario
  when no CU-UP is available the current design is just sending a list of failed to setup
  items in the Response message
* transfer PDU Session Resource/Initial Context Setup Request NAS PDU to UE

closes #878
This commit is contained in:
Guido Casati
2025-01-14 14:13:49 +01:00
parent f00a7a0197
commit a1abf90d5b
4 changed files with 153 additions and 42 deletions
+3 -1
View File
@@ -86,6 +86,7 @@ bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue);
sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue);
sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd);
int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req);
bool is_cuup_associated(gNB_RRC_INST *rrc);
/* Process indication of E1 connection loss on CU-CP */
void rrc_gNB_process_e1_lost_connection(gNB_RRC_INST *rrc, e1ap_lost_connection_t *lc, sctp_assoc_t assoc_id);
@@ -104,7 +105,8 @@ void ue_cxt_mod_direct(MessageDef *msg,
void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_context_p,
e1ap_bearer_setup_resp_t *e1ap_resp);
void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession_t *sessions, uint64_t ueAggMaxBitRateDownlink);
bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession_t *sessions, uint64_t ueAggMaxBitRateDownlink)
__attribute__((warn_unused_result));
int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib, uint32_t tmsi, uint8_t paging_drx);
+19 -2
View File
@@ -1403,6 +1403,14 @@ static int handle_rrcReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
return 0;
}
/**
* @brief Forward stored NAS PDU to UE (3GPP TS 38.413)
* - 8.2.1.2: If the NAS-PDU IE is included in the PDU SESSION RESOURCE SETUP REQUEST message,
* the NG-RAN node shall pass it to the UE.
* - 8.3.1.2: If the NAS-PDU IE is included in the INITIAL CONTEXT SETUP REQUEST message,
* the NG-RAN node shall pass it transparently towards the UE.
* - 8.6.2: The NAS-PDU IE contains an AMF–UE message that is transferred without interpretation in the NG-RAN node.
*/
void rrc_forward_ue_nas_message(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
{
if (UE->nas_pdu.buffer == NULL || UE->nas_pdu.length == 0)
@@ -1523,7 +1531,12 @@ static void handle_ueCapabilityInformation(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE,
* up security and request capabilities, so trigger PDU sessions now. The
* UE NAS message will be forwarded in the corresponding reconfiguration,
* the Initial context setup response after reconfiguration complete. */
trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0);
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0)) {
LOG_W(NR_RRC, "Failed to setup bearers for UE %d: send Initial Context Setup Response\n", UE->rrc_ue_id);
rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(rrc, UE);
rrc_forward_ue_nas_message(rrc, UE);
return;
}
} else {
rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(rrc, UE);
rrc_forward_ue_nas_message(rrc, UE);
@@ -1735,7 +1748,11 @@ static int rrc_gNB_decode_dcch(gNB_RRC_INST *rrc, const f1ap_ul_rrc_message_t *m
* to set up security, so trigger PDU sessions now. The UE NAS
* message will be forwarded in the corresponding reconfiguration,
* the Initial context setup response after reconfiguration complete. */
trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0);
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0)) {
LOG_W(NR_RRC, "Failed to setup bearers for UE %d: send Initial Context Setup Response\n", UE->rrc_ue_id);
rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(rrc, UE);
rrc_forward_ue_nas_message(rrc, UE);
}
} else {
/* we already have capabilities, and no PDU sessions to setup, ack
* this UE */
+121 -39
View File
@@ -320,11 +320,29 @@ static int decodePDUSessionResourceSetup(pdusession_t *session)
return 0;
}
void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession_t *sessions, uint64_t ueAggMaxBitRateDownlink)
/**
* @brief Triggers bearer setup for the specified UE.
*
* This function initiates the setup of bearer contexts for a given UE
* by preparing and sending an E1AP Bearer Setup Request message to the CU-UP.
*
* @return True if bearer setup was successfully initiated, false otherwise
* @retval true Bearer setup was initiated successfully
* @retval false No CU-UP is associated, so bearer setup could not be initiated
*
* @note the return value is expected to be used (as per declaration)
*
*/
bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession_t *sessions, uint64_t ueAggMaxBitRateDownlink)
{
AssertFatal(UE->as_security_active, "logic bug: security should be active when activating DRBs\n");
e1ap_bearer_setup_req_t bearer_req = {0};
// Reject bearers setup if there's no CU-UP associated
if (!is_cuup_associated(rrc)) {
return false;
}
e1ap_nssai_t cuup_nssai = {0};
for (int i = 0; i < n; i++) {
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true);
@@ -419,17 +437,49 @@ void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
* CU-UPs, and send them to the different CU-UPs. */
sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd);
rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req);
return true;
}
/**
* @brief Fill PDU Session Resource Failed to Setup Item of the
* PDU Session Resource Failed to Setup List for either:
* - NGAP PDU Session Resource Setup Response
* - NGAP Initial Context Setup Response
*/
static void fill_pdu_session_resource_failed_to_setup_item(pdusession_failed_t *f, int pdusession_id, ngap_cause_t cause)
{
f->pdusession_id = pdusession_id;
f->cause = cause;
}
/**
* @brief Fill Initial Context Setup Response with a PDU Session Resource Failed to Setup List
* and send ITTI message to TASK_NGAP
*/
static void send_ngap_initial_context_setup_resp_fail(instance_t instance,
ngap_initial_context_setup_req_t *msg,
ngap_cause_t cause)
{
MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, instance, NGAP_INITIAL_CONTEXT_SETUP_RESP);
ngap_initial_context_setup_resp_t *resp = &NGAP_INITIAL_CONTEXT_SETUP_RESP(msg_p);
resp->gNB_ue_ngap_id = msg->gNB_ue_ngap_id;
for (int i = 0; i < msg->nb_of_pdusessions; i++) {
fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i], msg->pdusession_param[i].pdusession_id, cause);
}
resp->nb_of_pdusessions = 0;
resp->nb_of_pdusessions_failed = msg->nb_of_pdusessions;
itti_send_msg_to_task(TASK_NGAP, instance, msg_p);
}
//------------------------------------------------------------------------------
int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t instance)
//------------------------------------------------------------------------------
{
gNB_RRC_INST *rrc = RC.nrrrc[instance];
ngap_initial_context_setup_req_t *req = &NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p);
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], req->gNB_ue_ngap_id);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_ue_ngap_id);
if (ue_context_p == NULL) {
/* Can not associate this message to an UE index, send a failure to NGAP and discard it! */
LOG_W(NR_RRC, "[gNB %ld] In NGAP_INITIAL_CONTEXT_SETUP_REQ: unknown UE from NGAP ids (%u)\n", instance, req->gNB_ue_ngap_id);
@@ -439,7 +489,8 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
cause);
return (-1);
}
gNB_RRC_INST *rrc = RC.nrrrc[instance];
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
UE->amf_ue_ngap_id = req->amf_ue_ngap_id;
/* store guami in gNB_RRC_UE_t context;
@@ -485,7 +536,13 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
// do not remove the above allocation which is reused here: this is used
// in handle_rrcReconfigurationComplete() to know that we need to send a
// Initial context setup response message
trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0);
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0)) {
LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in Initial Context 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_initial_context_setup_resp_fail(rrc->module_id, req, cause);
rrc_forward_ue_nas_message(rrc, UE);
return -1;
}
} else {
/* no PDU sesion to setup: acknowledge this message, and forward NAS
* message, if required */
@@ -528,10 +585,10 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_
}
} else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) {
session->status = PDU_SESSION_STATUS_FAILED;
pdusession_failed_t *fail = &resp->pdusessions_failed[pdu_sessions_failed];
fail->pdusession_id = session->param.pdusession_id;
fail->cause.type = NGAP_CAUSE_RADIO_NETWORK;
fail->cause.value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID;
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID};
fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[pdu_sessions_failed],
session->param.pdusession_id,
cause);
pdu_sessions_failed++;
}
}
@@ -760,47 +817,72 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
return;
}
//------------------------------------------------------------------------------
void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t instance)
//------------------------------------------------------------------------------
/**
* @brief Fill PDU Session Resource Setup Response with a list of PDU Session Resources Failed to Setup
* and send ITTI message to TASK_NGAP
*/
static void send_ngap_pdu_session_setup_resp_fail(instance_t instance, ngap_pdusession_setup_req_t *msg, ngap_cause_t cause)
{
MessageDef *msg_resp = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_RESP);
ngap_pdusession_setup_resp_t *resp = &NGAP_PDUSESSION_SETUP_RESP(msg_resp);
resp->gNB_ue_ngap_id = msg->gNB_ue_ngap_id;
resp->nb_of_pdusessions_failed = msg->nb_pdusessions_tosetup;
resp->nb_of_pdusessions = 0;
for (int i = 0; i < resp->nb_of_pdusessions_failed; ++i) {
fill_pdu_session_resource_failed_to_setup_item(&resp->pdusessions_failed[i],
msg->pdusession_setup_params[i].pdusession_id,
cause);
}
itti_send_msg_to_task(TASK_NGAP, instance, msg_resp);
}
ngap_pdusession_setup_req_t* msg=&NGAP_PDUSESSION_SETUP_REQ(msg_p);
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], msg->gNB_ue_ngap_id);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t instance)
{
gNB_RRC_INST *rrc = RC.nrrrc[instance];
ngap_pdusession_setup_req_t* msg=&NGAP_PDUSESSION_SETUP_REQ(msg_p);
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, msg->gNB_ue_ngap_id);
// Reject PDU Session Resource setup if no UE context is found
if (ue_context_p == NULL) {
MessageDef *msg_fail_p = NULL;
LOG_W(NR_RRC, "[gNB %ld] In NGAP_PDUSESSION_SETUP_REQ: unknown UE from NGAP ids (%u)\n", instance, msg->gNB_ue_ngap_id);
msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQUEST_FAIL);
NGAP_PDUSESSION_SETUP_FAIL(msg_fail_p).gNB_ue_ngap_id = msg->gNB_ue_ngap_id;
// TODO add failure cause when defined!
itti_send_msg_to_task (TASK_NGAP, instance, msg_fail_p);
return ;
LOG_W(NR_RRC,
"[gNB %ld] In NGAP_PDUSESSION_SETUP_REQ: no UE context found from UE NGAP ID (%u)\n",
instance,
msg->gNB_ue_ngap_id);
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_LOCAL_UE_NGAP_ID};
send_ngap_pdu_session_setup_resp_fail(instance, msg, cause);
return;
}
DevAssert(UE->rrc_ue_id == msg->gNB_ue_ngap_id);
LOG_I(NR_RRC, "UE %d: received PDU session setup request\n", UE->rrc_ue_id);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
LOG_I(NR_RRC, "UE %d: received PDU Session Resource Setup Request\n", UE->rrc_ue_id);
// Reject PDU Session Resource setup if gNB_ue_ngap_id is not matching
if (UE->rrc_ue_id != msg->gNB_ue_ngap_id) {
LOG_W(NR_RRC, "[gNB %ld] In NGAP_PDUSESSION_SETUP_REQ: unknown UE NGAP ID (%u)\n", instance, msg->gNB_ue_ngap_id);
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_LOCAL_UE_NGAP_ID};
send_ngap_pdu_session_setup_resp_fail(instance, msg, cause);
rrc_forward_ue_nas_message(rrc, UE);
return;
}
// Reject PDU Session Resource setup if there is no security context active
if (!UE->as_security_active) {
LOG_E(NR_RRC, "UE %d: no security context active for UE, rejecting PDU session setup request\n", UE->rrc_ue_id);
MessageDef *msg_resp = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_RESP);
ngap_pdusession_setup_resp_t *resp = &NGAP_PDUSESSION_SETUP_RESP(msg_resp);
resp->gNB_ue_ngap_id = UE->rrc_ue_id;
resp->nb_of_pdusessions_failed = msg->nb_pdusessions_tosetup;
for (int i = 0; i < resp->nb_of_pdusessions_failed; ++i) {
pdusession_failed_t *f = &resp->pdusessions_failed[i];
f->pdusession_id = msg->pdusession_setup_params[i].pdusession_id;
f->cause.type = NGAP_CAUSE_PROTOCOL;
f->cause.value = NGAP_CAUSE_PROTOCOL_MSG_NOT_COMPATIBLE_WITH_RECEIVER_STATE;
}
itti_send_msg_to_task(TASK_NGAP, instance, msg_resp);
LOG_E(NR_RRC, "UE %d: no security context active for UE, rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id);
ngap_cause_t cause = {.type = NGAP_CAUSE_PROTOCOL, .value = NGAP_CAUSE_PROTOCOL_MSG_NOT_COMPATIBLE_WITH_RECEIVER_STATE};
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;
trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink);
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);
}
return;
}
+10
View File
@@ -90,6 +90,16 @@ static const nr_rrc_cuup_container_t *select_cuup_round_robin(size_t n_t, const
return NULL;
}
bool is_cuup_associated(gNB_RRC_INST *rrc)
{
nr_rrc_cuup_container_t *cuup = NULL;
RB_FOREACH(cuup, rrc_cuup_tree, &rrc->cuups) {
return true;
}
LOG_W(NR_RRC, "no CU-UP associated to CU-CP\n");
return false;
}
bool ue_associated_to_cuup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue)
{
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id);