mirror of
https://gitlab.eurecom.fr/oai/openairinterface5g.git
synced 2026-07-13 04:30:28 +00:00
Paging (RRC): refactor NGAP Paging handler in CUCP
RRC now builds F1AP paging messages directly by calling F1AP/direct callbacks and aligning the CU/DU intergace with the F1AP design in the CU. Messages are forwarded based on TAI-based cell matching across DUs. - Remove F1AP_PAGING_IND message def and f1ap_paging_ind_t. RRC no longer sends ITTI F1AP_PAGING_IND; it builds f1ap_paging_t and passes it to the DU path. - rrc_gNB_process_PAGING_IND: new signature (rrc, instance, msg) with const where appropriate; call in rrc_gnb_task() updated. - NGAP handler logic: For each TAI, match (PLMN + TAC) to rrc->configuration; collect matching TAIs. Build one f1ap_paging_t (5G-S-TMSI via nr_construct_5g_s_tmsi(), identity type F1AP_PAGING_IDENTITY_CN_UE, optional drx/priority/origin copied from ngap_paging_ind_t), call rrc_send_paging_to_dus(), then free_f1ap_paging(). Remove the previous AssertFatal stub, CC loop, NODE_IS_CU branch, and UE lookup logic: it is now handled by F1AP/direct CU callbacks. - rrc_gNB_du: Add rrc_send_paging_to_dus(rrc, tais, n_tai, msg). Iterate DUs with RB_FOREACH; for each DU, fill msg->cells from du->cells whose (PLMN + TAC) matches any requested TAI, set n_cells, then call rrc->mac_rrc.paging_transfer(du->assoc_id, msg). Skip DUs with no matching cells. Prevents duplicate paging when multiple TAIs map to the same PLMN.
This commit is contained in:
@@ -65,4 +65,3 @@ MESSAGE_DEF(F1AP_UE_CONTEXT_MODIFICATION_REFUSE, MESSAGE_PRIORITY_MED, f1ap_ue_c
|
||||
|
||||
/* CU -> DU*/
|
||||
MESSAGE_DEF(F1AP_PAGING, MESSAGE_PRIORITY_MED, f1ap_paging_t, f1ap_paging)
|
||||
MESSAGE_DEF(F1AP_PAGING_IND, MESSAGE_PRIORITY_MED, f1ap_paging_ind_t, f1ap_paging_ind)
|
||||
|
||||
@@ -68,7 +68,6 @@
|
||||
#define F1AP_UE_CONTEXT_RELEASE_CMD(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_cmd
|
||||
#define F1AP_UE_CONTEXT_RELEASE_COMPLETE(mSGpTR) (mSGpTR)->ittiMsg.f1ap_ue_context_release_complete
|
||||
|
||||
#define F1AP_PAGING_IND(mSGpTR) (mSGpTR)->ittiMsg.f1ap_paging_ind
|
||||
#define F1AP_PAGING(mSGpTR) (mSGpTR)->ittiMsg.f1ap_paging
|
||||
|
||||
/* Length of the transport layer address string
|
||||
@@ -633,15 +632,6 @@ typedef struct f1ap_ue_context_rel_cplt_t {
|
||||
uint32_t gNB_DU_ue_id;
|
||||
} f1ap_ue_context_rel_cplt_t;
|
||||
|
||||
typedef struct f1ap_paging_ind_s {
|
||||
uint16_t ueidentityindexvalue;
|
||||
uint64_t fiveg_s_tmsi;
|
||||
uint8_t fiveg_s_tmsi_length;
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
uint8_t paging_drx;
|
||||
} f1ap_paging_ind_t;
|
||||
|
||||
typedef struct f1ap_paging_cell_item_s {
|
||||
plmn_id_t plmn;
|
||||
uint64_t nr_cellid;
|
||||
|
||||
@@ -3523,7 +3523,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
break;
|
||||
|
||||
case NGAP_PAGING_IND:
|
||||
rrc_gNB_process_PAGING_IND(msg_p, instance);
|
||||
rrc_gNB_process_PAGING_IND(RC.nrrrc[instance], instance, &NGAP_PAGING_IND(msg_p));
|
||||
break;
|
||||
|
||||
case NGAP_HANDOVER_REQUEST:
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
#include "nr_pdcp/nr_pdcp_oai_api.h"
|
||||
#include "oai_asn1.h"
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "openair2/F1AP/lib/f1ap_paging.h"
|
||||
#include "openair3/SECU/key_nas_deriver.h"
|
||||
#include "rrc_messages_types.h"
|
||||
#include "s1ap_messages_types.h"
|
||||
@@ -1629,57 +1630,67 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(ngap_pdusession_release_comm
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance)
|
||||
/** @brief Handle NGAP Paging Indication from the AMF.
|
||||
* For each TAI in the message, matches (PLMN + TAC) against the gNB configuration; on match,
|
||||
* builds an F1AP Paging message and distributes it to all DUs that serve cells in that PLMN. */
|
||||
int rrc_gNB_process_PAGING_IND(gNB_RRC_INST *rrc, const instance_t instance, const ngap_paging_ind_t *msg)
|
||||
{
|
||||
ngap_paging_ind_t *msg = &NGAP_PAGING_IND(msg_p);
|
||||
for (uint16_t tai_idx = 0; tai_idx < msg->n_tai; tai_idx++) {
|
||||
nr_tai_t *tai = &msg->tai_list[tai_idx];
|
||||
plmn_id_t *p = &tai->plmn;
|
||||
LOG_I(NR_RRC,
|
||||
"[gNB %ld] TAI List for Paging: MCC=%03d, MNC=%0*d, TAC=%d\n",
|
||||
DevAssert(rrc);
|
||||
DevAssert(msg);
|
||||
|
||||
// Construct 5G-S-TMSI from paging identity components
|
||||
const fiveg_s_tmsi_t *s_tmsi = &msg->ue_paging_identity.s_tmsi;
|
||||
const uint64_t fiveg_s_tmsi = nr_construct_5g_s_tmsi(s_tmsi->amf_set_id, s_tmsi->amf_pointer, s_tmsi->m_tmsi);
|
||||
const nr_rrc_config_t *req = &rrc->configuration;
|
||||
DevAssert(req->num_plmn > 0);
|
||||
|
||||
LOG_D(NR_RRC, "[gNB %ld] Processing NGAP Paging Indication for %d TAIs\n", instance, msg->n_tai);
|
||||
|
||||
// Paging Attempt Information (TS 38.413 §9.3.1.72, TS 38.300 §9.2.5)
|
||||
// AMF provides attempt count and intended attempts for paging optimization (area expansion, retransmission logic).
|
||||
if (msg->paging_attempt_info != NULL) {
|
||||
LOG_D(NR_RRC,
|
||||
"[gNB %ld] Paging Attempt Count: %u, Intended Number of Attempts: %u\n",
|
||||
instance,
|
||||
p->mcc,
|
||||
p->mnc_digit_length,
|
||||
p->mnc,
|
||||
tai->tac);
|
||||
nr_rrc_config_t *req = &RC.nrrrc[instance]->configuration;
|
||||
for (uint8_t j = 0; j < req->num_plmn; j++) {
|
||||
plmn_id_t *req_plmn = &req->plmn[j];
|
||||
if (req_plmn->mcc == p->mcc && req_plmn->mnc == p->mnc && req->tac == tai->tac) {
|
||||
for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
|
||||
AssertFatal(false, "to be implemented properly\n");
|
||||
if (NODE_IS_CU(RC.nrrrc[instance]->node_type)) {
|
||||
MessageDef *m = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_PAGING_IND);
|
||||
F1AP_PAGING_IND(m).plmn = *req_plmn;
|
||||
// Construct 5G-S-TMSI-Part1 from paging identity to find UE
|
||||
const fiveg_s_tmsi_t *s_tmsi = &msg->ue_paging_identity.s_tmsi;
|
||||
uint64_t s_tmsi_part1 = nr_construct_5g_s_tmsi_part1(s_tmsi->amf_set_id, s_tmsi->amf_pointer, s_tmsi->m_tmsi);
|
||||
// Try to find UE by 5G-S-TMSI-Part1
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_ue_context_5g_s_tmsi_exist(RC.nrrrc[instance], s_tmsi_part1);
|
||||
if (ue_context_p == NULL) {
|
||||
LOG_W(NR_RRC, "UE not found by paging identity\n");
|
||||
return -1;
|
||||
}
|
||||
// UE found: use its associated cell
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
nr_rrc_cell_container_t *cell = rrc_get_pcell_for_ue(RC.nrrrc[instance], UE);
|
||||
if (cell == NULL) {
|
||||
LOG_W(NR_RRC, "UE %d (rnti %04x) found by paging identity but has no valid cell\n", UE->rrc_ue_id, UE->rnti);
|
||||
return -1;
|
||||
}
|
||||
F1AP_PAGING_IND(m).nr_cellid = cell->info.cell_id;
|
||||
F1AP_PAGING_IND(m).ueidentityindexvalue = (uint16_t)(msg->ue_paging_identity.s_tmsi.m_tmsi % 1024);
|
||||
F1AP_PAGING_IND(m).fiveg_s_tmsi = msg->ue_paging_identity.s_tmsi.m_tmsi;
|
||||
F1AP_PAGING_IND(m).paging_drx = msg->paging_drx ? (uint8_t)*msg->paging_drx : 0;
|
||||
LOG_E(F1AP, "ueidentityindexvalue %u fiveg_s_tmsi %ld paging_drx %u\n", F1AP_PAGING_IND (m).ueidentityindexvalue, F1AP_PAGING_IND (m).fiveg_s_tmsi, F1AP_PAGING_IND (m).paging_drx);
|
||||
itti_send_msg_to_task(TASK_CU_F1, instance, m);
|
||||
} else {
|
||||
//rrc_gNB_generate_pcch_msg(NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi,(uint8_t)NGAP_PAGING_IND(msg_p).paging_drx, instance, CC_id);
|
||||
} // end of nodetype check
|
||||
} // end of cc loop
|
||||
} // end of mcc mnc check
|
||||
} // end of num_plmn
|
||||
} // end of tai size
|
||||
msg->paging_attempt_info->paging_attempt_count,
|
||||
msg->paging_attempt_info->intended_paging_attempts);
|
||||
}
|
||||
|
||||
if (msg->n_tai > NGAP_MAX_NO_TAI_PAGING) {
|
||||
LOG_E(NR_RRC,
|
||||
"[gNB %ld] Paging message error: n_tai (%d) exceeds NGAP_MAX_NO_TAI_PAGING (%d)\n",
|
||||
instance,
|
||||
msg->n_tai,
|
||||
NGAP_MAX_NO_TAI_PAGING);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Build F1AP paging message once for all TAIs
|
||||
f1ap_paging_t f1ap_msg = {0};
|
||||
f1ap_msg.ue_identity_index_value = s_tmsi->m_tmsi % 1024;
|
||||
f1ap_msg.identity_type = F1AP_PAGING_IDENTITY_CN_UE;
|
||||
f1ap_msg.identity.cn_ue_paging_identity = fiveg_s_tmsi;
|
||||
if (msg->paging_drx != NULL) {
|
||||
/* Mapping 1:1 between NGAP and F1AP Paging DRX */
|
||||
f1ap_msg.drx = malloc_or_fail(sizeof(*f1ap_msg.drx));
|
||||
*f1ap_msg.drx = (f1ap_paging_drx_t)*msg->paging_drx;
|
||||
}
|
||||
if (msg->paging_priority != NULL) {
|
||||
/* Mapping 1:1 between NGAP and F1AP Paging Priority */
|
||||
f1ap_msg.priority = malloc_or_fail(sizeof(*f1ap_msg.priority));
|
||||
*f1ap_msg.priority = (f1ap_paging_priority_t)*msg->paging_priority;
|
||||
}
|
||||
if (msg->origin != NULL) {
|
||||
/* Mapping 1:1 between NGAP and F1AP Paging Origin */
|
||||
f1ap_msg.origin = malloc_or_fail(sizeof(*f1ap_msg.origin));
|
||||
*f1ap_msg.origin = (f1ap_paging_origin_t)*msg->origin;
|
||||
}
|
||||
|
||||
// For each DU, collect cells matching any AMF TAI (PLMN+TAC) and send
|
||||
// one Paging with that cell list.
|
||||
rrc_send_paging_to_dus(rrc, msg->tai_list, msg->n_tai, &f1ap_msg);
|
||||
|
||||
free_f1ap_paging(&f1ap_msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE
|
||||
|
||||
void nr_rrc_pdcp_config_security(gNB_RRC_UE_t *UE, bool enable_ciphering);
|
||||
|
||||
int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance);
|
||||
int rrc_gNB_process_PAGING_IND(gNB_RRC_INST *rrc, const instance_t instance, const ngap_paging_ind_t *msg);
|
||||
|
||||
void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc,
|
||||
gNB_RRC_UE_t *UE,
|
||||
|
||||
@@ -820,3 +820,71 @@ void trigger_f1_reset(gNB_RRC_INST *rrc, sctp_assoc_t du_assoc_id)
|
||||
};
|
||||
rrc->mac_rrc.f1_reset(du_assoc_id, &reset);
|
||||
}
|
||||
|
||||
/** @brief Distribute paging to DUs serving cells matching any of the requested TAIs.
|
||||
* Loops DUs once, collects matching cells per DU, sends one message per DU.
|
||||
* Each cell is added at most once per DU (cells are unique by cell_id within a DU).
|
||||
* Per 3GPP TS 23.003, TAI is uniquely identified by (PLMN, TAC) combination.
|
||||
* @param rrc RRC instance
|
||||
* @param tais Array of TAIs (PLMN + TAC) to match against
|
||||
* @param n_tai Number of TAIs in the array (must be > 0)
|
||||
* @param msg Pre-filled F1AP paging message */
|
||||
void rrc_send_paging_to_dus(gNB_RRC_INST *rrc, const nr_tai_t tais[], uint8_t n_tai, f1ap_paging_t *msg)
|
||||
{
|
||||
DevAssert(msg && !msg->cells);
|
||||
DevAssert(n_tai > 0);
|
||||
|
||||
nr_rrc_du_container_t *du = NULL;
|
||||
// Loop over DUs once, for each DU, collects matching cells
|
||||
RB_FOREACH (du, rrc_du_tree, &rrc->dus) {
|
||||
RETURN_IF_INVALID_ASSOC_ID(du->assoc_id);
|
||||
|
||||
// Stack-allocated cell list for this DU iteration
|
||||
f1ap_paging_cell_item_t cells[F1AP_MAX_NB_CELLS] = {0};
|
||||
msg->cells = cells;
|
||||
msg->n_cells = 0;
|
||||
|
||||
// For each cell in this DU, check if it matches any of the matching TAIs
|
||||
FOR_EACH_SEQ_ARR (nr_rrc_cell_container_t **, cell, &du->cells) {
|
||||
if (msg->n_cells >= F1AP_MAX_NB_CELLS) {
|
||||
LOG_W(F1AP,
|
||||
"[gNB] Paging: DU assoc_id %d has more than %d matching cells, skipping next cells\n",
|
||||
du->assoc_id,
|
||||
F1AP_MAX_NB_CELLS);
|
||||
break;
|
||||
}
|
||||
|
||||
const nr_rrc_cell_info_t *info = &(*cell)->info;
|
||||
const plmn_id_t *cell_plmn = &info->plmn;
|
||||
const uint16_t cell_tac = info->tac;
|
||||
// Check if this cell's TAI (PLMN + TAC) matches any of the matching TAIs
|
||||
for (uint8_t j = 0; j < n_tai; j++) {
|
||||
const nr_tai_t *req_tai = &tais[j];
|
||||
const plmn_id_t *req_plmn = &req_tai->plmn;
|
||||
const uint16_t req_tac = req_tai->tac;
|
||||
if (cell_plmn->mcc == req_plmn->mcc && cell_plmn->mnc == req_plmn->mnc
|
||||
&& cell_plmn->mnc_digit_length == req_plmn->mnc_digit_length && cell_tac == req_tac) {
|
||||
f1ap_paging_cell_item_t *paging_cell = &msg->cells[msg->n_cells++];
|
||||
paging_cell->plmn = *cell_plmn;
|
||||
paging_cell->nr_cellid = info->cell_id;
|
||||
break; // Found match, no need to check other TAIs
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip DUs with no matching cells
|
||||
if (msg->n_cells == 0)
|
||||
continue;
|
||||
DevAssert(msg->n_cells <= F1AP_MAX_NB_CELLS);
|
||||
LOG_I(F1AP,
|
||||
"[gNB] Paging transfer to DU assoc_id %d: ue_identity_index_value=%u, paging_identity=%lu, n_cells=%u\n",
|
||||
du->assoc_id,
|
||||
msg->ue_identity_index_value,
|
||||
msg->identity.cn_ue_paging_identity,
|
||||
msg->n_cells);
|
||||
// Send one message to the DU with all matching cells
|
||||
rrc->mac_rrc.paging_transfer(du->assoc_id, msg);
|
||||
}
|
||||
|
||||
msg->cells = NULL; // Stack allocation, no need to free
|
||||
}
|
||||
|
||||
@@ -34,6 +34,9 @@ struct nr_rrc_cell_container_t;
|
||||
struct f1ap_gnb_du_configuration_update_s;
|
||||
struct f1ap_served_cell_info_t;
|
||||
|
||||
#include "f1ap_messages_types.h"
|
||||
#include "ngap_messages_types.h"
|
||||
|
||||
void rrc_gNB_process_f1_setup_req(struct f1ap_setup_req_s *req, sctp_assoc_t assoc_id);
|
||||
void rrc_CU_process_f1_lost_connection(struct gNB_RRC_INST_s *rrc, struct f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id);
|
||||
void rrc_gNB_process_f1_du_configuration_update(struct f1ap_gnb_du_configuration_update_s *conf_up, sctp_assoc_t assoc_id);
|
||||
@@ -58,4 +61,6 @@ struct nr_rrc_du_container_t *find_target_du(struct gNB_RRC_INST_s *rrc, sctp_as
|
||||
|
||||
void trigger_f1_reset(struct gNB_RRC_INST_s *rrc, sctp_assoc_t du_assoc_id);
|
||||
|
||||
void rrc_send_paging_to_dus(struct gNB_RRC_INST_s *rrc, const nr_tai_t tais[], uint8_t n_tai, f1ap_paging_t *f1ap_msg);
|
||||
|
||||
#endif /* RRC_GNB_DU_H_ */
|
||||
|
||||
Reference in New Issue
Block a user