Files
openairinterface5g/openair2/RRC/NR/rrc_gNB_nsa.c
T
Robert Schmidt d1fc95a8a1 GTP: when creating a tunnel, tell which functions to use
The GTP module is common for 4G and 5G. It hardcodes the functions to
call when creating S1U and NGU tunnels. The S1U case is both applicable
for LTE and NR (NSA), which until now was not a problem as the PDCP data
forwarding functions where called pdcp_data_req. The issue is that in this
branch, the NR PDCP functions have changed to nr_pdcp_data_req_drb().

When setting up a GTP tunnel, we now pass the PDCP data forwarding
functions into GTP, since the caller knows whether it is in 4G or 5G,
but GTP itself does not.
2023-03-31 11:53:52 +02:00

412 lines
20 KiB
C

/*
* 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
*/
/*! \file rrc_gNB_nsa.c
* \brief rrc NSA procedures for gNB
* \author Raymond Knopp
* \date 2019
* \version 1.0
* \company Eurecom
* \email: raymond.knopp@eurecom.fr
*/
#include "nr_rrc_defs.h"
#include "NR_RRCReconfiguration.h"
#include "NR_UE-NR-Capability.h"
//#include "NR_UE-CapabilityRAT-ContainerList.h"
#include "LTE_UE-CapabilityRAT-ContainerList.h"
#include "NR_CellGroupConfig.h"
#include "NR_CG-Config.h"
//#include "NR_SRB-ToAddModList.h"
#include "openair2/LAYER2/NR_MAC_gNB/mac_proto.h"
#include "openair2/LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include "openair2/RRC/LTE/rrc_eNB_GTPV1U.h"
#include "executables/softmodem-common.h"
#include "executables/nr-softmodem.h"
#include <openair2/RRC/NR/rrc_gNB_UE_context.h>
#include <openair3/ocp-gtpu/gtp_itf.h>
#include "UTIL/OSA/osa_defs.h"
#include <openair2/RRC/NR/nr_rrc_proto.h>
#include "nr_pdcp/nr_pdcp_oai_api.h"
void rrc_parse_ue_capabilities(gNB_RRC_INST *rrc, NR_UE_CapabilityRAT_ContainerList_t *UE_CapabilityRAT_ContainerList, x2ap_ENDC_sgnb_addition_req_t *m, NR_CG_ConfigInfo_IEs_t *cg_config_info)
{
OCTET_STRING_t *ueCapabilityRAT_Container_nr=NULL;
OCTET_STRING_t *ueCapabilityRAT_Container_MRDC=NULL;
asn_dec_rval_t dec_rval;
int list_size=0;
AssertFatal(UE_CapabilityRAT_ContainerList!=NULL,"UE_CapabilityRAT_ContainerList is null\n");
AssertFatal((list_size=UE_CapabilityRAT_ContainerList->list.count) >= 2, "UE_CapabilityRAT_ContainerList->list.size %d < 2\n",UE_CapabilityRAT_ContainerList->list.count);
for (int i=0; i<list_size; i++) {
if (UE_CapabilityRAT_ContainerList->list.array[i]->rat_Type == NR_RAT_Type_nr) ueCapabilityRAT_Container_nr = &UE_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container;
else if (UE_CapabilityRAT_ContainerList->list.array[i]->rat_Type == NR_RAT_Type_eutra_nr) ueCapabilityRAT_Container_MRDC = &UE_CapabilityRAT_ContainerList->list.array[i]->ue_CapabilityRAT_Container;
}
// decode and store capabilities
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_allocate_new_ue_context(rrc);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
if (ueCapabilityRAT_Container_nr != NULL) {
dec_rval = uper_decode(NULL, &asn_DEF_NR_UE_NR_Capability, (void **)&UE->UE_Capability_nr, ueCapabilityRAT_Container_nr->buf, ueCapabilityRAT_Container_nr->size, 0, 0);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
LOG_E(RRC, "Failed to decode UE NR capabilities (%zu bytes) container size %lu\n", dec_rval.consumed,ueCapabilityRAT_Container_nr->size);
ASN_STRUCT_FREE(asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr);
UE->UE_Capability_nr = 0;
AssertFatal(1==0,"exiting\n");
}
}
if (ueCapabilityRAT_Container_MRDC != NULL) {
dec_rval = uper_decode(NULL, &asn_DEF_NR_UE_MRDC_Capability, (void **)&UE->UE_Capability_MRDC, ueCapabilityRAT_Container_MRDC->buf, ueCapabilityRAT_Container_MRDC->size, 0, 0);
if ((dec_rval.code != RC_OK) && (dec_rval.consumed == 0)) {
LOG_E(RRC, "Failed to decode UE MRDC capabilities (%zu bytes)\n", dec_rval.consumed);
ASN_STRUCT_FREE(asn_DEF_NR_UE_MRDC_Capability, UE->UE_Capability_MRDC);
UE->UE_Capability_MRDC = 0;
AssertFatal(1==0,"exiting\n");
}
}
// dump ue_capabilities
if ( LOG_DEBUGFLAG(DEBUG_ASN1) && ueCapabilityRAT_Container_nr != NULL ) {
xer_fprint(stdout, &asn_DEF_NR_UE_NR_Capability, UE->UE_Capability_nr);
}
if ( LOG_DEBUGFLAG(DEBUG_ASN1) && ueCapabilityRAT_Container_MRDC != NULL ) {
xer_fprint(stdout, &asn_DEF_NR_UE_MRDC_Capability, UE->UE_Capability_MRDC);
}
LOG_A(NR_RRC, "Successfully decoded UE NR capabilities (NR and MRDC)\n");
UE->spCellConfig = calloc(1, sizeof(struct NR_SpCellConfig));
UE->spCellConfig->spCellConfigDedicated = rrc->carrier.servingcellconfig;
LOG_I(NR_RRC,"Adding new NSA user (%p)\n",ue_context_p);
rrc_add_nsa_user(rrc,ue_context_p, m);
}
/* 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);
void rrc_add_nsa_user(gNB_RRC_INST *rrc, rrc_gNB_ue_context_t *ue_context_p, x2ap_ENDC_sgnb_addition_req_t *m)
{
AssertFatal(!get_softmodem_params()->sa, "%s() cannot be called in SA mode, it is intrinsically for NSA\n", __func__);
// generate nr-Config-r15 containers for LTE RRC : inside message for X2 EN-DC (CG-Config Message from 38.331)
rrc_gNB_carrier_data_t *carrier=&rrc->carrier;
const gNB_RrcConfigurationReq *configuration = &rrc->configuration;
MessageDef *msg;
msg = itti_alloc_new_message(TASK_RRC_ENB, 0, X2AP_ENDC_SGNB_ADDITION_REQ_ACK);
gtpv1u_enb_create_tunnel_req_t create_tunnel_req;
gtpv1u_enb_create_tunnel_resp_t create_tunnel_resp;
protocol_ctxt_t ctxt={0};
unsigned char *kUPenc = NULL;
unsigned char *kUPint = NULL;
int i;
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
// In case of phy-test and do-ra mode, read UE capabilities directly from file
if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1) {
NR_UE_NR_Capability_t* UE_Capability_nr = NULL;
char UE_NR_Capability_xer[65536];
FILE *f = NULL;
if (uecap_file)
f = fopen(uecap_file, "r");
if(f){
size_t size = fread(UE_NR_Capability_xer, 1, sizeof UE_NR_Capability_xer, f);
if (size == 0 || size == sizeof UE_NR_Capability_xer)
LOG_E(NR_RRC,"UE Capabilities XER file %s is too large (%ld)\n", uecap_file, size);
else {
UE_Capability_nr = CALLOC(1,sizeof(NR_UE_NR_Capability_t));
asn_dec_rval_t dec_rval = xer_decode(0, &asn_DEF_NR_UE_NR_Capability, (void *)&UE_Capability_nr, UE_NR_Capability_xer, size);
assert(dec_rval.code == RC_OK);
xer_fprint(stdout,&asn_DEF_NR_UE_NR_Capability,(void *)UE_Capability_nr);
}
}
else
LOG_E(NR_RRC,"Could not open UE Capabilities input file. Not handling OAI UE Capabilities.\n");
UE->UE_Capability_nr = UE_Capability_nr;
}
// NR RRCReconfiguration
UE->reconfig = calloc(1, sizeof(NR_RRCReconfiguration_t));
UE->secondaryCellGroup = calloc(1, sizeof(NR_CellGroupConfig_t));
memset((void *)UE->reconfig, 0, sizeof(NR_RRCReconfiguration_t));
UE->reconfig->rrc_TransactionIdentifier = 0;
UE->reconfig->criticalExtensions.present = NR_RRCReconfiguration__criticalExtensions_PR_rrcReconfiguration;
NR_RRCReconfiguration_IEs_t *reconfig_ies=calloc(1,sizeof(NR_RRCReconfiguration_IEs_t));
UE->reconfig->criticalExtensions.choice.rrcReconfiguration = reconfig_ies;
UE->rb_config = calloc(1, sizeof(NR_RRCReconfiguration_t));
if (get_softmodem_params()->phy_test == 1 || get_softmodem_params()->do_ra == 1 || get_softmodem_params()->sa == 1){
fill_default_rbconfig(UE->rb_config, 10 /* EPS bearer ID */, 1 /* drb ID */, NR_CipheringAlgorithm_nea0, NR_SecurityConfig__keyToUse_master);
} else {
/* TODO: handle more than one bearer */
if (m == NULL) {
LOG_E(RRC, "fatal: m==NULL\n");
exit(1);
}
if (m->nb_e_rabs_tobeadded != 1) {
LOG_E(RRC, "fatal: m->nb_e_rabs_tobeadded = %d, should be 1\n", m->nb_e_rabs_tobeadded);
exit(1);
}
/* store security key and security capabilities */
memcpy(UE->kgnb, m->kgnb, 32);
UE->security_capabilities.nRencryption_algorithms = m->security_capabilities.encryption_algorithms;
UE->security_capabilities.nRintegrity_algorithms = m->security_capabilities.integrity_algorithms;
/* Select ciphering algorithm based on gNB configuration file and
* UE's supported algorithms.
* We take the first from the list that is supported by the UE.
* The ordering of the list comes from the configuration file.
*/
/* preset nea0 as fallback */
UE->ciphering_algorithm = 0;
for (i = 0; i < rrc->security.ciphering_algorithms_count; i++) {
int nea_mask[4] = {
0,
0x8000, /* nea1 */
0x4000, /* nea2 */
0x2000 /* nea3 */
};
if (rrc->security.ciphering_algorithms[i] == 0) {
/* nea0 already preselected */
break;
}
if (UE->security_capabilities.nRencryption_algorithms & nea_mask[rrc->security.ciphering_algorithms[i]]) {
UE->ciphering_algorithm = rrc->security.ciphering_algorithms[i];
break;
}
}
LOG_I(RRC, "selecting ciphering algorithm %d\n", (int)UE->ciphering_algorithm);
/* integrity: no integrity protection for DRB in ENDC mode
* as written in 38.331: "If UE is connected to E-UTRA/EPC, this field
* indicates the integrity protection algorithm to be used for SRBs
* configured with NR PDCP, as specified in TS 33.501"
* So nothing for DRB. Plus a test with a COTS UE revealed that it
* did not apply integrity on the DRB.
*/
UE->integrity_algorithm = 0;
LOG_I(RRC, "selecting integrity algorithm %d\n", UE->integrity_algorithm);
/* derive UP security key */
nr_derive_key_up_enc(UE->ciphering_algorithm, UE->kgnb, &kUPenc);
nr_derive_key_up_int(UE->integrity_algorithm, UE->kgnb, &kUPint);
e_NR_CipheringAlgorithm cipher_algo;
switch (UE->ciphering_algorithm) {
case 0:
cipher_algo = NR_CipheringAlgorithm_nea0;
break;
case 1:
cipher_algo = NR_CipheringAlgorithm_nea1;
break;
case 2:
cipher_algo = NR_CipheringAlgorithm_nea2;
break;
case 3:
cipher_algo = NR_CipheringAlgorithm_nea3;
break;
default:
LOG_E(RRC, "%s:%d:%s: fatal\n", __FILE__, __LINE__, __FUNCTION__);
exit(1);
}
fill_default_rbconfig(UE->rb_config, m->e_rabs_tobeadded[0].e_rab_id, m->e_rabs_tobeadded[0].drb_ID, cipher_algo, NR_SecurityConfig__keyToUse_secondary);
}
NR_ServingCellConfig_t *scc = UE->spCellConfig ? UE->spCellConfig->spCellConfigDedicated : NULL;
fill_default_reconfig(carrier->servingcellconfigcommon, scc, reconfig_ies, UE->secondaryCellGroup, UE->UE_Capability_nr, configuration, ue_context_p->ue_context.gNB_ue_ngap_id);
// the UE context is not yet inserted in the RRC UE manager
// rrc_gNB_update_ue_context_rnti(UE->secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity, rrc,
// UE->gNB_ue_ngap_id);
UE->rnti = UE->secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity;
NR_CG_Config_t *CG_Config = calloc(1,sizeof(*CG_Config));
memset((void *)CG_Config,0,sizeof(*CG_Config));
// int CG_Config_size = generate_CG_Config(rrc,CG_Config,UE->reconfig,UE->rb_config);
generate_CG_Config(rrc, CG_Config, UE->reconfig, UE->rb_config);
if(m!=NULL) {
uint8_t inde_list[m->nb_e_rabs_tobeadded];
memset(inde_list, 0, m->nb_e_rabs_tobeadded*sizeof(uint8_t));
if (m->nb_e_rabs_tobeadded>0) {
for (int i=0; i<m->nb_e_rabs_tobeadded; i++) {
// Add the new E-RABs at the corresponding rrc ue context of the gNB
UE->e_rab[i].param.e_rab_id = m->e_rabs_tobeadded[i].e_rab_id;
UE->e_rab[i].param.gtp_teid = m->e_rabs_tobeadded[i].gtp_teid;
memcpy(&UE->e_rab[i].param.sgw_addr, &m->e_rabs_tobeadded[i].sgw_addr, sizeof(transport_layer_addr_t));
UE->nb_of_e_rabs++;
//Fill the required E-RAB specific information for the creation of the S1-U tunnel between the gNB and the SGW
create_tunnel_req.eps_bearer_id[i] = UE->e_rab[i].param.e_rab_id;
create_tunnel_req.sgw_S1u_teid[i] = UE->e_rab[i].param.gtp_teid;
memcpy(&create_tunnel_req.sgw_addr[i], &UE->e_rab[i].param.sgw_addr, sizeof(transport_layer_addr_t));
inde_list[i] = i;
LOG_I(RRC,"S1-U tunnel: index %d target sgw ip %d.%d.%d.%d length %d gtp teid %u\n",
i,
create_tunnel_req.sgw_addr[i].buffer[0],
create_tunnel_req.sgw_addr[i].buffer[1],
create_tunnel_req.sgw_addr[i].buffer[2],
create_tunnel_req.sgw_addr[i].buffer[3],
create_tunnel_req.sgw_addr[i].length,
create_tunnel_req.sgw_S1u_teid[i]);
}
create_tunnel_req.rnti = ue_context_p->ue_context.rnti;
create_tunnel_req.num_tunnels = m->nb_e_rabs_tobeadded;
RB_INSERT(rrc_nr_ue_tree_s, &RC.nrrrc[rrc->module_id]->rrc_ue_head, ue_context_p);
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0, rrc->module_id);
memset(&create_tunnel_resp, 0, sizeof(create_tunnel_resp));
if (!IS_SOFTMODEM_NOS1) {
LOG_D(RRC, "Calling gtpv1u_create_s1u_tunnel()\n");
gtpv1u_create_s1u_tunnel(ctxt.instance, &create_tunnel_req, &create_tunnel_resp, nr_pdcp_data_req_drb);
rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(
&ctxt,
&create_tunnel_resp,
&inde_list[0]);
}
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).nb_e_rabs_admitted_tobeadded = m->nb_e_rabs_tobeadded;
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).target_assoc_id = m->target_assoc_id;
for (int i = 0; i < UE->nb_of_e_rabs; i++) {
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].e_rab_id = UE->e_rab[i].param.e_rab_id;
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gtp_teid = create_tunnel_resp.enb_S1u_teid[i];
memcpy(&X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr, &create_tunnel_resp.enb_addr, sizeof(transport_layer_addr_t));
//The length field in the X2AP targetting structure is expected in bits but the create_tunnel_resp returns the address length in bytes
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.length = create_tunnel_resp.enb_addr.length*8;
LOG_I(RRC,"S1-U create_tunnel_resp tunnel: index %d target gNB ip %d.%d.%d.%d length %d gtp teid %u\n",
i,
create_tunnel_resp.enb_addr.buffer[0],
create_tunnel_resp.enb_addr.buffer[1],
create_tunnel_resp.enb_addr.buffer[2],
create_tunnel_resp.enb_addr.buffer[3],
create_tunnel_resp.enb_addr.length,
create_tunnel_resp.enb_S1u_teid[i]);
LOG_I(RRC,"X2AP sGNB Addition Request: index %d target gNB ip %d.%d.%d.%d length %d gtp teid %u\n",
i,
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[0],
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[1],
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[2],
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.buffer[3],
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gnb_addr.length,
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).e_rabs_admitted_tobeadded[i].gtp_teid);
}
} else
LOG_W(RRC, "No E-RAB to be added received from SgNB Addition Request message \n");
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).MeNB_ue_x2_id = m->ue_x2_id;
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).SgNB_ue_x2_id = UE->secondaryCellGroup->spCellConfig->reconfigurationWithSync->newUE_Identity;
//X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = CG_Config_size; //Need to verify correct value for the buffer_size
// Send to X2 entity to transport to MeNB
asn_enc_rval_t enc_rval = uper_encode_to_buffer(&asn_DEF_NR_CG_Config,
NULL,
(void *)CG_Config,
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer,
sizeof(X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer));
X2AP_ENDC_SGNB_ADDITION_REQ_ACK(msg).rrc_buffer_size = (enc_rval.encoded+7)>>3;
itti_send_msg_to_task(TASK_X2AP, ENB_MODULE_ID_TO_INSTANCE(0), msg); //Check right id instead of hardcoding
}
// configure MAC and RLC
bool ret = false;
if (get_softmodem_params()->phy_test) {
// phytest mode: we don't set up RA, etc
ret = nr_mac_add_test_ue(RC.nrmac[rrc->module_id] , ue_context_p->ue_context.rnti, ue_context_p->ue_context.secondaryCellGroup);
} else {
ret = nr_mac_prepare_ra_nsa_ue(RC.nrmac[rrc->module_id], ue_context_p->ue_context.rnti, ue_context_p->ue_context.secondaryCellGroup);
}
AssertFatal(ret, "cannot add NSA UE in MAC, aborting\n");
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0, rrc->module_id);
if (get_softmodem_params()->do_ra) ctxt.enb_flag = 0;
LOG_W(RRC,
"Calling RRC PDCP/RLC ASN1 request functions for protocol context %p with module_id %d, rnti %lx, frame %d, subframe %d eNB_index %d \n",
&ctxt,
ctxt.module_id,
ctxt.rntiMaybeUEid,
ctxt.frame,
ctxt.subframe,
ctxt.eNB_index);
nr_pdcp_add_drbs(ctxt.enb_flag,
ctxt.rntiMaybeUEid,
0,
ue_context_p->ue_context.rb_config->drb_ToAddModList,
(ue_context_p->ue_context.integrity_algorithm << 4) | ue_context_p->ue_context.ciphering_algorithm,
kUPenc,
kUPint,
ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList);
// assume only a single bearer
const NR_DRB_ToAddModList_t *drb_list = ue_context_p->ue_context.rb_config->drb_ToAddModList;
DevAssert(drb_list->list.count == 1);
const NR_DRB_ToAddMod_t *drb = drb_list->list.array[0];
const struct NR_CellGroupConfig__rlc_BearerToAddModList *bearer_list =
ue_context_p->ue_context.secondaryCellGroup->rlc_BearerToAddModList;
const NR_RLC_BearerConfig_t *bearer = bearer_list->list.array[0];
DevAssert(bearer_list->list.count == 1);
DevAssert(drb->drb_Identity == bearer->servedRadioBearer->choice.drb_Identity);
nr_rlc_add_drb(ctxt.rntiMaybeUEid, drb->drb_Identity, bearer);
LOG_D(RRC, "%s:%d: done RRC PDCP/RLC ASN1 request for UE rnti %lx\n", __FUNCTION__, __LINE__, ctxt.rntiMaybeUEid);
}
void rrc_remove_nsa_user(gNB_RRC_INST *rrc, int rnti) {
protocol_ctxt_t ctxt;
rrc_gNB_ue_context_t *ue_context;
int e_rab;
LOG_D(RRC, "calling rrc_remove_nsa_user rnti %d\n", rnti);
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, rrc->module_id, GNB_FLAG_YES, rnti, 0, 0, rrc->module_id);
ue_context = rrc_gNB_get_ue_context_by_rnti(rrc, rnti);
if (ue_context == NULL) {
LOG_W(RRC, "rrc_remove_nsa_user: rnti %d not found\n", rnti);
return;
}
nr_pdcp_remove_UE(ctxt.rntiMaybeUEid);
rrc_rlc_remove_ue(&ctxt);
// WHAT A RACE CONDITION
mac_remove_nr_ue(RC.nrmac[rrc->module_id], rnti);
gtpv1u_enb_delete_tunnel_req_t tmp={0};
tmp.rnti=rnti;
tmp.from_gnb=1;
LOG_D(RRC, "ue_context->ue_context.nb_of_e_rabs %d will be deleted for rnti %d\n", ue_context->ue_context.nb_of_e_rabs, rnti);
for (e_rab = 0; e_rab < ue_context->ue_context.nb_of_e_rabs; e_rab++) {
tmp.eps_bearer_id[tmp.num_erab++]= ue_context->ue_context.gnb_gtp_ebi[e_rab];
// erase data
ue_context->ue_context.gnb_gtp_teid[e_rab] = 0;
memset(&ue_context->ue_context.gnb_gtp_addrs[e_rab], 0, sizeof(ue_context->ue_context.gnb_gtp_addrs[e_rab]));
ue_context->ue_context.gnb_gtp_ebi[e_rab] = 0;
}
gtpv1u_delete_s1u_tunnel(rrc->module_id, &tmp);
/* remove context */
rrc_gNB_remove_ue_context(rrc, ue_context);
}