RRC: refactor F1 DRB setup list filling into shared helpers
Extract common code from `fill_drb_to_be_setup_from_e1_resp` and `rrc_fill_f1_drb_to_setup` into reusable helper functions to reduce duplication and improve maintainability. This refactoring enables multi-QoS flow handling per DRB and prepares helpers for upcoming PDU Session Modify changes. Impact: - Enables multi-QoS flow support: `rrc_fill_f1_drb_to_setup` now collects all QFIs mapped to a DRB instead of only the first one - Reduces code duplication between E1 response and direct DRB setup code paths - Improves maintainability by centralizing F1 DRB setup logic Major changes: - Add `fill_f1_drb_info_nr`: fills DRB information IE including QoS flows from QFI list - Add `fill_f1_drb_to_be_setup`: creates F1 DRB to setup structure from RRC DRB, PDU session, and QFI list - Add `fill_f1_drbs_from_e1`: processes DRBs from E1 response and extracts QFIs from drb_config->qosFlows - Refactor `fill_drb_to_be_setup_from_e1_resp` to use `fill_f1_drbs_from_e1` - Refactor `rrc_fill_f1_drb_to_setup` to collect all QFIs mapped to each DRB and use `fill_f1_drb_to_be_setup`
This commit is contained in:
@@ -39,6 +39,7 @@
|
||||
#include "NR_CG-ConfigInfo.h"
|
||||
#include "NR_RRCReconfiguration.h"
|
||||
#include "RRC/NR/MESSAGES/asn1_msg.h"
|
||||
#include "f1ap_messages_types.h"
|
||||
|
||||
#define SRB1 1
|
||||
#define SRB2 2
|
||||
|
||||
+114
-76
@@ -2852,6 +2852,104 @@ f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qo
|
||||
return qos_char;
|
||||
}
|
||||
|
||||
static f1ap_drb_info_nr_t fill_f1_drb_info_nr(pdusession_t *pdu, const uint8_t *qfis, const int num_qfis)
|
||||
{
|
||||
f1ap_drb_info_nr_t drb_info = {0};
|
||||
drb_info.nssai = pdu->nssai;
|
||||
drb_info.flows_len = num_qfis;
|
||||
drb_info.flows = calloc_or_fail(num_qfis, sizeof(*drb_info.flows));
|
||||
for (int i = 0; i < num_qfis; i++) {
|
||||
int qfi = qfis[i];
|
||||
/* find the stored QoS flow parameters for this QFI */
|
||||
nr_rrc_qos_t *qos_param = find_qos(&pdu->qos, qfi);
|
||||
DevAssert(qos_param);
|
||||
/* QoS flows Flows Mapped to DRB Item */
|
||||
f1ap_drb_flows_mapped_t *flow = &drb_info.flows[i];
|
||||
flow->qfi = qfi;
|
||||
flow->param = get_qos_char_from_qos_flow_param(&qos_param->qos);
|
||||
}
|
||||
/* DRB QoS IE: we just reuse the ones from the first flow */
|
||||
drb_info.drb_qos = drb_info.flows[0].param;
|
||||
return drb_info;
|
||||
}
|
||||
|
||||
/** @brief Fill F1 DRB to Be Setup List (UE Context Setup Request)
|
||||
* @param rrc RRC instance
|
||||
* @param rrc_drb RRC DRB structure
|
||||
* @param pdu PDU session parameters
|
||||
* @param qfis List of QFIs
|
||||
* @param num_qfis Number of QFIs in list
|
||||
* @return Filled F1 DRB to setup structure */
|
||||
static f1ap_drb_to_setup_t fill_f1_drb_to_be_setup(const gNB_RRC_INST *rrc,
|
||||
const drb_t *rrc_drb,
|
||||
rrc_pdu_session_param_t *pdu,
|
||||
const uint8_t *qfis,
|
||||
int num_qfis)
|
||||
{
|
||||
DevAssert(rrc);
|
||||
DevAssert(rrc_drb);
|
||||
DevAssert(pdu);
|
||||
DevAssert(qfis);
|
||||
DevAssert(num_qfis > 0);
|
||||
DevAssert(num_qfis <= MAX_QOS_FLOWS);
|
||||
|
||||
f1ap_drb_to_setup_t drb = {0};
|
||||
|
||||
drb.id = rrc_drb->drb_id;
|
||||
drb.qos_choice = F1AP_QOS_CHOICE_NR;
|
||||
/* DRB Info (including QoS flows) */
|
||||
drb.nr = fill_f1_drb_info_nr(&pdu->param, qfis, num_qfis);
|
||||
|
||||
/* tunnel info */
|
||||
if (rrc_drb->cuup_tunnel_config.addr.length != sizeof(in_addr_t)) {
|
||||
LOG_W(RRC,
|
||||
"IPv4 address expected (length == %zu), got length %d\n",
|
||||
sizeof(in_addr_t),
|
||||
rrc_drb->cuup_tunnel_config.addr.length);
|
||||
}
|
||||
memcpy(&drb.up_ul_tnl[0].tl_address, rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(in_addr_t));
|
||||
drb.up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid;
|
||||
drb.up_ul_tnl_len = 1;
|
||||
|
||||
/* RLC mode */
|
||||
drb.rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM;
|
||||
|
||||
/* PDCP SN length */
|
||||
const nr_pdcp_configuration_t *pdcp = &rrc_drb->pdcp_config;
|
||||
DevAssert(pdcp->drb.sn_size == 18 || pdcp->drb.sn_size == 12);
|
||||
drb.dl_pdcp_sn_len = malloc_or_fail(sizeof(*drb.dl_pdcp_sn_len));
|
||||
*drb.dl_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
drb.ul_pdcp_sn_len = malloc_or_fail(sizeof(*drb.ul_pdcp_sn_len));
|
||||
*drb.ul_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
|
||||
return drb;
|
||||
}
|
||||
|
||||
/** @brief Helper function to process DRBs from a PDU session's DRB setup list */
|
||||
static int fill_f1_drbs_from_e1(const gNB_RRC_INST *rrc,
|
||||
gNB_RRC_UE_t *UE,
|
||||
rrc_pdu_session_param_t *pdu,
|
||||
const DRB_nGRAN_setup_t *drb_list,
|
||||
const int drb_list_len,
|
||||
f1ap_drb_to_setup_t drbs[32])
|
||||
{
|
||||
int nb_drb = 0;
|
||||
for (int i = 0; i < drb_list_len; i++) {
|
||||
const DRB_nGRAN_setup_t *drb_config = &drb_list[i];
|
||||
drb_t *rrc_drb = get_drb(&UE->drbs, drb_config->id);
|
||||
DevAssert(rrc_drb);
|
||||
int nb_qos_flows = drb_config->numQosFlowSetup;
|
||||
DevAssert(nb_qos_flows <= MAX_QOS_FLOWS);
|
||||
AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n");
|
||||
uint8_t qfis[MAX_QOS_FLOWS] = {0};
|
||||
for (int j = 0; j < nb_qos_flows; j++)
|
||||
qfis[j] = drb_config->qosFlows[j].qfi;
|
||||
drbs[nb_drb++] = fill_f1_drb_to_be_setup(rrc, rrc_drb, pdu, qfis, nb_qos_flows);
|
||||
}
|
||||
DevAssert(nb_drb < MAX_DRBS_PER_UE);
|
||||
return nb_drb;
|
||||
}
|
||||
|
||||
/* \brief fills a list of DRBs to be setup from a number of PDU sessions in E1
|
||||
* bearer setup response */
|
||||
static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc,
|
||||
@@ -2862,56 +2960,12 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc,
|
||||
{
|
||||
int nb_drb = 0;
|
||||
for (int p = 0; p < numPduSession; ++p) {
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession(&UE->pduSessions, pduSession[p].id);
|
||||
const pdu_session_setup_t *session = &pduSession[p];
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession(&UE->pduSessions, session->id);
|
||||
DevAssert(pdu);
|
||||
for (int i = 0; i < pduSession[p].numDRBSetup; i++) {
|
||||
const DRB_nGRAN_setup_t *drb_config = &pduSession[p].DRBnGRanList[i];
|
||||
drb_t *rrc_drb = get_drb(&UE->drbs, pduSession[p].DRBnGRanList[i].id);
|
||||
nr_pdcp_configuration_t pdcp = rrc_drb->pdcp_config;
|
||||
DevAssert(rrc_drb);
|
||||
|
||||
DevAssert(nb_drb < MAX_DRBS_PER_UE);
|
||||
f1ap_drb_to_setup_t *drb = &drbs[nb_drb];
|
||||
drb->id = rrc_drb->drb_id;
|
||||
|
||||
drb->qos_choice = F1AP_QOS_CHOICE_NR;
|
||||
|
||||
/* pass QoS info to MAC */
|
||||
int nb_qos_flows = drb_config->numQosFlowSetup;
|
||||
AssertFatal(nb_qos_flows > 0, "must map at least one flow to a DRB\n");
|
||||
DevAssert(nb_qos_flows <= MAX_QOS_FLOWS);
|
||||
drb->nr.flows_len = nb_qos_flows;
|
||||
drb->nr.flows = calloc_or_fail(nb_qos_flows, sizeof(*drb->nr.flows));
|
||||
for (int j = 0; j < nb_qos_flows; j++) {
|
||||
int qfi = drb_config->qosFlows[j].qfi;
|
||||
/* find the QoS characteristics stored at RRC based on QFI returned
|
||||
* from E1. We expect this to correspond to a QFI we passed to E1
|
||||
* previously, so we expect it to exist. */
|
||||
nr_rrc_qos_t *qos_param = find_qos(&pdu->param.qos, qfi);
|
||||
DevAssert(qos_param);
|
||||
f1ap_drb_flows_mapped_t *flow = &drb->nr.flows[j];
|
||||
flow->qfi = qfi;
|
||||
flow->param = get_qos_char_from_qos_flow_param(&qos_param->qos);
|
||||
}
|
||||
/* the DRB QoS parameters: we just reuse the ones from the first flow */
|
||||
drb->nr.drb_qos = drb->nr.flows[0].param;
|
||||
|
||||
/* pass NSSAI info to MAC */
|
||||
drb->nr.nssai = pdu->param.nssai;
|
||||
|
||||
drb->up_ul_tnl[0].tl_address = drb_config->UpParamList[0].tl_info.tlAddress;
|
||||
drb->up_ul_tnl[0].teid = drb_config->UpParamList[0].tl_info.teId;
|
||||
drb->up_ul_tnl_len = 1;
|
||||
drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM;
|
||||
DevAssert(pdcp.drb.sn_size == 18 || pdcp.drb.sn_size == 12);
|
||||
drb->dl_pdcp_sn_len = malloc_or_fail(sizeof(*drb->dl_pdcp_sn_len));
|
||||
*drb->dl_pdcp_sn_len = pdcp.drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
drb->ul_pdcp_sn_len = malloc_or_fail(sizeof(*drb->ul_pdcp_sn_len));
|
||||
*drb->ul_pdcp_sn_len = pdcp.drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
|
||||
nb_drb++;
|
||||
}
|
||||
nb_drb += fill_f1_drbs_from_e1(rrc, UE, pdu, session->DRBnGRanList, session->numDRBSetup, drbs);
|
||||
}
|
||||
DevAssert(nb_drb < MAX_DRBS_PER_UE);
|
||||
return nb_drb;
|
||||
}
|
||||
|
||||
@@ -3555,39 +3609,23 @@ static int rrc_fill_f1_drb_to_setup(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t
|
||||
|
||||
FOR_EACH_SEQ_ARR(drb_t *, rrc_drb, &ue->drbs) {
|
||||
DevAssert(nb_drb < MAX_DRBS_PER_UE);
|
||||
f1ap_drb_to_setup_t *drb = &drbs[nb_drb];
|
||||
nr_pdcp_configuration_t *pdcp = &rrc_drb->pdcp_config;
|
||||
nb_drb++;
|
||||
/* fetch an existing PDU session for this DRB */
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId((gNB_RRC_UE_t *)ue, rrc_drb->drb_id);
|
||||
AssertFatal(pdu != NULL, "no PDU session for DRB ID %d\n", rrc_drb->drb_id);
|
||||
|
||||
drb->id = rrc_drb->drb_id;
|
||||
/* Collect all QFIs mapped to this DRB */
|
||||
uint8_t qfis[MAX_QOS_FLOWS] = {0};
|
||||
int num_qfis = 0;
|
||||
FOR_EACH_SEQ_ARR (nr_rrc_qos_t *, qos, &pdu->param.qos) {
|
||||
if (qos->drb_id == rrc_drb->drb_id) {
|
||||
DevAssert(num_qfis < MAX_QOS_FLOWS);
|
||||
qfis[num_qfis++] = qos->qos.qfi;
|
||||
}
|
||||
}
|
||||
AssertFatal(num_qfis > 0, "no QoS flows mapped to DRB ID %d\n", rrc_drb->drb_id);
|
||||
|
||||
drb->qos_choice = F1AP_QOS_CHOICE_NR;
|
||||
drb->nr.nssai = pdu->param.nssai;
|
||||
drb->nr.flows_len = 1;
|
||||
drb->nr.flows = calloc_or_fail(1, sizeof(*drb->nr.flows));
|
||||
|
||||
/* QoS flow associated with this DRB: use first QoS flow */
|
||||
AssertFatal(seq_arr_size(&pdu->param.qos) == 1, "only 1 Qos flow supported\n");
|
||||
nr_rrc_qos_t *qos_param = (nr_rrc_qos_t *)seq_arr_at(&pdu->param.qos, 0);
|
||||
DevAssert(qos_param->qos.qfi > 0);
|
||||
drb->nr.flows[0].qfi = qos_param->qos.qfi;
|
||||
drb->nr.flows[0].param = get_qos_char_from_qos_flow_param(&qos_param->qos);
|
||||
/* the DRB QoS parameters: reuse the ones from the first flow */
|
||||
drb->nr.drb_qos = drb->nr.flows[0].param;
|
||||
|
||||
memcpy(&drb->up_ul_tnl[0].tl_address, &rrc_drb->cuup_tunnel_config.addr.buffer, sizeof(uint8_t) * 4);
|
||||
drb->up_ul_tnl[0].teid = rrc_drb->cuup_tunnel_config.teid;
|
||||
drb->up_ul_tnl_len = 1;
|
||||
|
||||
drb->rlc_mode = rrc->configuration.um_on_default_drb ? F1AP_RLC_MODE_UM_BIDIR : F1AP_RLC_MODE_AM;
|
||||
DevAssert(pdcp->drb.sn_size == 18 || pdcp->drb.sn_size == 12);
|
||||
drb->dl_pdcp_sn_len = malloc_or_fail(sizeof(*drb->dl_pdcp_sn_len));
|
||||
*drb->dl_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
drb->ul_pdcp_sn_len = malloc_or_fail(sizeof(*drb->ul_pdcp_sn_len));
|
||||
*drb->ul_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
/* Use the common function to fill DRB setup */
|
||||
drbs[nb_drb++] = fill_f1_drb_to_be_setup(rrc, rrc_drb, pdu, qfis, num_qfis);
|
||||
}
|
||||
return nb_drb;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user