From dfb0c61c62fb4ef340a843ba19d8b56ffd70ca3f Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 21 Jan 2026 12:46:27 +0100 Subject: [PATCH] Paging (RRC/ASN): refactor do_NR_Paging and extend UE identity support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the old buffer-based do_NR_Paging API with a params struct and byte_array_t return; add support for fullI-RNTI and optional accessType/ pagingCause. Encoding uses uper_encode_to_new_buffer, callers own and free the returned buffer. Changes: - asn1_msg.h: - Add nr_paging_params_t (ue_identity_type, union ue_identity union { m_tmsi or full_i_rnti }, access_type, paging_cause), - Add NR_PAGING_FULL_I_RNTI_SIZE define. - asn1_msg.c: - Implement do_NR_Paging with nr_paging_params_t. - Support ng-5G-S-TMSI (48-bit, M-TMSI in bytes 2–5) and fullI-RNTI (40-bit, 5 bytes). - Set optional accessType (non3GPP) and optional nonCriticalExtension (pagingRecordList-v1700 with pagingCause-r17). - Use asn1cCalloc for ASN.1 allocations and encode via uper_encode_to_new_buffer. On failure free buffer and return empty byte_array_t. - rrc_gNB.c: disable do_NR_Paging call in rrc_gNB_generate_pcch_msg with #if 0 (will be removed in a descendant commit, no need to update call site yet). - test_asn1_msg.cpp: update caller in asn1 tests (minimal change, test will be updated in a later commit) - common/platform_constants.h: add NR_PCCH_MAX_PAGING_RECORDS Signed-off-by: Guido Casati --- common/platform_constants.h | 3 + openair2/RRC/NR/MESSAGES/asn1_msg.c | 99 ++++++++++++++----- openair2/RRC/NR/MESSAGES/asn1_msg.h | 22 ++++- .../RRC/NR/MESSAGES/tests/test_asn1_msg.cpp | 14 ++- openair2/RRC/NR/rrc_gNB.c | 3 +- 5 files changed, 111 insertions(+), 30 deletions(-) diff --git a/common/platform_constants.h b/common/platform_constants.h index 53d93d027d..9597495e8c 100644 --- a/common/platform_constants.h +++ b/common/platform_constants.h @@ -71,6 +71,9 @@ // SDAP #define MAX_QOS_FLOWS 64 +/** Maximum number of PagingRecords in one PCCH Paging message (TS 38.331) */ +#define NR_PCCH_MAX_PAGING_RECORDS 32 + // SDAP/5G NAS NOS1 #define DEFAULT_NOS1_PDU_ID 10 diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.c b/openair2/RRC/NR/MESSAGES/asn1_msg.c index 367533ba9a..087bdf4fb3 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.c +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.c @@ -61,6 +61,7 @@ #include "NR_RRCReestablishmentRequest.h" #include "NR_PCCH-Message.h" #include "NR_PagingRecord.h" +#include "NR_Paging-v1700-IEs.h" #include "NR_UE-CapabilityRequestFilterNR.h" #include "NR_HandoverPreparationInformation.h" #include "NR_HandoverPreparationInformation-IEs.h" @@ -1517,44 +1518,90 @@ void free_MeasConfig(NR_MeasConfig_t *mc) ASN_STRUCT_FREE(asn_DEF_NR_MeasConfig, mc); } -int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi) +/** @brief Generate NR RRC Paging message (TS 38.331 §5.3.2) + * Creates a PCCH message with a single PagingRecord containing ng-5G-S-TMSI + * for CN-initiated paging of RRC_IDLE UEs. */ +byte_array_t do_NR_Paging(int count, const nr_paging_params_t *params) { - LOG_D(NR_RRC, "[gNB %d] do_NR_Paging start\n", Mod_id); + DevAssert(count > 0 && params != NULL); + DevAssert(count <= NR_PCCH_MAX_PAGING_RECORDS); + LOG_D(NR_RRC, "Generate NR RRC Paging message (count=%d, ue_identity_type=%d)\n", count, params->ue_identity_type); + byte_array_t msg = {.buf = NULL, .len = 0}; + NR_PCCH_Message_t pcch_msg = {0}; - pcch_msg.message.present = NR_PCCH_MessageType_PR_c1; + pcch_msg.message.present = NR_PCCH_MessageType_PR_c1; asn1cCalloc(pcch_msg.message.choice.c1, c1); c1->present = NR_PCCH_MessageType__c1_PR_paging; - c1->choice.paging = CALLOC(1, sizeof(NR_Paging_t)); - c1->choice.paging->pagingRecordList = CALLOC( - 1, sizeof(*pcch_msg.message.choice.c1->choice.paging->pagingRecordList)); - c1->choice.paging->nonCriticalExtension = NULL; - asn_set_empty(&c1->choice.paging->pagingRecordList->list); - c1->choice.paging->pagingRecordList->list.count = 0; + asn1cCalloc(c1->choice.paging, paging); - asn1cSequenceAdd(c1->choice.paging->pagingRecordList->list, NR_PagingRecord_t, - paging_record_p); - /* convert ue_paging_identity_t to PagingUE_Identity_t */ - paging_record_p->ue_Identity.present = NR_PagingUE_Identity_PR_ng_5G_S_TMSI; - // set ng_5G_S_TMSI - INT32_TO_BIT_STRING(tmsi, &paging_record_p->ue_Identity.choice.ng_5G_S_TMSI); + /* pagingRecordList (Optional) + * Network may address multiple UEs by including one PagingRecord per UE. + * If pagingRecordList-v1700 is included, it has same entries in same order. */ + asn1cCalloc(paging->pagingRecordList, pagingRecordList); + for (int i = 0; i < count; i++) { + asn1cSequenceAdd(pagingRecordList->list, NR_PagingRecord_t, paging_record_p); + const nr_paging_params_t *p = ¶ms[i]; - /* add to list */ - LOG_D(NR_RRC, "[gNB %d] do_Paging paging_record: PagingRecordList.count %d\n", - Mod_id, c1->choice.paging->pagingRecordList->list.count); - asn_enc_rval_t enc_rval = uper_encode_to_buffer( - &asn_DEF_NR_PCCH_Message, NULL, (void *)&pcch_msg, buffer, NR_RRC_BUF_SIZE); + /* PagingUE-Identity (choice) { ng-5G-S-TMSI | fullI-RNTI } */ + paging_record_p->ue_Identity.present = p->ue_identity_type; + if (p->ue_identity_type == NR_PagingUE_Identity_PR_ng_5G_S_TMSI) { + /* ng-5G-S-TMSI: BIT STRING (SIZE(48)) - AMF Set ID, AMF Pointer, 5G-TMSI (TS 38.331 / 23.003) */ + BIT_STRING_t *tmsi_bs = &paging_record_p->ue_Identity.choice.ng_5G_S_TMSI; + FIVEG_S_TMSI_TO_BIT_STRING(p->ue_identity.fiveg_s_tmsi, tmsi_bs); + } else { + /* fullI-RNTI: I-RNTI-Value BIT STRING (SIZE(40)) for RAN-initiated paging (RRC_INACTIVE). */ + BIT_STRING_t *i_rnti_bs = &paging_record_p->ue_Identity.choice.fullI_RNTI; + i_rnti_bs->size = NR_PAGING_FULL_I_RNTI_SIZE; + i_rnti_bs->buf = calloc_or_fail(NR_PAGING_FULL_I_RNTI_SIZE, sizeof(uint8_t)); + i_rnti_bs->bits_unused = 0; + memcpy(i_rnti_bs->buf, p->ue_identity.full_i_rnti, NR_PAGING_FULL_I_RNTI_SIZE); + } - if ( LOG_DEBUGFLAG(DEBUG_ASN1) ) { + /* accessType (optional): indicates whether paging is due to PDU sessions from non-3GPP access */ + if (p->access_type) { + paging_record_p->accessType = calloc_or_fail(1, sizeof(long)); + *paging_record_p->accessType = NR_PagingRecord__accessType_non3GPP; + } + } + + /** If pagingRecordList-v1700 is included: same count/order as pagingRecordList (38.331). + * pagingCause-r17 present means IMS voice, absent in v1700 entry means non-voice (UE-dependent). */ + int i = 0; + while (i < count && params[i].paging_cause == NULL) + i++; + if (i < count) { + asn1cCalloc(paging->nonCriticalExtension, ext_v1700); + ext_v1700->pagingGroupList_r17 = NULL; + ext_v1700->nonCriticalExtension = NULL; + asn1cCalloc(ext_v1700->pagingRecordList_v1700, list_v1700); + for (i = 0; i < count; i++) { + asn1cSequenceAdd(list_v1700->list, NR_PagingRecord_v1700_t, rec_v1700); + if (params[i].paging_cause != NULL) { + rec_v1700->pagingCause_r17 = calloc_or_fail(1, sizeof(long)); + *rec_v1700->pagingCause_r17 = NR_PagingRecord_v1700__pagingCause_r17_voice; + } + } + } + + LOG_D(NR_RRC, "Paging: PagingRecordList.count=%d\n", pagingRecordList->list.count); + + if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_PCCH_Message, (void *)&pcch_msg); } + + int val = uper_encode_to_new_buffer(&asn_DEF_NR_PCCH_Message, NULL, &pcch_msg, (void **)&msg.buf); ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_PCCH_Message, &pcch_msg); - if(enc_rval.encoded == -1) { - LOG_I(NR_RRC, "[gNB AssertFatal]ASN1 message encoding failed (%s, %lu)!\n", - enc_rval.failed_type->name, enc_rval.encoded); - return -1; + + if (val <= 0) { + LOG_E(NR_RRC, "Failed to encode NR RRC Paging message\n"); + free_byte_array(msg); + return msg; } - return((enc_rval.encoded+7)/8); + msg.len = val; + LOG_I(NR_RRC, "Encoded NR RRC Paging message (%zu bytes)\n", msg.len); + + return msg; } /* \brief generate HandoverPreparationInformation to be sent to the DU for diff --git a/openair2/RRC/NR/MESSAGES/asn1_msg.h b/openair2/RRC/NR/MESSAGES/asn1_msg.h index 384096ee16..1e6a733061 100644 --- a/openair2/RRC/NR/MESSAGES/asn1_msg.h +++ b/openair2/RRC/NR/MESSAGES/asn1_msg.h @@ -11,6 +11,7 @@ #include #include "common/platform_constants.h" +#include #include #include #include "NR_ARFCN-ValueNR.h" @@ -36,6 +37,7 @@ #include "NR_SIB2.h" #include "NR_SIB3.h" #include "NR_SIB4.h" +#include "NR_PagingUE-Identity.h" #include "ds/seq_arr.h" #include "ds/byte_array.h" #include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h" @@ -152,7 +154,25 @@ NR_MeasConfig_t *get_MeasConfig(const NR_MeasTiming_t *mt, seq_arr_t *neigh_seq, int *neigh_a3_id); void free_MeasConfig(NR_MeasConfig_t *mc); -int do_NR_Paging(uint8_t Mod_id, uint8_t *buffer, uint32_t tmsi); + +#define NR_PAGING_FULL_I_RNTI_SIZE 5 // 40 bits + +/** Paging parameters for do_NR_Paging */ +typedef struct { + /// UE Identity type (ng-5G-S-TMSI or fullI-RNTI) + NR_PagingUE_Identity_PR ue_identity_type; + union { + /// Full 48-bit 5G-S-TMSI (TS 23.003): AMF Set ID + AMF Pointer + 5G-TMSI + uint64_t fiveg_s_tmsi; + uint8_t full_i_rnti[NR_PAGING_FULL_I_RNTI_SIZE]; + } ue_identity; + /// true = accessType non3GPP + bool access_type; + /// pagingCause voice + int *paging_cause; +} nr_paging_params_t; + +byte_array_t do_NR_Paging(int count, const nr_paging_params_t *params); byte_array_t get_HandoverPreparationInformation(nr_rrc_reconfig_param_t *params); byte_array_t get_HandoverCommandMessage(nr_rrc_reconfig_param_t *params); diff --git a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp index c14e9bdba0..fc75f2c520 100644 --- a/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp +++ b/openair2/RRC/NR/MESSAGES/tests/test_asn1_msg.cpp @@ -113,8 +113,18 @@ TEST(nr_asn1, rrc_reestablishment) TEST(nr_asn1, paging) { - unsigned char buf[1000]; - EXPECT_GT(do_NR_Paging(0, buf, 0), 0); + nr_paging_params_t params = {}; + params.ue_identity_type = NR_PagingUE_Identity_PR_ng_5G_S_TMSI; + params.ue_identity.m_tmsi = 0; + params.access_type = false; + params.paging_cause = NULL; + + byte_array_t msg = do_NR_Paging(¶ms); + + EXPECT_GT(msg.len, 0); + EXPECT_NE(msg.buf, nullptr); + + free_byte_array(msg); } void free_RRCReconfiguration_params(nr_rrc_reconfig_param_t params) diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 58caa040a0..6bdf62ab19 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -3831,15 +3831,16 @@ int rrc_gNB_generate_pcch_msg(sctp_assoc_t assoc_id, const NR_SIB1_t *sib1, uint (void) Ns; /* not used, suppress warning */ (void) pfoffset; /* not used, suppress warning */ + #if 0 /* Create message for PDCP (DLInformationTransfer_t) */ int length = do_NR_Paging(instance, buffer, tmsi); - if (length == -1) { LOG_I(NR_RRC, "do_Paging error\n"); return -1; } // TODO, send message to pdcp (void) assoc_id; + #endif return 0; }