Paging UE (RRC/NAS): initial NAS UL transfer without SRB for paging

Route paging-triggered Service Request through NAS_INITIAL_UL_TRANSFER_REQ so
RRC can buffer the PDU for RRCSetupComplete (dedicatedNAS-Message, TS 38.331)
when no UL-DCCH SRB exists, start MAC RA from RRC_IDLE, or drop the ITTI PDU
with LOG_W if SRB1/SRB2 is already established (NAS paging path is 5GMM-IDLE
only).

Changes:
- Define ITTI NAS_INITIAL_UL_TRANSFER_REQ and
  NAS_INITIAL_UL_TRANSFER_REQ() (rrc_messages_def.h,
  rrc_messages_types.h).
- Extend NR_UE_RRC_INST_t with pending_initial_nas for setup-complete
  transport (rrc_defs.h).
- Refactor ULInformationTransfer+PDCP send into
  nr_rrc_ue_send_ul_information_transfer_nas(): on NAS_UPLINK_DATA_REQ,
  refuse PDCP when neither SRB1 nor SRB2 is established (free PDU).
- On NAS_INITIAL_UL_TRANSFER_REQ: store NAS in pending_initial_nas when
  no SRB, in RRC_STATE_IDLE_NR set ra_trigger to RRC_CONNECTION_SETUP,
  call nr_rrc_ue_prepare_RRCSetupRequest(), and nr_rrc_send_msg_to_mac()
  with NR_MAC_RRC_START_RA, otherwise replace pending and send on SRB.
- Use forwarded initial NAS messafe in rrc_ue_generate_RRCSetupComplete():
  if pending_initial_nas is set, move it into the NAS payload and refresh
  security keys when integrity context exists, else generateRegistrationRequest().
- In nr_nas_msg.c, add send_nas_initial_ul_transfer_req() and use it for
  paging Service Request instead of send_nas_uplink_data_req()

Refs: TS 24.501, TS 38.331 §5.3.3.4, TS 33.501 §6.8.1.2

Signed-off-by: Guido Casati <guido.casati@openairinterface.org>
This commit is contained in:
Guido Casati
2026-04-15 19:39:34 +02:00
parent c9e82d6a12
commit e5c95a2d7e
5 changed files with 112 additions and 15 deletions

View File

@@ -41,6 +41,7 @@ MESSAGE_DEF(NAS_KENB_REFRESH_REQ, MESSAGE_PRIORITY_MED, kenb_refresh_req_t, nas_
MESSAGE_DEF(NAS_CELL_SELECTION_REQ, MESSAGE_PRIORITY_MED, cell_info_req_t, nas_cell_selection_req)
MESSAGE_DEF(NAS_CONN_ESTABLI_REQ, MESSAGE_PRIORITY_MED, nas_establish_req_t, nas_conn_establi_req)
MESSAGE_DEF(NAS_UPLINK_DATA_REQ, MESSAGE_PRIORITY_MED, ul_info_transfer_req_t, nas_ul_data_req)
MESSAGE_DEF(NAS_INITIAL_UL_TRANSFER_REQ, MESSAGE_PRIORITY_MED, ul_info_transfer_req_t, nas_initial_ul_transfer_req)
MESSAGE_DEF(NAS_DETACH_REQ, MESSAGE_PRIORITY_MED, nas_detach_req_t, nas_detach_req)
MESSAGE_DEF(NAS_DEREGISTRATION_REQ, MESSAGE_PRIORITY_MED, nas_deregistration_req_t, nas_deregistration_req)
MESSAGE_DEF(NAS_5GMM_IND, MESSAGE_PRIORITY_MED, nas_5gmm_ind_t, nas_5gmm_ind)

View File

@@ -62,6 +62,7 @@
#define NAS_CELL_SELECTION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_cell_selection_req
#define NAS_CONN_ESTABLI_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_conn_establi_req
#define NAS_UPLINK_DATA_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_ul_data_req
#define NAS_INITIAL_UL_TRANSFER_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_initial_ul_transfer_req
#define NAS_DETACH_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_detach_req
#define NAS_DEREGISTRATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.nas_deregistration_req
#define NAS_5GMM_IND(mSGpTR) (mSGpTR)->ittiMsg.nas_5gmm_ind
@@ -471,6 +472,7 @@ enum payload_type {
NR_MAC_RRC_CONFIG_MIB,
NR_MAC_RRC_CONFIG_SIB1,
NR_MAC_RRC_CONFIG_OTHER_SIB,
NR_MAC_RRC_START_RA,
NR_MAC_RRC_SCHED_SIB,
NR_MAC_RRC_RESUME_RB
};

View File

@@ -2083,15 +2083,37 @@ static void nr_rrc_ue_decode_NR_BCCH_DL_SCH_Message(NR_UE_RRC_INST_t *rrc,
SEQUENCE_free(&asn_DEF_NR_BCCH_DL_SCH_Message, bcch_message, ASFM_FREE_EVERYTHING);
}
static void rrc_ue_generate_RRCSetupComplete(const NR_UE_RRC_INST_t *rrc, const uint8_t Transaction_id)
static void rrc_ue_generate_RRCSetupComplete(NR_UE_RRC_INST_t *rrc, const uint8_t Transaction_id)
{
uint8_t buffer[100];
as_nas_info_t initialNasMsg = {0};
if (IS_SA_MODE(get_softmodem_params())) {
/* 3GPP TS 38.331:
* - 5.3.3.1: RRC connection establishment is also used to transfer the initial NAS dedicated information
* message from the UE to the network.
* - 5.3.3.4: set the dedicatedNAS-Message to include the information received from upper layers.
* In paging-triggered service resumption (TS 24.501 service request procedure), the Service Request NAS PDU
* is therefore carried here as the initial NAS message in RRCSetupComplete. */
nr_ue_nas_t *nas = get_ue_nas_info(rrc->ue_id);
// Send Initial NAS message (Registration Request) before Security Mode control procedure
generateRegistrationRequest(&initialNasMsg, nas, false);
if (rrc->pending_initial_nas.nas_data && rrc->pending_initial_nas.length > 0) {
/* Deferred NAS PDU is placed in dedicatedNAS-Message (TS 38.331 §5.3.3.4). It is the initial NAS message that
* starts CM-IDLE to CM-CONNECTED transition (TS 33.501 §6.8.1.2.1, TS 24.501). */
initialNasMsg = rrc->pending_initial_nas;
/* Clear RRC copy of pointer after shallow copy: NAS payload is owned by initialNasMsg */
rrc->pending_initial_nas.nas_data = NULL;
rrc->pending_initial_nas.length = 0;
LOG_I(NR_RRC, "[UE %ld] Using pending initial NAS message for RRCSetupComplete\n", rrc->ue_id);
/* TS 33.501 §6.8.1.2.2: UE derives KgNB from KAMF using NAS UL COUNT of the NAS message that initiated
* CM-IDLE to CM-CONNECTED transition. §6.2.3.2 / Annex A.9 tie initial KgNB to ngKSI + that COUNT. In this case,
* NAS holds the derived KgNB value: copy into RRC so AS SMC and RRC keys (§6.2.3.1, §6.5) match after RRC release
* cleared AS keys (§6.8.1.2.1). */
if (nas->security_container && nas->security_container->integrity_context)
memcpy(rrc->kgnb, nas->security.kgnb, sizeof(rrc->kgnb));
} else {
// Send Initial NAS message (Registration Request) before Security Mode control procedure
generateRegistrationRequest(&initialNasMsg, nas, false);
}
if (!initialNasMsg.nas_data) {
LOG_E(NR_RRC, "Failed to complete RRCSetup. NAS InitialUEMessage message not found.\n");
return;
@@ -2758,6 +2780,22 @@ static int nr_rrc_ue_decode_dcch(NR_UE_RRC_INST_t *rrc,
return 0;
}
/** @brief Encode NAS in ULInformationTransfer, submit to PDCP on SRB2 if established else SRB1. */
static void nr_rrc_ue_send_ul_information_transfer_nas(NR_UE_RRC_INST_t *rrc, uint32_t nas_length, uint8_t *nas_pdu)
{
uint8_t *buffer = NULL;
const int enc_bytes = do_NR_ULInformationTransfer(&buffer, nas_length, nas_pdu);
const rb_id_t srb_id = rrc->Srb[2] == RB_ESTABLISHED ? 2 : 1;
LOG_D(NR_RRC,
"[UE %ld] PDCP_DATA_REQ ULInformationTransfer (NAS %u B) -> SRB%d encoded %d B\n",
rrc->ue_id,
nas_length,
(int)srb_id,
enc_bytes);
nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, enc_bytes, buffer, deliver_pdu_srb_rlc, NULL);
free(buffer);
}
static void apply_ema(val_init_t *vi_rsrp_dBm, float filter_coeff_rsrp, int rsrp_dBm)
{
int *quant = &vi_rsrp_dBm->val;
@@ -3275,18 +3313,55 @@ void *rrc_nrue(void *notUsed)
break;
case NAS_UPLINK_DATA_REQ: {
uint32_t length;
uint8_t *buffer = NULL;
ul_info_transfer_req_t *req = &NAS_UPLINK_DATA_REQ(msg_p);
/* Create message for PDCP (ULInformationTransfer_t) */
length = do_NR_ULInformationTransfer(&buffer, req->nasMsg.length, req->nasMsg.nas_data);
/* Transfer data to PDCP */
// check if SRB2 is created, if yes request data_req on SRB2
// error: the remote gNB is hardcoded here
rb_id_t srb_id = rrc->Srb[2] == RB_ESTABLISHED ? 2 : 1;
nr_pdcp_data_req_srb(rrc->ue_id, srb_id, 0, length, buffer, deliver_pdu_srb_rlc, NULL);
/* ULInformationTransfer (TS 38.331) requires an established UL-DCCH SRB: not used for CM-IDLE initial NAS
* (that path uses RRCSetupComplete dedicatedNAS-Message (TS 38.331 §5.3.3.4, TS 33.501 §6.8.1.2.1)). */
if (rrc->Srb[1] != RB_ESTABLISHED && rrc->Srb[2] != RB_ESTABLISHED) {
LOG_W(NR_RRC,
"[UE %ld] NAS UL requested but no SRB established: dropping UL request (%u B)\n",
rrc->ue_id,
req->nasMsg.length);
free(req->nasMsg.nas_data);
break;
}
nr_rrc_ue_send_ul_information_transfer_nas(rrc, req->nasMsg.length, req->nasMsg.nas_data);
free(req->nasMsg.nas_data);
break;
}
case NAS_INITIAL_UL_TRANSFER_REQ: {
ul_info_transfer_req_t *req = &NAS_INITIAL_UL_TRANSFER_REQ(msg_p);
if (rrc->Srb[1] != RB_ESTABLISHED && rrc->Srb[2] != RB_ESTABLISHED) {
/* No UL-DCCH SRB yet: cannot use ULInformationTransfer (TS 38.331). Buffer NAS for dedicatedNAS-Message in
* RRCSetupComplete (§5.3.3.4). Typical source is Service Request from 5GMM-IDLE (TS 24.501 §5.6.1). */
free(rrc->pending_initial_nas.nas_data);
rrc->pending_initial_nas.nas_data = req->nasMsg.nas_data;
rrc->pending_initial_nas.length = req->nasMsg.length;
LOG_I(NR_RRC,
"[UE %ld] Initial NAS UL: no SRB yet; buffered %u B for RRCSetupComplete dedicatedNAS (RRC state=%d)\n",
rrc->ue_id,
req->nasMsg.length,
rrc->nrRrcState);
if (rrc->nrRrcState == RRC_STATE_IDLE_NR) {
RA_trigger_t prev_trigger = rrc->ra_trigger;
rrc->ra_trigger = RRC_CONNECTION_SETUP;
nr_rrc_ue_prepare_RRCSetupRequest(rrc);
nr_rrc_trigger_mac_ra(rrc, NR_MAC_RA_START_SETUP);
LOG_I(NR_RRC,
"[UE %ld] Triggering MAC RA for RRCSetupComplete pending NAS (prev_trigger=%d)\n",
rrc->ue_id,
prev_trigger);
}
break;
}
LOG_W(NR_RRC,
"[UE %ld] Initial NAS UL requested but SRB established: dropping request (length=%u)\n",
rrc->ue_id,
req->nasMsg.length);
free(rrc->pending_initial_nas.nas_data);
rrc->pending_initial_nas.nas_data = NULL;
rrc->pending_initial_nas.length = 0;
free(req->nasMsg.nas_data);
free(buffer);
break;
}

View File

@@ -253,6 +253,8 @@ typedef struct NR_UE_RRC_INST_s {
NR_NTN_Config_r17_t *target_ntncfg;
bool process_target_ntncfg;
notifiedFIFO_t *mac_input_nf;
/* NAS PDU deferred until UL-DCCH exists: consumed in RRCSetupComplete/RRCResumeComplete dedicatedNAS-Message */
as_nas_info_t pending_initial_nas;
} NR_UE_RRC_INST_t;
#endif

View File

@@ -1925,6 +1925,18 @@ static void send_nas_uplink_data_req(nr_ue_nas_t *nas, const as_nas_info_t *init
itti_send_msg_to_task(TASK_RRC_NRUE, nas->UE_id, msg);
}
/** Send initial NAS to RRC as NAS_INITIAL_UL_TRANSFER_REQ (e.g. paging Service Request, TS 24.501 §5.6.1).
* RRC buffers for RRCSetupComplete dedicatedNAS when no SRB (TS 38.331 §5.3.3.4). */
static void send_nas_initial_ul_transfer_req(nr_ue_nas_t *nas, const as_nas_info_t *initial_nas_msg)
{
MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_INITIAL_UL_TRANSFER_REQ);
ul_info_transfer_req_t *req = &NAS_INITIAL_UL_TRANSFER_REQ(msg);
req->UEid = nas->UE_id;
req->nasMsg.nas_data = (uint8_t *)initial_nas_msg->nas_data;
req->nasMsg.length = initial_nas_msg->length;
itti_send_msg_to_task(TASK_RRC_NRUE, nas->UE_id, msg);
}
static void send_nas_detach_req(nr_ue_nas_t *nas, bool wait_release)
{
MessageDef *msg = itti_alloc_new_message(TASK_NAS_NRUE, nas->UE_id, NAS_DETACH_REQ);
@@ -2218,8 +2230,13 @@ void *nas_nrue(void *args_p)
LOG_E(NAS, "[UE %ld] Failed to generate Service Request after paging\n", nas->UE_id);
break;
}
send_nas_uplink_data_req(nas, &initialNasMsg);
LOG_I(NAS, "[UE %ld] Paging received: Service Request sent\n", nas->UE_id);
/* TS 24.501 §5.6.1.2: send SERVICE REQUEST, enter 5GMM-SERVICE-REQUEST-INITIATED (§5.1.3.2.1.2.6) */
nas->fiveGMM_state = FGS_SERVICE_REQUEST_INITIATED;
send_nas_initial_ul_transfer_req(nas, &initialNasMsg);
LOG_I(NAS,
"[UE %ld] Paging: Service Request (%u B) sent to RRC (NAS_INITIAL_UL_TRANSFER_REQ)\n",
nas->UE_id,
(unsigned)initialNasMsg.length);
break;
}