Files
openairinterface5g/openair2/E1AP/e1ap_api.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

194 lines
8.2 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
*
* Author and copyright: Laurent Thomas, open-cells.com
*
* 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 <arpa/inet.h>
#include "e1ap_api.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/cucp_cuup_if.h"
#include "openair2/RRC/LTE/MESSAGES/asn1_msg.h"
#include "openair3/ocp-gtpu/gtp_itf.h"
#include "e1ap_asnc.h"
#include "e1ap_common.h"
#include "e1ap.h"
struct NR_DRB_ToAddMod;
static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, pdu_session_to_setup_t *pdu) {
for (int i=0; i < pdu->numDRB2Setup; i++) {
DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + i;
asn1cSequenceAdd(DRB_configList->list, struct NR_DRB_ToAddMod, ie);
ie->drb_Identity = drb->id;
ie->cnAssociation = CALLOC(1, sizeof(*ie->cnAssociation));
ie->cnAssociation->present = NR_DRB_ToAddMod__cnAssociation_PR_sdap_Config;
// sdap_Config
asn1cCalloc(ie->cnAssociation->choice.sdap_Config, sdap_config);
sdap_config->pdu_Session = pdu->sessionId;
sdap_config->sdap_HeaderDL = drb->sDAP_Header_DL;
sdap_config->sdap_HeaderUL = drb->sDAP_Header_UL;
sdap_config->defaultDRB = drb->defaultDRB;
asn1cCalloc(sdap_config->mappedQoS_FlowsToAdd, FlowsToAdd);
for (int j=0; j < drb->numQosFlow2Setup; j++) {
asn1cSequenceAdd(FlowsToAdd->list, NR_QFI_t, qfi);
*qfi = drb->qosFlows[j].fiveQI;
}
sdap_config->mappedQoS_FlowsToRelease = NULL;
// pdcp_Config
ie->reestablishPDCP = NULL;
ie->recoverPDCP = NULL;
asn1cCalloc(ie->pdcp_Config, pdcp_config);
asn1cCalloc(pdcp_config->drb, drbCfg);
asn1cCallocOne(drbCfg->discardTimer, drb->discardTimer);
asn1cCallocOne(drbCfg->pdcp_SN_SizeUL, drb->pDCP_SN_Size_UL);
asn1cCallocOne(drbCfg->pdcp_SN_SizeDL, drb->pDCP_SN_Size_DL);
drbCfg->headerCompression.present = NR_PDCP_Config__drb__headerCompression_PR_notUsed;
drbCfg->headerCompression.choice.notUsed = 0;
drbCfg->integrityProtection = NULL;
drbCfg->statusReportRequired = NULL;
drbCfg->outOfOrderDelivery = NULL;
pdcp_config->moreThanOneRLC = NULL;
pdcp_config->t_Reordering = calloc(1, sizeof(*pdcp_config->t_Reordering));
*pdcp_config->t_Reordering = drb->reorderingTimer;
pdcp_config->ext1 = NULL;
if (pdu->integrityProtectionIndication == 0 || // Required
pdu->integrityProtectionIndication == 1) { // Preferred
asn1cCallocOne(drbCfg->integrityProtection, NR_PDCP_Config__drb__integrityProtection_enabled);
}
if (pdu->confidentialityProtectionIndication == 0 || // Required
pdu->confidentialityProtectionIndication == 1) { // Preferred
asn1cCalloc(pdcp_config->ext1, ext1);
asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true);
}
}
}
static int drb_config_N3gtpu_create(e1ap_bearer_setup_req_t * const req,
gtpv1u_gnb_create_tunnel_resp_t *create_tunnel_resp,
instance_t instance) {
gtpv1u_gnb_create_tunnel_req_t create_tunnel_req={0};
NR_DRB_ToAddModList_t DRB_configList = {0};
for (int i=0; i < req->numPDUSessions; i++) {
pdu_session_to_setup_t *const pdu = &req->pduSession[i];
create_tunnel_req.pdusession_id[i] = pdu->sessionId;
create_tunnel_req.incoming_rb_id[i] = pdu->DRBnGRanList[0].id; // taking only the first DRB. TODO:change this
memcpy(&create_tunnel_req.dst_addr[i].buffer,
&pdu->tlAddress,
sizeof(uint8_t)*4);
create_tunnel_req.dst_addr[i].length = 32; // 8bits * 4bytes
create_tunnel_req.outgoing_teid[i] = pdu->teId;
fill_DRB_configList_e1(&DRB_configList, pdu);
}
create_tunnel_req.num_tunnels = req->numPDUSessions;
create_tunnel_req.ue_id = (req->gNB_cu_cp_ue_id & 0xFFFF);
// Create N3 tunnel
int ret = gtpv1u_create_ngu_tunnel(instance, &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 id %ld\n",
create_tunnel_req.ue_id);
return ret;
}
// Configure DRBs
uint8_t *kUPenc = NULL;
uint8_t *kUPint = NULL;
nr_derive_key(UP_ENC_ALG, req->cipheringAlgorithm, (uint8_t *)req->encryptionKey, &kUPenc);
nr_derive_key(UP_INT_ALG, req->integrityProtectionAlgorithm, (uint8_t *)req->integrityProtectionKey, &kUPint);
nr_pdcp_e1_add_drbs(true, // set this to notify PDCP that his not UE
create_tunnel_req.ue_id,
&DRB_configList,
(req->integrityProtectionAlgorithm << 4) | req->cipheringAlgorithm,
kUPenc,
kUPint);
return ret;
}
void process_e1_bearer_context_setup_req(instance_t instance, e1ap_bearer_setup_req_t *const req)
{
e1ap_upcp_inst_t *inst = getCxtE1(instance);
AssertFatal(inst, "");
gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp_N3={0};
// GTP tunnel for UL
drb_config_N3gtpu_create(req, &create_tunnel_resp_N3, inst->gtpInstN3);
MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_RESP);
e1ap_bearer_setup_resp_t *resp = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg);
in_addr_t my_addr;
if (inet_pton(AF_INET, inst->setupReq.localAddressF1U, &my_addr) != 1)
LOG_E(E1AP, "can't use the F1-U local interface: %s\n", inst->setupReq.localAddressF1U);
fill_e1ap_bearer_setup_resp(resp, req, inst->gtpInstF1U, req->gNB_cu_cp_ue_id, inst->setupReq.remotePortF1U, my_addr);
resp->gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id;
resp->numPDUSessions = req->numPDUSessions;
for (int i=0; i < req->numPDUSessions; i++) {
pdu_session_setup_t *pduSetup = resp->pduSession + i;
pdu_session_to_setup_t *pdu2Setup = req->pduSession + i;
pduSetup->id = pdu2Setup->sessionId;
if (inet_pton(AF_INET, inst->setupReq.localAddressN3, &pduSetup->tlAddress) != 1)
LOG_E(E1AP, "can't use the N3 local interface: %s\n", inst->setupReq.localAddressN3);
pduSetup->teId = create_tunnel_resp_N3.gnb_NGu_teid[i];
pduSetup->numDRBSetup = pdu2Setup->numDRB2Setup;
// At this point we don't have a way to know the DRBs that failed to setup
// We assume all DRBs to setup have are setup successfully so we always send successful outcome in response
// TODO: Modify nr_pdcp_add_drbs() to return DRB list that failed to setup to support E1AP
pduSetup->numDRBFailed = 0;
}
e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(inst, resp);
}
void CUUP_process_bearer_context_mod_req(instance_t instance, e1ap_bearer_setup_req_t *const req)
{
e1ap_upcp_inst_t *inst = getCxtE1(instance);
AssertFatal(inst, "");
// assume we receive modification of F1-U but it is wrong, we can also get modification of N3 when HO will occur
CU_update_UP_DL_tunnel(req, inst->gtpInstF1U, req->gNB_cu_cp_ue_id);
// TODO: send bearer cxt mod response
}
void CUUP_process_bearer_release_command(instance_t instance, e1ap_bearer_release_cmd_t *const cmd)
{
e1ap_upcp_inst_t *inst = getCxtE1(instance);
AssertFatal(inst, "");
newGtpuDeleteAllTunnels(inst->gtpInstN3, cmd->gNB_cu_up_ue_id);
newGtpuDeleteAllTunnels(inst->gtpInstF1U, cmd->gNB_cu_up_ue_id);
e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(inst, cmd);
}