Files
openairinterface5g/openair2/RRC/NR/cucp_cuup_direct.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

220 lines
9.7 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:
* conmnc_digit_lengtht@openairinterface.org
*/
#include <arpa/inet.h>
#include "cucp_cuup_if.h"
#include "platform_types.h"
#include "nr_rrc_defs.h"
#include "softmodem-common.h"
#include "nr_rrc_proto.h"
#include "nr_rrc_extern.h"
#include "openair2/COMMON/e1ap_messages_types.h"
#include "UTIL/OSA/osa_defs.h"
#include "nr_pdcp/nr_pdcp_entity.h"
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h"
#include <openair2/RRC/NR/rrc_gNB_UE_context.h>
#include "openair3/ocp-gtpu/gtp_itf.h"
#include "rrc_gNB_GTPV1U.h"
#include "common/ran_context.h"
#include "openair2/F1AP/f1ap_common.h"
#include "openair2/E1AP/e1ap_common.h"
extern RAN_CONTEXT_t RC;
void fill_e1ap_bearer_setup_resp(e1ap_bearer_setup_resp_t *resp,
e1ap_bearer_setup_req_t *const req,
instance_t gtpInst,
ue_id_t ue_id,
int remote_port,
in_addr_t my_addr) {
resp->numPDUSessions = req->numPDUSessions;
transport_layer_addr_t dummy_address = {0};
dummy_address.length = 32; // IPv4
for (int i=0; i < req->numPDUSessions; i++) {
resp->pduSession[i].numDRBSetup = req->pduSession[i].numDRB2Setup;
for (int j=0; j < req->pduSession[i].numDRB2Setup; j++) {
DRB_nGRAN_to_setup_t *drb2Setup = req->pduSession[i].DRBnGRanList + j;
DRB_nGRAN_setup_t *drbSetup = resp->pduSession[i].DRBnGRanList + j;
drbSetup->numUpParam = 1;
drbSetup->UpParamList[0].tlAddress = my_addr;
drbSetup->UpParamList[0].teId = newGtpuCreateTunnel(gtpInst,
(ue_id & 0xFFFF),
drb2Setup->id,
drb2Setup->id,
0xFFFF, // We will set the right value from DU answer
-1, // no qfi
dummy_address, // We will set the right value from DU answer
remote_port,
cu_f1u_data_req,
NULL);
drbSetup->id = drb2Setup->id;
drbSetup->numQosFlowSetup = drb2Setup->numQosFlow2Setup;
for (int k=0; k < drbSetup->numQosFlowSetup; k++) {
drbSetup->qosFlows[k].id = drb2Setup->qosFlows[k].id;
}
}
}
}
void CU_update_UP_DL_tunnel(e1ap_bearer_setup_req_t *const req, instance_t instance, ue_id_t ue_id) {
for (int i=0; i < req->numPDUSessionsMod; i++) {
for (int j=0; j < req->pduSessionMod[i].numDRB2Modify; j++) {
DRB_nGRAN_to_setup_t *drb_p = req->pduSessionMod[i].DRBnGRanModList + j;
transport_layer_addr_t newRemoteAddr;
newRemoteAddr.length = 32; // IPv4
memcpy(newRemoteAddr.buffer,
&drb_p->DlUpParamList[0].tlAddress,
sizeof(in_addr_t));
GtpuUpdateTunnelOutgoingAddressAndTeid(instance,
(ue_id & 0xFFFF),
(ebi_t)drb_p->id,
*(in_addr_t*)&newRemoteAddr.buffer,
drb_p->DlUpParamList[0].teId);
}
}
}
static int drb_config_gtpu_create(const protocol_ctxt_t *const ctxt_p,
rrc_gNB_ue_context_t *ue_context_p,
e1ap_bearer_setup_req_t *const req,
NR_DRB_ToAddModList_t *DRB_configList,
NR_SRB_ToAddModList_t *SRB_configList,
instance_t instance) {
gtpv1u_gnb_create_tunnel_req_t create_tunnel_req={0};
gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp={0};
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
LOG_W(NR_RRC, "recreate existing tunnels, while adding new ones\n");
for (int i = 0; i < UE->nb_of_pdusessions; i++) {
rrc_pdu_session_param_t *pdu = UE->pduSession + i;
create_tunnel_req.pdusession_id[i] = pdu->param.pdusession_id;
create_tunnel_req.incoming_rb_id[i] = i + 1;
create_tunnel_req.outgoing_qfi[i] = req->pduSession[i].DRBnGRanList[0].qosFlows[0].id;
memcpy(&create_tunnel_req.dst_addr[i].buffer, &pdu->param.upf_addr.buffer, sizeof(create_tunnel_req.dst_addr[0].buffer));
create_tunnel_req.dst_addr[i].length = pdu->param.upf_addr.length;
create_tunnel_req.outgoing_teid[i] = pdu->param.gtp_teid;
}
create_tunnel_req.num_tunnels = UE->nb_of_pdusessions;
create_tunnel_req.ue_id = UE->rnti;
int ret = gtpv1u_create_ngu_tunnel(getCxtE1(instance)->gtpInstN3,
&create_tunnel_req,
&create_tunnel_resp,
nr_pdcp_data_req_drb,
sdap_data_req);
if (ret != 0) {
LOG_E(NR_RRC,"rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ : gtpv1u_create_ngu_tunnel failed,start to release UE rnti %ld\n",
create_tunnel_req.ue_id);
return ret;
}
nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(ctxt_p, &create_tunnel_resp, 0);
uint8_t *kRRCenc = NULL;
uint8_t *kRRCint = NULL;
uint8_t *kUPenc = NULL;
uint8_t *kUPint = NULL;
/* Derive the keys from kgnb */
if (DRB_configList != NULL) {
nr_derive_key_up_enc(UE->ciphering_algorithm, UE->kgnb, &kUPenc);
nr_derive_key_up_int(UE->integrity_algorithm, UE->kgnb, &kUPint);
}
nr_derive_key_rrc_enc(UE->ciphering_algorithm, UE->kgnb, &kRRCenc);
nr_derive_key_rrc_int(UE->integrity_algorithm, UE->kgnb, &kRRCint);
/* Refresh SRBs/DRBs */
LOG_D(NR_RRC, "Configuring PDCP DRBs/SRBs for UE %x\n", UE->rnti);
nr_pdcp_add_srbs(ctxt_p->enb_flag, ctxt_p->rntiMaybeUEid, SRB_configList, (UE->integrity_algorithm << 4) | UE->ciphering_algorithm, kRRCenc, kRRCint);
nr_pdcp_add_drbs(ctxt_p->enb_flag,
ctxt_p->rntiMaybeUEid,
0,
DRB_configList,
(UE->integrity_algorithm << 4) | UE->ciphering_algorithm,
kUPenc,
kUPint,
get_softmodem_params()->sa ? UE->masterCellGroup->rlc_BearerToAddModList : NULL);
return ret;
}
static NR_SRB_ToAddModList_t **generateSRB2_confList(gNB_RRC_UE_t *ue, NR_SRB_ToAddModList_t *SRB_configList, uint8_t xid)
{
NR_SRB_ToAddModList_t **SRB_configList2 = NULL;
SRB_configList2 = &ue->SRB_configList2[xid];
if (*SRB_configList2 == NULL) {
*SRB_configList2 = CALLOC(1, sizeof(**SRB_configList2));
NR_SRB_ToAddMod_t *SRB2_config = CALLOC(1, sizeof(*SRB2_config));
SRB2_config->srb_Identity = 2;
asn1cSeqAdd(&(*SRB_configList2)->list, SRB2_config);
asn1cSeqAdd(&SRB_configList->list, SRB2_config);
}
return SRB_configList2;
}
static void cucp_cuup_bearer_context_setup_direct(e1ap_bearer_setup_req_t *const req, instance_t instance) {
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context_by_rnti(RC.nrrrc[instance], req->rnti);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
protocol_ctxt_t ctxt = {0};
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, GNB_FLAG_YES, UE->rnti, 0, 0, 0);
fill_DRB_configList(&ctxt, ue_context_p);
gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id];
// Fixme: xid not random, but almost!
NR_SRB_ToAddModList_t **SRB_configList2 = generateSRB2_confList(UE, UE->SRB_configList, UE->pduSession[0].xid);
// GTP tunnel for UL
int ret = drb_config_gtpu_create(&ctxt, ue_context_p, req, UE->DRB_configList, *SRB_configList2, rrc->e1_inst);
if (ret < 0) AssertFatal(false, "Unable to configure DRB or to create GTP Tunnel\n");
if(!NODE_IS_CU(RC.nrrrc[ctxt.module_id]->node_type)) {
rrc_gNB_generate_dedicatedRRCReconfiguration(&ctxt, ue_context_p, NULL);
} else {
e1ap_bearer_setup_resp_t resp; // Used to store teids
int remote_port = RC.nrrrc[ctxt.module_id]->eth_params_s.remote_portd;
in_addr_t my_addr = inet_addr(RC.nrrrc[ctxt.module_id]->eth_params_s.my_addr);
instance_t gtpInst = getCxt(CUtype, instance)->gtpInst;
// GTP tunnel for DL
fill_e1ap_bearer_setup_resp(&resp, req, gtpInst, UE->rnti, remote_port, my_addr);
prepare_and_send_ue_context_modification_f1(ue_context_p, &resp);
}
}
static void cucp_cuup_bearer_context_mod_direct(e1ap_bearer_setup_req_t *const req, instance_t instance) {
instance_t gtpInst = getCxt(CUtype, instance)->gtpInst;
CU_update_UP_DL_tunnel(req, gtpInst, req->rnti);
}
void cucp_cuup_message_transfer_direct_init(gNB_RRC_INST *rrc) {
rrc->cucp_cuup.bearer_context_setup = cucp_cuup_bearer_context_setup_direct;
rrc->cucp_cuup.bearer_context_mod = cucp_cuup_bearer_context_mod_direct;
}