From 45d989ec7b555a3ad994b15f4b040bcf5d07d23b Mon Sep 17 00:00:00 2001 From: Guido Casati Date: Wed, 27 Aug 2025 17:29:46 +0200 Subject: [PATCH] Adopt dynamic seq_arr in QoS Flow list (RRC PDU Session) --- .../RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c | 6 +- openair2/RRC/NR/nr_rrc_defs.h | 8 +- openair2/RRC/NR/nr_rrc_proto.h | 1 - openair2/RRC/NR/rrc_gNB.c | 35 +++--- openair2/RRC/NR/rrc_gNB_NGAP.c | 100 +++++++++++++----- openair2/RRC/NR/rrc_gNB_mobility.c | 7 +- openair2/RRC/NR/rrc_gNB_radio_bearers.c | 63 ++++++++++- openair2/RRC/NR/rrc_gNB_radio_bearers.h | 6 ++ 8 files changed, 162 insertions(+), 64 deletions(-) diff --git a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c index 4213ea8aa3..4e30773313 100644 --- a/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c +++ b/openair2/E2AP/RAN_FUNCTION/CUSTOMIZED/ran_func_gtp.c @@ -67,9 +67,9 @@ bool read_gtp_sm(void * data) gtp->msg.ngut[i].teidgnb = session->param.n3_outgoing.teid; gtp->msg.ngut[i].teidupf = session->param.n3_incoming.teid; // TODO: one PDU session has multiple QoS Flow - int nb_qos_flow = session->param.nb_qos; - if (nb_qos_flow > 0) { - gtp->msg.ngut[i].qfi = session->param.qos[nb_qos_flow - 1].qfi; + DevAssert(seq_arr_size(&session->param.qos) == 1); + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->param.qos) { + gtp->msg.ngut[i].qfi = qos->qos.qfi; } break; } diff --git a/openair2/RRC/NR/nr_rrc_defs.h b/openair2/RRC/NR/nr_rrc_defs.h index 43909e0cd0..3491154923 100644 --- a/openair2/RRC/NR/nr_rrc_defs.h +++ b/openair2/RRC/NR/nr_rrc_defs.h @@ -103,9 +103,8 @@ typedef struct pdusession_s { /* Unique pdusession_id for the UE. */ int pdusession_id; byte_array_t nas_pdu; - uint8_t nb_qos; /* Quality of service for this pdusession */ - pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE]; + seq_arr_t qos; /* The transport layer address for the IP packets */ pdu_session_type_t pdu_session_type; // NG-RAN endpoint of the NG-U (N3) transport bearer @@ -176,6 +175,11 @@ typedef struct nr_redcap_ue_cap { bool rlc_am_drb_long_sn_redcap_r17; } nr_redcap_ue_cap_t; +typedef struct { + int drb_id; + pdusession_level_qos_parameter_t qos; +} nr_rrc_qos_t; + /* forward declaration */ typedef struct nr_handover_context_s nr_handover_context_t; diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 0c545575ba..d7c1c0efce 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -122,7 +122,6 @@ byte_array_t rrc_gNB_encode_RRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t * nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t srb_reest_bitmap, bool drb_reestablish); -pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession); f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param); void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *configuration); NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1919ccaa5c..5e95ad690a 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -733,9 +733,8 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t } // Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping - for (qos_flow_index = 0; qos_flow_index < session->nb_qos; qos_flow_index++) { - pdusession_level_qos_parameter_t *qos = &session->qos[qos_flow_index]; - switch (qos->fiveQI) { + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) { + switch (qos->qos.fiveQI) { case 1: //100ms case 2: //150ms case 3: //50ms @@ -749,14 +748,14 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t break; default: - LOG_E(NR_RRC, "not supported 5qi %lu\n", qos->fiveQI); + LOG_E(NR_RRC, "not supported 5qi %lu\n", qos->qos.fiveQI); ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_not_supported_5QI_value}; item->status = PDU_SESSION_STATUS_FAILED; item->xid = params.transaction_id; item->cause = cause; continue; } - LOG_I(NR_RRC, "PDU Session ID %d, QOS flow %d, 5QI %ld \n", session->pdusession_id, qos_flow_index, qos->fiveQI); + LOG_I(NR_RRC, "PDU Session ID %d, QOS flow %d, 5QI %ld \n", session->pdusession_id, qos_flow_index, qos->qos.fiveQI); } item->status = PDU_SESSION_STATUS_DONE; item->xid = params.transaction_id; @@ -2101,14 +2100,15 @@ void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb }; bool is_inter_cu_ho = UE->ho_context && UE->ho_context->source && !UE->ho_context->target; - for (int i = 0; i < MAX_DRBS_PER_UE; i++) { - int drb_id = i + 1; + int drb_index = 0; + FOR_EACH_SEQ_ARR(drb_t *, drb, &UE->drbs) { + int drb_id = drb->drb_id; DRB_nGRAN_to_mod_t drb_to_mod = {0}; if (n > 0) { /* DRBs to Setup in F1 UE Context Modifcation Response */ - if (i == n) + if (drb_index == n) break; - const f1ap_drb_setup_t *drb_f1 = &drbs[i]; + const f1ap_drb_setup_t *drb_f1 = &drbs[drb_index]; drb_id = drb_f1->id; fill_e1_bearer_modif(&drb_to_mod, drb_f1); } else if (is_inter_cu_ho) { @@ -2134,6 +2134,8 @@ void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb to_mod->sessionId = pdu->param.pdusession_id; // Fill E1 DRB to Modify item to_mod->DRBnGRanModList[to_mod->numDRB2Modify++] = drb_to_mod; + + drb_index++; } DevAssert(req.numPDUSessionsMod > 0); DevAssert(req.numPDUSessions == 0); @@ -2448,17 +2450,6 @@ unsigned int mask_flip(unsigned int x) { return((((x>>8) + (x<<8))&0xffff)>>6); } -pdusession_level_qos_parameter_t *get_qos_characteristics(const int qfi, rrc_pdu_session_param_t *pduSession) -{ - pdusession_t *pdu = &pduSession->param; - for (int i = 0; i < pdu->nb_qos; i++) { - if (qfi == pdu->qos[i].qfi) - return &pdu->qos[i]; - } - AssertFatal(1 == 0, "The pdu session %d does not contain a qos flow with qfi = %d\n", pdu->pdusession_id, qfi); - return NULL; -} - /* \bref return F1AP QoS characteristics based on Qos flow parameters */ f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qos_parameter_t *qos_param) { @@ -2516,11 +2507,11 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc, /* 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. */ - pdusession_level_qos_parameter_t *qos_param = get_qos_characteristics(qfi, pdu); + 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); + 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; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index ddf97b2499..e584912a38 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -172,20 +172,30 @@ static nr_guami_t get_guami(const uint32_t amf_Id, const plmn_id_t plmn) /** @brief Copy NGAP PDU Session Transfer item to RRC pdusession_t struct */ static void cp_pdusession_transfer_to_pdusession(pdusession_t *dst, const pdusession_transfer_t *src) { - dst->nb_qos = src->nb_qos; - for (uint8_t i = 0; i < src->nb_qos && i < QOSFLOW_MAX_VALUE; ++i) { - dst->qos[i] = src->qos[i]; - } dst->pdu_session_type = src->pdu_session_type; dst->n3_incoming = src->n3_incoming; + /* QoS handling */ + DevAssert(!dst->qos.data); + DevAssert(src->nb_qos < QOSFLOW_MAX_VALUE); + // Initialise mapped QoS list per PDU Session + seq_arr_init(&dst->qos, sizeof(nr_rrc_qos_t)); + // Add QoS flow to list + for (uint8_t i = 0; i < src->nb_qos; ++i) { + if (!add_qos(&dst->qos, &src->qos[i])) { + LOG_E(NR_RRC, "Failed to add QoS flow %d for PDU session %d\n", src->qos[i].qfi, dst->pdusession_id); + continue; + } + } } -/** @brief Copy NGAP PDU Session Resource item to RRC pdusession_t struct */ +/** @brief Copy NGAP PDU Session Resource item to RRC pdusession_t struct to setup */ static void cp_pdusession_resource_item_to_pdusession(pdusession_t *dst, const pdusession_resource_item_t *src) { dst->pdusession_id = src->pdusession_id; dst->nas_pdu = src->nas_pdu; dst->nssai = src->nssai; + + // Use the PDU session transfer function to handle QoS and other PDU session transfer-specific fields cp_pdusession_transfer_to_pdusession(dst, &src->pdusessionTransfer); } @@ -343,11 +353,10 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession *cellGroup = MCG; } - drb->numQosFlow2Setup = session->nb_qos; - for (int k=0; k < drb->numQosFlow2Setup; k++) { - qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; - pdusession_level_qos_parameter_t *qos_session = session->qos + k; - + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) { + pdusession_level_qos_parameter_t *qos_session = &qos->qos; + DevAssert(drb->numQosFlow2Setup < QOSFLOW_MAX_VALUE); + qos_flow_to_setup_t *qos_flow = &drb->qosFlows[drb->numQosFlow2Setup++]; qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; qos_flow->qfi = qos_session->qfi; qos_char->qos_type = qos_session->fiveQI_type; @@ -505,10 +514,11 @@ static pdusession_setup_t fill_ngap_pdusession_setup(pdusession_t *session) out.pdusession_id = session->pdusession_id; out.pdu_session_type = session->pdu_session_type; out.n3_outgoing = cp_gtp_tunnel(session->n3_outgoing); - out.nb_of_qos_flow = session->nb_qos; - for (int q = 0; q < session->nb_qos; q++) { - out.associated_qos_flows[q].qfi = session->qos[q].qfi; - out.associated_qos_flows[q].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos_session, &session->qos) { + DevAssert(out.nb_of_qos_flow < QOSFLOW_MAX_VALUE); + pdusession_associate_qosflow_t *q = &out.associated_qos_flows[out.nb_of_qos_flow++]; + q->qfi = qos_session->qos.qfi; + q->qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; } char ip_str[INET_ADDRSTRLEN] = {0}; inet_ntop(AF_INET, out.n3_outgoing.addr.buffer, ip_str, sizeof(ip_str)); @@ -868,6 +878,36 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins } } +/** @brief Update existing QoS Flow mapped in the UE context */ +static void nr_rrc_update_qos(seq_arr_t *list, const int nb_qos, const pdusession_level_qos_parameter_t *in_qos) +{ + DevAssert(nb_qos == 1); + DevAssert(nb_qos < QOSFLOW_MAX_VALUE); + for (uint8_t i = 0; i < nb_qos; ++i) { + nr_rrc_qos_t *qos = find_qos(list, in_qos[i].qfi); + if (qos) { + AssertFatal(qos->qos.qfi == in_qos[i].qfi, "QoS Flow to modify must match existing one"); + LOG_I(NR_RRC, "Updating QoS for QFI=%d\n", in_qos[i].qfi); + qos->qos = in_qos[i]; + } else { + LOG_E(NR_RRC, "Failed to update QoS for QFI=%d: QoS flow not found\n", in_qos[i].qfi); + } + } +} + +/** @brief Update stored pdusession_t in list from NGAP PDU Session Resource item */ +static void nr_rrc_update_pdusession(pdusession_t *dst, const pdusession_resource_item_t *src) +{ + dst->pdusession_id = src->pdusession_id; + dst->nas_pdu = src->nas_pdu; + dst->pdu_session_type = src->pdusessionTransfer.pdu_session_type; + dst->n3_incoming = src->pdusessionTransfer.n3_incoming; + dst->nssai = src->nssai; + DevAssert(dst->qos.data); // QoS list has to be initialized at this stage + // Update QoS flow + nr_rrc_update_qos(&dst->qos, src->pdusessionTransfer.nb_qos, src->pdusessionTransfer.qos); +} + //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t instance) //------------------------------------------------------------------------------ @@ -900,7 +940,7 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins all_failed = false; session->status = PDU_SESSION_STATUS_NEW; session->cause.type = NGAP_CAUSE_NOTHING; - cp_pdusession_resource_item_to_pdusession(&session->param, sessMod); + nr_rrc_update_pdusession(&session->param, sessMod); } } @@ -969,20 +1009,20 @@ int rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE session->cause.type = NGAP_CAUSE_NOTHING; // Fill response DevAssert(pdu_sessions_done < NGAP_MAX_PDU_SESSION); - resp->pdusessions[pdu_sessions_done].pdusession_id = session->param.pdusession_id; - for (int qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) { - resp->pdusessions[pdu_sessions_done].qos[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi; + pdusession_modify_t *p = &resp->pdusessions[pdu_sessions_done++]; + p->pdusession_id = session->param.pdusession_id; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos_session, &session->param.qos) { + DevAssert(p->nb_of_qos_flow < QOSFLOW_MAX_VALUE); + qos_flow_tobe_modified_t *q = &p->qos[p->nb_of_qos_flow++]; + q->qfi = qos_session->qos.qfi; } - resp->pdusessions[pdu_sessions_done].pdusession_id = session->param.pdusession_id; - resp->pdusessions[pdu_sessions_done].nb_of_qos_flow = session->param.nb_qos; LOG_I(NR_RRC, "Modify Resp (msg index %d, status %d, xid %d): nb_of_pduSessions %ld, pdusession_id %d \n ", pdu_sessions_done, session->status, xid, seq_arr_size(&UE->pduSessions), - resp->pdusessions[pdu_sessions_done].pdusession_id); - pdu_sessions_done++; + p->pdusession_id); } else if ((session->status == PDU_SESSION_STATUS_NEW) || (session->status == PDU_SESSION_STATUS_ESTABLISHED)) { LOG_D(NR_RRC, "PDU SESSION is NEW or already ESTABLISHED\n"); } else if (session->status == PDU_SESSION_STATUS_FAILED) { @@ -1373,10 +1413,11 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(gNB_RRC_INST *rrc, gNB_RRC_U transfer->gtp_teid = session->param.n3_outgoing.teid; memcpy(transfer->gNB_addr.buffer, session->param.n3_outgoing.addr.buffer, session->param.n3_outgoing.addr.length); transfer->gNB_addr.length = session->param.n3_outgoing.addr.length; - transfer->nb_of_qos_flow = session->param.nb_qos; - for (int q = 0; q < transfer->nb_of_qos_flow; q++) { - transfer->qos_setup_list[q].qfi = session->param.qos[q].qfi; - transfer->qos_setup_list[q].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->param.qos) { + DevAssert(transfer->nb_of_qos_flow < QOSFLOW_MAX_VALUE); + pdusession_associate_qosflow_t *qos_setup = &transfer->qos_setup_list[transfer->nb_of_qos_flow++]; + qos_setup->qfi = qos->qos.qfi; + qos_setup->qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; } } // Target to Source Transparent Container @@ -1620,9 +1661,10 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc, DevAssert(msg.source2target->nb_pdu_session_resource < NGAP_MAX_PDU_SESSION); pdusession_resource_info_t *pdu_info = &msg.source2target->pdu_session_resource[msg.source2target->nb_pdu_session_resource++]; pdu_info->pdusession_id = session->pdusession_id; - pdu_info->nb_of_qos_flow = session->nb_qos; - for (int j = 0; j < pdu_info->nb_of_qos_flow; ++j) { - pdu_info->qos_flow_info[j].qfi = session->qos[j].qfi; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) { + DevAssert(pdu_info->nb_of_qos_flow < QOSFLOW_MAX_VALUE); + qosflow_info_t *qos_flow = &pdu_info->qos_flow_info[pdu_info->nb_of_qos_flow++]; + qos_flow->qfi = qos->qos.qfi; } } diff --git a/openair2/RRC/NR/rrc_gNB_mobility.c b/openair2/RRC/NR/rrc_gNB_mobility.c index 3c17f45189..0d97e5d30a 100644 --- a/openair2/RRC/NR/rrc_gNB_mobility.c +++ b/openair2/RRC/NR/rrc_gNB_mobility.c @@ -77,11 +77,8 @@ static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_ rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue, rrc_drb->drb_id); AssertFatal(pdu != NULL, "no PDU session for DRB ID %d\n", rrc_drb->drb_id); - // for the moment, we only support one QoS flow. Put a reminder in case - // this changes - AssertFatal(pdu->param.nb_qos == 1, "only 1 Qos flow supported\n"); int qfi = rrc_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[0]; - pdusession_level_qos_parameter_t *qos_param = get_qos_characteristics(qfi, pdu); + nr_rrc_qos_t *qos_param = find_qos(&pdu->param.qos, qfi); drb->id = rrc_drb->drb_id; @@ -91,7 +88,7 @@ static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_ drb->nr.flows = calloc_or_fail(1, sizeof(*drb->nr.flows)); DevAssert(qfi > 0); drb->nr.flows[0].qfi = qfi; - drb->nr.flows[0].param = get_qos_char_from_qos_flow_param(qos_param); + drb->nr.flows[0].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; diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.c b/openair2/RRC/NR/rrc_gNB_radio_bearers.c index 1f2f721eaa..ab68a4c367 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.c +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.c @@ -33,6 +33,61 @@ #include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h" #include "common/utils/alg/find.h" +static bool eq_qfi(const void *vval, const void *vit) +{ + const int id = *(const int *)vval; + const nr_rrc_qos_t *elem = (const nr_rrc_qos_t *)vit; + return elem->qos.qfi == id; +} + +/** @brief Retrieves mapped QoS in UE context for the input @param qfi + * @return pointer to the found QoS, NULL if not found */ +nr_rrc_qos_t *find_qos(seq_arr_t *seq, int qfi) +{ + DevAssert(seq); + elm_arr_t elm = find_if(seq, &qfi, eq_qfi); + if (elm.found) + return (nr_rrc_qos_t *)elm.it; + return NULL; +} + +/** @brief Adds a new QoS @param in to UE context the list + * @note A UE can have up to 64 QoS flows which can be multiplexed + * into one or more DRBs. The QFI is the unique ID of the mapping. + * @return pointer to the newly added QoS */ +nr_rrc_qos_t *add_qos(seq_arr_t *qos, const pdusession_level_qos_parameter_t *in) +{ + DevAssert(qos); + DevAssert(in); + + if (seq_arr_size(qos) == QOSFLOW_MAX_VALUE) { + LOG_W(NR_RRC, "Reached maximum number of QoS flows = %ld\n", seq_arr_size(qos)); + return NULL; + } + + nr_rrc_qos_t item = {.qos = *in}; + seq_arr_push_back(qos, &item, sizeof(nr_rrc_qos_t)); + + // Double check successful add + nr_rrc_qos_t *added = find_qos(qos, in->qfi); + DevAssert(added); + LOG_I(NR_RRC, "Added QoS flow with qfi=%d, total number of QoS flows = %ld\n", in->qfi, seq_arr_size(qos)); + + // Only one QoS flow is supported + AssertFatal(seq_arr_size(qos) == 1, "only 1 Qos flow supported\n"); + + return added; +} + +/** @brief Free QoS flows list items */ +static void free_qos(void *ptr) { /*nothing to do*/ } + +/** @brief Free QoS flows list */ +static void free_rrc_qos_list(seq_arr_t *seq) +{ + seq_arr_free(seq, free_qos); +} + static bool eq_pdu_session_id(const void *vval, const void *vit) { const int id = *(const int *)vval; @@ -44,6 +99,7 @@ static bool eq_pdu_session_id(const void *vval, const void *vit) void free_pdusession(void *ptr) { rrc_pdu_session_param_t *elem = ptr; + free_rrc_qos_list(&elem->param.qos); free_byte_array(elem->param.nas_pdu); } @@ -210,8 +266,11 @@ drb_t *generateDRB(gNB_RRC_UE_t *ue, est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_absent; est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_absent; } - for (int qos_flow_index = 0; qos_flow_index < pduSession->nb_qos; qos_flow_index++) { - est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->qos[qos_flow_index].qfi; + int qos_flow_index = 0; + FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos_session, &pduSession->qos) { + qos_session->drb_id = est_drb->drb_id; // Map DRB to QoS + est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index++] = qos_session->qos.qfi; + DevAssert(qos_flow_index <= QOSFLOW_MAX_VALUE); } /* PDCP Configuration */ set_default_drb_pdcp_config(&est_drb->pdcp_config, do_drb_integrity, do_drb_ciphering, pdcp_config, ue->redcap_cap); diff --git a/openair2/RRC/NR/rrc_gNB_radio_bearers.h b/openair2/RRC/NR/rrc_gNB_radio_bearers.h index 982e7ea42d..e5ec90c5c6 100644 --- a/openair2/RRC/NR/rrc_gNB_radio_bearers.h +++ b/openair2/RRC/NR/rrc_gNB_radio_bearers.h @@ -72,4 +72,10 @@ drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id); /// @brief Function to free DRB in RRC void free_drb(void *ptr); +/// @brief retrieve QoS flow associated to @param qfi +nr_rrc_qos_t *find_qos(seq_arr_t *seq, int qfi); + +/// @brief Add a new QoS to the list +nr_rrc_qos_t *add_qos(seq_arr_t *qos, const pdusession_level_qos_parameter_t *in); + #endif