Merge remote-tracking branch 'origin/rrc-qos-refactor' into integration_2026_w07 (!3907)
RRC QoS refactor: PDU Session Modify support, SDAP fixes, and code improvements
The goal of this MR is to prepare the RRC/NGAP layer for the multi-QoS
support. The MR:
- enables PDU Session Resource Modify support in RRC/NGAP/E1AP
- fixes SDAP header mapping
- enables SDAP by default
- refactors QoS flow handling in RRC/NGAP
- improves error handling, and code maintainability in RRC/NGAP
Changes:
- NGAP PDU Session Modify:
* add NGAP PDU Session Resource Modify Request/Response handling with
proper error reporting for unrecognized sessions and AMF UE NGAP ID
validation
- E1AP Bearer Context Modification:
* add DRB To Remove List IE to support DRB release during modify
* rename numQosFlow2Setup to numQosFlowsMod in DRB To Modify List
- RRC QoS flow handling:
* enable multi-QoS flow support per DRB
* add utilities to map NGAP QoS parameters to E1AP
* filter QoS flows by DRB ID
- SDAP configuration:
* Fix SDAP header UL/DL mapping between internal representation and
ASN.1 enum (invert mapping)
* change SDAP header fields from long to bool for clarity
- F1 DRB setup refactoring:
* Extract shared helpers for F1 DRB setup list filling
* reduce duplication between E1 response and direct DRB setup paths
- AMBR management:
* Store AMBR in UE context
* validate AMBR is set before bearer setup
- Configuration:
* remove unused drbs configuration parameter
* enable SDAP by default (change default from false to true)
This commit is contained in:
@@ -18,7 +18,7 @@ gNBs =
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 6;
|
||||
enable_sdap = 1;
|
||||
enable_sdap = 0;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
|
||||
@@ -18,7 +18,7 @@ gNBs =
|
||||
////////// Physical parameters:
|
||||
|
||||
min_rxtxtime = 6;
|
||||
enable_sdap = 1;
|
||||
enable_sdap = 0;
|
||||
|
||||
servingCellConfigCommon = (
|
||||
{
|
||||
|
||||
@@ -84,7 +84,7 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration.
|
||||
`0xffffff` is a reserved value and means "no SD"
|
||||
Note that: SST=1, no SD is "eMBB"; SST=2, no SD is "URLLC"; SST=3, no SD
|
||||
is "mMTC"
|
||||
- `enable_sdap` (default: false): enable the use of the SDAP layer. If
|
||||
- `enable_sdap` (default: true): enable the use of the SDAP layer. If
|
||||
deactivated, a transparent SDAP header is prepended to packets, but no
|
||||
further processing is being done.
|
||||
- `cu_sibs` (default: `[]`) list of SIBs to give to the DU for transmission.
|
||||
@@ -94,8 +94,6 @@ the [MAC configuration](../MAC/mac-usage.md) as well for SIB configuration.
|
||||
|
||||
- `um_on_default_drb` (default: false): use RLC UM instead of RLC AM on default
|
||||
bearers
|
||||
- `drbs` (default: 0): the number of DRBs to allocate for a UE, only useful for
|
||||
do-ra or phy-test testing
|
||||
|
||||
#### Neighbor-gNB configuration
|
||||
|
||||
|
||||
+1
-1
@@ -544,7 +544,7 @@ sudo ./nr-uesoftmodem --do-ra
|
||||
|
||||
#### Run OAI with SDAP & Custom DRBs
|
||||
|
||||
To run OAI gNB with SDAP, simply include `--gNBs.[0].enable_sdap 1` to the binary's arguments.
|
||||
SDAP is enabled by default. To disable SDAP, include `--gNBs.[0].enable_sdap 0` to the binary's arguments.
|
||||
|
||||
The DRB creation is dependent on the 5QI.
|
||||
If the 5QI corresponds to a GBR Flow it assigns a dedicated data radio bearer.
|
||||
|
||||
@@ -268,8 +268,8 @@ typedef struct up_params_s {
|
||||
/* IE SDAP Configuration (clause 9.3.1.39 of 3GPP TS 38.463) */
|
||||
typedef struct bearer_context_sdap_config_s {
|
||||
long defaultDRB;
|
||||
long sDAP_Header_UL;
|
||||
long sDAP_Header_DL;
|
||||
bool sDAP_Header_UL;
|
||||
bool sDAP_Header_DL;
|
||||
} bearer_context_sdap_config_t;
|
||||
|
||||
/* IE PDCP Configuration (clause 9.3.1.38 of 3GPP TS 38.463) */
|
||||
@@ -404,11 +404,17 @@ typedef struct DRB_nGRAN_to_modify_s {
|
||||
// DL UP Transport Layer Information (O) (clause 9.3.1.13, 9.3.2.1)
|
||||
int numDlUpParam;
|
||||
up_params_t DlUpParamList[E1AP_MAX_NUM_UP_PARAM];
|
||||
// QoS Flows Information To Modify (O) (clause 9.3.1.25, 9.3.1.26)
|
||||
int numQosFlow2Setup;
|
||||
// Flow Mapping Information (O) (clause 9.3.1.25, 9.3.1.26)
|
||||
int numQosFlowsMod;
|
||||
qos_flow_to_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS];
|
||||
} DRB_nGRAN_to_mod_t;
|
||||
|
||||
/* DRB To Remove Item (NG-RAN) clause 9.3.1.11 */
|
||||
typedef struct {
|
||||
// DRB ID (M)
|
||||
long id;
|
||||
} drb_to_remove_t;
|
||||
|
||||
typedef enum e1ap_indication_e {
|
||||
SECURITY_REQUIRED = 0,
|
||||
SECURITY_PREFERRED,
|
||||
@@ -472,6 +478,9 @@ typedef struct pdu_session_to_mod_s {
|
||||
long numDRB2Modify;
|
||||
// DRB To Modify Item (1..<E1AP_MAX_NUM_DRBS>)
|
||||
DRB_nGRAN_to_mod_t DRBnGRanModList[E1AP_MAX_NUM_DRBS];
|
||||
// DRB To Remove List (0..maxnoofDRBs)
|
||||
int n_drb_to_remove;
|
||||
drb_to_remove_t drbs_to_remove[E1AP_MAX_NUM_DRBS];
|
||||
} pdu_session_to_mod_t;
|
||||
|
||||
/** PDU Session Resource To Remove List (3GPP TS 38.463 clause 9.3.3.12) */
|
||||
|
||||
@@ -226,18 +226,21 @@ typedef struct pdusession_setup_s {
|
||||
pdusession_associate_qosflow_t associated_qos_flows[MAX_QOS_FLOWS];
|
||||
} pdusession_setup_t;
|
||||
|
||||
/* QoS Flow Add or Modify Response Item (3GPP TS 38.413 9.2.1.6) */
|
||||
typedef struct qos_flow_tobe_modified_s {
|
||||
uint8_t qfi; // 0~63
|
||||
} qos_flow_tobe_modified_t;
|
||||
// QoS Flow Identifier
|
||||
uint8_t qfi;
|
||||
} qos_flow_addmod_response_item_t;
|
||||
|
||||
/* PDU Session Resource Modify Response Item (3GPP TS 38.413 9.2.1.6) */
|
||||
typedef struct pdusession_modify_s {
|
||||
/* Unique pdusession_id for the UE. */
|
||||
// PDU Session ID
|
||||
uint8_t pdusession_id;
|
||||
|
||||
/* PDU Session Resource Modify Response Transfer */
|
||||
// QoS Flow Add or Modify Response List
|
||||
uint8_t nb_of_qos_flow;
|
||||
|
||||
// qos_flow_add_or_modify
|
||||
qos_flow_tobe_modified_t qos[MAX_QOS_FLOWS];
|
||||
qos_flow_addmod_response_item_t qos[MAX_QOS_FLOWS];
|
||||
} pdusession_modify_t;
|
||||
|
||||
/* Cause (9.3.1.2 of 3GPP TS 38.413) */
|
||||
@@ -889,17 +892,17 @@ typedef struct ngap_pdusession_modify_req_s {
|
||||
pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION];
|
||||
} ngap_pdusession_modify_req_t;
|
||||
|
||||
/* 9.2.1.6 of 3GPP TS 38.413 */
|
||||
typedef struct ngap_pdusession_modify_resp_s {
|
||||
// RAN UE NGAP ID
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* Number of pdusession modify-ed in the list */
|
||||
// AMF UE NGAP ID
|
||||
uint64_t amf_ue_ngap_id;
|
||||
// PDU Session Resource Modify Response List (0..256)
|
||||
uint16_t nb_of_pdusessions;
|
||||
/* list of pdusession modify-ed by RRC layers */
|
||||
pdusession_modify_t pdusessions[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* Number of pdusession failed to be modify in list */
|
||||
// PDU Session Resource Failed to Modify List (0..256)
|
||||
uint16_t nb_of_pdusessions_failed;
|
||||
/* list of pdusessions that failed to be modify */
|
||||
pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION];
|
||||
} ngap_pdusession_modify_resp_t;
|
||||
|
||||
|
||||
@@ -422,7 +422,6 @@ typedef struct NRRrcConfigurationReq_s {
|
||||
|
||||
bool um_on_default_drb;
|
||||
bool enable_sdap;
|
||||
int drbs;
|
||||
} gNB_RrcConfigurationReq;
|
||||
|
||||
typedef struct NRDuDlReq_s {
|
||||
|
||||
@@ -192,8 +192,8 @@ static E1AP_SDAP_Configuration_t e1_encode_sdap_config(const bearer_context_sdap
|
||||
{
|
||||
E1AP_SDAP_Configuration_t out = {0};
|
||||
out.defaultDRB = in->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false;
|
||||
out.sDAP_Header_UL = in->sDAP_Header_UL;
|
||||
out.sDAP_Header_DL = in->sDAP_Header_DL;
|
||||
out.sDAP_Header_UL = in->sDAP_Header_UL ? E1AP_SDAP_Header_UL_present : E1AP_SDAP_Header_UL_absent;
|
||||
out.sDAP_Header_DL = in->sDAP_Header_DL ? E1AP_SDAP_Header_DL_present : E1AP_SDAP_Header_DL_absent;
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -201,8 +201,8 @@ static E1AP_SDAP_Configuration_t e1_encode_sdap_config(const bearer_context_sdap
|
||||
static bool e1_decode_sdap_config(bearer_context_sdap_config_t *out, const E1AP_SDAP_Configuration_t *in)
|
||||
{
|
||||
out->defaultDRB = in->defaultDRB == E1AP_DefaultDRB_true;
|
||||
out->sDAP_Header_UL = in->sDAP_Header_UL;
|
||||
out->sDAP_Header_DL = in->sDAP_Header_DL;
|
||||
out->sDAP_Header_UL = in->sDAP_Header_UL == E1AP_SDAP_Header_UL_present;
|
||||
out->sDAP_Header_DL = in->sDAP_Header_DL == E1AP_SDAP_Header_DL_present;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -212,8 +212,8 @@ static bool e1_decode_sdap_config(bearer_context_sdap_config_t *out, const E1AP_
|
||||
static bool eq_sdap_config(const bearer_context_sdap_config_t *a, const bearer_context_sdap_config_t *b)
|
||||
{
|
||||
_E1_EQ_CHECK_LONG(a->defaultDRB, b->defaultDRB);
|
||||
_E1_EQ_CHECK_LONG(a->sDAP_Header_UL, b->sDAP_Header_UL);
|
||||
_E1_EQ_CHECK_LONG(a->sDAP_Header_DL, b->sDAP_Header_DL);
|
||||
_E1_EQ_CHECK_INT(a->sDAP_Header_UL, b->sDAP_Header_UL);
|
||||
_E1_EQ_CHECK_INT(a->sDAP_Header_DL, b->sDAP_Header_DL);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1459,12 +1459,20 @@ static E1AP_PDU_Session_Resource_To_Modify_Item_t e1_encode_pdu_session_to_mod_i
|
||||
}
|
||||
}
|
||||
// QoS Flows to setup (O)
|
||||
for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlow2Setup; k++) {
|
||||
for (const qos_flow_to_setup_t *k = j->qosFlows; k < j->qosFlows + j->numQosFlowsMod; k++) {
|
||||
asn1cCalloc(drb2Mod->flow_Mapping_Information, flow_Mapping_Information);
|
||||
asn1cSequenceAdd(flow_Mapping_Information->list, E1AP_QoS_Flow_QoS_Parameter_Item_t, ie1_2);
|
||||
*ie1_2 = e1_encode_qos_flow_to_setup(k);
|
||||
}
|
||||
}
|
||||
// DRB To Remove List (O)
|
||||
if (in->n_drb_to_remove > 0) {
|
||||
asn1cCalloc(out.dRB_To_Remove_List_NG_RAN, drb2Remove_List);
|
||||
for (int r = 0; r < in->n_drb_to_remove; r++) {
|
||||
asn1cSequenceAdd(drb2Remove_List->list, E1AP_DRB_To_Remove_Item_NG_RAN_t, drb2Rem);
|
||||
drb2Rem->dRB_ID = in->drbs_to_remove[r].id;
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -1740,12 +1748,21 @@ static bool e1_decode_pdu_session_to_mod_item(pdu_session_to_mod_t *out, const E
|
||||
// QoS Flows Information To Be Setup (O)
|
||||
if (drb2Mod->flow_Mapping_Information) {
|
||||
E1AP_QoS_Flow_QoS_Parameter_List_t *qos2SetupList = drb2Mod->flow_Mapping_Information;
|
||||
drb->numQosFlow2Setup = qos2SetupList->list.count;
|
||||
drb->numQosFlowsMod = qos2SetupList->list.count;
|
||||
for (int k = 0; k < qos2SetupList->list.count; k++) {
|
||||
CHECK_E1AP_DEC(e1_decode_qos_flow_to_setup(drb->qosFlows + k, qos2SetupList->list.array[k]));
|
||||
}
|
||||
}
|
||||
}
|
||||
// DRB To Remove List (O)
|
||||
if (in->dRB_To_Remove_List_NG_RAN) {
|
||||
E1AP_DRB_To_Remove_List_NG_RAN_t *rm = in->dRB_To_Remove_List_NG_RAN;
|
||||
out->n_drb_to_remove = rm->list.count;
|
||||
for (int r = 0; r < rm->list.count; r++) {
|
||||
E1AP_DRB_To_Remove_Item_NG_RAN_t *item = rm->list.array[r];
|
||||
out->drbs_to_remove[r].id = item->dRB_ID;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1931,6 +1948,9 @@ static pdu_session_to_mod_t cp_pdu_session_to_mod_item(const pdu_session_to_mod_
|
||||
// DRB to modify list
|
||||
for (int j = 0; j < msg->numDRB2Modify; j++)
|
||||
cp.DRBnGRanModList[j] = cp_drb_to_mod_item(&msg->DRBnGRanModList[j]);
|
||||
// DRB to remove list
|
||||
for (int r = 0; r < msg->n_drb_to_remove; r++)
|
||||
cp.drbs_to_remove[r] = msg->drbs_to_remove[r];
|
||||
_E1_CP_OPTIONAL_IE(&cp, msg, securityIndication);
|
||||
_E1_CP_OPTIONAL_IE(&cp, msg, UP_TL_information);
|
||||
return cp;
|
||||
@@ -1972,8 +1992,8 @@ static bool eq_security_ind(security_indication_t *a, security_indication_t *b)
|
||||
static bool eq_drb_to_mod(const DRB_nGRAN_to_mod_t *a, const DRB_nGRAN_to_mod_t *b)
|
||||
{
|
||||
_E1_EQ_CHECK_LONG(a->id, b->id);
|
||||
_E1_EQ_CHECK_INT(a->numQosFlow2Setup, b->numQosFlow2Setup);
|
||||
for (int i = 0; i < a->numQosFlow2Setup; i++) {
|
||||
_E1_EQ_CHECK_INT(a->numQosFlowsMod, b->numQosFlowsMod);
|
||||
for (int i = 0; i < a->numQosFlowsMod; i++) {
|
||||
if (!eq_qos_flow(&a->qosFlows[i], &b->qosFlows[i]))
|
||||
return false;
|
||||
}
|
||||
@@ -2021,6 +2041,10 @@ static bool eq_pdu_session_to_mod_item(const pdu_session_to_mod_t *a, const pdu_
|
||||
return false;
|
||||
}
|
||||
_E1_EQ_CHECK_OPTIONAL_PTR(a, b, securityIndication);
|
||||
_E1_EQ_CHECK_INT(a->n_drb_to_remove, b->n_drb_to_remove);
|
||||
for (int r = 0; r < a->n_drb_to_remove; r++) {
|
||||
_E1_EQ_CHECK_LONG(a->drbs_to_remove[r].id, b->drbs_to_remove[r].id);
|
||||
}
|
||||
if (a->securityIndication && b->securityIndication) {
|
||||
if (!eq_security_ind(a->securityIndication, b->securityIndication))
|
||||
return false;
|
||||
|
||||
@@ -76,6 +76,8 @@
|
||||
#include "E1AP_PDU-Session-Resource-To-Modify-Item.h"
|
||||
#include "E1AP_DRB-To-Modify-List-NG-RAN.h"
|
||||
#include "E1AP_DRB-To-Modify-Item-NG-RAN.h"
|
||||
#include "E1AP_DRB-To-Remove-List-NG-RAN.h"
|
||||
#include "E1AP_DRB-To-Remove-Item-NG-RAN.h"
|
||||
#include "E1AP_PDU-Session-Resource-To-Setup-Mod-Item.h"
|
||||
#include "E1AP_DRB-To-Setup-Mod-Item-NG-RAN.h"
|
||||
#include "E1AP_PDU-Session-Resource-To-Remove-Item.h"
|
||||
|
||||
@@ -505,7 +505,7 @@ static void test_bearer_context_modification_request(void)
|
||||
.pdcp_config = malloc_or_fail(sizeof(*drb_to_mod.pdcp_config)),
|
||||
.pdcp_sn_status_requested = true,
|
||||
.pdcp_status = malloc_or_fail(sizeof(*drb_to_mod.pdcp_status)),
|
||||
.numQosFlow2Setup = 1,
|
||||
.numQosFlowsMod = 1,
|
||||
.qosFlows[0] = dummy_qos_flows,
|
||||
};
|
||||
*drb_to_mod.pdcp_config = dummy_pdcp_config;
|
||||
@@ -515,6 +515,8 @@ static void test_bearer_context_modification_request(void)
|
||||
.sessionId = 1,
|
||||
.numDRB2Modify = 1,
|
||||
.DRBnGRanModList[0] = drb_to_mod,
|
||||
.n_drb_to_remove = 1,
|
||||
.drbs_to_remove[0].id = 2,
|
||||
};
|
||||
|
||||
DRB_nGRAN_to_setup_t drb_to_setup = {
|
||||
|
||||
@@ -717,7 +717,6 @@ void RCconfig_verify(configmodule_interface_t *cfg, ngran_node_t node_type)
|
||||
} else if (NODE_IS_DU(node_type)) {
|
||||
// verify that there is no bearer config
|
||||
verify_gnb_param_notset(gnbp, GNB_ENABLE_SDAP_IDX, GNB_CONFIG_STRING_ENABLE_SDAP);
|
||||
verify_gnb_param_notset(gnbp, GNB_DRBS, GNB_CONFIG_STRING_DRBS);
|
||||
|
||||
verify_section_notset(cfg, GNB_CONFIG_STRING_GNB_LIST ".[0]", GNB_CONFIG_STRING_AMF_IP_ADDRESS);
|
||||
verify_section_notset(cfg, NULL, CONFIG_STRING_SECURITY);
|
||||
@@ -2092,9 +2091,7 @@ gNB_RRC_INST *RCconfig_NRRRC()
|
||||
nrrrc_config.num_plmn = set_plmn_config(nrrrc_config.plmn, k);
|
||||
nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr;
|
||||
LOG_I(GNB_APP, "SDAP layer is %s\n", nrrrc_config.enable_sdap ? "enabled" : "disabled");
|
||||
nrrrc_config.drbs = *GNBParamList.paramarray[i][GNB_DRBS].iptr;
|
||||
nrrrc_config.um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr);
|
||||
LOG_I(GNB_APP, "Data Radio Bearer count %d\n", nrrrc_config.drbs);
|
||||
|
||||
}//
|
||||
}//End for (k=0; k <num_gnbs ; k++)
|
||||
|
||||
@@ -110,7 +110,6 @@ typedef enum {
|
||||
#define GNB_CONFIG_STRING_MAXMIMOLAYERS "maxMIMO_layers"
|
||||
#define GNB_CONFIG_STRING_DISABLE_HARQ "disable_harq"
|
||||
#define GNB_CONFIG_STRING_ENABLE_SDAP "enable_sdap"
|
||||
#define GNB_CONFIG_STRING_DRBS "drbs"
|
||||
#define GNB_CONFIG_STRING_USE_DELTA_MCS "use_deltaMCS"
|
||||
#define GNB_CONFIG_HLP_USE_DELTA_MCS "Use deltaMCS-based power headroom reporting in PUSCH-Config"
|
||||
#define GNB_CONFIG_HLP_FORCEUL256QAMOFF "suppress activation of UL 256 QAM despite UE support"
|
||||
@@ -130,7 +129,6 @@ typedef enum {
|
||||
#define GNB_CONFIG_HLP_FORCE256QAMOFF "suppress activation of 256 QAM despite UE support"
|
||||
#define GNB_CONFIG_HLP_MAXMIMOLAYERS "limit on maxMIMO-layers for DL"
|
||||
#define GNB_CONFIG_HLP_DISABLE_HARQ "disable feedback for all HARQ processes (REL17 feature)"
|
||||
#define GNB_CONFIG_HLP_STRING_DRBS "Number of total DRBs to establish, including the mandatory for PDU SEssion (default=1)\n"
|
||||
#define GNB_CONFIG_HLP_GNB_DU_ID "defines the gNB-DU ID (only applicable for DU)"
|
||||
#define GNB_CONFIG_HLP_GNB_CU_UP_ID "defines the gNB-CU-UP ID (only applicable for CU-UP)"
|
||||
#define GNB_CONFIG_HLP_NUM_DL_HARQ "Set Num DL harq processes. Valid values 2,4,6,8,10,12,16,32. Default 16"
|
||||
@@ -172,8 +170,7 @@ typedef enum {
|
||||
{GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, .strptr=NULL,.defstrval="", TYPE_STRING, 0}, \
|
||||
{GNB_CONFIG_STRING_UMONDEFAULTDRB, NULL, PARAMFLAG_BOOL, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
|
||||
{GNB_CONFIG_STRING_FORCE256QAMOFF, GNB_CONFIG_HLP_FORCE256QAMOFF, PARAMFLAG_BOOL, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
|
||||
{GNB_CONFIG_STRING_ENABLE_SDAP, GNB_CONFIG_HLP_STRING_ENABLE_SDAP, PARAMFLAG_BOOL,.iptr=NULL, .defintval=0, TYPE_INT, 0}, \
|
||||
{GNB_CONFIG_STRING_DRBS, GNB_CONFIG_HLP_STRING_DRBS, 0, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \
|
||||
{GNB_CONFIG_STRING_ENABLE_SDAP, GNB_CONFIG_HLP_STRING_ENABLE_SDAP, PARAMFLAG_BOOL,.iptr=NULL, .defintval=1, TYPE_INT, 0}, \
|
||||
{GNB_CONFIG_STRING_GNB_DU_ID, GNB_CONFIG_HLP_GNB_DU_ID, 0, .u64ptr=NULL, .defint64val=1, TYPE_UINT64, 0}, \
|
||||
{GNB_CONFIG_STRING_GNB_CU_UP_ID, GNB_CONFIG_HLP_GNB_CU_UP_ID, 0, .u64ptr=NULL, .defint64val=1, TYPE_UINT64, 0}, \
|
||||
{GNB_CONFIG_STRING_USE_DELTA_MCS, GNB_CONFIG_HLP_USE_DELTA_MCS, 0, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
|
||||
@@ -219,21 +216,20 @@ typedef enum {
|
||||
#define GNB_UMONDEFAULTDRB_IDX 23
|
||||
#define GNB_FORCE256QAMOFF_IDX 24
|
||||
#define GNB_ENABLE_SDAP_IDX 25
|
||||
#define GNB_DRBS 26
|
||||
#define GNB_GNB_DU_ID_IDX 27
|
||||
#define GNB_GNB_CU_UP_ID_IDX 28
|
||||
#define GNB_USE_DELTA_MCS_IDX 29
|
||||
#define GNB_FORCEUL256QAMOFF_IDX 30
|
||||
#define GNB_MAXMIMOLAYERS_IDX 31
|
||||
#define GNB_DISABLE_HARQ_IDX 32
|
||||
#define GNB_NUM_DL_HARQ_IDX 33
|
||||
#define GNB_NUM_UL_HARQ_IDX 34
|
||||
#define GNB_UESS_AGG_LEVEL_LIST_IDX 35
|
||||
#define GNB_CU_SIBS_IDX 36
|
||||
#define GNB_DU_SIBS_IDX 37
|
||||
#define GNB_CONFIG_REP_IDX 38
|
||||
#define GNB_1ST_ACTIVE_BWP_IDX 39
|
||||
#define GNB_LIMIT_RSRP_REPORT_IDX 40
|
||||
#define GNB_GNB_DU_ID_IDX 26
|
||||
#define GNB_GNB_CU_UP_ID_IDX 27
|
||||
#define GNB_USE_DELTA_MCS_IDX 28
|
||||
#define GNB_FORCEUL256QAMOFF_IDX 29
|
||||
#define GNB_MAXMIMOLAYERS_IDX 30
|
||||
#define GNB_DISABLE_HARQ_IDX 31
|
||||
#define GNB_NUM_DL_HARQ_IDX 32
|
||||
#define GNB_NUM_UL_HARQ_IDX 33
|
||||
#define GNB_UESS_AGG_LEVEL_LIST_IDX 34
|
||||
#define GNB_CU_SIBS_IDX 35
|
||||
#define GNB_DU_SIBS_IDX 36
|
||||
#define GNB_CONFIG_REP_IDX 37
|
||||
#define GNB_1ST_ACTIVE_BWP_IDX 38
|
||||
#define GNB_LIMIT_RSRP_REPORT_IDX 39
|
||||
|
||||
#define TRACKING_AREA_CODE_OKRANGE {0x0001,0xFFFD}
|
||||
#define NUM_DL_HARQ_OKVALUES {2,4,6,8,10,12,16,32}
|
||||
@@ -272,7 +268,6 @@ typedef enum {
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
{ .s1 = { config_check_intval, NUM_DL_HARQ_OKVALUES,8 } }, \
|
||||
{ .s1 = { config_check_intval, NUM_UL_HARQ_OKVALUES,2 } }, \
|
||||
{ .s5 = { NULL } }, \
|
||||
|
||||
@@ -60,8 +60,11 @@ static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, const
|
||||
asn1cCalloc(ie->cnAssociation->choice.sdap_Config, sdap_config);
|
||||
sdap_config->pdu_Session = pdu->sessionId;
|
||||
/* SDAP */
|
||||
sdap_config->sdap_HeaderDL = drb->sdap_config.sDAP_Header_DL;
|
||||
sdap_config->sdap_HeaderUL = drb->sdap_config.sDAP_Header_UL;
|
||||
/* Convert from internal representation to ASN.1 enum:
|
||||
* Internal: false=absent, true=present (or uninitialized=false means absent)
|
||||
* ASN.1: 0=present, 1=absent */
|
||||
sdap_config->sdap_HeaderDL = drb->sdap_config.sDAP_Header_DL ? NR_SDAP_Config__sdap_HeaderDL_present : NR_SDAP_Config__sdap_HeaderDL_absent;
|
||||
sdap_config->sdap_HeaderUL = drb->sdap_config.sDAP_Header_UL ? NR_SDAP_Config__sdap_HeaderUL_present : NR_SDAP_Config__sdap_HeaderUL_absent;
|
||||
sdap_config->defaultDRB = drb->sdap_config.defaultDRB;
|
||||
asn1cCalloc(sdap_config->mappedQoS_FlowsToAdd, FlowsToAdd);
|
||||
for (int j = 0; j < drb->numQosFlow2Setup; j++) {
|
||||
|
||||
@@ -166,6 +166,11 @@ typedef struct {
|
||||
pdusession_level_qos_parameter_t qos;
|
||||
} nr_rrc_qos_t;
|
||||
|
||||
typedef struct {
|
||||
uint64_t dl_br;
|
||||
uint64_t ul_br;
|
||||
} nr_rrc_ambr_t;
|
||||
|
||||
/* forward declaration */
|
||||
typedef struct nr_handover_context_s nr_handover_context_t;
|
||||
|
||||
@@ -244,6 +249,9 @@ typedef struct gNB_RRC_UE_s {
|
||||
int n_initial_pdu;
|
||||
pdusession_t *initial_pdus;
|
||||
|
||||
// Aggregate Maximum Bit Rate
|
||||
nr_rrc_ambr_t ambr;
|
||||
|
||||
/* Nas Pdu */
|
||||
byte_array_t nas_pdu;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+117
-78
@@ -1963,7 +1963,7 @@ static void handle_ueCapabilityInformation(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE,
|
||||
* up security and request capabilities, so trigger PDU sessions now. The
|
||||
* UE NAS message will be forwarded in the corresponding reconfiguration,
|
||||
* the Initial context setup response after reconfiguration complete. */
|
||||
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0)) {
|
||||
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, UE->ambr.dl_br)) {
|
||||
LOG_W(NR_RRC, "Failed to setup bearers for UE %d: send Initial Context Setup Response\n", UE->rrc_ue_id);
|
||||
rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(rrc, UE);
|
||||
rrc_forward_ue_nas_message(rrc, UE);
|
||||
@@ -2213,7 +2213,7 @@ static int rrc_gNB_decode_dcch(gNB_RRC_INST *rrc, const f1ap_ul_rrc_message_t *m
|
||||
* to set up security, so trigger PDU sessions now. The UE NAS
|
||||
* message will be forwarded in the corresponding reconfiguration,
|
||||
* the Initial context setup response after reconfiguration complete. */
|
||||
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0)) {
|
||||
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, UE->ambr.dl_br)) {
|
||||
LOG_W(NR_RRC, "Failed to setup bearers for UE %d: send Initial Context Setup Response\n", UE->rrc_ue_id);
|
||||
rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(rrc, UE);
|
||||
rrc_forward_ue_nas_message(rrc, UE);
|
||||
@@ -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,55 +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");
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -3261,7 +3316,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
break;
|
||||
|
||||
case NGAP_PDUSESSION_MODIFY_REQ:
|
||||
rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(msg_p, instance);
|
||||
rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(&NGAP_PDUSESSION_MODIFY_REQ(msg_p), instance);
|
||||
break;
|
||||
|
||||
case NGAP_PDUSESSION_RELEASE_COMMAND:
|
||||
@@ -3554,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;
|
||||
}
|
||||
|
||||
+115
-86
@@ -289,6 +289,31 @@ void rrc_gNB_send_NGAP_NAS_FIRST_REQ(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, NR_RRC
|
||||
itti_send_msg_to_task(TASK_NGAP, rrc->module_id, message_p);
|
||||
}
|
||||
|
||||
/// @brief set QoS Flows to Setup in E1 DRB To Setup List
|
||||
static qos_flow_to_setup_t fill_e1_qos_flow_to_setup(const pdusession_level_qos_parameter_t *qos)
|
||||
{
|
||||
qos_flow_to_setup_t qos_flow = { .qfi = qos->qfi };
|
||||
// ARP
|
||||
ngran_allocation_retention_priority_t *arp_out = &qos_flow.qos_params.alloc_reten_priority;
|
||||
const qos_arp_t *arp_in = &qos->arp;
|
||||
arp_out->priority_level = arp_in->priority_level;
|
||||
arp_out->preemption_capability = arp_in->pre_emp_capability;
|
||||
arp_out->preemption_vulnerability = arp_in->pre_emp_vulnerability;
|
||||
// QoS Characteristics
|
||||
qos_characteristics_t *qos_characteristics = &qos_flow.qos_params.qos_characteristics;
|
||||
if (qos->fiveQI_type == NON_DYNAMIC) {
|
||||
qos_characteristics->non_dynamic.fiveqi = qos->fiveQI;
|
||||
qos_characteristics->non_dynamic.qos_priority_level = qos->qos_priority;
|
||||
} else {
|
||||
qos_characteristics->dynamic.fiveqi = qos->fiveQI;
|
||||
qos_characteristics->dynamic.qos_priority_level = qos->qos_priority;
|
||||
// NOTE: missing packet error rate and delay budget
|
||||
}
|
||||
qos_characteristics->qos_type = qos->fiveQI_type;
|
||||
|
||||
return qos_flow;
|
||||
}
|
||||
|
||||
/** @brief Returns an instance of E1AP DRB To Setup List */
|
||||
static DRB_nGRAN_to_setup_t fill_e1_drb_to_setup(const drb_t *rrc_drb,
|
||||
const pdusession_t *session,
|
||||
@@ -299,8 +324,8 @@ static DRB_nGRAN_to_setup_t fill_e1_drb_to_setup(const drb_t *rrc_drb,
|
||||
drb_ngran.id = rrc_drb->drb_id;
|
||||
|
||||
drb_ngran.sdap_config.defaultDRB = true;
|
||||
drb_ngran.sdap_config.sDAP_Header_UL = session->sdap_config.header_ul_absent ? 1 : 0;
|
||||
drb_ngran.sdap_config.sDAP_Header_DL = session->sdap_config.header_dl_absent ? 1 : 0;
|
||||
drb_ngran.sdap_config.sDAP_Header_UL = session->sdap_config.header_ul_absent ? false : true;
|
||||
drb_ngran.sdap_config.sDAP_Header_DL = session->sdap_config.header_dl_absent ? false : true;
|
||||
|
||||
drb_ngran.pdcp_config = set_bearer_context_pdcp_config(rrc_drb->pdcp_config, um_on_default_drb, redcap_cap);
|
||||
|
||||
@@ -310,26 +335,13 @@ static DRB_nGRAN_to_setup_t fill_e1_drb_to_setup(const drb_t *rrc_drb,
|
||||
}
|
||||
|
||||
FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) {
|
||||
pdusession_level_qos_parameter_t *qos_session = &qos->qos;
|
||||
if (qos->drb_id != drb_ngran.id)
|
||||
continue;
|
||||
const pdusession_level_qos_parameter_t *qos_session = &qos->qos;
|
||||
DevAssert(drb_ngran.numQosFlow2Setup < MAX_QOS_FLOWS);
|
||||
qos_flow_to_setup_t *qos_flow = &drb_ngran.qosFlows[drb_ngran.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;
|
||||
if (qos_char->qos_type == DYNAMIC) {
|
||||
qos_char->dynamic.fiveqi = qos_session->fiveQI;
|
||||
qos_char->dynamic.qos_priority_level = qos_session->qos_priority;
|
||||
} else {
|
||||
qos_char->non_dynamic.fiveqi = qos_session->fiveQI;
|
||||
qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority;
|
||||
}
|
||||
|
||||
ngran_allocation_retention_priority_t *arp_out = &qos_flow->qos_params.alloc_reten_priority;
|
||||
qos_arp_t *arp_in = &qos_session->arp;
|
||||
arp_out->priority_level = arp_in->priority_level;
|
||||
arp_out->preemption_capability = arp_in->pre_emp_capability;
|
||||
arp_out->preemption_vulnerability = arp_in->pre_emp_vulnerability;
|
||||
drb_ngran.qosFlows[drb_ngran.numQosFlow2Setup++] = fill_e1_qos_flow_to_setup(qos_session);
|
||||
}
|
||||
DevAssert(drb_ngran.numQosFlow2Setup > 0);
|
||||
|
||||
return drb_ngran;
|
||||
}
|
||||
@@ -355,6 +367,10 @@ static nr_sdap_configuration_t get_sdap_config(const bool enable_sdap)
|
||||
*/
|
||||
bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession_t *sessions, uint64_t ueAggMaxBitRateDownlink)
|
||||
{
|
||||
if (ueAggMaxBitRateDownlink == UINT64_MAX) {
|
||||
LOG_E(NR_RRC, "UE %d: UE aggregate maximum bitrate must be known by the NG-RAN node\n", UE->rrc_ue_id);
|
||||
return false;
|
||||
}
|
||||
AssertFatal(UE->as_security_active, "logic bug: security should be active when activating DRBs\n");
|
||||
e1ap_bearer_setup_req_t bearer_req = {0};
|
||||
|
||||
@@ -485,12 +501,15 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
|
||||
UE->nas_pdu = req->nas_pdu;
|
||||
|
||||
if (req->nb_of_pdusessions > 0) {
|
||||
AssertFatal(req->has_ue_ambr, "UE aggregate maximum bitrate is required when there are PDU sessions to setup");
|
||||
/* if there are PDU sessions to setup, store them to be created once
|
||||
* security (and UE capabilities) are received */
|
||||
UE->n_initial_pdu = req->nb_of_pdusessions;
|
||||
UE->initial_pdus = calloc_or_fail(UE->n_initial_pdu, sizeof(*UE->initial_pdus));
|
||||
for (int i = 0; i < UE->n_initial_pdu; ++i)
|
||||
cp_pdusession_resource_item_to_pdusession(&UE->initial_pdus[i], &req->pdusession[i]);
|
||||
UE->ambr.dl_br = req->ue_ambr.br_dl;
|
||||
UE->ambr.ul_br = req->ue_ambr.br_ul;
|
||||
}
|
||||
|
||||
/* security */
|
||||
@@ -513,7 +532,7 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
|
||||
// do not remove the above allocation which is reused here: this is used
|
||||
// in handle_rrcReconfigurationComplete() to know that we need to send a
|
||||
// Initial context setup response message
|
||||
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, 0)) {
|
||||
if (!trigger_bearer_setup(rrc, UE, UE->n_initial_pdu, UE->initial_pdus, UE->ambr.dl_br)) {
|
||||
LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in Initial Context Setup Response\n", UE->rrc_ue_id);
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE};
|
||||
send_ngap_initial_context_setup_resp_fail(rrc->module_id, req, cause);
|
||||
@@ -866,9 +885,13 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
|
||||
for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i)
|
||||
cp_pdusession_resource_item_to_pdusession(&to_setup[i], &msg->pdusession[i]);
|
||||
|
||||
uint64_t dl_ambr = msg->has_ue_ambr ? msg->ueAggMaxBitRate.br_dl : 0;
|
||||
/** Set AMBR if provided (optional) */
|
||||
if (msg->has_ue_ambr) {
|
||||
UE->ambr.dl_br = msg->ueAggMaxBitRate.br_dl;
|
||||
UE->ambr.ul_br = msg->ueAggMaxBitRate.br_ul;
|
||||
}
|
||||
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, to_setup, dl_ambr)) {
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, to_setup, UE->ambr.dl_br)) {
|
||||
// Reject PDU Session Resource setup if there's no CU-UP associated
|
||||
LOG_W(NR_RRC, "UE %d: reject PDU Session Setup in PDU Session Resource Setup Response\n", UE->rrc_ue_id);
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_RESOURCES_NOT_AVAILABLE_FOR_THE_SLICE};
|
||||
@@ -911,33 +934,64 @@ static void nr_rrc_update_pdusession(pdusession_t *dst, const pdusession_resourc
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t instance)
|
||||
//------------------------------------------------------------------------------
|
||||
/** @brief Handle abnormal conditions in PDU Session Modify procedure.
|
||||
* Send a response with failed of PDU sessions only, for all PDU Sessions in the request */
|
||||
static int rrc_gNB_ngap_pdusession_mod_failure(int module_id, const ngap_pdusession_modify_req_t *req, const ngap_cause_t cause)
|
||||
{
|
||||
rrc_gNB_ue_context_t *ue_context_p = NULL;
|
||||
|
||||
ngap_pdusession_modify_req_t *req = &NGAP_PDUSESSION_MODIFY_REQ(msg_p);
|
||||
MessageDef *msg_p = itti_alloc_new_message (TASK_RRC_GNB, module_id, NGAP_PDUSESSION_MODIFY_RESP);
|
||||
if (msg_p == NULL) {
|
||||
LOG_E(NR_RRC, "itti_alloc_new_message failed, msg_p is NULL \n");
|
||||
return -1;
|
||||
}
|
||||
ngap_pdusession_modify_resp_t *resp = &NGAP_PDUSESSION_MODIFY_RESP(msg_p);
|
||||
resp->amf_ue_ngap_id = req->amf_ue_ngap_id;
|
||||
resp->gNB_ue_ngap_id = req->gNB_ue_ngap_id;
|
||||
resp->nb_of_pdusessions_failed = req->nb_pdusessions_tomodify;
|
||||
resp->pdusessions_failed->cause = cause;
|
||||
for (int i = 0; i < req->nb_pdusessions_tomodify; i++)
|
||||
resp->pdusessions_failed[i].pdusession_id = req->pdusession[i].pdusession_id;
|
||||
itti_send_msg_to_task(TASK_NGAP, module_id, msg_p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(const ngap_pdusession_modify_req_t *req, instance_t instance)
|
||||
{
|
||||
gNB_RRC_INST *rrc = RC.nrrrc[instance];
|
||||
ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_ue_ngap_id);
|
||||
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, req->gNB_ue_ngap_id);
|
||||
if (ue_context_p == NULL) {
|
||||
LOG_W(NR_RRC, "[gNB %ld] In NGAP_PDUSESSION_MODIFY_REQ: unknown UE from NGAP ids (%u)\n", instance, req->gNB_ue_ngap_id);
|
||||
// TO implement return setup failed
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_INCONSISTENT_REMOTE_UE_NGAP_ID};
|
||||
rrc_gNB_ngap_pdusession_mod_failure(rrc->module_id, req, cause);
|
||||
return (-1);
|
||||
}
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
if (UE->amf_ue_ngap_id != req->amf_ue_ngap_id) {
|
||||
LOG_W(NR_RRC,
|
||||
"Stored amf_ue_ngap_id %ld for UE %x does not match the requested one %ld\n",
|
||||
UE->amf_ue_ngap_id,
|
||||
UE->rrc_ue_id,
|
||||
req->amf_ue_ngap_id);
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_INCONSISTENT_REMOTE_UE_NGAP_ID};
|
||||
rrc_gNB_ngap_pdusession_mod_failure(rrc->module_id, req, cause);
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id);
|
||||
bool all_failed = true;
|
||||
DevAssert(req->nb_pdusessions_tomodify <= NGAP_MAX_PDU_SESSION);
|
||||
for (int i = 0; i < req->nb_pdusessions_tomodify; i++) {
|
||||
const pdusession_resource_item_t *sessMod = &req->pdusession[i];
|
||||
rrc_pdu_session_param_t *session = find_pduSession(&UE->pduSessions, sessMod->pdusession_id);
|
||||
if (!session) {
|
||||
/* 8.2.3.4 3GPP TS 38.413: If the NG-RAN node receives unrecognized PDU Session ID IEs,
|
||||
the NG-RAN node shall report the corresponding invalid PDU sessions as failed. So we add it to the list. */
|
||||
LOG_W(NR_RRC, "Requested modification of non-existing PDU session, refusing modification\n");
|
||||
rrc_pdu_session_param_t to_add = {0};
|
||||
to_add.status = PDU_SESSION_STATUS_FAILED;
|
||||
to_add.param.pdusession_id = sessMod->pdusession_id;
|
||||
to_add.cause.type = NGAP_CAUSE_RADIO_NETWORK;
|
||||
to_add.cause.value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID;
|
||||
seq_arr_push_back(&UE->pduSessions, &to_add, sizeof(to_add));
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID};
|
||||
pdusession_t session = {.pdusession_id = sessMod->pdusession_id};
|
||||
rrc_pdu_session_param_t *added = add_pduSession(&UE->pduSessions, &session);
|
||||
added->status = PDU_SESSION_STATUS_FAILED;
|
||||
added->cause = cause;
|
||||
} else {
|
||||
all_failed = false;
|
||||
session->status = PDU_SESSION_STATUS_NEW;
|
||||
@@ -949,50 +1003,34 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins
|
||||
if (!all_failed) {
|
||||
rrc_gNB_modify_dedicatedRRCReconfiguration(rrc, UE);
|
||||
} else {
|
||||
LOG_I(NR_RRC,
|
||||
"pdu session modify failed, fill NGAP_PDUSESSION_MODIFY_RESP with the pdu session information that failed to modify \n");
|
||||
MessageDef *msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_MODIFY_RESP);
|
||||
if (msg_fail_p == NULL) {
|
||||
LOG_E(NR_RRC, "itti_alloc_new_message failed, msg_fail_p is NULL \n");
|
||||
return (-1);
|
||||
return -1;
|
||||
}
|
||||
ngap_pdusession_modify_resp_t *msg = &NGAP_PDUSESSION_MODIFY_RESP(msg_fail_p);
|
||||
msg->gNB_ue_ngap_id = req->gNB_ue_ngap_id;
|
||||
msg->nb_of_pdusessions = 0;
|
||||
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) {
|
||||
if (session->status == PDU_SESSION_STATUS_FAILED) {
|
||||
msg->pdusessions_failed[msg->nb_of_pdusessions_failed].pdusession_id = session->param.pdusession_id;
|
||||
msg->pdusessions_failed[msg->nb_of_pdusessions_failed].cause.type = session->cause.type;
|
||||
msg->pdusessions_failed[msg->nb_of_pdusessions_failed].cause.value = session->cause.value;
|
||||
msg->nb_of_pdusessions_failed++;
|
||||
}
|
||||
}
|
||||
itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p);
|
||||
rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(rrc, UE, xid);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/** @brief Send PDU Session Resource Setup Response (9.2.1.6 3GPP TS 38.413)
|
||||
* Direction: Direction: NG-RAN node → AMF */
|
||||
int rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid)
|
||||
{
|
||||
MessageDef *msg_p = NULL;
|
||||
uint16_t pdu_sessions_failed = 0;
|
||||
uint16_t pdu_sessions_done = 0;
|
||||
|
||||
if (!seq_arr_size(&UE->pduSessions)) {
|
||||
LOG_W(NR_RRC, "UE %d: No PDU sessions in the list, don't send NG PDU Session Modify Response\n", UE->rrc_ue_id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
msg_p = itti_alloc_new_message (TASK_RRC_GNB, rrc->module_id, NGAP_PDUSESSION_MODIFY_RESP);
|
||||
MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, rrc->module_id, NGAP_PDUSESSION_MODIFY_RESP);
|
||||
if (msg_p == NULL) {
|
||||
LOG_E(NR_RRC, "itti_alloc_new_message failed, msg_p is NULL \n");
|
||||
return (-1);
|
||||
}
|
||||
ngap_pdusession_modify_resp_t *resp = &NGAP_PDUSESSION_MODIFY_RESP(msg_p);
|
||||
LOG_I(NR_RRC, "send message NGAP_PDUSESSION_MODIFY_RESP \n");
|
||||
|
||||
ngap_pdusession_modify_resp_t *resp = &NGAP_PDUSESSION_MODIFY_RESP(msg_p);
|
||||
resp->gNB_ue_ngap_id = UE->rrc_ue_id;
|
||||
resp->amf_ue_ngap_id = UE->amf_ue_ngap_id;
|
||||
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) {
|
||||
if (xid != session->xid) {
|
||||
@@ -1005,47 +1043,35 @@ int rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
continue;
|
||||
}
|
||||
if (session->status == PDU_SESSION_STATUS_DONE) {
|
||||
LOG_I(NR_RRC, "Successfully modified PDU Session %d \n", session->param.pdusession_id);
|
||||
LOG_I(NR_RRC, "PDU Session Modify successful (pdusession_id=%d) \n", session->param.pdusession_id);
|
||||
// Update status
|
||||
session->status = PDU_SESSION_STATUS_ESTABLISHED;
|
||||
session->cause.type = NGAP_CAUSE_NOTHING;
|
||||
// Fill response
|
||||
DevAssert(pdu_sessions_done < NGAP_MAX_PDU_SESSION);
|
||||
pdusession_modify_t *p = &resp->pdusessions[pdu_sessions_done++];
|
||||
DevAssert(resp->nb_of_pdusessions <= NGAP_MAX_PDU_SESSION);
|
||||
pdusession_modify_t *p = &resp->pdusessions[resp->nb_of_pdusessions++];
|
||||
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 < MAX_QOS_FLOWS);
|
||||
qos_flow_tobe_modified_t *q = &p->qos[p->nb_of_qos_flow++];
|
||||
qos_flow_addmod_response_item_t *q = &p->qos[p->nb_of_qos_flow++];
|
||||
q->qfi = qos_session->qos.qfi;
|
||||
}
|
||||
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),
|
||||
p->pdusession_id);
|
||||
p->pdusession_id = session->param.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) {
|
||||
DevAssert(pdu_sessions_failed < NGAP_MAX_PDU_SESSION);
|
||||
resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = session->param.pdusession_id;
|
||||
resp->pdusessions_failed[pdu_sessions_failed].cause.type = session->cause.type;
|
||||
resp->pdusessions_failed[pdu_sessions_failed].cause.value = session->cause.value;
|
||||
pdu_sessions_failed++;
|
||||
DevAssert(resp->nb_of_pdusessions_failed <= NGAP_MAX_PDU_SESSION);
|
||||
pdusession_failed_t *failed = &resp->pdusessions_failed[resp->nb_of_pdusessions_failed++];
|
||||
failed->pdusession_id = session->param.pdusession_id;
|
||||
failed->cause = session->cause;
|
||||
rm_pduSession(&UE->pduSessions, &UE->drbs, session->param.pdusession_id);
|
||||
} else
|
||||
LOG_W(NR_RRC, "Modify pdu session %d, unknown state %d \n ", session->param.pdusession_id, session->status);
|
||||
}
|
||||
|
||||
resp->nb_of_pdusessions = pdu_sessions_done;
|
||||
resp->nb_of_pdusessions_failed = pdu_sessions_failed;
|
||||
|
||||
if (pdu_sessions_done > 0 || pdu_sessions_failed > 0) {
|
||||
LOG_D(NR_RRC, "NGAP_PDUSESSION_MODIFY_RESP: sending the message (total pdu session %ld)\n", seq_arr_size(&UE->pduSessions));
|
||||
itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p);
|
||||
} else {
|
||||
itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
|
||||
}
|
||||
// Send message to NGAP (always send: if no PDU sessions, only mandatory IEs)
|
||||
LOG_D(NR_RRC, "Send NG PDU Session Modify Response (nb_of_pdusessions %d, xid %d)\n", resp->nb_of_pdusessions, xid);
|
||||
itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1184,7 +1210,11 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
|
||||
cp_pdusession_transfer_to_pdusession(pdu, &ho_pdu->pdusessionTransfer);
|
||||
}
|
||||
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_of_pdusessions, to_setup, msg->ue_ambr.br_dl)) {
|
||||
// Store UE aggregate maximum bitrate
|
||||
UE->ambr.dl_br = msg->ue_ambr.br_dl;
|
||||
UE->ambr.ul_br = msg->ue_ambr.br_ul;
|
||||
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_of_pdusessions, to_setup, UE->ambr.dl_br)) {
|
||||
LOG_E(NR_RRC, "Failed to establish PDU session: handover failed\n");
|
||||
|
||||
ngap_handover_failure_t fail = {
|
||||
@@ -1196,7 +1226,6 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
|
||||
rrc_remove_ue(rrc, ue_context_p);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,7 +60,7 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
|
||||
void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t instance);
|
||||
|
||||
int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t instance);
|
||||
int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(const ngap_pdusession_modify_req_t *req, instance_t instance);
|
||||
|
||||
int rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid);
|
||||
|
||||
|
||||
@@ -218,6 +218,8 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id,
|
||||
ue->rrc_ue_id);
|
||||
bool success = cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data);
|
||||
DevAssert(success);
|
||||
ue->ambr.dl_br = UINT64_MAX;
|
||||
ue->ambr.ul_br = UINT64_MAX;
|
||||
|
||||
// Initialise setup PDU Sessions list
|
||||
seq_arr_init(&ue->pduSessions, sizeof(rrc_pdu_session_param_t));
|
||||
|
||||
@@ -1084,7 +1084,7 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_
|
||||
ie->id = NGAP_ProtocolIE_ID_id_AMF_UE_NGAP_ID;
|
||||
ie->criticality = NGAP_Criticality_ignore;
|
||||
ie->value.present = NGAP_PDUSessionResourceModifyResponseIEs__value_PR_AMF_UE_NGAP_ID;
|
||||
asn_uint642INTEGER(&ie->value.choice.AMF_UE_NGAP_ID, ue_context_p->amf_ue_ngap_id);
|
||||
asn_uint642INTEGER(&ie->value.choice.AMF_UE_NGAP_ID, pdusession_modify_resp_p->amf_ue_ngap_id);
|
||||
asn1cSeqAdd(&out->protocolIEs.list, ie);
|
||||
}
|
||||
/* mandatory */
|
||||
@@ -1115,12 +1115,11 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_
|
||||
qos->qosFlowIdentifier = pdusession_modify_resp_p->pdusessions[i].qos[qos_flow_index].qfi;
|
||||
}
|
||||
asn_encode_to_new_buffer_result_t res = {0};
|
||||
NGAP_PDUSessionResourceModifyResponseTransfer_t *transfer_p = NULL;
|
||||
res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceModifyResponseTransfer, transfer_p);
|
||||
res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceModifyResponseTransfer, &transfer);
|
||||
item->pDUSessionResourceModifyResponseTransfer.buf = res.buffer;
|
||||
item->pDUSessionResourceModifyResponseTransfer.size = res.result.encoded;
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceModifyResponseTransfer, transfer_p);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceModifyResponseTransfer, &transfer);
|
||||
|
||||
NGAP_DEBUG("pdusession_modify_resp: modified pdusession ID %ld\n", item->pDUSessionID);
|
||||
}
|
||||
@@ -1143,12 +1142,11 @@ int ngap_gNB_pdusession_modify_resp(instance_t instance, ngap_pdusession_modify_
|
||||
encode_ngap_cause(&pdusessionTransfer.cause, &pdusession_modify_resp_p->pdusessions_failed[i].cause);
|
||||
|
||||
asn_encode_to_new_buffer_result_t res = {0};
|
||||
NGAP_PDUSessionResourceModifyUnsuccessfulTransfer_t *pdusessionTransfer_p = NULL;
|
||||
res = asn_encode_to_new_buffer(NULL, ATS_ALIGNED_CANONICAL_PER, &asn_DEF_NGAP_PDUSessionResourceModifyUnsuccessfulTransfer, &pdusessionTransfer);
|
||||
item->pDUSessionResourceModifyUnsuccessfulTransfer.buf = res.buffer;
|
||||
item->pDUSessionResourceModifyUnsuccessfulTransfer.size = res.result.encoded;
|
||||
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceModifyUnsuccessfulTransfer, pdusessionTransfer_p);
|
||||
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceModifyUnsuccessfulTransfer, &pdusessionTransfer);
|
||||
|
||||
NGAP_INFO("pdusession_modify_resp: failed pdusession ID %ld\n", item->pDUSessionID);
|
||||
}
|
||||
|
||||
@@ -418,7 +418,9 @@ static void *sender_thread(void *v)
|
||||
{
|
||||
struct thr_data *d = v;
|
||||
|
||||
size_t oh = d->is_ul ? 3 : 0;
|
||||
// Overhead: PDCP header (2 bytes) for UL packets
|
||||
// SDAP headers are disabled, so only PDCP header is added
|
||||
size_t oh = d->is_ul ? 2 : 0;
|
||||
size_t packet_len = d->data_len + oh;
|
||||
uint8_t buf[packet_len];
|
||||
memset(buf, 0, packet_len);
|
||||
|
||||
Reference in New Issue
Block a user