Merge remote-tracking branch 'origin/rrc-pdusession-handling-improvements' into integration_2025_w39 (!3513)
Improvements to RRC PDU session and DRB handling logic This merge request introduces a major simplification and cleanup of the gNB RRC PDU Sessions and DRBs handling logic. The core goals of this work are to: - Replace fixed-size PDU Session, DRBs and QoS arrays with dynamic containers - Simplify and modularize helper functions for session/DRB management - Prepare for further refactoring of the PDU Session state machine - Improve code safety and maintainability through better bounds checking
This commit is contained in:
@@ -1167,6 +1167,7 @@ set(L2_NR_SRC
|
||||
${NR_RRC_DIR}/rrc_gNB.c
|
||||
${NR_RRC_DIR}/mac_rrc_dl_direct.c
|
||||
${NR_RRC_DIR}/mac_rrc_dl_f1ap.c
|
||||
${NR_RRC_DIR}/rrc_gNB_asn1.c
|
||||
${NR_RRC_DIR}/rrc_gNB_nsa.c
|
||||
${NR_RRC_DIR}/rrc_gNB_UE_context.c
|
||||
${NR_RRC_DIR}/rrc_gNB_NGAP.c
|
||||
@@ -1893,6 +1894,7 @@ target_link_libraries(nr-cuup PRIVATE
|
||||
CONFIG_LIB ITTI SCTP_CLIENT
|
||||
GTPV1U e1ap f1ap
|
||||
time_management
|
||||
alg
|
||||
z dl pthread shlib_loader ${T_LIB})
|
||||
target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
if(E2_AGENT)
|
||||
|
||||
@@ -55,4 +55,53 @@ typedef enum {
|
||||
|
||||
typedef enum { NON_DYNAMIC, DYNAMIC } fiveQI_t;
|
||||
|
||||
/* QoS Priority Level */
|
||||
typedef enum {
|
||||
QOS_PRIORITY_SPARE = 0,
|
||||
QOS_PRIORITY_HIGHEST,
|
||||
QOS_PRIORITY_2,
|
||||
QOS_PRIORITY_3,
|
||||
QOS_PRIORITY_4,
|
||||
QOS_PRIORITY_5,
|
||||
QOS_PRIORITY_6,
|
||||
QOS_PRIORITY_7,
|
||||
QOS_PRIORITY_8,
|
||||
QOS_PRIORITY_9,
|
||||
QOS_PRIORITY_10,
|
||||
QOS_PRIORITY_11,
|
||||
QOS_PRIORITY_12,
|
||||
QOS_PRIORITY_13,
|
||||
QOS_PRIORITY_LOWEST,
|
||||
QOS_NO_PRIORITY
|
||||
} qos_priority_t;
|
||||
|
||||
/* Pre-emption Capability */
|
||||
typedef enum {
|
||||
PEC_SHALL_NOT_TRIGGER_PREEMPTION = 0,
|
||||
PEC_MAY_TRIGGER_PREEMPTION,
|
||||
PEC_MAX,
|
||||
} qos_pec_t;
|
||||
|
||||
/* Pre-emption Vulnerability */
|
||||
typedef enum {
|
||||
PEV_NOT_PREEMPTABLE = 0,
|
||||
PEV_PREEMPTABLE = 1,
|
||||
PEV_MAX,
|
||||
} qos_pev_t;
|
||||
|
||||
/* Allocation Retention Priority */
|
||||
typedef struct {
|
||||
qos_priority_t priority_level;
|
||||
qos_pec_t pre_emp_capability;
|
||||
qos_pev_t pre_emp_vulnerability;
|
||||
} qos_arp_t;
|
||||
|
||||
typedef struct pdusession_level_qos_parameter_s {
|
||||
uint8_t qfi;
|
||||
uint64_t fiveQI;
|
||||
uint64_t qos_priority;
|
||||
fiveQI_t fiveQI_type;
|
||||
qos_arp_t arp;
|
||||
} pdusession_level_qos_parameter_t;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -97,4 +97,7 @@
|
||||
#define UNUSED_VARIABLE(vARIABLE) (void)(vARIABLE)
|
||||
#define NUM_PRACH_RX_FOR_NOISE_ESTIMATE 100
|
||||
|
||||
// SDAP
|
||||
#define MAX_QOS_FLOWS 64
|
||||
|
||||
#endif /* __PLATFORM_CONSTANTS_H__ */
|
||||
|
||||
@@ -91,8 +91,6 @@
|
||||
#define NGAP_MAX_NB_AMF_IP_ADDRESS 10
|
||||
#define NGAP_IMSI_LENGTH 16
|
||||
|
||||
#define QOSFLOW_MAX_VALUE 64
|
||||
|
||||
#define NGAP_MAX_NO_TAI_PAGING 16 // 9.2.4.1 3GPP TS 38.413
|
||||
|
||||
/* Security key length used within gNB
|
||||
@@ -141,43 +139,6 @@ typedef struct ngap_ambr_s {
|
||||
bitrate_t br_dl;
|
||||
} ngap_ambr_t;
|
||||
|
||||
typedef enum ngap_priority_level_s {
|
||||
NGAP_PRIORITY_LEVEL_SPARE = 0,
|
||||
NGAP_PRIORITY_LEVEL_HIGHEST = 1,
|
||||
NGAP_PRIORITY_LEVEL_2 = 2,
|
||||
NGAP_PRIORITY_LEVEL_3 = 3,
|
||||
NGAP_PRIORITY_LEVEL_4 = 4,
|
||||
NGAP_PRIORITY_LEVEL_5 = 5,
|
||||
NGAP_PRIORITY_LEVEL_6 = 6,
|
||||
NGAP_PRIORITY_LEVEL_7 = 7,
|
||||
NGAP_PRIORITY_LEVEL_8 = 8,
|
||||
NGAP_PRIORITY_LEVEL_9 = 9,
|
||||
NGAP_PRIORITY_LEVEL_10 = 10,
|
||||
NGAP_PRIORITY_LEVEL_11 = 11,
|
||||
NGAP_PRIORITY_LEVEL_12 = 12,
|
||||
NGAP_PRIORITY_LEVEL_13 = 13,
|
||||
NGAP_PRIORITY_LEVEL_LOWEST = 14,
|
||||
NGAP_PRIORITY_LEVEL_NO_PRIORITY = 15
|
||||
} ngap_priority_level_t;
|
||||
|
||||
typedef enum ngap_pre_emp_capability_e {
|
||||
NGAP_PRE_EMPTION_CAPABILITY_SHALL_NOT_TRIGGER_PREEMPTION = 0,
|
||||
NGAP_PRE_EMPTION_CAPABILITY_MAY_TRIGGER_PREEMPTION = 1,
|
||||
NGAP_PRE_EMPTION_CAPABILITY_MAX,
|
||||
} ngap_pre_emp_capability_t;
|
||||
|
||||
typedef enum ngap_pre_emp_vulnerability_e {
|
||||
NGAP_PRE_EMPTION_VULNERABILITY_NOT_PREEMPTABLE = 0,
|
||||
NGAP_PRE_EMPTION_VULNERABILITY_PREEMPTABLE = 1,
|
||||
NGAP_PRE_EMPTION_VULNERABILITY_MAX,
|
||||
} ngap_pre_emp_vulnerability_t;
|
||||
|
||||
typedef struct ngap_allocation_retention_priority_s {
|
||||
ngap_priority_level_t priority_level;
|
||||
ngap_pre_emp_capability_t pre_emp_capability;
|
||||
ngap_pre_emp_vulnerability_t pre_emp_vulnerability;
|
||||
} ngap_allocation_retention_priority_t;
|
||||
|
||||
typedef struct ngap_security_capabilities_s {
|
||||
uint16_t nRencryption_algorithms;
|
||||
uint16_t nRintegrity_algorithms;
|
||||
@@ -205,14 +166,6 @@ typedef enum ngap_rrc_establishment_cause_e {
|
||||
NGAP_RRC_CAUSE_LAST
|
||||
} ngap_rrc_establishment_cause_t;
|
||||
|
||||
typedef struct pdusession_level_qos_parameter_s {
|
||||
uint8_t qfi;
|
||||
uint64_t fiveQI;
|
||||
uint64_t qos_priority;
|
||||
fiveQI_t fiveQI_type;
|
||||
ngap_allocation_retention_priority_t allocation_retention_priority;
|
||||
} pdusession_level_qos_parameter_t;
|
||||
|
||||
typedef struct fiveg_s_tmsi_s {
|
||||
uint16_t amf_set_id;
|
||||
uint8_t amf_pointer;
|
||||
@@ -241,7 +194,7 @@ typedef struct ngap_mobility_restriction_s{
|
||||
/* PDU Session Resource Setup Request Transfer (9.3.4.1 3GPP TS 38.413) */
|
||||
typedef struct {
|
||||
uint8_t nb_qos;
|
||||
pdusession_level_qos_parameter_t qos[QOSFLOW_MAX_VALUE];
|
||||
pdusession_level_qos_parameter_t qos[MAX_QOS_FLOWS];
|
||||
pdu_session_type_t pdu_session_type;
|
||||
// UPF endpoint of the NG-U (N3) transport bearer
|
||||
gtpu_tunnel_t n3_incoming;
|
||||
@@ -272,7 +225,7 @@ typedef struct pdusession_setup_s {
|
||||
uint8_t nb_of_qos_flow;
|
||||
|
||||
/* qos flow list(1 ~ 64) */
|
||||
pdusession_associate_qosflow_t associated_qos_flows[QOSFLOW_MAX_VALUE];
|
||||
pdusession_associate_qosflow_t associated_qos_flows[MAX_QOS_FLOWS];
|
||||
} pdusession_setup_t;
|
||||
|
||||
typedef struct qos_flow_tobe_modified_s {
|
||||
@@ -286,7 +239,7 @@ typedef struct pdusession_modify_s {
|
||||
uint8_t nb_of_qos_flow;
|
||||
|
||||
// qos_flow_add_or_modify
|
||||
qos_flow_tobe_modified_t qos[QOSFLOW_MAX_VALUE];
|
||||
qos_flow_tobe_modified_t qos[MAX_QOS_FLOWS];
|
||||
} pdusession_modify_t;
|
||||
|
||||
/* Cause (9.3.1.2 of 3GPP TS 38.413) */
|
||||
@@ -506,7 +459,7 @@ typedef struct {
|
||||
uint8_t pdusession_id;
|
||||
// QoS Flow Information List
|
||||
uint8_t nb_of_qos_flow;
|
||||
qosflow_info_t qos_flow_info[QOSFLOW_MAX_VALUE];
|
||||
qosflow_info_t qos_flow_info[MAX_QOS_FLOWS];
|
||||
} pdusession_resource_info_t;
|
||||
|
||||
/* 3GPP TS 38.413 9.3.1.97 */
|
||||
@@ -545,8 +498,6 @@ typedef enum {
|
||||
typedef struct {
|
||||
// PDU Session ID
|
||||
uint8_t pdusession_id;
|
||||
// Handover Required Transfer
|
||||
byte_array_t ho_required_transfer;
|
||||
} pdusession_resource_t;
|
||||
|
||||
/* 3GPP TS 38.413 9.2.3.1 */
|
||||
@@ -562,7 +513,7 @@ typedef struct {
|
||||
// Target ID
|
||||
target_ran_node_id_t target_gnb_id;
|
||||
// PDU Session Resource List
|
||||
uint8_t nb_of_pdusessions;
|
||||
uint16_t nb_of_pdusessions;
|
||||
pdusession_resource_t pdusessions[NGAP_MAX_PDU_SESSION];
|
||||
// Source to Target Transparent Container
|
||||
source_to_target_transparent_container_t *source2target;
|
||||
@@ -610,7 +561,7 @@ typedef struct {
|
||||
// Security Context
|
||||
ngap_security_context_t security_context;
|
||||
// PDU Session Resource Setup List
|
||||
uint8_t nb_of_pdusessions;
|
||||
uint16_t nb_of_pdusessions;
|
||||
ho_request_pdusession_t pduSessionResourceSetupList[NGAP_MAX_PDU_SESSION];
|
||||
// Allowed NSSAI
|
||||
uint8_t nb_allowed_nssais;
|
||||
@@ -629,7 +580,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
// QoS Flow Setup Response List
|
||||
uint8_t nb_of_qos_flow;
|
||||
pdusession_associate_qosflow_t qos_setup_list[QOSFLOW_MAX_VALUE];
|
||||
pdusession_associate_qosflow_t qos_setup_list[MAX_QOS_FLOWS];
|
||||
// DL NG-U UP TNL Information
|
||||
uint32_t gtp_teid;
|
||||
transport_layer_addr_t gNB_addr;
|
||||
@@ -650,7 +601,7 @@ typedef struct {
|
||||
uint64_t amf_ue_ngap_id;
|
||||
// PDU Session Resource Admitted List
|
||||
pdu_session_resource_admitted_t pdusessions[NGAP_MAX_PDU_SESSION];
|
||||
uint8_t nb_of_pdusessions;
|
||||
uint16_t nb_of_pdusessions;
|
||||
// Target to Source Transparent Container
|
||||
byte_array_t target2source;
|
||||
} ngap_handover_request_ack_t;
|
||||
@@ -659,7 +610,7 @@ typedef struct {
|
||||
typedef struct {
|
||||
// QoS Flow to be Forwarded List
|
||||
uint8_t nb_of_qos_flow;
|
||||
pdusession_associate_qosflow_t qos_setup_list[QOSFLOW_MAX_VALUE];
|
||||
pdusession_associate_qosflow_t qos_setup_list[MAX_QOS_FLOWS];
|
||||
// UL Forwarding UP TNL Information
|
||||
uint32_t gtp_teid;
|
||||
transport_layer_addr_t gNB_addr;
|
||||
@@ -680,7 +631,7 @@ typedef struct {
|
||||
// Handover Type
|
||||
ho_type_t handoverType;
|
||||
// PDU Session Resource Handover List
|
||||
uint8_t nb_of_pdusessions;
|
||||
uint16_t nb_of_pdusessions;
|
||||
pdusession_resource_handover_t pdu_sessions[NGAP_MAX_PDU_SESSION];
|
||||
// Target to Source Transparent Container
|
||||
byte_array_t handoverCommand;
|
||||
@@ -730,12 +681,12 @@ typedef struct ngap_initial_context_setup_resp_s {
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* Number of pdusession setup-ed in the list */
|
||||
uint8_t nb_of_pdusessions;
|
||||
uint16_t nb_of_pdusessions;
|
||||
/* list of pdusession setup-ed by RRC layers */
|
||||
pdusession_setup_t pdusessions[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* Number of pdusession failed to be setup in list */
|
||||
uint8_t nb_of_pdusessions_failed;
|
||||
uint16_t nb_of_pdusessions_failed;
|
||||
/* list of pdusessions that failed to be setup */
|
||||
pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION];
|
||||
} ngap_initial_context_setup_resp_t;
|
||||
@@ -823,7 +774,7 @@ typedef struct ngap_initial_context_setup_req_s {
|
||||
uint8_t security_key[SECURITY_KEY_LENGTH];
|
||||
|
||||
/* Number of pdusession to be setup in the list */
|
||||
uint8_t nb_of_pdusessions;
|
||||
uint16_t nb_of_pdusessions;
|
||||
// PDU Session Resource Setup Request List
|
||||
pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
@@ -871,7 +822,7 @@ typedef struct ngap_pdusession_setup_req_s {
|
||||
nssai_t allowed_nssai[8];
|
||||
|
||||
/* Number of pdusession to be setup in the list */
|
||||
uint8_t nb_pdusessions_tosetup;
|
||||
uint16_t nb_pdusessions_tosetup;
|
||||
|
||||
// PDU Session Resource Setup Request List
|
||||
pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION];
|
||||
@@ -885,12 +836,12 @@ typedef struct ngap_pdusession_setup_req_s {
|
||||
typedef struct ngap_pdusession_setup_resp_s {
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
/* Number of pdusession setup-ed in the list */
|
||||
uint8_t nb_of_pdusessions;
|
||||
uint16_t nb_of_pdusessions;
|
||||
/* list of pdusession setup-ed by RRC layers */
|
||||
pdusession_setup_t pdusessions[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* Number of pdusession failed to be setup in list */
|
||||
uint8_t nb_of_pdusessions_failed;
|
||||
uint16_t nb_of_pdusessions_failed;
|
||||
/* list of pdusessions that failed to be setup */
|
||||
pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION];
|
||||
} ngap_pdusession_setup_resp_t;
|
||||
@@ -914,7 +865,7 @@ typedef struct pdusession_release_s {
|
||||
typedef struct ngap_ue_release_req_s {
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
/* Number of pdusession resource in the list */
|
||||
uint8_t nb_of_pdusessions;
|
||||
uint16_t nb_of_pdusessions;
|
||||
/* list of pdusession resource by RRC layers */
|
||||
pdusession_release_t pdusessions[NGAP_MAX_PDU_SESSION];
|
||||
ngap_cause_t cause;
|
||||
@@ -928,7 +879,7 @@ typedef struct ngap_pdusession_modify_req_s {
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* Number of pdusession to be modify in the list */
|
||||
uint8_t nb_pdusessions_tomodify;
|
||||
uint16_t nb_pdusessions_tomodify;
|
||||
|
||||
// PDU Session Resource Modify Request List
|
||||
pdusession_resource_item_t pdusession[NGAP_MAX_PDU_SESSION];
|
||||
@@ -938,12 +889,12 @@ typedef struct ngap_pdusession_modify_resp_s {
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* Number of pdusession modify-ed in the list */
|
||||
uint8_t nb_of_pdusessions;
|
||||
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 */
|
||||
uint8_t nb_of_pdusessions_failed;
|
||||
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;
|
||||
@@ -959,7 +910,7 @@ typedef struct ngap_pdusession_release_command_s {
|
||||
byte_array_t nas_pdu;
|
||||
|
||||
/* Number of pdusession to be released in the list */
|
||||
uint8_t nb_pdusessions_torelease;
|
||||
uint16_t nb_pdusessions_torelease;
|
||||
|
||||
/* PDUSession release command */
|
||||
pdusession_release_t pdusession_release_params[NGAP_MAX_PDU_SESSION];
|
||||
@@ -967,23 +918,13 @@ typedef struct ngap_pdusession_release_command_s {
|
||||
} ngap_pdusession_release_command_t;
|
||||
|
||||
typedef struct ngap_pdusession_release_resp_s {
|
||||
/* AMF UE id */
|
||||
// AMF UE NGAP ID
|
||||
uint64_t amf_ue_ngap_id;
|
||||
|
||||
/* gNB ue ngap id as initialized by NGAP layer */
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
|
||||
/* Number of pdusession released in the list */
|
||||
uint8_t nb_of_pdusessions_released;
|
||||
|
||||
/* list of pdusessions released */
|
||||
// RAN UE NGAP ID
|
||||
uint32_t gNB_ue_ngap_id;
|
||||
// PDU Session Resource Released List
|
||||
uint16_t nb_of_pdusessions_released;
|
||||
pdusession_release_t pdusession_release[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
/* Number of pdusession failed to be released in list */
|
||||
uint8_t nb_of_pdusessions_failed;
|
||||
/* list of pdusessions that failed to be released */
|
||||
pdusession_failed_t pdusessions_failed[NGAP_MAX_PDU_SESSION];
|
||||
|
||||
} ngap_pdusession_release_resp_t;
|
||||
|
||||
/** 9.2.3.14 Uplink RAN Status Transfer (3GPP TS 38.413)
|
||||
|
||||
@@ -27,10 +27,11 @@
|
||||
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
|
||||
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_oai_api.h"
|
||||
|
||||
#include "ds/seq_arr.h"
|
||||
|
||||
#if defined (NGRAN_GNB_CUCP)
|
||||
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
|
||||
#include "openair2/RRC/NR/rrc_gNB_radio_bearers.h"
|
||||
#endif
|
||||
|
||||
bool read_gtp_sm(void * data)
|
||||
@@ -62,16 +63,15 @@ bool read_gtp_sm(void * data)
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[0], ue_id_list[i]);
|
||||
|
||||
gtp->msg.ngut[i].rnti = ue_id_list[i];
|
||||
int nb_pdu_session = ue_context_p->ue_context.nb_of_pdusessions;
|
||||
if (nb_pdu_session > 0) {
|
||||
int nb_pdu_idx = nb_pdu_session - 1;
|
||||
gtp->msg.ngut[i].teidgnb = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.n3_outgoing.teid;
|
||||
gtp->msg.ngut[i].teidupf = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.n3_incoming.teid;
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t*, session, &ue_context_p->ue_context.pduSessions) {
|
||||
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 = ue_context_p->ue_context.pduSession[nb_pdu_idx].param.nb_qos;
|
||||
if (nb_qos_flow > 0) {
|
||||
gtp->msg.ngut[i].qfi = ue_context_p->ue_context.pduSession[nb_pdu_idx].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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "openair2/E1AP/e1ap_common.h"
|
||||
#include "openair2/E2AP/flexric/src/util/time_now_us.h"
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "ds/seq_arr.h"
|
||||
|
||||
static pthread_once_t once_kpm_mutex = PTHREAD_ONCE_INIT;
|
||||
|
||||
@@ -212,8 +213,8 @@ static arr_ue_id_t filter_ues_by_s_nssai_in_cu(const test_info_lst_t test_info)
|
||||
/* UE has no AMF UE NGAP ID yet => can't send message */
|
||||
if (ue->amf_ue_ngap_id >= (1LL << 40))
|
||||
continue;
|
||||
for (int p = 0; p < ue->nb_of_pdusessions; ++p) {
|
||||
pdusession_t *pdu = &ue->pduSession[p].param;
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t*, item, &ue->pduSessions) {
|
||||
pdusession_t* pdu = &item->param;
|
||||
if (nssai_matches(pdu->nssai, sst, sd)) {
|
||||
arr_ue_id.ue_id[arr_ue_id.sz] = fill_ue_id_data[ngran_gNB_CU](ue, 0, 0);
|
||||
|
||||
|
||||
@@ -1344,7 +1344,7 @@ void config_rlc(configmodule_interface_t *cfg, nr_rlc_configuration_t *rlc_confi
|
||||
rlc_config->drb_um.sn_field_length = config_get_processedint(cfg, &rlc_drb_um_params[CONFIG_NR_RLC_DRB_UM_SN_FIELD_LENGTH_IDX]);
|
||||
}
|
||||
|
||||
void config_pdcp(configmodule_interface_t *cfg, nr_pdcp_configuration_t *pdcp_config)
|
||||
static void config_pdcp(configmodule_interface_t *cfg, nr_pdcp_configuration_t *pdcp_config)
|
||||
{
|
||||
/* DRB configuration */
|
||||
paramdef_t pdcp_params[] = NR_PDCP_DRB_GLOBALPARAMS_DESC;
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
add_subdirectory(MESSAGES)
|
||||
|
||||
if(ENABLE_TESTS)
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
||||
@@ -319,51 +319,6 @@ int do_RRCReject(uint8_t *const buffer)
|
||||
return (enc_rval.encoded + 7) / 8;
|
||||
}
|
||||
|
||||
/* returns a default radio bearer config suitable for NSA etc */
|
||||
NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id,
|
||||
int rb_id,
|
||||
e_NR_CipheringAlgorithm ciphering_algorithm,
|
||||
e_NR_SecurityConfig__keyToUse key_to_use,
|
||||
const nr_pdcp_configuration_t *pdcp_config)
|
||||
{
|
||||
NR_RadioBearerConfig_t *rbconfig = calloc(1, sizeof(*rbconfig));
|
||||
rbconfig->srb_ToAddModList = NULL;
|
||||
rbconfig->srb3_ToRelease = NULL;
|
||||
rbconfig->drb_ToAddModList = calloc(1,sizeof(*rbconfig->drb_ToAddModList));
|
||||
NR_DRB_ToAddMod_t *drb_ToAddMod = calloc(1,sizeof(*drb_ToAddMod));
|
||||
drb_ToAddMod->cnAssociation = calloc(1,sizeof(*drb_ToAddMod->cnAssociation));
|
||||
drb_ToAddMod->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity;
|
||||
drb_ToAddMod->cnAssociation->choice.eps_BearerIdentity= eps_bearer_id;
|
||||
drb_ToAddMod->drb_Identity = rb_id;
|
||||
drb_ToAddMod->reestablishPDCP = NULL;
|
||||
drb_ToAddMod->recoverPDCP = NULL;
|
||||
drb_ToAddMod->pdcp_Config = calloc(1,sizeof(*drb_ToAddMod->pdcp_Config));
|
||||
asn1cCalloc(drb_ToAddMod->pdcp_Config->drb, drb);
|
||||
asn1cCallocOne(drb->discardTimer, encode_discard_timer(pdcp_config->drb.discard_timer));
|
||||
asn1cCallocOne(drb->pdcp_SN_SizeUL, encode_sn_size_ul(pdcp_config->drb.sn_size));
|
||||
asn1cCallocOne(drb->pdcp_SN_SizeDL, encode_sn_size_dl(pdcp_config->drb.sn_size));
|
||||
drb->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed;
|
||||
drb->headerCompression.choice.notUsed = 0;
|
||||
drb->integrityProtection = NULL;
|
||||
drb->statusReportRequired = NULL;
|
||||
drb->outOfOrderDelivery = NULL;
|
||||
|
||||
drb_ToAddMod->pdcp_Config->moreThanOneRLC = NULL;
|
||||
asn1cCallocOne(drb_ToAddMod->pdcp_Config->t_Reordering, encode_t_reordering(pdcp_config->drb.t_reordering));
|
||||
drb_ToAddMod->pdcp_Config->ext1 = NULL;
|
||||
|
||||
asn1cSeqAdd(&rbconfig->drb_ToAddModList->list,drb_ToAddMod);
|
||||
|
||||
rbconfig->drb_ToReleaseList = NULL;
|
||||
|
||||
asn1cCalloc(rbconfig->securityConfig, secConf);
|
||||
asn1cCalloc(secConf->securityAlgorithmConfig, secConfAlgo);
|
||||
secConfAlgo->cipheringAlgorithm = ciphering_algorithm;
|
||||
secConfAlgo->integrityProtAlgorithm = NULL;
|
||||
asn1cCallocOne(secConf->keyToUse, key_to_use);
|
||||
return rbconfig;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int do_RRCSetup(uint8_t *const buffer,
|
||||
size_t buffer_size,
|
||||
|
||||
@@ -89,12 +89,6 @@ int do_SIB2_NR(uint8_t **msg_SIB2, NR_SSB_MTC_t *ssbmtc);
|
||||
|
||||
int do_RRCReject(uint8_t *const buffer);
|
||||
|
||||
NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id,
|
||||
int rb_id,
|
||||
e_NR_CipheringAlgorithm ciphering_algorithm,
|
||||
e_NR_SecurityConfig__keyToUse key_to_use,
|
||||
const nr_pdcp_configuration_t *pdcp_config);
|
||||
|
||||
int do_RRCSetup(uint8_t *const buffer,
|
||||
size_t buffer_size,
|
||||
const uint8_t transaction_id,
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
#include "intertask_interface.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h"
|
||||
#include "openair2/LAYER2/nr_rlc/nr_rlc_configuration.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap_configuration.h"
|
||||
|
||||
typedef enum {
|
||||
NR_RRC_OK=0,
|
||||
@@ -103,9 +104,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
|
||||
@@ -113,6 +113,8 @@ typedef struct pdusession_s {
|
||||
// UPF endpoint of the NG-U (N3) transport bearer
|
||||
gtpu_tunnel_t n3_incoming;
|
||||
nssai_t nssai;
|
||||
// PDU Session specific SDAP configuration
|
||||
nr_sdap_configuration_t sdap_config;
|
||||
} pdusession_t;
|
||||
|
||||
typedef struct pdu_session_param_s {
|
||||
@@ -125,35 +127,13 @@ typedef struct pdu_session_param_s {
|
||||
typedef struct drb_s {
|
||||
int status;
|
||||
int drb_id;
|
||||
struct cnAssociation_s {
|
||||
int present;
|
||||
int eps_BearerIdentity;
|
||||
struct sdap_config_s {
|
||||
bool defaultDRB;
|
||||
int pdusession_id;
|
||||
int sdap_HeaderDL;
|
||||
int sdap_HeaderUL;
|
||||
int mappedQoS_FlowsToAdd[QOSFLOW_MAX_VALUE];
|
||||
} sdap_config;
|
||||
} cnAssociation;
|
||||
struct pdcp_config_s {
|
||||
int discardTimer;
|
||||
int pdcp_SN_SizeUL;
|
||||
int pdcp_SN_SizeDL;
|
||||
int t_Reordering;
|
||||
int integrityProtection;
|
||||
struct headerCompression_s {
|
||||
int NotUsed;
|
||||
int present;
|
||||
} headerCompression;
|
||||
struct ext1_s {
|
||||
int cipheringDisabled;
|
||||
} ext1;
|
||||
} pdcp_config;
|
||||
int pdusession_id;
|
||||
// F1-U Downlink Tunnel Config (on DU side)
|
||||
gtpu_tunnel_t du_tunnel_config;
|
||||
// F1-U Uplink Tunnel Config (on CU-UP side)
|
||||
gtpu_tunnel_t cuup_tunnel_config;
|
||||
// DRB-specific PDCP configuration
|
||||
nr_pdcp_configuration_t pdcp_config;
|
||||
} drb_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -176,13 +156,17 @@ 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;
|
||||
|
||||
typedef struct gNB_RRC_UE_s {
|
||||
time_t last_seen; // last time this UE has been accessed
|
||||
|
||||
drb_t established_drbs[MAX_DRBS_PER_UE];
|
||||
NR_DRB_ToReleaseList_t *DRB_ReleaseList;
|
||||
|
||||
NR_SRB_INFO_TABLE_ENTRY Srb[NR_NUM_SRB];
|
||||
@@ -238,8 +222,10 @@ typedef struct gNB_RRC_UE_s {
|
||||
rb_id_t nsa_gtp_psi[S1AP_MAX_E_RAB];
|
||||
|
||||
//SA block
|
||||
int nb_of_pdusessions;
|
||||
rrc_pdu_session_param_t pduSession[NGAP_MAX_PDU_SESSION];
|
||||
seq_arr_t pduSessions;
|
||||
// Established DRBs
|
||||
seq_arr_t drbs;
|
||||
|
||||
rrc_action_t xids[NR_RRC_TRANSACTION_IDENTIFIER_NUMBER];
|
||||
uint8_t e_rab_release_command_flag;
|
||||
uint32_t ue_rrc_inactivity_timer;
|
||||
@@ -400,6 +386,7 @@ typedef struct gNB_RRC_INST_s {
|
||||
RB_HEAD(rrc_cuup_tree, nr_rrc_cuup_container_t) cuups; // CU-UPs, indexed by assoc_id
|
||||
size_t num_cuups;
|
||||
|
||||
// PDCP configuration parameters loaded during startup
|
||||
nr_pdcp_configuration_t pdcp_config;
|
||||
nr_rlc_configuration_t rlc_config;
|
||||
} gNB_RRC_INST;
|
||||
|
||||
@@ -122,11 +122,10 @@ 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);
|
||||
NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish);
|
||||
NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do_integrity, bool do_ciphering);
|
||||
void activate_srb(gNB_RRC_UE_t *UE, int srb_id);
|
||||
void e1_send_bearer_updates(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, f1ap_drb_setup_t *drbs, const ngap_drb_status_t *drb_status);
|
||||
|
||||
|
||||
+157
-112
@@ -38,6 +38,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include "5g_platform_types.h"
|
||||
#include "openair2/RRC/NR/nr_rrc_proto.h"
|
||||
#include "openair2/RRC/NR/rrc_gNB_UE_context.h"
|
||||
#include "openair3/SECU/key_nas_deriver.h"
|
||||
@@ -86,6 +87,7 @@
|
||||
#include "rrc_gNB_mobility.h"
|
||||
#include "rrc_gNB_radio_bearers.h"
|
||||
#include "rrc_messages_types.h"
|
||||
#include "rrc_gNB_asn1.h"
|
||||
#include "seq_arr.h"
|
||||
#include "tree.h"
|
||||
#include "uper_decoder.h"
|
||||
@@ -99,6 +101,7 @@
|
||||
#include "ds/byte_array.h"
|
||||
#include "alg/find.h"
|
||||
#include "NR_HandoverCommand.h"
|
||||
#include "openair2/SDAP/nr_sdap/nr_sdap_configuration.h"
|
||||
|
||||
#ifdef E2_AGENT
|
||||
#include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h"
|
||||
@@ -329,19 +332,63 @@ NR_SRB_ToAddModList_t *createSRBlist(gNB_RRC_UE_t *ue, uint8_t reestablish)
|
||||
return list;
|
||||
}
|
||||
|
||||
NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish)
|
||||
static NR_SDAP_Config_t *nr_rrc_build_sdap_config_ie(const int pdusession_id,
|
||||
uint8_t n_flows,
|
||||
pdusession_level_qos_parameter_t *qos,
|
||||
const nr_sdap_configuration_t *sdap_config)
|
||||
{
|
||||
DevAssert(n_flows < MAX_QOS_FLOWS);
|
||||
// SDAP
|
||||
NR_SDAP_Config_t *sc = calloc_or_fail(1, sizeof(*sc));
|
||||
sc->defaultDRB = true;
|
||||
sc->pdu_Session = pdusession_id;
|
||||
sc->sdap_HeaderDL = sdap_config->header_dl_absent ? NR_SDAP_Config__sdap_HeaderDL_absent : NR_SDAP_Config__sdap_HeaderDL_present;
|
||||
sc->sdap_HeaderUL = sdap_config->header_ul_absent ? NR_SDAP_Config__sdap_HeaderUL_absent : NR_SDAP_Config__sdap_HeaderUL_present;
|
||||
// QoS
|
||||
asn1cCalloc(sc->mappedQoS_FlowsToAdd, mappedQoS_FlowsToAdd);
|
||||
for (uint8_t i = 0; i < n_flows; ++i) {
|
||||
DevAssert(i < MAX_QOS_FLOWS);
|
||||
NR_QFI_t *qfi = calloc_or_fail(1, sizeof(*qfi));
|
||||
*qfi = qos[i].qfi;
|
||||
LOG_D(NR_RRC, "Adding QFI %ld to PDU Session %d\n", *qfi, pdusession_id);
|
||||
asn1cSeqAdd(&mappedQoS_FlowsToAdd->list, qfi);
|
||||
}
|
||||
return sc;
|
||||
}
|
||||
|
||||
NR_DRB_ToAddModList_t *createDRBlist(gNB_RRC_UE_t *ue, bool reestablish, bool do_integrity, bool do_ciphering)
|
||||
{
|
||||
NR_DRB_ToAddMod_t *DRB_config = NULL;
|
||||
NR_DRB_ToAddModList_t *DRB_configList = CALLOC(sizeof(*DRB_configList), 1);
|
||||
|
||||
for (int i = 0; i < MAX_DRBS_PER_UE; i++) {
|
||||
if (ue->established_drbs[i].status != DRB_INACTIVE) {
|
||||
DRB_config = generateDRB_ASN1(&ue->established_drbs[i]);
|
||||
if (reestablish) {
|
||||
asn1cCallocOne(DRB_config->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true);
|
||||
}
|
||||
asn1cSeqAdd(&DRB_configList->list, DRB_config);
|
||||
FOR_EACH_SEQ_ARR(drb_t *, drb, &ue->drbs) {
|
||||
rrc_pdu_session_param_t *pduSession = find_pduSession(&ue->pduSessions, drb->pdusession_id);
|
||||
if (!pduSession) {
|
||||
LOG_D(NR_RRC, "PDU Session %d not found, skip\n", drb->pdusession_id);
|
||||
continue;
|
||||
}
|
||||
pdusession_t *session = &pduSession->param;
|
||||
NR_DRB_ToAddMod_t *drb_ToAddMod = calloc_or_fail(1, sizeof(*drb_ToAddMod));
|
||||
drb_ToAddMod->drb_Identity = drb->drb_id;
|
||||
// PDCP config
|
||||
drb_ToAddMod->pdcp_Config = nr_rrc_build_pdcp_config_ie(do_integrity, do_ciphering, &drb->pdcp_config);
|
||||
if (reestablish) {
|
||||
asn1cCallocOne(drb_ToAddMod->reestablishPDCP, NR_DRB_ToAddMod__reestablishPDCP_true);
|
||||
}
|
||||
// cn-association: SDAP config
|
||||
// Get all QoS flows mapped to this DRB
|
||||
pdusession_level_qos_parameter_t flows_to_add[MAX_QOS_FLOWS] = {0};
|
||||
uint8_t n_flows = 0;
|
||||
FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, q, &session->qos)
|
||||
{
|
||||
if (q->drb_id == drb->drb_id) {
|
||||
DevAssert(n_flows < MAX_QOS_FLOWS);
|
||||
flows_to_add[n_flows++] = q->qos;
|
||||
}
|
||||
}
|
||||
asn1cCalloc(drb_ToAddMod->cnAssociation, cn_association);
|
||||
cn_association->present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config;
|
||||
cn_association->choice.sdap_Config = nr_rrc_build_sdap_config_ie(drb->pdusession_id, n_flows, flows_to_add, &session->sdap_config);
|
||||
asn1cSeqAdd(&DRB_configList->list, drb_ToAddMod);
|
||||
}
|
||||
if (DRB_configList->list.count == 0) {
|
||||
free(DRB_configList);
|
||||
@@ -645,8 +692,10 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC
|
||||
uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id);
|
||||
|
||||
// Re-establish PDCP for SRB2 only
|
||||
bool do_integrity = rrc->security.do_drb_integrity;
|
||||
bool do_ciphering = rrc->security.do_drb_ciphering;
|
||||
NR_SRB_ToAddModList_t *SRBs = createSRBlist(UE, srb_reest_bitmap);
|
||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish);
|
||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(UE, drb_reestablish, do_integrity, do_ciphering);
|
||||
|
||||
nr_rrc_reconfig_param_t params = {.cell_group_config = UE->masterCellGroup,
|
||||
.transaction_id = xid,
|
||||
@@ -656,14 +705,16 @@ nr_rrc_reconfig_param_t get_RRCReconfiguration_params(gNB_RRC_INST *rrc, gNB_RRC
|
||||
.srb_config_list = SRBs};
|
||||
UE->DRB_ReleaseList = NULL; // pointer transferred to params
|
||||
|
||||
for (int i = 0; i < UE->nb_of_pdusessions; i++) {
|
||||
if (UE->pduSession[i].param.nas_pdu.len > 0) {
|
||||
params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->pduSession[i].param.nas_pdu;
|
||||
UE->pduSession[i].param.nas_pdu.buf = NULL;
|
||||
UE->pduSession[i].param.nas_pdu.len = 0;
|
||||
LOG_D(NR_RRC, "Transfer NAS info with size %ld (pdusession idx %d) to RRCReconfiguration params\n", UE->pduSession[i].param.nas_pdu.len, i);
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &UE->pduSessions) {
|
||||
pdusession_t *session = &item->param;
|
||||
if (session->nas_pdu.len > 0) {
|
||||
params.dedicated_NAS_msg_list[params.num_nas_msg++] = session->nas_pdu;
|
||||
session->nas_pdu.buf = NULL;
|
||||
session->nas_pdu.len = 0;
|
||||
LOG_D(NR_RRC, "Transfer NAS info with size %ld to RRCReconfiguration params\n", session->nas_pdu.len);
|
||||
}
|
||||
}
|
||||
|
||||
if (UE->nas_pdu.len > 0) {
|
||||
params.dedicated_NAS_msg_list[params.num_nas_msg++] = UE->nas_pdu;
|
||||
UE->nas_pdu.buf = NULL;
|
||||
@@ -696,12 +747,11 @@ static void rrc_gNB_generate_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < ue_p->nb_of_pdusessions; i++) {
|
||||
if (ue_p->pduSession[i].param.nas_pdu.buf != NULL) {
|
||||
ue_p->pduSession[i].xid = params.transaction_id;
|
||||
}
|
||||
if (ue_p->pduSession[i].status < PDU_SESSION_STATUS_ESTABLISHED) {
|
||||
ue_p->pduSession[i].status = PDU_SESSION_STATUS_DONE;
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) {
|
||||
if (item->param.nas_pdu.buf)
|
||||
item->xid = params.transaction_id;
|
||||
if (item->status < PDU_SESSION_STATUS_ESTABLISHED) {
|
||||
item->status = PDU_SESSION_STATUS_DONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,40 +768,24 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t
|
||||
nr_rrc_reconfig_param_t params = get_RRCReconfiguration_params(rrc, ue_p, 0, false);
|
||||
ue_p->xids[params.transaction_id] = RRC_PDUSESSION_MODIFY;
|
||||
|
||||
for (int i = 0; i < ue_p->nb_of_pdusessions; i++) {
|
||||
rrc_pdu_session_param_t *session = &ue_p->pduSession[i];
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) {
|
||||
pdusession_t *session = &item->param;
|
||||
// bypass the new and already configured pdu sessions
|
||||
if (session->status >= PDU_SESSION_STATUS_DONE) {
|
||||
session->xid = params.transaction_id;
|
||||
if (item->status >= PDU_SESSION_STATUS_DONE) {
|
||||
item->xid = params.transaction_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (session->cause.type != NGAP_CAUSE_NOTHING) {
|
||||
if (item->cause.type != NGAP_CAUSE_NOTHING) {
|
||||
// set xid of failure pdu session
|
||||
session->xid = params.transaction_id;
|
||||
session->status = PDU_SESSION_STATUS_FAILED;
|
||||
continue;
|
||||
}
|
||||
|
||||
// search exist DRB_config
|
||||
int j;
|
||||
for (j = 0; i < MAX_DRBS_PER_UE; j++) {
|
||||
if (ue_p->established_drbs[j].status != DRB_INACTIVE
|
||||
&& ue_p->established_drbs[j].cnAssociation.sdap_config.pdusession_id == session->param.pdusession_id)
|
||||
break;
|
||||
}
|
||||
|
||||
if (j == MAX_DRBS_PER_UE) {
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CauseRadioNetwork_unspecified};
|
||||
session->xid = params.transaction_id;
|
||||
session->status = PDU_SESSION_STATUS_FAILED;
|
||||
session->cause = cause;
|
||||
item->xid = params.transaction_id;
|
||||
item->status = PDU_SESSION_STATUS_FAILED;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Reference TS23501 Table 5.7.4-1: Standardized 5QI to QoS characteristics mapping
|
||||
for (qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) {
|
||||
switch (session->param.qos[qos_flow_index].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
|
||||
@@ -765,18 +799,17 @@ void rrc_gNB_modify_dedicatedRRCReconfiguration(gNB_RRC_INST *rrc, gNB_RRC_UE_t
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_E(NR_RRC, "not supported 5qi %lu\n", session->param.qos[qos_flow_index].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};
|
||||
session->status = PDU_SESSION_STATUS_FAILED;
|
||||
session->xid = params.transaction_id;
|
||||
session->cause = cause;
|
||||
item->status = PDU_SESSION_STATUS_FAILED;
|
||||
item->xid = params.transaction_id;
|
||||
item->cause = cause;
|
||||
continue;
|
||||
}
|
||||
LOG_I(NR_RRC, "index %d, QOS flow %d, 5QI %ld \n", i, qos_flow_index, session->param.qos[qos_flow_index].fiveQI);
|
||||
LOG_I(NR_RRC, "PDU Session ID %d, QOS flow %d, 5QI %ld \n", session->pdusession_id, qos_flow_index, qos->qos.fiveQI);
|
||||
}
|
||||
|
||||
session->status = PDU_SESSION_STATUS_DONE;
|
||||
session->xid = params.transaction_id;
|
||||
item->status = PDU_SESSION_STATUS_DONE;
|
||||
item->xid = params.transaction_id;
|
||||
}
|
||||
|
||||
byte_array_t msg = do_RRCReconfiguration(¶ms);
|
||||
@@ -800,16 +833,21 @@ void rrc_gNB_generate_dedicatedRRCReconfiguration_release(gNB_RRC_INST *rrc,
|
||||
uint8_t *nas_buffer)
|
||||
//-----------------------------------------------------------------------------
|
||||
{
|
||||
NR_DRB_ToReleaseList_t *DRB_Release_configList2 = CALLOC(sizeof(*DRB_Release_configList2), 1);
|
||||
nr_rrc_reconfig_param_t params = {.transaction_id = xid};
|
||||
|
||||
for (int i = 0; i < NB_RB_MAX; i++) {
|
||||
if ((ue_p->pduSession[i].status == PDU_SESSION_STATUS_TORELEASE) && ue_p->pduSession[i].xid == xid) {
|
||||
asn1cSequenceAdd(DRB_Release_configList2->list, NR_DRB_Identity_t, DRB_release);
|
||||
*DRB_release = i + 1;
|
||||
NR_DRB_ToReleaseList_t *to_release = CALLOC(sizeof(*to_release), 1);
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, item, &ue_p->pduSessions) {
|
||||
if ((item->status != PDU_SESSION_STATUS_TORELEASE) && item->xid != xid)
|
||||
continue;
|
||||
FOR_EACH_SEQ_ARR(drb_t *, drb, &ue_p->drbs) {
|
||||
if (drb->pdusession_id == item->param.pdusession_id) {
|
||||
asn1cSequenceAdd(to_release->list, NR_DRB_Identity_t, DRB_release);
|
||||
*DRB_release = drb->drb_id; // DRB ID
|
||||
}
|
||||
}
|
||||
}
|
||||
params.drb_release_list = to_release;
|
||||
|
||||
nr_rrc_reconfig_param_t params = {.drb_release_list = DRB_Release_configList2, .transaction_id = xid};
|
||||
if (nas_length > 0) {
|
||||
params.dedicated_NAS_msg_list[params.num_nas_msg].buf = nas_buffer;
|
||||
params.dedicated_NAS_msg_list[params.num_nas_msg++].len = nas_length;
|
||||
@@ -870,8 +908,8 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
|
||||
return;
|
||||
/* loop through active DRBs */
|
||||
for (int drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) {
|
||||
drb_t *drb = get_drb(ue_p, drb_id);
|
||||
if (drb->status == DRB_INACTIVE)
|
||||
drb_t *drb = get_drb(&ue_p->drbs, drb_id);
|
||||
if (!drb)
|
||||
continue;
|
||||
/* fetch an existing PDU session for this DRB */
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession_from_drbId(ue_p, drb_id);
|
||||
@@ -897,9 +935,8 @@ static void cuup_notify_reestablishment(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue_p)
|
||||
/* PDCP configuration */
|
||||
if (!drb_e1->pdcp_config)
|
||||
drb_e1->pdcp_config = malloc_or_fail(sizeof(*drb_e1->pdcp_config));
|
||||
bearer_context_pdcp_config_t *pdcp_config = drb_e1->pdcp_config;
|
||||
set_bearer_context_pdcp_config(pdcp_config, drb, rrc->configuration.um_on_default_drb);
|
||||
pdcp_config->pDCP_Reestablishment = true;
|
||||
*drb_e1->pdcp_config = set_bearer_context_pdcp_config(drb->pdcp_config, rrc->configuration.um_on_default_drb, ue_p->redcap_cap);
|
||||
drb_e1->pdcp_config->pDCP_Reestablishment = true;
|
||||
/* increase DRB to modify counter */
|
||||
pdu_e1->numDRB2Modify += 1;
|
||||
}
|
||||
@@ -1063,7 +1100,9 @@ static void rrc_gNB_process_RRCReestablishmentComplete(gNB_RRC_INST *rrc, gNB_RR
|
||||
* or at the first reconfiguration after RRC connection reestablishment in NR */
|
||||
NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, 1 << SRB2); // Re-establish PDCP for SRB2 only
|
||||
/* Create drb-ToAddModList */
|
||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true);
|
||||
bool do_integrity = rrc->security.do_drb_integrity;
|
||||
bool do_ciphering = rrc->security.do_drb_ciphering;
|
||||
NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, true, do_integrity, do_ciphering);
|
||||
|
||||
uint8_t new_xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id);
|
||||
ue_p->xids[new_xid] = RRC_REESTABLISH_COMPLETE;
|
||||
@@ -1783,8 +1822,12 @@ static void handle_rrcReconfigurationComplete(gNB_RRC_INST *rrc, gNB_RRC_UE_t *U
|
||||
UE->n_initial_pdu = 0;
|
||||
free(UE->initial_pdus);
|
||||
UE->initial_pdus = NULL;
|
||||
} else if (UE->nb_of_pdusessions > 0)
|
||||
} else if (seq_arr_size(&UE->pduSessions) > 0)
|
||||
rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(rrc, UE, xid);
|
||||
else
|
||||
LOG_W(NR_RRC,
|
||||
"UE %d: RRC Reconfiguration Complete for PDU session establishment, but no PDU sessions were setup\n",
|
||||
UE->rrc_ue_id);
|
||||
break;
|
||||
case RRC_PDUSESSION_MODIFY:
|
||||
rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(rrc, UE, xid);
|
||||
@@ -2071,7 +2114,8 @@ static void store_du_f1u_tunnel(const f1ap_drb_setup_t *drbs, int n, gNB_RRC_UE_
|
||||
const f1ap_drb_setup_t *drb_f1 = &drbs[i];
|
||||
AssertFatal(drb_f1->up_dl_tnl_len == 1, "can handle only one UP param\n");
|
||||
AssertFatal(drb_f1->id < MAX_DRBS_PER_UE, "illegal DRB ID %d\n", drb_f1->id);
|
||||
drb_t *drb = get_drb(ue, drb_f1->id);
|
||||
drb_t *drb = get_drb(&ue->drbs, drb_f1->id);
|
||||
DevAssert(drb);
|
||||
drb->du_tunnel_config = f1u_gtp_update(drb_f1->up_dl_tnl[0].teid, drb_f1->up_dl_tnl[0].tl_address);
|
||||
}
|
||||
}
|
||||
@@ -2087,7 +2131,8 @@ static void fill_e1_bearer_modif_pdcp_status(gNB_RRC_UE_t *UE,
|
||||
drb_to_mod->pdcp_sn_status_requested = false;
|
||||
// PDCP SN Status Information
|
||||
drb_to_mod->pdcp_config = calloc_or_fail(1, sizeof(*drb_to_mod->pdcp_config));
|
||||
set_bearer_context_pdcp_config(drb_to_mod->pdcp_config, get_drb(UE, drb_id), um_on_default_drb);
|
||||
drb_t *drb = get_drb(&UE->drbs, drb_id);
|
||||
*drb_to_mod->pdcp_config = set_bearer_context_pdcp_config(drb->pdcp_config, um_on_default_drb, UE->redcap_cap);
|
||||
drb_to_mod->pdcp_status = calloc_or_fail(1, sizeof(*drb_to_mod->pdcp_status));
|
||||
drb_to_mod->pdcp_status->dl_count.hfn = drb_status->dl_count.hfn;
|
||||
drb_to_mod->pdcp_status->dl_count.sn = drb_status->dl_count.pdcp_sn;
|
||||
@@ -2111,20 +2156,24 @@ 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) {
|
||||
/* On-going handover: send PDCP Status Request */
|
||||
if (UE->established_drbs[i].status == DRB_INACTIVE)
|
||||
drb_t *drb = get_drb(&UE->drbs, drb_id);
|
||||
if (!drb) {
|
||||
LOG_E(NR_RRC, "Failed to send PDCP Status Request: DRB %d not found\n", drb_id);
|
||||
continue;
|
||||
}
|
||||
drb_to_mod.id = drb_id;
|
||||
// PDCP SN Status Request
|
||||
drb_to_mod.pdcp_sn_status_requested = true;
|
||||
@@ -2141,6 +2190,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);
|
||||
@@ -2197,7 +2248,7 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance
|
||||
}
|
||||
|
||||
if (resp->drbs_len > 0) {
|
||||
int num_drb = get_number_active_drbs(UE);
|
||||
int num_drb = seq_arr_size(&UE->drbs);
|
||||
DevAssert(num_drb == 0 || num_drb == resp->drbs_len);
|
||||
|
||||
/* Note: we would ideally check that SRB2 is acked, but at least LiteOn DU
|
||||
@@ -2288,6 +2339,8 @@ static void rrc_delete_ue_data(gNB_RRC_UE_t *UE)
|
||||
free_MeasConfig(UE->measConfig);
|
||||
free(UE->redcap_cap);
|
||||
UE->redcap_cap = NULL;
|
||||
seq_arr_free(&UE->pduSessions, free_pdusession);
|
||||
seq_arr_free(&UE->drbs, free_drb);
|
||||
}
|
||||
|
||||
void rrc_remove_ue(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p)
|
||||
@@ -2318,9 +2371,7 @@ static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p)
|
||||
/* only trigger release if it has been requested by core
|
||||
* otherwise, it might be CU that requested release on a DU during normal
|
||||
* operation (i.e, handover) */
|
||||
uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION];
|
||||
get_pduSession_array(UE, pdu_sessions);
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, UE->nb_of_pdusessions, pdu_sessions);
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, &UE->pduSessions);
|
||||
rrc_remove_ue(RC.nrrrc[0], ue_context_p);
|
||||
}
|
||||
}
|
||||
@@ -2455,17 +2506,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)
|
||||
{
|
||||
@@ -2480,13 +2520,11 @@ f1ap_qos_flow_param_t get_qos_char_from_qos_flow_param(const pdusession_level_qo
|
||||
qos_char.qos_type = NON_DYNAMIC;
|
||||
qos_char.nondyn.fiveQI = qos_param->fiveQI;
|
||||
}
|
||||
const ngap_allocation_retention_priority_t *a = &qos_param->allocation_retention_priority;
|
||||
const qos_arp_t *a = &qos_param->arp;
|
||||
qos_char.arp.prio = a->priority_level;
|
||||
qos_char.arp.preempt_cap = a->pre_emp_capability == NGAP_PRE_EMPTION_CAPABILITY_MAY_TRIGGER_PREEMPTION
|
||||
? MAY_TRIGGER_PREEMPTION
|
||||
: SHALL_NOT_TRIGGER_PREEMPTION;
|
||||
qos_char.arp.preempt_vuln =
|
||||
a->pre_emp_vulnerability == NGAP_PRE_EMPTION_VULNERABILITY_PREEMPTABLE ? PREEMPTABLE : NOT_PREEMPTABLE;
|
||||
qos_char.arp.preempt_cap =
|
||||
a->pre_emp_capability == PEC_MAY_TRIGGER_PREEMPTION ? MAY_TRIGGER_PREEMPTION : SHALL_NOT_TRIGGER_PREEMPTION;
|
||||
qos_char.arp.preempt_vuln = a->pre_emp_vulnerability == PEV_PREEMPTABLE ? PREEMPTABLE : NOT_PREEMPTABLE;
|
||||
return qos_char;
|
||||
}
|
||||
|
||||
@@ -2500,13 +2538,15 @@ 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, pduSession[p].id, false);
|
||||
rrc_pdu_session_param_t *pdu = find_pduSession(&UE->pduSessions, pduSession[p].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, pduSession[p].DRBnGRanList[i].id);
|
||||
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;
|
||||
|
||||
@@ -2522,11 +2562,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;
|
||||
@@ -2538,10 +2578,11 @@ static int fill_drb_to_be_setup_from_e1_resp(const gNB_RRC_INST *rrc,
|
||||
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 = rrc_drb->pdcp_config.pdcp_SN_SizeDL == 1 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
*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 = rrc_drb->pdcp_config.pdcp_SN_SizeUL == 1 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
*drb->ul_pdcp_sn_len = pdcp.drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
|
||||
nb_drb++;
|
||||
}
|
||||
@@ -2569,7 +2610,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
|
||||
// save the tunnel address for the PDU sessions
|
||||
for (int i = 0; i < resp->numPDUSessions; i++) {
|
||||
pdu_session_setup_t *e1_pdu = &resp->pduSession[i];
|
||||
rrc_pdu_session_param_t *rrc_pdu = find_pduSession(UE, e1_pdu->id, false);
|
||||
rrc_pdu_session_param_t *rrc_pdu = find_pduSession(&UE->pduSessions, e1_pdu->id);
|
||||
if (rrc_pdu == NULL) {
|
||||
LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id);
|
||||
continue;
|
||||
@@ -2577,11 +2618,15 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp
|
||||
rrc_pdu->param.n3_outgoing = f1u_gtp_update(e1_pdu->tl_info.teId, e1_pdu->tl_info.tlAddress);
|
||||
|
||||
// save the tunnel address for the DRBs
|
||||
for (int i = 0; i < e1_pdu->numDRBSetup; i++) {
|
||||
DRB_nGRAN_setup_t *drb_config = &e1_pdu->DRBnGRanList[i];
|
||||
for (int j = 0; j < e1_pdu->numDRBSetup; j++) {
|
||||
DRB_nGRAN_setup_t *drb_config = &e1_pdu->DRBnGRanList[j];
|
||||
// numUpParam only relevant in F1, but not monolithic
|
||||
AssertFatal(drb_config->numUpParam <= 1, "can only up to one UP param\n");
|
||||
drb_t *drb = get_drb(UE, drb_config->id);
|
||||
drb_t *drb = get_drb(&UE->drbs, drb_config->id);
|
||||
if (!drb) {
|
||||
LOG_E(RRC, "E1: DRB %ld not found for PDU session %ld\n", drb_config->id, e1_pdu->id);
|
||||
continue;
|
||||
}
|
||||
UP_TL_information_t *tl_info = &drb_config->UpParamList[0].tl_info;
|
||||
drb->cuup_tunnel_config = f1u_gtp_update(tl_info->teId, tl_info->tlAddress);
|
||||
}
|
||||
@@ -2623,6 +2668,7 @@ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t
|
||||
}
|
||||
|
||||
int n_drb_mod = 0;
|
||||
int drb_ids[MAX_DRBS_PER_UE] = {0};
|
||||
e1_pdcp_status_info_t pdcp_status[MAX_DRBS_PER_UE] = {0};
|
||||
for (int i = 0; i < resp->numPDUSessionsMod; ++i) {
|
||||
const pdu_session_modif_t *pdu = &resp->pduSessionMod[i];
|
||||
@@ -2630,6 +2676,8 @@ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t
|
||||
for (int j = 0; j < pdu->numDRBModified; j++) {
|
||||
// Trigger UL RAN Status Transfer
|
||||
if (pdu->DRBnGRanModList[j].pdcp_status) {
|
||||
DevAssert(n_drb_mod < MAX_DRBS_PER_UE);
|
||||
drb_ids[n_drb_mod] = pdu->DRBnGRanModList[j].id;
|
||||
pdcp_status[n_drb_mod++] = *pdu->DRBnGRanModList[j].pdcp_status;
|
||||
}
|
||||
}
|
||||
@@ -2638,7 +2686,7 @@ void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t
|
||||
LOG_I(NR_RRC, "UE %d: received PDU Status Info - send UL RAN Status Transfer\n", resp->gNB_cu_cp_ue_id);
|
||||
gNB_RRC_UE_t *ue = &ue_context_p->ue_context;
|
||||
if (ue->ho_context && ue->ho_context->source)
|
||||
ue->ho_context->source->ho_status_transfer(rrc, ue, n_drb_mod, pdcp_status);
|
||||
ue->ho_context->source->ho_status_transfer(rrc, ue, n_drb_mod, drb_ids, pdcp_status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2774,11 +2822,8 @@ static bool write_rrc_stats(const gNB_RRC_INST *rrc)
|
||||
time_t last_seen = now - ue_ctxt->last_seen;
|
||||
fprintf(f, " last RRC activity: %ld seconds ago\n", last_seen);
|
||||
|
||||
if (ue_ctxt->nb_of_pdusessions == 0)
|
||||
fprintf(f, " (no PDU sessions)\n");
|
||||
for (int nb_pdu = 0; nb_pdu < ue_ctxt->nb_of_pdusessions; ++nb_pdu) {
|
||||
const rrc_pdu_session_param_t *pdu = &ue_ctxt->pduSession[nb_pdu];
|
||||
fprintf(f, " PDU session %d ID %d status %s\n", nb_pdu, pdu->param.pdusession_id, get_pdusession_status_text(pdu->status));
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, pdu, &ue_ctxt->pduSessions) {
|
||||
fprintf(f, " PDU session ID %d status %s\n", pdu->param.pdusession_id, get_pdusession_status_text(pdu->status));
|
||||
}
|
||||
|
||||
fprintf(f, " associated DU: ");
|
||||
|
||||
+289
-240
@@ -42,6 +42,8 @@
|
||||
#include "NR_UE-CapabilityRAT-ContainerList.h"
|
||||
#include "NR_HandoverCommand.h"
|
||||
#include "NR_HandoverCommand-IEs.h"
|
||||
#include "E1AP_RLC-Mode.h"
|
||||
#include "NR_PDCP-Config.h"
|
||||
#include "NGAP_CauseRadioNetwork.h"
|
||||
#include "NGAP_Dynamic5QIDescriptor.h"
|
||||
#include "NGAP_GTPTunnel.h"
|
||||
@@ -88,6 +90,7 @@
|
||||
#include "uper_encoder.h"
|
||||
#include "rrc_gNB_mobility.h"
|
||||
#include "rrc_gNB_du.h"
|
||||
#include "common/utils/alg/find.h"
|
||||
|
||||
#ifdef E2_AGENT
|
||||
#include "openair2/E2AP/RAN_FUNCTION/O-RAN/ran_func_rc_extern.h"
|
||||
@@ -171,20 +174,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 < MAX_QOS_FLOWS);
|
||||
// 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);
|
||||
}
|
||||
|
||||
@@ -253,6 +266,57 @@ 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 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,
|
||||
bool const um_on_default_drb,
|
||||
const nr_redcap_ue_cap_t *redcap_cap)
|
||||
{
|
||||
DRB_nGRAN_to_setup_t drb_ngran = {0};
|
||||
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.pdcp_config = set_bearer_context_pdcp_config(rrc_drb->pdcp_config, um_on_default_drb, redcap_cap);
|
||||
|
||||
drb_ngran.numCellGroups = 1;
|
||||
for (int k = 0; k < drb_ngran.numCellGroups; k++) {
|
||||
drb_ngran.cellGroupList[k] = MCG; // 1 cellGroup only
|
||||
}
|
||||
|
||||
FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) {
|
||||
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;
|
||||
}
|
||||
|
||||
return drb_ngran;
|
||||
}
|
||||
|
||||
static nr_sdap_configuration_t get_sdap_config(const bool enable_sdap)
|
||||
{
|
||||
nr_sdap_configuration_t sdap = {.header_dl_absent = !enable_sdap, .header_ul_absent = !enable_sdap};
|
||||
return sdap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Triggers bearer setup for the specified UE.
|
||||
*
|
||||
@@ -278,9 +342,15 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
|
||||
|
||||
e1ap_nssai_t cuup_nssai = {0};
|
||||
for (int i = 0; i < n; i++) {
|
||||
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true);
|
||||
// Retrieve SDAP configuration and PDU Session to the list
|
||||
sessions[i].sdap_config = get_sdap_config(rrc->configuration.enable_sdap);
|
||||
rrc_pdu_session_param_t *pduSession = add_pduSession(&UE->pduSessions, &sessions[i]);
|
||||
if (!pduSession) {
|
||||
LOG_E(NR_RRC, "Could not add PDU Session %d for UE %d\n", sessions[i].pdusession_id, UE->rrc_ue_id);
|
||||
continue;
|
||||
}
|
||||
pdusession_t *session = &pduSession->param;
|
||||
cp_pdusession(session, &sessions[i]);
|
||||
// Fill E1 Bearer Context Modification Request
|
||||
bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id;
|
||||
security_information_t *secInfo = &bearer_req.secInfo;
|
||||
secInfo->cipheringAlgorithm = rrc->security.do_drb_ciphering ? UE->ciphering_algorithm : 0;
|
||||
@@ -307,60 +377,18 @@ bool trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession
|
||||
inet_ntop(AF_INET, n3_incoming->addr.buffer, ip_str, sizeof(ip_str));
|
||||
LOG_I(NR_RRC, "Bearer Context Setup: PDU Session ID=%d, incoming TEID=0x%08x, Addr=%s\n", session->pdusession_id, n3_incoming->teid, ip_str);
|
||||
|
||||
/* we assume for the moment one DRB per PDU session. Activate the bearer,
|
||||
* and configure in RRC. */
|
||||
int drb_id = get_next_available_drb_id(UE);
|
||||
drb_t *rrc_drb = generateDRB(UE,
|
||||
drb_id,
|
||||
pduSession,
|
||||
rrc->configuration.enable_sdap,
|
||||
rrc->security.do_drb_integrity,
|
||||
rrc->security.do_drb_ciphering,
|
||||
&rrc->pdcp_config);
|
||||
|
||||
pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding
|
||||
for (int j=0; j < pdu->numDRB2Setup; j++) {
|
||||
DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j;
|
||||
|
||||
drb->id = rrc_drb->drb_id;
|
||||
/* SDAP */
|
||||
struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config;
|
||||
drb->sdap_config.defaultDRB = sdap_config->defaultDRB;
|
||||
drb->sdap_config.sDAP_Header_UL = sdap_config->sdap_HeaderUL;
|
||||
drb->sdap_config.sDAP_Header_DL = sdap_config->sdap_HeaderDL;
|
||||
/* PDCP */
|
||||
set_bearer_context_pdcp_config(&drb->pdcp_config, rrc_drb, rrc->configuration.um_on_default_drb);
|
||||
|
||||
drb->numCellGroups = 1; // assume one cell group associated with a DRB
|
||||
|
||||
// Set all Cell Group IDs to MCG
|
||||
for (int k=0; k < drb->numCellGroups; k++) {
|
||||
cell_group_id_t *cellGroup = drb->cellGroupList + k;
|
||||
*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;
|
||||
|
||||
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 *rent_priority = &qos_flow->qos_params.alloc_reten_priority;
|
||||
ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority;
|
||||
rent_priority->priority_level = rent_priority_in->priority_level;
|
||||
rent_priority->preemption_capability = rent_priority_in->pre_emp_capability;
|
||||
rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability;
|
||||
for (int j = 0; j < pdu->numDRB2Setup; j++) {
|
||||
drb_t *rrc_drb = nr_rrc_add_drb(&UE->drbs, session->pdusession_id, &rrc->pdcp_config);
|
||||
if (!rrc_drb) {
|
||||
LOG_E(NR_RRC, "UE %d: failed to add DRB for PDU session ID %d\n", UE->rrc_ue_id, session->pdusession_id);
|
||||
return false;
|
||||
}
|
||||
DevAssert(seq_arr_size(&pduSession->param.qos) == 1);
|
||||
nr_rrc_qos_t *qos = (nr_rrc_qos_t *)seq_arr_at(&pduSession->param.qos, 0);
|
||||
qos->drb_id = rrc_drb->drb_id; // map DRB to QFI
|
||||
LOG_I(NR_RRC, "UE %d: added DRB %d for PDU session ID %d\n", UE->rrc_ue_id, rrc_drb->drb_id, rrc_drb->pdusession_id);
|
||||
pdu->DRBnGRanList[0] = fill_e1_drb_to_setup(rrc_drb, session, rrc->configuration.um_on_default_drb, UE->redcap_cap);
|
||||
}
|
||||
}
|
||||
/* Limitation: we assume one fixed CU-UP per UE. We base the selection on
|
||||
@@ -493,6 +521,26 @@ static gtpu_tunnel_t cp_gtp_tunnel(const gtpu_tunnel_t in)
|
||||
return out;
|
||||
}
|
||||
|
||||
/** @brief Fill NG PDU Session Setup item from stored setup PDU Session in RRC list */
|
||||
static pdusession_setup_t fill_ngap_pdusession_setup(pdusession_t *session)
|
||||
{
|
||||
DevAssert(session != NULL);
|
||||
pdusession_setup_t out = {0};
|
||||
out.pdusession_id = session->pdusession_id;
|
||||
out.pdu_session_type = session->pdu_session_type;
|
||||
out.n3_outgoing = cp_gtp_tunnel(session->n3_outgoing);
|
||||
FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos_session, &session->qos) {
|
||||
DevAssert(out.nb_of_qos_flow < MAX_QOS_FLOWS);
|
||||
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));
|
||||
LOG_I(NR_RRC, "PDU Session Setup: ID=%d, outgoing TEID=0x%08x, Addr=%s\n", out.pdusession_id, out.n3_outgoing.teid, ip_str);
|
||||
return out;
|
||||
}
|
||||
|
||||
void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE)
|
||||
{
|
||||
MessageDef *msg_p = NULL;
|
||||
@@ -503,17 +551,10 @@ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_
|
||||
|
||||
resp->gNB_ue_ngap_id = UE->rrc_ue_id;
|
||||
|
||||
for (int pdusession = 0; pdusession < UE->nb_of_pdusessions; pdusession++) {
|
||||
rrc_pdu_session_param_t *session = &UE->pduSession[pdusession];
|
||||
// Optional: PDU Sessions to Setup
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) {
|
||||
if (session->status == PDU_SESSION_STATUS_DONE) {
|
||||
pdu_sessions_done++;
|
||||
resp->pdusessions[pdusession].pdusession_id = session->param.pdusession_id;
|
||||
resp->pdusessions[pdusession].n3_outgoing = cp_gtp_tunnel(session->param.n3_outgoing);
|
||||
resp->pdusessions[pdusession].nb_of_qos_flow = session->param.nb_qos;
|
||||
for (int qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) {
|
||||
resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi;
|
||||
resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL;
|
||||
}
|
||||
resp->pdusessions[pdu_sessions_done++] = fill_ngap_pdusession_setup(&session->param);
|
||||
} else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) {
|
||||
session->status = PDU_SESSION_STATUS_FAILED;
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID};
|
||||
@@ -693,25 +734,10 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
ngap_pdusession_setup_resp_t *resp = &NGAP_PDUSESSION_SETUP_RESP(msg_p);
|
||||
resp->gNB_ue_ngap_id = UE->rrc_ue_id;
|
||||
|
||||
for (int pdusession = 0; pdusession < UE->nb_of_pdusessions; pdusession++) {
|
||||
rrc_pdu_session_param_t *session = &UE->pduSession[pdusession];
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) {
|
||||
if (session->status == PDU_SESSION_STATUS_DONE) {
|
||||
pdusession_setup_t *tmp = &resp->pdusessions[pdu_sessions_done];
|
||||
tmp->pdusession_id = session->param.pdusession_id;
|
||||
tmp->nb_of_qos_flow = session->param.nb_qos;
|
||||
tmp->n3_outgoing = cp_gtp_tunnel(session->param.n3_outgoing);
|
||||
tmp->pdu_session_type = session->param.pdu_session_type;
|
||||
|
||||
for (int qos_flow_index = 0; qos_flow_index < tmp->nb_of_qos_flow; qos_flow_index++) {
|
||||
tmp->associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi;
|
||||
tmp->associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL;
|
||||
}
|
||||
|
||||
resp->pdusessions[pdu_sessions_done++] = fill_ngap_pdusession_setup(&session->param);
|
||||
session->status = PDU_SESSION_STATUS_ESTABLISHED;
|
||||
char ip_str[INET_ADDRSTRLEN] = {0};
|
||||
inet_ntop(AF_INET, tmp->n3_outgoing.addr.buffer, ip_str, sizeof(ip_str));
|
||||
LOG_I(NR_RRC, "PDU Session Setup Response: ID=%d, outgoing TEID=0x%08x, Addr=%s\n", tmp->pdusession_id, tmp->n3_outgoing.teid, ip_str);
|
||||
pdu_sessions_done++;
|
||||
} else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) {
|
||||
session->status = PDU_SESSION_STATUS_FAILED;
|
||||
pdusession_failed_t *fail = &resp->pdusessions_failed[pdu_sessions_failed];
|
||||
@@ -729,8 +755,8 @@ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
itti_send_msg_to_task(TASK_NGAP, rrc->module_id, msg_p);
|
||||
}
|
||||
|
||||
for(int i = 0; i < NB_RB_MAX; i++) {
|
||||
UE->pduSession[i].xid = -1;
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) {
|
||||
session->xid = -1;
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -818,7 +844,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
|
||||
// might be more work than is worth it. See 8.2.1.4 in 38.413
|
||||
for (int i = 0; i < msg->nb_pdusessions_tosetup; ++i) {
|
||||
const pdusession_resource_item_t *p = &msg->pdusession[i];
|
||||
rrc_pdu_session_param_t *exist = find_pduSession(UE, p->pdusession_id, false /* don't create */);
|
||||
rrc_pdu_session_param_t *exist = find_pduSession(&UE->pduSessions, p->pdusession_id);
|
||||
if (exist) {
|
||||
LOG_E(NR_RRC, "UE %d: already has existing PDU session %d rejecting PDU Session Resource Setup Request\n", UE->rrc_ue_id, p->pdusession_id);
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_PDU_SESSION_ID_INSTANCES};
|
||||
@@ -867,6 +893,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 < MAX_QOS_FLOWS);
|
||||
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)
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -885,33 +941,21 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins
|
||||
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
|
||||
bool all_failed = true;
|
||||
for (int i = 0; i < req->nb_pdusessions_tomodify; i++) {
|
||||
rrc_pdu_session_param_t *sess;
|
||||
const pdusession_resource_item_t *sessMod = req->pdusession + i;
|
||||
for (sess = UE->pduSession; sess < UE->pduSession + UE->nb_of_pdusessions; sess++)
|
||||
if (sess->param.pdusession_id == sessMod->pdusession_id)
|
||||
break;
|
||||
if (sess == UE->pduSession + UE->nb_of_pdusessions) {
|
||||
const pdusession_resource_item_t *sessMod = &req->pdusession[i];
|
||||
rrc_pdu_session_param_t *session = find_pduSession(&UE->pduSessions, sessMod->pdusession_id);
|
||||
if (!session) {
|
||||
LOG_W(NR_RRC, "Requested modification of non-existing PDU session, refusing modification\n");
|
||||
UE->nb_of_pdusessions++;
|
||||
sess->status = PDU_SESSION_STATUS_FAILED;
|
||||
sess->param.pdusession_id = sessMod->pdusession_id;
|
||||
sess->cause.type = NGAP_CAUSE_RADIO_NETWORK;
|
||||
UE->pduSession[i].cause.type = NGAP_CAUSE_RADIO_NETWORK;
|
||||
UE->pduSession[i].cause.value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID;
|
||||
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));
|
||||
} else {
|
||||
all_failed = false;
|
||||
sess->status = PDU_SESSION_STATUS_NEW;
|
||||
sess->param.pdusession_id = sessMod->pdusession_id;
|
||||
sess->cause.type = NGAP_CAUSE_RADIO_NETWORK;
|
||||
sess->cause.value = NGAP_CAUSE_RADIO_NETWORK_MULTIPLE_PDU_SESSION_ID_INSTANCES;
|
||||
sess->status = PDU_SESSION_STATUS_NEW;
|
||||
sess->param.pdusession_id = sessMod->pdusession_id;
|
||||
sess->cause.type = NGAP_CAUSE_NOTHING;
|
||||
if (sessMod->nas_pdu.buf != NULL) {
|
||||
UE->pduSession[i].param.nas_pdu = sessMod->nas_pdu;
|
||||
}
|
||||
for (int i = 0; i < req->nb_pdusessions_tomodify; ++i)
|
||||
cp_pdusession_resource_item_to_pdusession(&UE->pduSession[i].param, &req->pdusession[i]);
|
||||
session->status = PDU_SESSION_STATUS_NEW;
|
||||
session->cause.type = NGAP_CAUSE_NOTHING;
|
||||
nr_rrc_update_pdusession(&session->param, sessMod);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -929,11 +973,12 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins
|
||||
msg->gNB_ue_ngap_id = req->gNB_ue_ngap_id;
|
||||
msg->nb_of_pdusessions = 0;
|
||||
|
||||
for (int i = 0; i < UE->nb_of_pdusessions; i++) {
|
||||
if (UE->pduSession[i].status == PDU_SESSION_STATUS_FAILED) {
|
||||
msg->pdusessions_failed[i].pdusession_id = UE->pduSession[i].param.pdusession_id;
|
||||
msg->pdusessions_failed[i].cause.type = UE->pduSession[i].cause.type;
|
||||
msg->pdusessions_failed[i].cause.value = UE->pduSession[i].cause.value;
|
||||
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);
|
||||
@@ -944,8 +989,13 @@ int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t ins
|
||||
int rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid)
|
||||
{
|
||||
MessageDef *msg_p = NULL;
|
||||
uint8_t pdu_sessions_failed = 0;
|
||||
uint8_t pdu_sessions_done = 0;
|
||||
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);
|
||||
if (msg_p == NULL) {
|
||||
@@ -957,63 +1007,54 @@ int rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
|
||||
resp->gNB_ue_ngap_id = UE->rrc_ue_id;
|
||||
|
||||
for (int i = 0; i < UE->nb_of_pdusessions; i++) {
|
||||
if (xid != UE->pduSession[i].xid) {
|
||||
LOG_W(NR_RRC, "xid does not correspond (context pdu session index %d, status %d, xid %d/%d) \n ", i, UE->pduSession[i].status, xid, UE->pduSession[i].xid);
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) {
|
||||
if (xid != session->xid) {
|
||||
LOG_W(NR_RRC,
|
||||
"xid does not correspond (PDU Session %d, status %d, xid %d/%d) \n ",
|
||||
session->param.pdusession_id,
|
||||
session->status,
|
||||
xid,
|
||||
session->xid);
|
||||
continue;
|
||||
}
|
||||
if (UE->pduSession[i].status == PDU_SESSION_STATUS_DONE) {
|
||||
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, UE->pduSession[i].param.pdusession_id, false);
|
||||
if (pduSession) {
|
||||
LOG_I(NR_RRC, "update pdu session %d \n", pduSession->param.pdusession_id);
|
||||
// Update UE->pduSession
|
||||
pduSession->status = PDU_SESSION_STATUS_ESTABLISHED;
|
||||
pduSession->cause.type = NGAP_CAUSE_NOTHING;
|
||||
for (int qos_flow_index = 0; qos_flow_index < UE->pduSession[i].param.nb_qos; qos_flow_index++) {
|
||||
pduSession->param.qos[qos_flow_index] = UE->pduSession[i].param.qos[qos_flow_index];
|
||||
}
|
||||
resp->pdusessions[pdu_sessions_done].pdusession_id = UE->pduSession[i].param.pdusession_id;
|
||||
for (int qos_flow_index = 0; qos_flow_index < UE->pduSession[i].param.nb_qos; qos_flow_index++) {
|
||||
resp->pdusessions[pdu_sessions_done].qos[qos_flow_index].qfi = UE->pduSession[i].param.qos[qos_flow_index].qfi;
|
||||
}
|
||||
resp->pdusessions[pdu_sessions_done].pdusession_id = UE->pduSession[i].param.pdusession_id;
|
||||
resp->pdusessions[pdu_sessions_done].nb_of_qos_flow = UE->pduSession[i].param.nb_qos;
|
||||
LOG_I(NR_RRC,
|
||||
"Modify Resp (msg index %d, pdu session index %d, status %d, xid %d): nb_of_pduSessions %d, pdusession_id %d \n ",
|
||||
pdu_sessions_done,
|
||||
i,
|
||||
UE->pduSession[i].status,
|
||||
xid,
|
||||
UE->nb_of_pdusessions,
|
||||
resp->pdusessions[pdu_sessions_done].pdusession_id);
|
||||
pdu_sessions_done++;
|
||||
} else {
|
||||
LOG_W(NR_RRC, "PDU SESSION modify of a not existing pdu session %d \n", UE->pduSession[i].param.pdusession_id);
|
||||
resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = UE->pduSession[i].param.pdusession_id;
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID};
|
||||
resp->pdusessions_failed[pdu_sessions_failed].cause = cause;
|
||||
pdu_sessions_failed++;
|
||||
if (session->status == PDU_SESSION_STATUS_DONE) {
|
||||
LOG_I(NR_RRC, "Successfully modified PDU Session %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++];
|
||||
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++];
|
||||
q->qfi = qos_session->qos.qfi;
|
||||
}
|
||||
} else if ((UE->pduSession[i].status == PDU_SESSION_STATUS_NEW) || (UE->pduSession[i].status == PDU_SESSION_STATUS_ESTABLISHED)) {
|
||||
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);
|
||||
} 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 (UE->pduSession[i].status == PDU_SESSION_STATUS_FAILED) {
|
||||
resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = UE->pduSession[i].param.pdusession_id;
|
||||
resp->pdusessions_failed[pdu_sessions_failed].cause.type = UE->pduSession[i].cause.type;
|
||||
resp->pdusessions_failed[pdu_sessions_failed].cause.value = UE->pduSession[i].cause.value;
|
||||
} 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++;
|
||||
}
|
||||
else
|
||||
LOG_W(NR_RRC,
|
||||
"Modify pdu session %d, unknown state %d \n ",
|
||||
UE->pduSession[i].param.pdusession_id,
|
||||
UE->pduSession[i].status);
|
||||
} 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 %d)\n", UE->nb_of_pdusessions);
|
||||
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);
|
||||
@@ -1038,8 +1079,10 @@ void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ(const module_id_t gnb_mod_idP,
|
||||
req->gNB_ue_ngap_id = UE->rrc_ue_id;
|
||||
req->cause.type = causeP.type;
|
||||
req->cause.value = causeP.value;
|
||||
for (int i = 0; i < UE->nb_of_pdusessions; i++) {
|
||||
req->pdusessions[i].pdusession_id = UE->pduSession[i].param.pdusession_id;
|
||||
// PDU Session Resource List (optional)
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) {
|
||||
DevAssert(req->nb_of_pdusessions < NGAP_MAX_PDU_SESSION);
|
||||
req->pdusessions[req->nb_of_pdusessions].pdusession_id = session->param.pdusession_id;
|
||||
req->nb_of_pdusessions++;
|
||||
}
|
||||
itti_send_msg_to_task(TASK_NGAP, GNB_MODULE_ID_TO_INSTANCE(gnb_mod_idP), msg);
|
||||
@@ -1138,14 +1181,19 @@ int rrc_gNB_process_Handover_Request(gNB_RRC_INST *rrc, instance_t instance, nga
|
||||
activate_srb(UE, SRB2);
|
||||
nr_rrc_pdcp_config_security(UE, false);
|
||||
|
||||
// Copy PDU Session Resource Setup item to RRC struct and do PDU Session Resource Setup procedure
|
||||
pdusession_t to_setup = {
|
||||
.nssai = msg->pduSessionResourceSetupList->nssai,
|
||||
.pdu_session_type = msg->pduSessionResourceSetupList->pdu_session_type ,
|
||||
.pdusession_id = msg->pduSessionResourceSetupList->pdusession_id,
|
||||
};
|
||||
cp_pdusession_transfer_to_pdusession(&to_setup, &msg->pduSessionResourceSetupList->pdusessionTransfer);
|
||||
if (!trigger_bearer_setup(rrc, UE, msg->nb_of_pdusessions, &to_setup, msg->ue_ambr.br_dl)) {
|
||||
// Process all PDU Session Resource Setup items from handover request
|
||||
DevAssert(msg->nb_of_pdusessions <= NGAP_MAX_PDU_SESSION);
|
||||
pdusession_t to_setup[NGAP_MAX_PDU_SESSION];
|
||||
for (int i = 0; i < msg->nb_of_pdusessions; i++) {
|
||||
ho_request_pdusession_t *ho_pdu = &msg->pduSessionResourceSetupList[i];
|
||||
pdusession_t *pdu = &to_setup[i];
|
||||
pdu->nssai = ho_pdu->nssai;
|
||||
pdu->pdu_session_type = ho_pdu->pdu_session_type;
|
||||
pdu->pdusession_id = ho_pdu->pdusession_id;
|
||||
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)) {
|
||||
LOG_E(NR_RRC, "Failed to establish PDU session: handover failed\n");
|
||||
ngap_handover_failure_t fail = {
|
||||
.amf_ue_ngap_id = msg->amf_ue_ngap_id,
|
||||
@@ -1167,9 +1215,15 @@ void rrc_gNB_free_Handover_Request(ngap_handover_request_t *msg)
|
||||
|
||||
/** @brief Send NG Uplink RAN Status Transfer message (8.4.6 3GPP TS 38.413)
|
||||
* Direction: source NG-RAN node -> AMF */
|
||||
int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const int n_to_mod, const e1_pdcp_status_info_t *pdcp_status)
|
||||
int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc,
|
||||
gNB_RRC_UE_t *UE,
|
||||
const int n_to_mod,
|
||||
const int *drb_ids,
|
||||
const e1_pdcp_status_info_t *pdcp_status)
|
||||
{
|
||||
AssertFatal(UE != NULL, "UE context is NULL\n");
|
||||
DevAssert(n_to_mod <= MAX_DRBS_PER_UE);
|
||||
DevAssert(drb_ids);
|
||||
|
||||
LOG_I(NR_RRC,
|
||||
"Sending NGAP Uplink RAN Status Transfer (AMF_UE_NGAP_ID=%" PRIu64 ", GNB_UE_NGAP_ID=%u)\n",
|
||||
@@ -1183,14 +1237,20 @@ int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE
|
||||
|
||||
// Loop through DRBs and extract COUNT values
|
||||
for (int i = 0; i < n_to_mod; ++i) {
|
||||
drb_t *drb = &UE->established_drbs[i];
|
||||
if (!drb->status)
|
||||
int drb_id = drb_ids[i];
|
||||
|
||||
// Find the DRB in the UE's DRB list
|
||||
drb_t *drb = get_drb(&UE->drbs, drb_id);
|
||||
if (!drb) {
|
||||
LOG_E(NR_RRC, "Failed to send UL RAN Status Transfer: DRB %d not found\n", drb_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
bool sn_length_18 = rrc->pdcp_config.drb.sn_size == 18;
|
||||
bool sn_length_18 = drb->pdcp_config.drb.sn_size == 18;
|
||||
|
||||
DevAssert(msg.ran_status.nb_drb < MAX_DRBS_PER_UE);
|
||||
ngap_drb_status_t *item = &msg.ran_status.drb_status_list[msg.ran_status.nb_drb++];
|
||||
item->drb_id = drb->drb_id;
|
||||
item->drb_id = drb_id;
|
||||
|
||||
const e1_pdcp_count_t *ul_pdcp = &pdcp_status[i].ul_count;
|
||||
const e1_pdcp_count_t *dl_pdcp = &pdcp_status[i].dl_count;
|
||||
@@ -1252,7 +1312,7 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_
|
||||
LOG_W(NR_RRC, "[gNB %ld] In NGAP_UE_CONTEXT_RELEASE_COMMAND: unknown UE from gNB_ue_ngap_id (%u)\n",
|
||||
instance,
|
||||
gNB_ue_ngap_id);
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance, gNB_ue_ngap_id, 0, NULL);
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance, gNB_ue_ngap_id, NULL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1283,25 +1343,24 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_
|
||||
/* UE will be freed after UE context release complete */
|
||||
} else {
|
||||
// the DU is offline already
|
||||
uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION];
|
||||
get_pduSession_array(UE, pdu_sessions);
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, UE->nb_of_pdusessions, pdu_sessions);
|
||||
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(0, UE->rrc_ue_id, &UE->pduSessions);
|
||||
rrc_remove_ue(rrc, ue_context_p);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance,
|
||||
uint32_t gNB_ue_ngap_id,
|
||||
int num_pdu,
|
||||
uint32_t pdu_session_id[256])
|
||||
void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t gNB_ue_ngap_id, seq_arr_t *pdusessions)
|
||||
{
|
||||
MessageDef *msg = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_COMPLETE);
|
||||
NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg).gNB_ue_ngap_id = gNB_ue_ngap_id;
|
||||
NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg).num_pdu_sessions = num_pdu;
|
||||
for (int i = 0; i < num_pdu; ++i)
|
||||
NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg).pdu_session_id[i] = pdu_session_id[i];
|
||||
ngap_ue_release_complete_t *complete = &NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg);
|
||||
complete->gNB_ue_ngap_id = gNB_ue_ngap_id;
|
||||
// PDU Session Resource List (Optional)
|
||||
if (pdusessions && seq_arr_size(pdusessions)) {
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, pdusessions) {
|
||||
complete->pdu_session_id[complete->num_pdu_sessions++] = session->param.pdusession_id;
|
||||
}
|
||||
}
|
||||
itti_send_msg_to_task(TASK_NGAP, instance, msg);
|
||||
}
|
||||
|
||||
@@ -1358,21 +1417,22 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUEST_ACKNOWLEDGE(gNB_RRC_INST *rrc, gNB_RRC_U
|
||||
// AMF UE NGAP ID
|
||||
msg->amf_ue_ngap_id = UE->amf_ue_ngap_id;
|
||||
// PDU Session Resource Admitted List
|
||||
msg->nb_of_pdusessions = UE->nb_of_pdusessions;
|
||||
for (int i = 0; i < UE->nb_of_pdusessions; i++) {
|
||||
rrc_pdu_session_param_t *session = &UE->pduSession[i];
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t*, session, &UE->pduSessions) {
|
||||
session->status = PDU_SESSION_STATUS_ESTABLISHED;
|
||||
// PDU Session ID
|
||||
msg->pdusessions[i].pdu_session_id = session->param.pdusession_id;
|
||||
DevAssert(msg->nb_of_pdusessions < NGAP_MAX_PDU_SESSION);
|
||||
pdu_session_resource_admitted_t *pdu = &msg->pdusessions[msg->nb_of_pdusessions++];
|
||||
pdu->pdu_session_id = session->param.pdusession_id;
|
||||
// Handover Request Acknowledge Transfer
|
||||
ho_request_ack_transfer_t *transfer = &msg->pdusessions[i].ack_transfer;
|
||||
ho_request_ack_transfer_t *transfer = &pdu->ack_transfer;
|
||||
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 < MAX_QOS_FLOWS);
|
||||
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
|
||||
@@ -1429,27 +1489,24 @@ void rrc_gNB_send_NGAP_HANDOVER_CANCEL(int module_id, gNB_RRC_UE_t *UE, ngap_cau
|
||||
|
||||
void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, uint8_t xid)
|
||||
{
|
||||
int pdu_sessions_released = 0;
|
||||
MessageDef *msg_p;
|
||||
msg_p = itti_alloc_new_message (TASK_RRC_GNB, rrc->module_id, NGAP_PDUSESSION_RELEASE_RESPONSE);
|
||||
ngap_pdusession_release_resp_t *resp = &NGAP_PDUSESSION_RELEASE_RESPONSE(msg_p);
|
||||
memset(resp, 0, sizeof(*resp));
|
||||
resp->gNB_ue_ngap_id = UE->rrc_ue_id;
|
||||
|
||||
for (int i = 0; i < UE->nb_of_pdusessions; i++) {
|
||||
if (xid == UE->pduSession[i].xid) {
|
||||
resp->pdusession_release[pdu_sessions_released].pdusession_id = UE->pduSession[i].param.pdusession_id;
|
||||
pdu_sessions_released++;
|
||||
//clear
|
||||
memset(&UE->pduSession[i], 0, sizeof(*UE->pduSession));
|
||||
UE->pduSession[i].status = PDU_SESSION_STATUS_RELEASED;
|
||||
LOG_W(NR_RRC, "Released pdu session, but code to finish to free memory\n");
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t *, session, &UE->pduSessions) {
|
||||
if (xid == session->xid) {
|
||||
const pdusession_t *pdusession = &session->param;
|
||||
if (session->status == PDU_SESSION_STATUS_TORELEASE) {
|
||||
DevAssert(resp->nb_of_pdusessions_released < NGAP_MAX_PDU_SESSION);
|
||||
resp->pdusession_release[resp->nb_of_pdusessions_released++].pdusession_id = pdusession->pdusession_id;
|
||||
}
|
||||
session->status = PDU_SESSION_STATUS_RELEASED;
|
||||
}
|
||||
}
|
||||
|
||||
resp->nb_of_pdusessions_released = pdu_sessions_released;
|
||||
resp->nb_of_pdusessions_failed = 0;
|
||||
LOG_I(NR_RRC, "NGAP PDUSESSION RELEASE RESPONSE: rrc_ue_id %u release_pdu_sessions %d\n", resp->gNB_ue_ngap_id, pdu_sessions_released);
|
||||
LOG_I(NR_RRC, "NGAP PDUSESSION RELEASE RESPONSE: rrc_ue_id %u release_pdu_sessions %d\n", resp->gNB_ue_ngap_id, resp->nb_of_pdusessions_released);
|
||||
itti_send_msg_to_task (TASK_NGAP, rrc->module_id, msg_p);
|
||||
}
|
||||
|
||||
@@ -1476,14 +1533,9 @@ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_
|
||||
uint8_t xid = rrc_gNB_get_next_transaction_identifier(rrc->module_id);
|
||||
UE->xids[xid] = RRC_PDUSESSION_RELEASE;
|
||||
for (int pdusession = 0; pdusession < cmd->nb_pdusessions_torelease; pdusession++) {
|
||||
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, cmd->pdusession_release_params[pdusession].pdusession_id, false);
|
||||
rrc_pdu_session_param_t *pduSession = find_pduSession(&UE->pduSessions, cmd->pdusession_release_params[pdusession].pdusession_id);
|
||||
if (!pduSession) {
|
||||
LOG_I(NR_RRC, "no pdusession_id, AMF requested to close it id=%d\n", cmd->pdusession_release_params[pdusession].pdusession_id);
|
||||
int j=UE->nb_of_pdusessions++;
|
||||
UE->pduSession[j].status = PDU_SESSION_STATUS_FAILED;
|
||||
UE->pduSession[j].param.pdusession_id = cmd->pdusession_release_params[pdusession].pdusession_id;
|
||||
ngap_cause_t cause = {.type = NGAP_CAUSE_RADIO_NETWORK, .value = NGAP_CAUSE_RADIO_NETWORK_UNKNOWN_PDU_SESSION_ID};
|
||||
UE->pduSession[j].cause = cause;
|
||||
LOG_E(NR_RRC, "Failed to release non-existing PDU Session %d\n", cmd->pdusession_release_params[pdusession].pdusession_id);
|
||||
continue;
|
||||
}
|
||||
if (pduSession->status == PDU_SESSION_STATUS_FAILED) {
|
||||
@@ -1575,7 +1627,6 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc,
|
||||
ngap_handover_required_t msg = {
|
||||
.amf_ue_ngap_id = UE->amf_ue_ngap_id,
|
||||
.gNB_ue_ngap_id = UE->rrc_ue_id,
|
||||
.nb_of_pdusessions = UE->nb_of_pdusessions,
|
||||
.cause.type = NGAP_CAUSE_RADIO_NETWORK,
|
||||
.cause.value = NGAP_CAUSE_RADIO_NETWORK_HANDOVER_DESIRABLE_FOR_RADIO_REASON,
|
||||
.handoverType = HANDOVER_TYPE_INTRA5GS,
|
||||
@@ -1604,24 +1655,22 @@ void rrc_gNB_send_NGAP_HANDOVER_REQUIRED(gNB_RRC_INST *rrc,
|
||||
/* Fill both PDU Session Resource List IE (M) in Handover Required
|
||||
and PDU Session Resource Information List IE (O) in the Source NG-RAN
|
||||
Node to Target NG-RAN Node Transparent Container */
|
||||
for (int i = 0; i < UE->nb_of_pdusessions; ++i) {
|
||||
if (UE->pduSession[i].status == PDU_SESSION_STATUS_DONE || UE->pduSession[i].status == PDU_SESSION_STATUS_ESTABLISHED) {
|
||||
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, UE->pduSession[i].param.pdusession_id, false);
|
||||
if (!pduSession)
|
||||
continue;
|
||||
// Handover Required Transfer (M)
|
||||
uint8_t ho_required_transfer[128] = {0};
|
||||
msg.pdusessions[i].ho_required_transfer.buf = ho_required_transfer;
|
||||
msg.pdusessions[i].ho_required_transfer.len = sizeof(ho_required_transfer);
|
||||
// PDU Session ID
|
||||
msg.pdusessions[i].pdusession_id = pduSession->param.pdusession_id;
|
||||
|
||||
// PDU Session Resource Information List (O)
|
||||
msg.source2target->pdu_session_resource[i].nb_of_qos_flow = pduSession->param.nb_qos;
|
||||
for (int j = 0; j < pduSession->param.nb_qos; ++j) {
|
||||
msg.source2target->pdu_session_resource[i].qos_flow_info[j].qfi = pduSession->param.qos[j].qfi;
|
||||
}
|
||||
msg.source2target->nb_pdu_session_resource++;
|
||||
FOR_EACH_SEQ_ARR(rrc_pdu_session_param_t*, pduSession, &UE->pduSessions) {
|
||||
if (pduSession->status != PDU_SESSION_STATUS_DONE && pduSession->status != PDU_SESSION_STATUS_ESTABLISHED)
|
||||
continue;
|
||||
pdusession_t *session = &pduSession->param;
|
||||
DevAssert(msg.nb_of_pdusessions < NGAP_MAX_PDU_SESSION);
|
||||
pdusession_resource_t *pdu = &msg.pdusessions[msg.nb_of_pdusessions++];
|
||||
// PDU Session ID
|
||||
pdu->pdusession_id = session->pdusession_id;
|
||||
// PDU Session Resource Information List (O)
|
||||
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;
|
||||
FOR_EACH_SEQ_ARR(nr_rrc_qos_t *, qos, &session->qos) {
|
||||
DevAssert(pdu_info->nb_of_qos_flow < MAX_QOS_FLOWS);
|
||||
qosflow_info_t *qos_flow = &pdu_info->qos_flow_info[pdu_info->nb_of_qos_flow++];
|
||||
qos_flow->qfi = qos->qos.qfi;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,10 +74,7 @@ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_REQ(MessageDef *msg_p, instance_t in
|
||||
|
||||
int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance);
|
||||
|
||||
void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance,
|
||||
uint32_t gNB_ue_ngap_id,
|
||||
int num_pdu,
|
||||
uint32_t pdu_session_id[256]);
|
||||
void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance_t instance, uint32_t gNB_ue_ngap_id, seq_arr_t *pduSessions);
|
||||
|
||||
void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const NR_UECapabilityInformation_t *const ue_cap_info);
|
||||
|
||||
@@ -107,7 +104,11 @@ void rrc_gNB_free_Handover_Command(ngap_handover_command_t *msg);
|
||||
void rrc_gNB_send_NGAP_HANDOVER_NOTIFY(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE);
|
||||
void rrc_gNB_send_NGAP_HANDOVER_CANCEL(int module_id, gNB_RRC_UE_t *UE, ngap_cause_t cause);
|
||||
|
||||
int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const int n_to_mod, const e1_pdcp_status_info_t *pdcp_status);
|
||||
int rrc_gNB_send_NGAP_ul_ran_status_transfer(gNB_RRC_INST *rrc,
|
||||
gNB_RRC_UE_t *UE,
|
||||
const int n_to_mod,
|
||||
const int *drb_ids,
|
||||
const e1_pdcp_status_info_t *pdcp_status);
|
||||
|
||||
int rrc_gNB_process_NGAP_DL_RAN_STATUS_TRANSFER(MessageDef *msg_p, instance_t instance);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
#include "linear_alloc.h"
|
||||
#include "openair2/F1AP/f1ap_ids.h"
|
||||
#include "tree.h"
|
||||
#include "rrc_gNB_radio_bearers.h"
|
||||
|
||||
static void rrc_gNB_ue_context_update_time(rrc_gNB_ue_context_t *ctxt)
|
||||
{
|
||||
@@ -78,9 +79,6 @@ rrc_gNB_ue_context_t *rrc_gNB_allocate_new_ue_context(gNB_RRC_INST *rrc_instance
|
||||
new_p->ue_context.rrc_ue_id = uid_linear_allocator_new(&rrc_instance_pP->uid_allocator) + 1;
|
||||
rrc_gNB_ue_context_update_time(new_p);
|
||||
|
||||
for(int i = 0; i < NB_RB_MAX; i++)
|
||||
new_p->ue_context.pduSession[i].xid = -1;
|
||||
|
||||
LOG_D(NR_RRC, "Returning new RRC UE context RRC ue id: %d\n", new_p->ue_context.rrc_ue_id);
|
||||
return(new_p);
|
||||
}
|
||||
@@ -211,6 +209,11 @@ rrc_gNB_ue_context_t *rrc_gNB_create_ue_context(sctp_assoc_t assoc_id,
|
||||
ue->max_delays_pdu_session = 20; /* see rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ() */
|
||||
ue->ongoing_pdusession_setup_request = false;
|
||||
|
||||
// Initialise setup PDU Sessions list
|
||||
seq_arr_init(&ue->pduSessions, sizeof(rrc_pdu_session_param_t));
|
||||
// Initialise setup DRBs list
|
||||
seq_arr_init(&ue->drbs, sizeof(drb_t));
|
||||
|
||||
RB_INSERT(rrc_nr_ue_tree_s, &rrc_instance_pP->rrc_ue_head, ue_context_p);
|
||||
LOG_UE_EVENT(ue,
|
||||
"Create UE context: CU UE ID %u DU UE ID %u (rnti: %04x, random ue id %lx)\n",
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "NR_DRB-ToAddMod.h"
|
||||
#include "NR_RadioBearerConfig.h"
|
||||
#include "common/utils/oai_asn1.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h"
|
||||
|
||||
NR_PDCP_Config_t *nr_rrc_build_pdcp_config_ie(const bool integrity, const bool ciphering, const nr_pdcp_configuration_t *pdcp)
|
||||
{
|
||||
NR_PDCP_Config_t *out = calloc_or_fail(1, sizeof(*out));
|
||||
asn1cCallocOne(out->t_Reordering, encode_t_reordering(pdcp->drb.t_reordering));
|
||||
if (!ciphering) {
|
||||
asn1cCalloc(out->ext1, ext1);
|
||||
asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true);
|
||||
}
|
||||
asn1cCalloc(out->drb, drb);
|
||||
asn1cCallocOne(drb->discardTimer, encode_discard_timer(pdcp->drb.discard_timer));
|
||||
asn1cCallocOne(drb->pdcp_SN_SizeUL, encode_sn_size_ul(pdcp->drb.sn_size));
|
||||
asn1cCallocOne(drb->pdcp_SN_SizeDL, encode_sn_size_dl(pdcp->drb.sn_size));
|
||||
drb->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed;
|
||||
drb->headerCompression.choice.notUsed = 0;
|
||||
if (integrity) {
|
||||
asn1cCallocOne(drb->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _RRC_GNB_ASN1_H_
|
||||
#define _RRC_GNB_ASN1_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include "seq_arr.h"
|
||||
#include "NR_DRB-ToAddMod.h"
|
||||
#include "NR_RadioBearerConfig.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_configuration.h"
|
||||
|
||||
NR_PDCP_Config_t *nr_rrc_build_pdcp_config_ie(const bool integrity, const bool ciphering, const nr_pdcp_configuration_t *pdcp);
|
||||
|
||||
#endif
|
||||
@@ -63,24 +63,20 @@ static void free_ho_ctx(nr_handover_context_t *ho_ctx)
|
||||
free(ho_ctx);
|
||||
}
|
||||
|
||||
/** @brief Fill DRB to Be Setup List in F1 UE Context Setup Request (optional list)
|
||||
* @return 0 if list is empty, list size otherwise */
|
||||
static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_drb_to_setup_t drbs[MAX_DRBS_PER_UE])
|
||||
{
|
||||
int nb_drb = 0;
|
||||
for (int i = 0; i < MAX_DRBS_PER_UE; ++i) {
|
||||
drb_t *rrc_drb = &ue->established_drbs[i];
|
||||
if (rrc_drb->status == DRB_INACTIVE)
|
||||
continue;
|
||||
|
||||
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(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);
|
||||
|
||||
drb->id = rrc_drb->drb_id;
|
||||
|
||||
@@ -88,9 +84,14 @@ static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_
|
||||
drb->nr.nssai = pdu->param.nssai;
|
||||
drb->nr.flows_len = 1;
|
||||
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);
|
||||
|
||||
// Find the QoS flow associated with this DRB
|
||||
// Since we don't have QFI mapping in the new structure, we'll use the 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: we just reuse the ones from the first flow */
|
||||
drb->nr.drb_qos = drb->nr.flows[0].param;
|
||||
|
||||
@@ -99,10 +100,11 @@ static int fill_drb_to_be_setup(const gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue, f1ap_
|
||||
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 = rrc_drb->pdcp_config.pdcp_SN_SizeDL == 1 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
*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 = rrc_drb->pdcp_config.pdcp_SN_SizeUL == 1 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;;
|
||||
*drb->ul_pdcp_sn_len = pdcp->drb.sn_size == 18 ? F1AP_PDCP_SN_18B : F1AP_PDCP_SN_12B;
|
||||
}
|
||||
return nb_drb;
|
||||
}
|
||||
|
||||
@@ -33,7 +33,11 @@ typedef struct nr_rrc_du_container_t nr_rrc_du_container_t;
|
||||
typedef struct NR_CellGroupConfig NR_CellGroupConfig_t;
|
||||
|
||||
typedef void (*ho_cancel_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *ue);
|
||||
typedef int (*ho_status_transfer_t)(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, const int n_to_mod, const e1_pdcp_status_info_t *pdcp_status);
|
||||
typedef int (*ho_status_transfer_t)(gNB_RRC_INST *rrc,
|
||||
gNB_RRC_UE_t *UE,
|
||||
const int n_to_mod,
|
||||
const int *drb_ids,
|
||||
const e1_pdcp_status_info_t *pdcp_status);
|
||||
|
||||
typedef struct nr_ho_source_cu {
|
||||
/// pointer to the (source) DU structure
|
||||
|
||||
@@ -72,6 +72,7 @@
|
||||
#include "xer_encoder.h"
|
||||
#include "f1ap_common.h"
|
||||
#include "lib/f1ap_ue_context.h"
|
||||
#include "rrc_gNB_asn1.h"
|
||||
|
||||
// In case of phy-test and do-ra mode, read UE capabilities directly from file
|
||||
// and put it into a CG-ConfigInfo field
|
||||
@@ -134,6 +135,32 @@ static instance_t get_f1_gtp_instance(void)
|
||||
return inst->gtpInst;
|
||||
}
|
||||
|
||||
/* returns a default radio bearer config suitable for NSA etc */
|
||||
static NR_RadioBearerConfig_t *get_default_rbconfig(int eps_bearer_id,
|
||||
int rb_id,
|
||||
e_NR_CipheringAlgorithm ciphering_algorithm,
|
||||
e_NR_SecurityConfig__keyToUse key_to_use,
|
||||
const nr_pdcp_configuration_t *pdcp_config)
|
||||
{
|
||||
NR_RadioBearerConfig_t *rbconfig = calloc_or_fail(1, sizeof(*rbconfig));
|
||||
rbconfig->drb_ToAddModList = calloc_or_fail(1, sizeof(*rbconfig->drb_ToAddModList));
|
||||
NR_DRB_ToAddMod_t *drb_ToAddMod = calloc_or_fail(1, sizeof(*drb_ToAddMod));
|
||||
drb_ToAddMod->drb_Identity = rb_id;
|
||||
drb_ToAddMod->pdcp_Config = nr_rrc_build_pdcp_config_ie(false, false, pdcp_config);
|
||||
asn1cCalloc(drb_ToAddMod->cnAssociation, cn_association);
|
||||
cn_association->present = NR_DRB_ToAddMod__cnAssociation_PR_eps_BearerIdentity;
|
||||
cn_association->choice.eps_BearerIdentity = eps_bearer_id;
|
||||
asn1cSeqAdd(&rbconfig->drb_ToAddModList->list, drb_ToAddMod);
|
||||
asn1cCalloc(rbconfig->securityConfig, secConf);
|
||||
asn1cCalloc(secConf->securityAlgorithmConfig, secConfAlgo);
|
||||
secConfAlgo->cipheringAlgorithm = ciphering_algorithm;
|
||||
secConfAlgo->integrityProtAlgorithm = NULL;
|
||||
asn1cCallocOne(secConf->keyToUse, key_to_use);
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
xer_fprint(stdout, &asn_DEF_NR_DRB_ToAddMod, drb_ToAddMod);
|
||||
return rbconfig;
|
||||
}
|
||||
|
||||
/* generate prototypes for the tree management functions (RB_INSERT used in rrc_add_nsa_user) */
|
||||
RB_PROTOTYPE(rrc_nr_ue_tree_s, rrc_gNB_ue_context_s, entries,
|
||||
rrc_gNB_compare_ue_rnti_id);
|
||||
|
||||
@@ -31,197 +31,198 @@
|
||||
#include "ngap_messages_types.h"
|
||||
#include "oai_asn1.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_asn1_utils.h"
|
||||
#include "common/utils/alg/find.h"
|
||||
|
||||
/** @brief Deep copy pdusession_t */
|
||||
void cp_pdusession(pdusession_t *dst, const pdusession_t *src)
|
||||
static bool eq_qfi(const void *vval, const void *vit)
|
||||
{
|
||||
// Shallow copy
|
||||
*dst = *src;
|
||||
// nas_pdu
|
||||
dst->nas_pdu = copy_byte_array(src->nas_pdu);
|
||||
const int id = *(const int *)vval;
|
||||
const nr_rrc_qos_t *elem = (const nr_rrc_qos_t *)vit;
|
||||
return elem->qos.qfi == id;
|
||||
}
|
||||
|
||||
rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create)
|
||||
/** @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)
|
||||
{
|
||||
int j;
|
||||
for (j = 0; j < ue->nb_of_pdusessions; j++)
|
||||
if (id == ue->pduSession[j].param.pdusession_id)
|
||||
break;
|
||||
if (j == ue->nb_of_pdusessions) {
|
||||
if (create)
|
||||
ue->nb_of_pdusessions++;
|
||||
else
|
||||
return NULL;
|
||||
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) == MAX_QOS_FLOWS) {
|
||||
LOG_W(NR_RRC, "Reached maximum number of QoS flows = %ld\n", seq_arr_size(qos));
|
||||
return NULL;
|
||||
}
|
||||
return ue->pduSession + j;
|
||||
|
||||
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;
|
||||
const rrc_pdu_session_param_t *elem = vit;
|
||||
return elem->param.pdusession_id == id;
|
||||
}
|
||||
|
||||
/** @brief Free pdusession_t */
|
||||
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);
|
||||
}
|
||||
|
||||
/** @brief Retrieves PDU Session for the input ID
|
||||
* @return pointer to the found PDU Session, NULL if not found */
|
||||
rrc_pdu_session_param_t *find_pduSession(seq_arr_t *seq, int id)
|
||||
{
|
||||
DevAssert(seq);
|
||||
elm_arr_t elm = find_if(seq, &id, eq_pdu_session_id);
|
||||
if (elm.found)
|
||||
return (rrc_pdu_session_param_t *)elm.it;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** @brief Adds a new PDU Session to the list
|
||||
* @return pointer to the new PDU Session */
|
||||
rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusession_t *in)
|
||||
{
|
||||
DevAssert(sessions_ptr);
|
||||
DevAssert(in);
|
||||
|
||||
if (seq_arr_size(sessions_ptr) == NGAP_MAX_PDU_SESSION) {
|
||||
LOG_W(NR_RRC, "Reached maximum number of PDU Session = %ld\n", seq_arr_size(sessions_ptr));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rrc_pdu_session_param_t *exists = find_pduSession(sessions_ptr, in->pdusession_id);
|
||||
if (exists) {
|
||||
LOG_E(NR_RRC, "Trying to add an already existing PDU Session with ID=%d\n", in->pdusession_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rrc_pdu_session_param_t new = {.param = *in, .status = PDU_SESSION_STATUS_NEW, .xid = -1};
|
||||
seq_arr_push_back(sessions_ptr, &new, sizeof(rrc_pdu_session_param_t));
|
||||
rrc_pdu_session_param_t *added = find_pduSession(sessions_ptr, in->pdusession_id);
|
||||
DevAssert(added);
|
||||
LOG_I(NR_RRC, "Added PDU Session %d, (total nb of sessions = %ld)\n", in->pdusession_id, seq_arr_size(sessions_ptr));
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
/** @brief Add drb_t item in the UE context list for @param pdusession_id */
|
||||
drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp)
|
||||
{
|
||||
DevAssert(drb_ptr);
|
||||
DevAssert(pdcp != NULL);
|
||||
DevAssert(pdusession_id > 0 && pdusession_id <= NGAP_MAX_PDU_SESSION);
|
||||
|
||||
// Get next available DRB ID
|
||||
int drb_id = 0;
|
||||
|
||||
// First, try to find the lowest available ID (prefer smaller IDs)
|
||||
for (drb_id = 1; drb_id <= MAX_DRBS_PER_UE; drb_id++) {
|
||||
if (get_drb(drb_ptr, drb_id) == NULL) {
|
||||
break; // Found available ID
|
||||
}
|
||||
}
|
||||
|
||||
if (drb_id > MAX_DRBS_PER_UE) {
|
||||
LOG_E(NR_RRC, "Cannot set up new DRB for pdusession_id=%d - reached maximum capacity\n", pdusession_id);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Add item to the list
|
||||
drb_t in = {.drb_id = drb_id, .pdusession_id = pdusession_id, .pdcp_config = *pdcp};
|
||||
seq_arr_push_back(drb_ptr, &in, sizeof(drb_t));
|
||||
drb_t *out = get_drb(drb_ptr, drb_id);
|
||||
DevAssert(out);
|
||||
LOG_I(NR_RRC, "Added DRB %d to established list (PDU Session ID=%d, total DRBs = %ld)\n", out->drb_id, pdusession_id, seq_arr_size(drb_ptr));
|
||||
return out;
|
||||
}
|
||||
|
||||
static bool eq_drb_id(const void *vval, const void *vit)
|
||||
{
|
||||
const int id = *(const int *)vval;
|
||||
const drb_t *elem = (const drb_t *)vit;
|
||||
return elem->drb_id == id;
|
||||
}
|
||||
|
||||
/** @brief Retrieves DRB for the input ID
|
||||
* @return pointer to the found DRB, NULL if not found */
|
||||
drb_t *get_drb(seq_arr_t *seq, int id)
|
||||
{
|
||||
DevAssert(id > 0 && id <= MAX_DRBS_PER_UE);
|
||||
elm_arr_t elm = find_if(seq, &id, eq_drb_id);
|
||||
if (elm.found)
|
||||
return (drb_t *)elm.it;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** @brief Free pdusession_t */
|
||||
void free_drb(void *ptr)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id)
|
||||
{
|
||||
DevAssert(drb_id > 0 && drb_id <= 32);
|
||||
const drb_t *drb = &ue->established_drbs[drb_id - 1];
|
||||
if (drb->status == DRB_INACTIVE) {
|
||||
LOG_E(NR_RRC, "UE %d: DRB %d inactive\n", ue->rrc_ue_id, drb_id);
|
||||
const drb_t *drb = get_drb(&ue->drbs, drb_id);
|
||||
if (!drb) {
|
||||
LOG_E(NR_RRC, "UE %d: DRB %d not found\n", ue->rrc_ue_id, drb_id);
|
||||
return NULL;
|
||||
}
|
||||
int id = drb->cnAssociation.sdap_config.pdusession_id;
|
||||
return find_pduSession(ue, id, false);
|
||||
int id = drb->pdusession_id;
|
||||
return find_pduSession(&ue->pduSessions, id);
|
||||
}
|
||||
|
||||
void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION])
|
||||
bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp,
|
||||
bool um_on_default_drb,
|
||||
const nr_redcap_ue_cap_t *redcap_cap)
|
||||
{
|
||||
for (int i = 0; i < ue->nb_of_pdusessions && i < NGAP_MAX_PDU_SESSION; ++i)
|
||||
pdu_sessions[i] = ue->pduSession[i].param.pdusession_id;
|
||||
}
|
||||
|
||||
drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id)
|
||||
{
|
||||
DevAssert(drb_id > 0 && drb_id <= 32);
|
||||
DevAssert(ue != NULL);
|
||||
|
||||
return &ue->established_drbs[drb_id - 1];
|
||||
}
|
||||
|
||||
void set_default_drb_pdcp_config(struct pdcp_config_s *pdcp_config,
|
||||
int do_drb_integrity,
|
||||
int do_drb_ciphering,
|
||||
const nr_pdcp_configuration_t *default_pdcp_config,
|
||||
const nr_redcap_ue_cap_t *redcap_cap)
|
||||
{
|
||||
AssertError(pdcp_config != NULL, return, "Failed to set default PDCP configuration for DRB!\n");
|
||||
pdcp_config->discardTimer = encode_discard_timer(default_pdcp_config->drb.discard_timer);
|
||||
bearer_context_pdcp_config_t out = {0};
|
||||
if (redcap_cap && redcap_cap->support_of_redcap_r17 && !redcap_cap->pdcp_drb_long_sn_redcap_r17) {
|
||||
LOG_I(NR_RRC, "UE is RedCap without long PDCP SN support: overriding PDCP SN size to 12\n");
|
||||
pdcp_config->pdcp_SN_SizeDL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len12bits;
|
||||
pdcp_config->pdcp_SN_SizeUL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len12bits;
|
||||
out.pDCP_SN_Size_DL = NR_PDCP_Config__drb__pdcp_SN_SizeDL_len12bits;
|
||||
out.pDCP_SN_Size_UL = NR_PDCP_Config__drb__pdcp_SN_SizeUL_len12bits;
|
||||
} else {
|
||||
pdcp_config->pdcp_SN_SizeDL = encode_sn_size_dl(default_pdcp_config->drb.sn_size);
|
||||
pdcp_config->pdcp_SN_SizeUL = encode_sn_size_ul(default_pdcp_config->drb.sn_size);
|
||||
out.pDCP_SN_Size_DL = encode_sn_size_dl(pdcp.drb.sn_size);
|
||||
out.pDCP_SN_Size_UL = encode_sn_size_ul(pdcp.drb.sn_size);
|
||||
}
|
||||
pdcp_config->t_Reordering = encode_t_reordering(default_pdcp_config->drb.t_reordering);
|
||||
pdcp_config->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed;
|
||||
pdcp_config->headerCompression.NotUsed = 0;
|
||||
pdcp_config->integrityProtection = do_drb_integrity ? NR_PDCP_Config__drb__integrityProtection_enabled : 1;
|
||||
pdcp_config->ext1.cipheringDisabled = do_drb_ciphering ? 1 : NR_PDCP_Config__ext1__cipheringDisabled_true;
|
||||
}
|
||||
|
||||
void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb)
|
||||
{
|
||||
AssertError(rrc_drb != NULL && pdcp_config != NULL, return, "Failed to set default bearer context PDCP configuration!\n");
|
||||
pdcp_config->pDCP_SN_Size_UL = rrc_drb->pdcp_config.pdcp_SN_SizeUL;
|
||||
pdcp_config->pDCP_SN_Size_DL = rrc_drb->pdcp_config.pdcp_SN_SizeDL;
|
||||
pdcp_config->discardTimer = rrc_drb->pdcp_config.discardTimer;
|
||||
pdcp_config->reorderingTimer = rrc_drb->pdcp_config.t_Reordering;
|
||||
pdcp_config->rLC_Mode = um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am;
|
||||
}
|
||||
|
||||
drb_t *generateDRB(gNB_RRC_UE_t *ue,
|
||||
uint8_t drb_id,
|
||||
const rrc_pdu_session_param_t *pduSession,
|
||||
bool enable_sdap,
|
||||
int do_drb_integrity,
|
||||
int do_drb_ciphering,
|
||||
const nr_pdcp_configuration_t *pdcp_config)
|
||||
{
|
||||
DevAssert(ue != NULL);
|
||||
|
||||
LOG_I(NR_RRC, "UE %d: configure DRB ID %d for PDU session ID %d\n", ue->rrc_ue_id, drb_id, pduSession->param.pdusession_id);
|
||||
|
||||
drb_t *est_drb = &ue->established_drbs[drb_id - 1];
|
||||
DevAssert(est_drb->status == DRB_INACTIVE);
|
||||
|
||||
est_drb->status = DRB_ACTIVE;
|
||||
est_drb->drb_id = drb_id;
|
||||
est_drb->cnAssociation.sdap_config.defaultDRB = true;
|
||||
|
||||
/* SDAP Configuration */
|
||||
est_drb->cnAssociation.present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config;
|
||||
est_drb->cnAssociation.sdap_config.pdusession_id = pduSession->param.pdusession_id;
|
||||
if (enable_sdap) {
|
||||
est_drb->cnAssociation.sdap_config.sdap_HeaderDL = NR_SDAP_Config__sdap_HeaderDL_present;
|
||||
est_drb->cnAssociation.sdap_config.sdap_HeaderUL = NR_SDAP_Config__sdap_HeaderUL_present;
|
||||
} else {
|
||||
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->param.nb_qos; qos_flow_index++) {
|
||||
est_drb->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] = pduSession->param.qos[qos_flow_index].qfi;
|
||||
if (pduSession->param.qos[qos_flow_index].fiveQI > 5)
|
||||
est_drb->status = DRB_ACTIVE_NONGBR;
|
||||
else
|
||||
est_drb->status = DRB_ACTIVE;
|
||||
}
|
||||
/* PDCP Configuration */
|
||||
set_default_drb_pdcp_config(&est_drb->pdcp_config, do_drb_integrity, do_drb_ciphering, pdcp_config, ue->redcap_cap);
|
||||
|
||||
drb_t *rrc_drb = get_drb(ue, drb_id);
|
||||
DevAssert(rrc_drb == est_drb); /* to double check that we create the same which we would retrieve */
|
||||
return rrc_drb;
|
||||
}
|
||||
|
||||
NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1)
|
||||
{
|
||||
NR_DRB_ToAddMod_t *DRB_config = CALLOC(1, sizeof(*DRB_config));
|
||||
NR_SDAP_Config_t *SDAP_config = CALLOC(1, sizeof(NR_SDAP_Config_t));
|
||||
|
||||
asn1cCalloc(DRB_config->cnAssociation, association);
|
||||
asn1cCalloc(SDAP_config->mappedQoS_FlowsToAdd, sdapFlows);
|
||||
asn1cCalloc(DRB_config->pdcp_Config, pdcpConfig);
|
||||
asn1cCalloc(pdcpConfig->drb, drb);
|
||||
|
||||
DRB_config->drb_Identity = drb_asn1->drb_id;
|
||||
association->present = drb_asn1->cnAssociation.present;
|
||||
|
||||
/* SDAP Configuration */
|
||||
SDAP_config->pdu_Session = drb_asn1->cnAssociation.sdap_config.pdusession_id;
|
||||
SDAP_config->sdap_HeaderDL = drb_asn1->cnAssociation.sdap_config.sdap_HeaderDL;
|
||||
SDAP_config->sdap_HeaderUL = drb_asn1->cnAssociation.sdap_config.sdap_HeaderUL;
|
||||
SDAP_config->defaultDRB = drb_asn1->cnAssociation.sdap_config.defaultDRB;
|
||||
|
||||
for (int qos_flow_index = 0; qos_flow_index < QOSFLOW_MAX_VALUE; qos_flow_index++) {
|
||||
if (drb_asn1->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index] != 0) {
|
||||
asn1cSequenceAdd(sdapFlows->list, NR_QFI_t, qfi);
|
||||
*qfi = drb_asn1->cnAssociation.sdap_config.mappedQoS_FlowsToAdd[qos_flow_index];
|
||||
}
|
||||
}
|
||||
|
||||
association->choice.sdap_Config = SDAP_config;
|
||||
|
||||
/* PDCP Configuration */
|
||||
asn1cCallocOne(drb->discardTimer, drb_asn1->pdcp_config.discardTimer);
|
||||
asn1cCallocOne(drb->pdcp_SN_SizeUL, drb_asn1->pdcp_config.pdcp_SN_SizeUL);
|
||||
asn1cCallocOne(drb->pdcp_SN_SizeDL, drb_asn1->pdcp_config.pdcp_SN_SizeDL);
|
||||
asn1cCallocOne(pdcpConfig->t_Reordering, drb_asn1->pdcp_config.t_Reordering);
|
||||
|
||||
drb->headerCompression.present = drb_asn1->pdcp_config.headerCompression.present;
|
||||
drb->headerCompression.choice.notUsed = drb_asn1->pdcp_config.headerCompression.NotUsed;
|
||||
|
||||
if (!drb_asn1->pdcp_config.integrityProtection) {
|
||||
asn1cCallocOne(drb->integrityProtection, drb_asn1->pdcp_config.integrityProtection);
|
||||
}
|
||||
if (!drb_asn1->pdcp_config.ext1.cipheringDisabled) {
|
||||
asn1cCalloc(pdcpConfig->ext1, ext1);
|
||||
asn1cCallocOne(ext1->cipheringDisabled, drb_asn1->pdcp_config.ext1.cipheringDisabled);
|
||||
}
|
||||
|
||||
return DRB_config;
|
||||
}
|
||||
|
||||
uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue)
|
||||
{
|
||||
for (uint8_t drb_id = 0; drb_id < MAX_DRBS_PER_UE; drb_id++)
|
||||
if (ue->established_drbs[drb_id].status == DRB_INACTIVE)
|
||||
return drb_id + 1;
|
||||
/* From this point, we need to handle the case that all DRBs are already used by the UE. */
|
||||
LOG_E(RRC, "Error - All the DRBs are used - Handle this\n");
|
||||
return DRB_INACTIVE;
|
||||
}
|
||||
|
||||
int get_number_active_drbs(gNB_RRC_UE_t *ue)
|
||||
{
|
||||
int n = 0;
|
||||
for (int i = 0; i < MAX_DRBS_PER_UE; ++i)
|
||||
if (ue->established_drbs[i].status != DRB_INACTIVE)
|
||||
n++;
|
||||
return n;
|
||||
out.discardTimer = encode_discard_timer(pdcp.drb.discard_timer);
|
||||
out.reorderingTimer = encode_t_reordering(pdcp.drb.t_reordering);
|
||||
out.rLC_Mode = um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am;
|
||||
out.pDCP_Reestablishment = false;
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -24,61 +24,38 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "NR_DRB-ToAddMod.h"
|
||||
#include "e1ap_messages_types.h"
|
||||
#include "nr_rrc_defs.h"
|
||||
|
||||
#define DRB_ACTIVE_NONGBR (2) /* DRB is used for Non-GBR Flows */
|
||||
#define DRB_ACTIVE (1)
|
||||
#define DRB_INACTIVE (0)
|
||||
#define GBR_FLOW (1)
|
||||
#define NONGBR_FLOW (0)
|
||||
|
||||
/// @brief Generates an ASN1 DRB-ToAddMod, from the established_drbs in gNB_RRC_UE_t.
|
||||
/// @param drb_t drb_asn1
|
||||
/// @return Returns the ASN1 DRB-ToAddMod structs.
|
||||
NR_DRB_ToAddMod_t *generateDRB_ASN1(const drb_t *drb_asn1);
|
||||
|
||||
/// @brief retrieve the data structure representing DRB with ID drb_id of UE ue
|
||||
drb_t *get_drb(gNB_RRC_UE_t *ue, uint8_t drb_id);
|
||||
drb_t *get_drb(seq_arr_t *seq, int id);
|
||||
|
||||
/// @brief Creates and stores a DRB in the gNB_RRC_UE_t struct
|
||||
/// @param ue The gNB_RRC_UE_t struct that holds information for the UEs
|
||||
/// @param drb_id The Data Radio Bearer Identity to be created for the established DRB.
|
||||
/// @param pduSession The PDU Session that the DRB is created for.
|
||||
/// @param enable_sdap If true the SDAP header will be added to the packet, else it will not add or search for SDAP header.
|
||||
/// @param do_drb_integrity
|
||||
/// @param do_drb_ciphering
|
||||
/// @param pdcp_config
|
||||
/// @return returns a pointer to the generated DRB structure
|
||||
drb_t *generateDRB(gNB_RRC_UE_t *ue,
|
||||
uint8_t drb_id,
|
||||
const rrc_pdu_session_param_t *pduSession,
|
||||
bool enable_sdap,
|
||||
int do_drb_integrity,
|
||||
int do_drb_ciphering,
|
||||
const nr_pdcp_configuration_t *pdcp_config);
|
||||
/// @brief retrieve PDU session of UE ue with ID id
|
||||
rrc_pdu_session_param_t *find_pduSession(seq_arr_t *seq, int id);
|
||||
|
||||
/// @brief return the next available (inactive) DRB ID of UE ue
|
||||
uint8_t get_next_available_drb_id(gNB_RRC_UE_t *ue);
|
||||
|
||||
/// @brief returns the number of active DRBs for this UE
|
||||
int get_number_active_drbs(gNB_RRC_UE_t *ue);
|
||||
|
||||
/// @brief retrieve PDU session of UE ue with ID id, optionally creating it if
|
||||
/// create is true
|
||||
rrc_pdu_session_param_t *find_pduSession(gNB_RRC_UE_t *ue, int id, bool create);
|
||||
/// @brief Add a new PDU session for UE @param ue and configuration @param in
|
||||
rrc_pdu_session_param_t *add_pduSession(seq_arr_t *sessions_ptr, const pdusession_t *in);
|
||||
|
||||
/// @brief get PDU session of UE ue through the DRB drb_id
|
||||
rrc_pdu_session_param_t *find_pduSession_from_drbId(gNB_RRC_UE_t *ue, int drb_id);
|
||||
|
||||
/// @brief get the PDU sessions of this UE in a single array
|
||||
void get_pduSession_array(gNB_RRC_UE_t *ue, uint32_t pdu_sessions[NGAP_MAX_PDU_SESSION]);
|
||||
/// @brief set PDCP configuration in E1 Bearer Context Management message
|
||||
bearer_context_pdcp_config_t set_bearer_context_pdcp_config(const nr_pdcp_configuration_t pdcp,
|
||||
bool um_on_default_drb,
|
||||
const nr_redcap_ue_cap_t *redcap_cap);
|
||||
|
||||
/// @brief set PDCP configuration in a bearer context management message
|
||||
void set_bearer_context_pdcp_config(bearer_context_pdcp_config_t *pdcp_config, drb_t *rrc_drb, bool um_on_default_drb);
|
||||
void free_pdusession(void *ptr);
|
||||
|
||||
/// @brief Deep copy an instance of struct pdusession_t
|
||||
void cp_pdusession(pdusession_t *dst, const pdusession_t *src);
|
||||
/// @brief Add DRB to RRC list
|
||||
drb_t *nr_rrc_add_drb(seq_arr_t *drb_ptr, int pdusession_id, nr_pdcp_configuration_t *pdcp);
|
||||
|
||||
/// @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
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
add_executable(rrc_bearers_test rrc_bearers_test.c ../rrc_gNB_radio_bearers.c ${OPENAIR2_DIR}/LAYER2/nr_pdcp/asn1_utils.c)
|
||||
add_dependencies(tests rrc_bearers_test)
|
||||
add_test(NAME rrc_bearers_test COMMAND rrc_bearers_test)
|
||||
target_include_directories(rrc_bearers_test PRIVATE ./common/utils/ds common/utils/LOG)
|
||||
target_link_libraries(rrc_bearers_test PRIVATE ds alg asn1_e1ap asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs LOG T)
|
||||
target_compile_definitions(rrc_bearers_test PRIVATE ENABLE_TESTS)
|
||||
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "common/utils/utils.h"
|
||||
#include "common/utils/assertions.h"
|
||||
#include "openair2/RRC/NR/rrc_gNB_radio_bearers.h"
|
||||
#include "ds/seq_arr.h"
|
||||
#include "common/utils/LOG/log.h"
|
||||
|
||||
int nr_rlc_get_available_tx_space(int module_id, int rnti, int drb_id) { return 0; }
|
||||
softmodem_params_t *get_softmodem_params(void) { return NULL; }
|
||||
configmodule_interface_t *uniqCfg = NULL;
|
||||
|
||||
void exit_function(const char *file, const char *function, const int line, const char *s, const int assert)
|
||||
{
|
||||
printf("detected error at %s:%d:%s: %s\n", file, line, function, s);
|
||||
abort();
|
||||
}
|
||||
|
||||
static void test_rrc_pdu_session(void)
|
||||
{
|
||||
const int pdu_session_id = 3;
|
||||
gNB_RRC_UE_t ue = {0};
|
||||
seq_arr_init(&ue.pduSessions, sizeof(rrc_pdu_session_param_t));
|
||||
|
||||
/* test add */
|
||||
pdusession_t p1 = {0};
|
||||
seq_arr_init(&p1.qos, sizeof(nr_rrc_qos_t));
|
||||
p1.pdusession_id = pdu_session_id;
|
||||
p1.n3_incoming.teid = 2002;
|
||||
LOG_I(NR_RRC, "Adding first PDU Session with ID %d\n", p1.pdusession_id);
|
||||
rrc_pdu_session_param_t *s1 = add_pduSession(&ue.pduSessions, &p1); // add 1st PDU Session
|
||||
AssertFatal(s1 != NULL, "Could not add PDU Session\n");
|
||||
AssertFatal(s1->param.pdusession_id == p1.pdusession_id, "PDU Session ID mismatch in added PDU Session\n");
|
||||
AssertFatal(s1->param.n3_incoming.teid == p1.n3_incoming.teid, "teid mismatch in added PDU Session\n");
|
||||
LOG_A(NR_RRC, "First PDU Session added successfully\n");
|
||||
|
||||
/* test find */
|
||||
rrc_pdu_session_param_t *a1 = find_pduSession(&ue.pduSessions, p1.pdusession_id);
|
||||
AssertFatal(a1 != NULL, "Could not find PDU Session\n");
|
||||
AssertFatal(a1 == s1, "Found PDU Session mismatch\n");
|
||||
LOG_A(NR_RRC, "PDU Session find test passed\n");
|
||||
|
||||
/* test add duplicate */
|
||||
pdusession_t input2 = {0};
|
||||
seq_arr_init(&input2.qos, sizeof(nr_rrc_qos_t));
|
||||
input2.pdusession_id = pdu_session_id;
|
||||
input2.n3_incoming.teid = 9999;
|
||||
rrc_pdu_session_param_t *s2 = add_pduSession(&ue.pduSessions, &input2); // add 2nd PDU Session
|
||||
AssertFatal(s2 == NULL, "Duplicated PDU session was added!\n");
|
||||
LOG_A(NR_RRC, "Duplicated PDU session test passed\n");
|
||||
seq_arr_free(&input2.qos, NULL);
|
||||
|
||||
/* add DRB and fetch PDU Session */
|
||||
seq_arr_init(&ue.drbs, sizeof(drb_t));
|
||||
nr_pdcp_configuration_t pdcp = {.drb.discard_timer = 100, .drb.sn_size = 18, .drb.t_reordering = 50};
|
||||
drb_t *added = nr_rrc_add_drb(&ue.drbs, pdu_session_id, &pdcp);
|
||||
AssertFatal(added != NULL, "Failed to add DRB");
|
||||
rrc_pdu_session_param_t *a2 = find_pduSession_from_drbId(&ue, added->drb_id);
|
||||
AssertFatal(a2 && a2->param.pdusession_id == pdu_session_id, "find_pduSession_from_drbId failed");
|
||||
|
||||
seq_arr_free(&ue.pduSessions, free_pdusession);
|
||||
seq_arr_free(&ue.drbs, free_drb);
|
||||
}
|
||||
|
||||
// ---------------- DRB TESTS ----------------
|
||||
|
||||
static void test_rrc_drb(void)
|
||||
{
|
||||
LOG_I(NR_RRC, "Starting DRB test\n");
|
||||
seq_arr_t pduSessions = {0};
|
||||
seq_arr_t drbs = {0};
|
||||
seq_arr_init(&pduSessions, sizeof(rrc_pdu_session_param_t));
|
||||
seq_arr_init(&drbs, sizeof(drb_t));
|
||||
|
||||
/* test add 1 DRB to 1st PDU session */
|
||||
const int id1 = 1;
|
||||
pdusession_t s1 = {0};
|
||||
seq_arr_init(&s1.qos, sizeof(nr_rrc_qos_t));
|
||||
s1.pdusession_id = id1;
|
||||
add_pduSession(&pduSessions, &s1); // add PDU session
|
||||
|
||||
nr_pdcp_configuration_t pdcp = {.drb.discard_timer = 100, .drb.sn_size = 18, .drb.t_reordering = 50};
|
||||
drb_t *in1 = nr_rrc_add_drb(&drbs, id1, &pdcp); // add DRB
|
||||
AssertFatal(in1, "add_rrc_drb failed");
|
||||
LOG_A(NR_RRC, "First DRB created with ID %d\n", in1->drb_id);
|
||||
|
||||
drb_t *out1 = get_drb(&drbs, 1); // fetch DRB
|
||||
AssertFatal(out1 && out1 == in1, "get_drb failed");
|
||||
LOG_A(NR_RRC, "DRB retrieval test passed\n");
|
||||
|
||||
/* test add DRB to 2nd PDU session */
|
||||
const int id2 = 2;
|
||||
pdusession_t s2 = {0};
|
||||
seq_arr_init(&s2.qos, sizeof(nr_rrc_qos_t));
|
||||
s2.pdusession_id = id2;
|
||||
add_pduSession(&pduSessions, &s2); // add 2nd PDU session
|
||||
drb_t *in2 = nr_rrc_add_drb(&drbs, id2, &pdcp); // add DRB to 2nd PDU session
|
||||
AssertFatal(in2, "add_rrc_drb failed");
|
||||
LOG_A(NR_RRC, "Second DRB created with ID %d\n", in2->drb_id);
|
||||
drb_t *out2 = get_drb(&drbs, 2);
|
||||
AssertFatal(out2 && out2->drb_id == 2, "get_drb failed");
|
||||
LOG_A(NR_RRC, "Second DRB retrieval test passed\n");
|
||||
|
||||
seq_arr_free(&pduSessions, free_pdusession);
|
||||
seq_arr_free(&drbs, free_drb);
|
||||
}
|
||||
|
||||
// ---------------- DRB TESTS ----------------
|
||||
|
||||
static void test_rrc_qos(void)
|
||||
{
|
||||
seq_arr_t pduSessions = {0};
|
||||
seq_arr_init(&pduSessions, sizeof(rrc_pdu_session_param_t));
|
||||
|
||||
const int session_id = 70;
|
||||
pdusession_t in = {0};
|
||||
in.pdusession_id = session_id;
|
||||
seq_arr_init(&in.qos, sizeof(nr_rrc_qos_t));
|
||||
add_pduSession(&pduSessions, &in);
|
||||
LOG_A(NR_RRC, "Created PDU Session %d for QoS test\n", session_id);
|
||||
|
||||
const int qfi = 4;
|
||||
const pdusession_level_qos_parameter_t param = { .fiveQI = 9, .fiveQI_type = NON_DYNAMIC, .qfi = qfi };
|
||||
LOG_A(NR_RRC, "Adding QoS flow with QFI %d\n", qfi);
|
||||
nr_rrc_qos_t *added = add_qos(&in.qos, ¶m);
|
||||
AssertFatal(added, "add_qos failed");
|
||||
LOG_A(NR_RRC, "QoS flow added successfully\n");
|
||||
|
||||
nr_rrc_qos_t *found = find_qos(&in.qos, qfi);
|
||||
AssertFatal(found && found == added, "find_qos failed");
|
||||
LOG_A(NR_RRC, "QoS flow find test passed\n");
|
||||
|
||||
seq_arr_free(&pduSessions, free_pdusession);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// Initialize logging system
|
||||
logInit();
|
||||
// Set logging level for NR_RRC to show INFO messages
|
||||
set_log(NR_RRC, OAILOG_INFO);
|
||||
// PDU Session
|
||||
test_rrc_pdu_session();
|
||||
// DRB
|
||||
test_rrc_drb();
|
||||
// QoS
|
||||
test_rrc_qos();
|
||||
LOG_A(NR_RRC, "All RRC Bearers tests passed successfully!\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The OpenAirInterface Software Alliance licenses this file to You under
|
||||
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
||||
* except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.openairinterface.org/?page_id=698
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*-------------------------------------------------------------------------------
|
||||
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
||||
* contact@openairinterface.org
|
||||
*/
|
||||
|
||||
#ifndef _NR_SDAP_CONFIGURATION_H_
|
||||
#define _NR_SDAP_CONFIGURATION_H_
|
||||
|
||||
#include "stdbool.h"
|
||||
|
||||
typedef struct {
|
||||
// SDAP Headers
|
||||
bool header_dl_absent;
|
||||
bool header_ul_absent;
|
||||
} nr_sdap_configuration_t;
|
||||
|
||||
#endif /* _NR_SDAP_CONFIGURATION_H_ */
|
||||
@@ -577,12 +577,11 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
||||
{
|
||||
nr_sdap_entity_t *entityPtr = sdap_info.sdap_entity_llist;
|
||||
nr_sdap_entity_t *entityPrev = NULL;
|
||||
bool ret = false;
|
||||
int upperBound = 0;
|
||||
|
||||
if (entityPtr == NULL && (pdusession_id) * (pdusession_id - NGAP_MAX_PDU_SESSION) > 0) {
|
||||
LOG_E(SDAP, "SDAP entities not established or Invalid range of pdusession_id [0, 256].\n");
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
LOG_D(SDAP, "Deleting SDAP entity for UE %lx and PDU Session id %d\n", ue_id, entityPtr->pdusession_id);
|
||||
|
||||
@@ -592,7 +591,7 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
||||
remove_ip_if(entityPtr);
|
||||
free(entityPtr);
|
||||
LOG_D(SDAP, "Successfully deleted Entity.\n");
|
||||
ret = true;
|
||||
return true;
|
||||
} else {
|
||||
while ((entityPtr->ue_id != ue_id || entityPtr->pdusession_id != pdusession_id) && entityPtr->next_entity != NULL
|
||||
&& upperBound < SDAP_MAX_NUM_OF_ENTITIES) {
|
||||
@@ -608,11 +607,11 @@ bool nr_sdap_delete_entity(ue_id_t ue_id, int pdusession_id)
|
||||
}
|
||||
free(entityPtr);
|
||||
LOG_D(SDAP, "Successfully deleted Entity.\n");
|
||||
ret = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
LOG_E(SDAP, "Entity does not exist or it was not found.\n");
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool nr_sdap_delete_ue_entities(ue_id_t ue_id)
|
||||
|
||||
@@ -201,9 +201,9 @@ pdusession_level_qos_parameter_t fill_qos(uint8_t qfi, const NGAP_QosFlowLevelQo
|
||||
}
|
||||
// Allocation and Retention Priority
|
||||
const NGAP_AllocationAndRetentionPriority_t *arp = ¶ms->allocationAndRetentionPriority;
|
||||
out.allocation_retention_priority.priority_level = arp->priorityLevelARP;
|
||||
out.allocation_retention_priority.pre_emp_capability = arp->pre_emptionCapability;
|
||||
out.allocation_retention_priority.pre_emp_vulnerability = arp->pre_emptionVulnerability;
|
||||
out.arp.priority_level = arp->priorityLevelARP;
|
||||
out.arp.pre_emp_capability = arp->pre_emptionCapability;
|
||||
out.arp.pre_emp_vulnerability = arp->pre_emptionVulnerability;
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -88,7 +88,9 @@ NGAP_NGAP_PDU_t *encode_ng_handover_required(const ngap_handover_required_t *msg
|
||||
asn1cSequenceAdd(ie6->value.choice.PDUSessionResourceListHORqd.list, NGAP_PDUSessionResourceItemHORqd_t, hoRequiredPduSession);
|
||||
// PDU Session ID (M)
|
||||
hoRequiredPduSession->pDUSessionID = msg->pdusessions[i].pdusession_id;
|
||||
// Handover Required Transfer (M)
|
||||
// Handover Required Transfer (M) - ASN.1 encoding of empty transfer structure
|
||||
// This is a mandatory field in the NGAP Handover Required message, however it contains
|
||||
// only Direct Forwarding Path Availability IE, which is optional and is not sent
|
||||
NGAP_HandoverRequiredTransfer_t hoRequiredTransfer = {0};
|
||||
uint8_t ho_req_transfer_transparent_container_buffer[128] = {0};
|
||||
if (LOG_DEBUGFLAG(DEBUG_ASN1))
|
||||
@@ -123,7 +125,7 @@ NGAP_NGAP_PDU_t *encode_ng_handover_required(const ngap_handover_required_t *msg
|
||||
|
||||
// PDU Session Resource Information List (O)
|
||||
asn1cCalloc(source2target->pDUSessionResourceInformationList, pduSessionList);
|
||||
for (uint8_t i = 0; i < msg->nb_of_pdusessions; ++i) {
|
||||
for (uint16_t i = 0; i < msg->nb_of_pdusessions; ++i) {
|
||||
const pdusession_resource_t *pduSession = &msg->pdusessions[i];
|
||||
NGAP_DEBUG("Handover Required: preparing PDU Session Resource Information List for PDU Session ID %d\n",
|
||||
pduSession->pdusession_id);
|
||||
|
||||
@@ -1206,11 +1206,10 @@ int ngap_gNB_pdusession_release_resp(instance_t instance, ngap_pdusession_releas
|
||||
|
||||
/* UE associated signalling -> use the allocated stream */
|
||||
ngap_gNB_itti_send_sctp_data_req(ngap_gNB_instance_p->instance, ue_context_p->amf_ref->assoc_id, buffer, length, ue_context_p->tx_stream);
|
||||
NGAP_INFO("pdusession_release_response sended gNB_UE_NGAP_ID %u amf_ue_ngap_id %lu nb_of_pdusessions_released %d nb_of_pdusessions_failed %d\n",
|
||||
NGAP_INFO("pdusession_release_response sended gNB_UE_NGAP_ID %u amf_ue_ngap_id %lu nb_of_pdusessions_released %d \n",
|
||||
pdusession_release_resp_p->gNB_ue_ngap_id,
|
||||
(uint64_t)ue_context_p->amf_ue_ngap_id,
|
||||
pdusession_release_resp_p->nb_of_pdusessions_released,
|
||||
pdusession_release_resp_p->nb_of_pdusessions_failed);
|
||||
pdusession_release_resp_p->nb_of_pdusessions_released);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user