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.
412 lines
20 KiB
C
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);
|
|
}
|