Merge remote-tracking branch 'origin/e1-multiple-cuup' into integration_2023_w43

This commit is contained in:
Robert Schmidt
2023-10-30 10:21:48 +01:00
61 changed files with 1457 additions and 1023 deletions
+6
View File
@@ -20,6 +20,9 @@
*/
/* gNB_CUUP application layer -> E1AP messages */
MESSAGE_DEF(E1AP_REGISTER_REQ, MESSAGE_PRIORITY_MED, e1ap_register_req_t, e1ap_register_req)
/* E1AP messages -> RRC (CU-CP) */
MESSAGE_DEF(E1AP_SETUP_REQ , MESSAGE_PRIORITY_MED , e1ap_setup_req_t , e1ap_setup_req)
/* E1AP -> eNB_DU or eNB_CU_RRC -> E1AP application layer messages */
@@ -30,4 +33,7 @@ MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_REQ , MESSAGE_PRIORITY_MED , e1ap_bearer_s
MESSAGE_DEF(E1AP_BEARER_CONTEXT_SETUP_RESP , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_resp_t , e1ap_bearer_setup_resp)
MESSAGE_DEF(E1AP_BEARER_CONTEXT_MODIFICATION_REQ , MESSAGE_PRIORITY_MED , e1ap_bearer_setup_req_t , e1ap_bearer_mod_req)
MESSAGE_DEF(E1AP_BEARER_CONTEXT_MODIFICATION_RESP, MESSAGE_PRIORITY_MED, e1ap_bearer_modif_resp_t, e1ap_bearer_modif_resp)
MESSAGE_DEF(E1AP_BEARER_CONTEXT_RELEASE_CMD, MESSAGE_PRIORITY_MED, e1ap_bearer_release_cmd_t, e1ap_bearer_release_cmd)
MESSAGE_DEF(E1AP_BEARER_CONTEXT_RELEASE_CPLT, MESSAGE_PRIORITY_MED, e1ap_bearer_release_cplt_t, e1ap_bearer_release_cplt)
+51 -23
View File
@@ -32,6 +32,7 @@
#define E1AP_MAX_NUM_TRANSAC_IDS 4
#define E1AP_MAX_NUM_PLMNS 4
#define E1AP_MAX_NUM_SLICES 1024
#define E1AP_MAX_NUM_CELL_GROUPS 4
#define E1AP_MAX_NUM_QOS_FLOWS 4
#define E1AP_MAX_NUM_NGRAN_DRB 4
@@ -40,11 +41,15 @@
#define E1AP_MAX_NUM_DRBS 4
#define E1AP_MAX_NUM_UP_PARAM 4
#define E1AP_REGISTER_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_register_req
#define E1AP_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_req
#define E1AP_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_setup_resp
#define E1AP_BEARER_CONTEXT_SETUP_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_req
#define E1AP_BEARER_CONTEXT_SETUP_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_resp
#define E1AP_BEARER_CONTEXT_MODIFICATION_REQ(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_setup_req
#define E1AP_BEARER_CONTEXT_MODIFICATION_RESP(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_modif_resp
#define E1AP_BEARER_CONTEXT_RELEASE_CMD(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_release_cmd
#define E1AP_BEARER_CONTEXT_RELEASE_CPLT(mSGpTR) (mSGpTR)->ittiMsg.e1ap_bearer_release_cplt
typedef f1ap_net_ip_address_t e1ap_net_ip_address_t;
@@ -54,27 +59,39 @@ typedef struct PLMN_ID_s {
int mnc_digit_length;
} PLMN_ID_t;
typedef struct e1ap_setup_req_s {
uint64_t gNB_cu_up_id;
char * gNB_cu_up_name;
sctp_assoc_t assoc_id;
uint64_t transac_id;
int supported_plmns;
PLMN_ID_t plmns[E1AP_MAX_NUM_PLMNS];
uint16_t sctp_in_streams;
uint16_t sctp_out_streams;
uint16_t default_sctp_stream_id;
typedef struct e1ap_nssai_t {
uint8_t sst;
uint32_t sd; // optional: "No SD" is 0xffffff, see 23.003 Sec 28.4.2
} e1ap_nssai_t;
typedef struct e1ap_net_config_t {
net_ip_address_t CUUP_e1_ip_address;
net_ip_address_t CUCP_e1_ip_address;
long cn_support;
uint16_t remotePortF1U;
char* localAddressF1U;
uint16_t localPortF1U;
char* localAddressN3;
uint16_t localPortN3;
uint16_t remotePortN3;
} e1ap_net_config_t;
typedef struct e1ap_setup_req_s {
uint64_t gNB_cu_up_id;
char * gNB_cu_up_name;
uint64_t transac_id;
int supported_plmns;
struct {
PLMN_ID_t id;
int supported_slices;
e1ap_nssai_t *slice;
} plmn[E1AP_MAX_NUM_PLMNS];
} e1ap_setup_req_t;
typedef struct e1ap_register_req_t {
e1ap_setup_req_t setup_req;
e1ap_net_config_t net_config;
} e1ap_register_req_t;
typedef struct e1ap_setup_resp_s {
long transac_id;
} e1ap_setup_resp_t;
@@ -140,7 +157,7 @@ typedef struct DRB_nGRAN_to_setup_s {
typedef struct pdu_session_to_setup_s {
long sessionId;
long sessionType;
int8_t sst;
e1ap_nssai_t nssai;
long integrityProtectionIndication;
long confidentialityProtectionIndication;
in_addr_t tlAddress;
@@ -165,8 +182,6 @@ typedef struct e1ap_bearer_setup_req_s {
long ueDlAggMaxBitRate;
PLMN_ID_t servingPLMNid;
long activityNotificationLevel;
int numDRBs;
drb_to_setup_t DRBList[E1AP_MAX_NUM_DRBS];
int numPDUSessions;
pdu_session_to_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS];
int numPDUSessionsMod;
@@ -180,13 +195,10 @@ typedef struct e1ap_bearer_release_cmd_s {
long cause;
} e1ap_bearer_release_cmd_t;
typedef struct drb_setup_s {
int drbId;
in_addr_t tlAddress;
int teId;
int numUpParam;
up_params_t UpParamList[E1AP_MAX_NUM_UP_PARAM];
} drb_setup_t;
typedef struct e1ap_bearer_release_cplt_s {
uint32_t gNB_cu_cp_ue_id;
uint32_t gNB_cu_up_ue_id;
} e1ap_bearer_release_cplt_t;
typedef struct qos_flow_setup_s {
long id;
@@ -200,6 +212,10 @@ typedef struct DRB_nGRAN_setup_s {
qos_flow_setup_t qosFlows[E1AP_MAX_NUM_QOS_FLOWS];
} DRB_nGRAN_setup_t;
typedef struct DRB_nGRAN_modified_s {
long id;
} DRB_nGRAN_modified_t;
typedef struct DRB_nGRAN_failed_s {
long id;
long cause_type;
@@ -216,13 +232,25 @@ typedef struct pdu_session_setup_s {
DRB_nGRAN_failed_t DRBnGRanFailedList[E1AP_MAX_NUM_NGRAN_DRB];
} pdu_session_setup_t;
typedef struct pdu_session_modif_s {
long id;
// setup as part of PDU session modification not supported yet
int numDRBModified;
DRB_nGRAN_modified_t DRBnGRanModList[E1AP_MAX_NUM_NGRAN_DRB];
} pdu_session_modif_t;
typedef struct e1ap_bearer_setup_resp_s {
uint32_t gNB_cu_cp_ue_id;
uint32_t gNB_cu_up_ue_id;
int numDRBs;
drb_setup_t DRBList[E1AP_MAX_NUM_DRBS];
int numPDUSessions;
pdu_session_setup_t pduSession[E1AP_MAX_NUM_PDU_SESSIONS];
} e1ap_bearer_setup_resp_t;
typedef struct e1ap_bearer_modif_resp_s {
uint32_t gNB_cu_cp_ue_id;
uint32_t gNB_cu_up_ue_id;
int numPDUSessionsMod;
pdu_session_modif_t pduSessionMod[E1AP_MAX_NUM_PDU_SESSIONS];
} e1ap_bearer_modif_resp_t;
#endif /* E1AP_MESSAGES_TYPES_H */
+1 -1
View File
@@ -403,13 +403,13 @@ typedef struct NbIoTRrcConfigurationReq_s {
// gNB: GNB_APP -> RRC messages
typedef struct NRRrcConfigurationReq_s {
uint64_t cell_identity;
uint32_t tac;
uint16_t mcc[PLMN_LIST_MAX_SIZE];
uint16_t mnc[PLMN_LIST_MAX_SIZE];
uint8_t mnc_digit_length[PLMN_LIST_MAX_SIZE];
uint8_t num_plmn;
bool um_on_default_drb;
bool enable_sdap;
int drbs;
} gNB_RrcConfigurationReq;
+2 -2
View File
@@ -1,7 +1,7 @@
add_subdirectory(MESSAGES)
add_library(e1ap e1ap.c e1ap_common.c e1ap_api.c)
add_library(e1ap e1ap.c e1ap_common.c)
target_link_libraries(e1ap
PUBLIC asn1_e1ap f1ap
PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap UTIL e1_pdcp_if e1_if)
PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap UTIL e1_if)
target_include_directories(e1ap PUBLIC ${CMAKE_CURRENT_DIR})
+366 -165
View File
File diff suppressed because it is too large Load Diff
+13 -11
View File
@@ -28,27 +28,29 @@
#include "e1ap_asnc.h"
#include "openair2/E1AP/e1ap_common.h"
int e1apCUCP_handle_SETUP_REQUEST(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUCP_handle_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_SETUP_FAILURE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUCP_handle_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_BEARER_CONTEXT_MODIFICATION_REQUEST(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_upcp_inst_t *inst, e1ap_bearer_setup_resp_t *const resp);
int e1apCUCP_handle_BEARER_CONTEXT_MODIFICATION_RESPONSE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *e1_inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_bearer_setup_resp_t *resp);
int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(e1ap_upcp_inst_t *inst, e1ap_bearer_release_cmd_t *const cmd);
int e1apCUCP_handle_BEARER_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
int e1apCUUP_send_BEARER_CONTEXT_RELEASE_COMPLETE(sctp_assoc_t assoc_id, const e1ap_bearer_release_cplt_t *cplt);
void *E1AP_CUUP_task(void *arg);
-194
View File
@@ -1,194 +0,0 @@
/*
* 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 "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/SECU/key_nas_deriver.h"
#include "openair3/ocp-gtpu/gtp_itf.h"
#include "openair2/F1AP/f1ap_ids.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 == 2) { // Not Needed
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;
// 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,
"drb_config_N3gtpu_create=>gtpv1u_create_ngu_tunnel failed, cannot set up GTP tunnel for data transmissions of UE %ld\n",
create_tunnel_req.ue_id);
return ret;
}
// Configure DRBs
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,
(uint8_t *)req->encryptionKey,
(uint8_t *)req->integrityProtectionKey);
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};
uint32_t gNB_cu_up_ue_id = req ->gNB_cu_cp_ue_id;
LOG_I(E1AP, "adding UE with CU-CP UE ID %d and CU-UP UE ID %d\n", req->gNB_cu_cp_ue_id, gNB_cu_up_ue_id);
f1_ue_data_t ue_data = {.secondary_ue = req->gNB_cu_cp_ue_id};
cu_add_f1_ue_data(gNB_cu_up_ue_id, &ue_data);
// 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->gNB_cu_up_ue_id = gNB_cu_up_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);
}
+6
View File
@@ -47,10 +47,14 @@
#include <E1AP_DRB-Failed-Item-NG-RAN.h>
#include <E1AP_BearerContextSetupResponse.h>
#include <E1AP_BearerContextSetupRequest.h>
#include <E1AP_DRB-Modified-Item-NG-RAN.h>
#include <E1AP_DRB-Modified-List-NG-RAN.h>
#include <E1AP_DRB-To-Setup-Item-EUTRAN.h>
#include <E1AP_DRB-To-Setup-Item-NG-RAN.h>
#include <E1AP_Cell-Group-Information-Item.h>
#include <E1AP_PDU-Session-Resource-To-Setup-Item.h>
#include <E1AP_PDU-Session-Resource-Modified-Item.h>
#include <E1AP_PDU-Session-Resource-Modified-List.h>
#include <E1AP_PDU-Session-Resource-To-Modify-List.h>
#include <E1AP_PDU-Session-Resource-To-Modify-Item.h>
#include <E1AP_DRB-To-Modify-List-NG-RAN.h>
@@ -61,5 +65,7 @@
#include <E1AP_T-ReorderingTimer.h>
#include <E1AP_SDAP-Configuration.h>
#include <E1AP_PDCP-Configuration.h>
#include <E1AP_Slice-Support-List.h>
#include <E1AP_Slice-Support-Item.h>
#endif
+26 -16
View File
@@ -37,18 +37,19 @@ e1ap_upcp_inst_t *getCxtE1(instance_t instance)
return e1ap_inst[instance];
}
int e1ap_assoc_id(E1_t type, instance_t instance) {
AssertFatal(e1ap_inst[instance] != NULL, "Trying to access uninitiated instance of CUCP\n");
return e1ap_inst[instance]->setupReq.assoc_id;
}
void createE1inst(E1_t type, instance_t instance, e1ap_setup_req_t *req) {
void createE1inst(E1_t type, instance_t instance, e1ap_net_config_t *nc, e1ap_setup_req_t *req)
{
AssertFatal(e1ap_inst[instance] == NULL, "Double call to E1 instance %d\n", (int)instance);
e1ap_inst[instance] = calloc(1, sizeof(e1ap_upcp_inst_t));
e1ap_inst[instance]->type = type;
e1ap_inst[instance]->instance = instance;
if (req)
memcpy(&e1ap_inst[instance]->setupReq, req, sizeof(*req));
e1ap_inst[instance]->cuup.assoc_id = -1;
if (nc)
memcpy(&e1ap_inst[instance]->net_config, nc, sizeof(*nc));
if (req) {
AssertFatal(type == UPtype, "E1 setup request only to be stored for CU-UP\n");
memcpy(&e1ap_inst[instance]->cuup.setupReq, req, sizeof(*req));
}
e1ap_inst[instance]->gtpInstN3 = -1;
e1ap_inst[instance]->gtpInstF1U = -1;
}
@@ -59,8 +60,8 @@ void e1ap_common_init() {
srand(time(NULL));
}
bool check_transac_id(E1AP_TransactionID_t id, int *freeIdx) {
static bool check_transac_id(E1AP_TransactionID_t id, int *freeIdx)
{
bool isFreeIdxSet = false;
for (int i=0; i < E1AP_MAX_NUM_TRANSAC_IDS; i++) {
if (id == transacID[i])
@@ -74,10 +75,10 @@ bool check_transac_id(E1AP_TransactionID_t id, int *freeIdx) {
return true;
}
E1AP_TransactionID_t E1AP_get_next_transaction_identifier() {
long E1AP_get_next_transaction_identifier() {
E1AP_TransactionID_t genTransacId;
bool isTransacIdValid = false;
int freeIdx;
int freeIdx = 0;
while (!isTransacIdValid) {
genTransacId = rand() & 255;
@@ -89,7 +90,7 @@ E1AP_TransactionID_t E1AP_get_next_transaction_identifier() {
return genTransacId;
}
void E1AP_free_transaction_identifier(E1AP_TransactionID_t id) {
void E1AP_free_transaction_identifier(long id) {
for (int i=0; i < E1AP_MAX_NUM_TRANSAC_IDS; i++) {
if (id == transacID[i]) {
@@ -116,6 +117,9 @@ int e1ap_decode_initiating_message(E1AP_E1AP_PDU_t *pdu) {
case E1AP_ProcedureCode_id_bearerContextModification:
break;
case E1AP_ProcedureCode_id_bearerContextRelease:
break;
default:
LOG_E(E1AP, "Unsupported procedure code (%d) for initiating message\n",
(int)pdu->choice.initiatingMessage->procedureCode);
@@ -133,6 +137,12 @@ int e1ap_decode_successful_outcome(E1AP_E1AP_PDU_t *pdu) {
case E1AP_ProcedureCode_id_bearerContextSetup:
break;
case E1AP_ProcedureCode_id_bearerContextModification:
break;
case E1AP_ProcedureCode_id_bearerContextRelease:
break;
default:
LOG_E(E1AP, "Unsupported procedure code (%d) for successful message\n",
(int)pdu->choice.successfulOutcome->procedureCode);
@@ -195,7 +205,7 @@ int e1ap_decode_pdu(E1AP_E1AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t
return -1;
}
int e1ap_encode_send(E1_t type, e1ap_setup_req_t *setupReq, E1AP_E1AP_PDU_t *pdu, uint16_t stream, const char *func)
int e1ap_encode_send(E1_t type, sctp_assoc_t assoc_id, E1AP_E1AP_PDU_t *pdu, uint16_t stream, const char *func)
{
DevAssert(pdu != NULL);
@@ -223,11 +233,11 @@ int e1ap_encode_send(E1_t type, e1ap_setup_req_t *setupReq, E1AP_E1AP_PDU_t *pdu
}
MessageDef *message = itti_alloc_new_message((type == CPtype) ? TASK_CUCP_E1 : TASK_CUUP_E1, 0, SCTP_DATA_REQ);
sctp_data_req_t *s = &message->ittiMsg.sctp_data_req;
s->assoc_id = setupReq->assoc_id;
s->assoc_id = assoc_id;
s->buffer = buffer;
s->buffer_length = encoded;
s->stream = stream;
LOG_I(E1AP, "%s: Sending ITTI message to SCTP Task\n", func);
LOG_D(E1AP, "%s: Sending ITTI message to SCTP Task\n", func);
itti_send_msg_to_task(TASK_SCTP, 0 /*unused by callee*/, message);
return encoded;
+14 -16
View File
@@ -24,41 +24,39 @@
#ifndef E1AP_COMMON_H_
#define E1AP_COMMON_H_
#include "openair2/COMMON/e1ap_messages_types.h"
#include "e1ap_asnc.h"
#include "openair2/COMMON/sctp_messages_types.h"
#include "common/ngran_types.h"
typedef struct e1ap_upcp_inst_s {
bool incoming_sock;
instance_t instance;
bool same_process;
E1_t type;
enum sctp_state_e sockState;
sctp_assoc_t assoc_id;
struct {
sctp_assoc_t assoc_id;
e1ap_setup_req_t setupReq;
} cuup;
instance_t gtpInstN3;
instance_t gtpInstF1U;
e1ap_setup_req_t setupReq;
e1ap_bearer_setup_req_t bearerSetupReq;
e1ap_bearer_setup_resp_t bearerSetupResp;
e1ap_net_config_t net_config;
} e1ap_upcp_inst_t;
extern int asn1_xer_print;
int e1ap_decode_pdu(E1AP_E1AP_PDU_t *pdu, const uint8_t *const buffer, uint32_t length);
// forward declaration so we don't require E1AP ASN.1 when including this
// header
struct E1AP_E1AP_PDU;
int e1ap_decode_pdu(struct E1AP_E1AP_PDU *pdu, const uint8_t *const buffer, uint32_t length);
e1ap_upcp_inst_t *getCxtE1(instance_t instance);
E1AP_TransactionID_t E1AP_get_next_transaction_identifier();
long E1AP_get_next_transaction_identifier();
void E1AP_free_transaction_identifier(long id);
void createE1inst(E1_t type, instance_t instance, e1ap_setup_req_t *req);
void createE1inst(E1_t type, instance_t instance, e1ap_net_config_t *nc, e1ap_setup_req_t *req);
bool check_transac_id(E1AP_TransactionID_t id, int *freeIdx);
int e1ap_assoc_id(E1_t type, instance_t instance);
int e1ap_encode_send(E1_t type, e1ap_setup_req_t *setupReq, E1AP_E1AP_PDU_t *pdu, uint16_t stream, const char *func);
int e1ap_encode_send(E1_t type, sctp_assoc_t assoc_id, struct E1AP_E1AP_PDU *pdu, uint16_t stream, const char *func);
void e1ap_common_init();
void cuup_init_n3(instance_t instance);
void E1AP_free_transaction_identifier(E1AP_TransactionID_t id);
#endif /* E1AP_COMMON_H_ */
+31 -15
View File
@@ -68,7 +68,7 @@ static void get_NGU_S1U_addr(char **addr, uint16_t *port)
MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process)
{
MessageDef *msgConfig = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_SETUP_REQ);
MessageDef *msgConfig = itti_alloc_new_message(TASK_GNB_APP, 0, E1AP_REGISTER_REQ);
if (!msgConfig)
return NULL;
@@ -85,9 +85,11 @@ MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process)
config_getlist(&GNBParamList, GNBParams, sizeofArray(GNBParams), NULL);
paramdef_t *gnbParms = GNBParamList.paramarray[0];
AssertFatal(gnbParms[GNB_GNB_ID_IDX].uptr != NULL, "gNB id %d is not defined in configuration file\n", 0);
e1ap_setup_req_t *e1Setup = &E1AP_SETUP_REQ(msgConfig);
e1ap_setup_req_t *e1Setup = &E1AP_REGISTER_REQ(msgConfig).setup_req;
msgConfig->ittiMsgHeader.destinationInstance = 0;
e1Setup->gNB_cu_up_id = *(gnbParms[GNB_GNB_ID_IDX].uptr);
if (*gnbParms[GNB_GNB_NAME_IDX].strptr)
e1Setup->gNB_cu_up_name = *(gnbParms[GNB_GNB_NAME_IDX].strptr);
paramdef_t PLMNParams[] = GNBPLMNPARAMS_DESC;
paramlist_def_t PLMNParamList = {GNB_CONFIG_STRING_PLMN_LIST, NULL, 0};
@@ -102,27 +104,41 @@ MessageDef *RCconfig_NR_CU_E1(bool separate_CUUP_process)
e1Setup->supported_plmns = numPLMNs;
for (int I = 0; I < numPLMNs; I++) {
e1Setup->plmns[I].mcc = *PLMNParamList.paramarray[I][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
e1Setup->plmns[I].mnc = *PLMNParamList.paramarray[I][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
e1Setup->plmns[I].mnc = *PLMNParamList.paramarray[I][GNB_MNC_DIGIT_LENGTH].u8ptr;
e1Setup->plmn[I].id.mcc = *PLMNParamList.paramarray[I][GNB_MOBILE_COUNTRY_CODE_IDX].uptr;
e1Setup->plmn[I].id.mnc = *PLMNParamList.paramarray[I][GNB_MOBILE_NETWORK_CODE_IDX].uptr;
e1Setup->plmn[I].id.mnc_digit_length = *PLMNParamList.paramarray[I][GNB_MNC_DIGIT_LENGTH].uptr;
char snssaistr[MAX_OPTNAME_SIZE*2 + 8];
sprintf(snssaistr, "%s.[%i].%s.[%i]", GNB_CONFIG_STRING_GNB_LIST, 0, GNB_CONFIG_STRING_PLMN_LIST, I);
paramlist_def_t SNSSAIParamList = {GNB_CONFIG_STRING_SNSSAI_LIST, NULL, 0};
paramdef_t SNSSAIParams[] = GNBSNSSAIPARAMS_DESC;
config_getlist(&SNSSAIParamList, SNSSAIParams, sizeof(SNSSAIParams)/sizeof(paramdef_t), snssaistr);
e1Setup->plmn[I].supported_slices = SNSSAIParamList.numelt;
e1Setup->plmn[I].slice = calloc(SNSSAIParamList.numelt, sizeof(*e1Setup->plmn[I].slice));
AssertFatal(e1Setup->plmn[I].slice != NULL, "out of memory\n");
for (int s = 0; s < SNSSAIParamList.numelt; ++s) {
e1ap_nssai_t *slice = &e1Setup->plmn[I].slice[s];
slice->sst = *SNSSAIParamList.paramarray[s][GNB_SLICE_SERVICE_TYPE_IDX].uptr;
slice->sd = *SNSSAIParamList.paramarray[s][GNB_SLICE_DIFFERENTIATOR_IDX].uptr;
}
}
e1Setup->remotePortF1U = *(GNBParamList.paramarray[0][GNB_REMOTE_S_PORTD_IDX].uptr);
e1Setup->localAddressF1U = strdup(*(GNBParamList.paramarray[0][GNB_LOCAL_S_ADDRESS_IDX].strptr));
e1Setup->localPortF1U = *(GNBParamList.paramarray[0][GNB_LOCAL_S_PORTD_IDX].uptr);
get_NGU_S1U_addr(&e1Setup->localAddressN3, &e1Setup->localPortN3);
e1Setup->remotePortN3 = e1Setup->localPortN3 ;
e1ap_net_config_t *e1ap_nc = &E1AP_REGISTER_REQ(msgConfig).net_config;
e1ap_nc->remotePortF1U = *(GNBParamList.paramarray[0][GNB_REMOTE_S_PORTD_IDX].uptr);
e1ap_nc->localAddressF1U = strdup(*(GNBParamList.paramarray[0][GNB_LOCAL_S_ADDRESS_IDX].strptr));
e1ap_nc->localPortF1U = *(GNBParamList.paramarray[0][GNB_LOCAL_S_PORTD_IDX].uptr);
get_NGU_S1U_addr(&e1ap_nc->localAddressN3, &e1ap_nc->localPortN3);
e1ap_nc->remotePortN3 = e1ap_nc->localPortN3 ;
if (separate_CUUP_process) {
paramlist_def_t GNBE1ParamList = {GNB_CONFIG_STRING_E1_PARAMETERS, NULL, 0};
paramdef_t GNBE1Params[] = GNBE1PARAMS_DESC;
config_getlist(&GNBE1ParamList, GNBE1Params, sizeofArray(GNBE1Params), aprefix);
paramdef_t *e1Parms = GNBE1ParamList.paramarray[0];
strcpy(e1Setup->CUCP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUCP].strptr));
e1Setup->CUCP_e1_ip_address.ipv4 = 1;
strcpy(e1Setup->CUUP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUUP].strptr));
e1Setup->CUUP_e1_ip_address.ipv4 = 1;
e1Setup->cn_support = *e1Parms[GNB_CONFIG_E1_CN_SUPPORT].uptr;
strcpy(e1ap_nc->CUCP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUCP].strptr));
e1ap_nc->CUCP_e1_ip_address.ipv4 = 1;
strcpy(e1ap_nc->CUUP_e1_ip_address.ipv4_address, *(e1Parms[GNB_CONFIG_E1_IPV4_ADDRESS_CUUP].strptr));
e1ap_nc->CUUP_e1_ip_address.ipv4 = 1;
}
}
return msgConfig;
+1
View File
@@ -45,6 +45,7 @@ static instance_t cu_task_create_gtpu_instance(eth_params_t *IPaddrs) {
openAddr_t tmp= {0};
strncpy(tmp.originHost, IPaddrs->my_addr, sizeof(tmp.originHost)-1);
sprintf(tmp.originService, "%d", IPaddrs->my_portd);
sprintf(tmp.destinationService, "%d", IPaddrs->remote_portd);
return gtpv1Init(tmp);
}
+4 -1
View File
@@ -27,10 +27,13 @@
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/sctp.h>
typedef struct f1_ue_data_t {
uint32_t secondary_ue;
/* can be extended with F1-specific data also relevant for monolithic */
sctp_assoc_t e1_assoc_id;
} f1_ue_data_t;
void cu_init_f1_ue_data(void);
+4 -4
View File
@@ -147,10 +147,10 @@ void *gNB_app_task(void *args_p)
if (itti_create_task(TASK_CUCP_E1, E1AP_CUCP_task, NULL) < 0)
AssertFatal(false, "Create task for E1AP CP failed\n");
MessageDef *msg = RCconfig_NR_CU_E1(true);
if (msg)
itti_send_msg_to_task(TASK_CUCP_E1, 0, msg);
else
AssertFatal(false, "Send inti to task for E1AP CP failed\n");
AssertFatal(msg != NULL, "Send inti to task for E1AP CP failed\n");
// this sends the E1AP_REGISTER_REQ to CU-CP so it sets up the socket
// it does NOT use the E1AP part
itti_send_msg_to_task(TASK_CUCP_E1, 0, msg);
}
if (node_type == ngran_gNB_CUUP) {
+2 -3
View File
@@ -1523,7 +1523,7 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc)
char aprefix[MAX_OPTNAME_SIZE*2 + 8];
sprintf(aprefix,"%s.[%u].%s",GNB_CONFIG_STRING_GNB_LIST,i,GNB_CONFIG_STRING_SCTP_CONFIG);
config_get(SCTPParams,sizeof(SCTPParams)/sizeof(paramdef_t),aprefix);
rrc->node_id = *(GNBParamList.paramarray[0][GNB_GNB_ID_IDX].uptr);
rrc->node_id = gnb_id;
LOG_I(GNB_APP,"F1AP: gNB_CU_id[%d] %d\n",k,rrc->node_id);
rrc->node_name = strdup(*(GNBParamList.paramarray[0][GNB_GNB_NAME_IDX].strptr));
LOG_I(GNB_APP,"F1AP: gNB_CU_name[%d] %s\n",k,rrc->node_name);
@@ -1541,7 +1541,6 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc)
rrc->nr_cellid = (uint64_t)*(GNBParamList.paramarray[i][GNB_NRCELLID_IDX].u64ptr);
rrc->um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr);
if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "local_mac") == 0) {
} else if (strcmp(*(GNBParamList.paramarray[i][GNB_TRANSPORT_S_PREFERENCE_IDX].strptr), "cudu") == 0) {
@@ -1575,7 +1574,6 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc)
for (int I = 0; I < sizeof(PLMNParams) / sizeof(paramdef_t); ++I)
PLMNParams[I].chkPptr = &(config_check_PLMNParams[I]);
nrrrc_config.cell_identity = gnb_id;
nrrrc_config.tac = *GNBParamList.paramarray[i][GNB_TRACKING_AREA_CODE_IDX].uptr;
AssertFatal(!GNBParamList.paramarray[i][GNB_MOBILE_COUNTRY_CODE_IDX_OLD].strptr
&& !GNBParamList.paramarray[i][GNB_MOBILE_NETWORK_CODE_IDX_OLD].strptr,
@@ -1606,6 +1604,7 @@ void RCconfig_NRRRC(gNB_RRC_INST *rrc)
nrrrc_config.enable_sdap = *GNBParamList.paramarray[i][GNB_ENABLE_SDAP_IDX].iptr;
LOG_I(GNB_APP, "SDAP layer is %s\n", nrrrc_config.enable_sdap ? "enabled" : "disabled");
nrrrc_config.drbs = *GNBParamList.paramarray[i][GNB_DRBS].iptr;
nrrrc_config.um_on_default_drb = *(GNBParamList.paramarray[i][GNB_UMONDEFAULTDRB_IDX].uptr);
LOG_I(GNB_APP, "Data Radio Bearer count %d\n", nrrrc_config.drbs);
}//
+1 -4
View File
@@ -161,7 +161,7 @@ typedef enum {
{GNB_CONFIG_STRING_NRCELLID, NULL, 0, .u64ptr=NULL,.defint64val=1, TYPE_UINT64, 0}, \
{GNB_CONFIG_STRING_MINRXTXTIME, NULL, 0, .iptr=NULL, .defintval=2, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_ULPRBBLACKLIST, NULL, 0, .strptr=NULL,.defstrval="", TYPE_STRING, 0}, \
{GNB_CONFIG_STRING_UMONDEFAULTDRB, NULL, 0, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_UMONDEFAULTDRB, NULL, PARAMFLAG_BOOL, .uptr=NULL, .defuintval=0, TYPE_UINT, 0}, \
{GNB_CONFIG_STRING_FORCE256QAMOFF, GNB_CONFIG_HLP_FORCE256QAMOFF, PARAMFLAG_BOOL, .iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_ENABLE_SDAP, GNB_CONFIG_HLP_STRING_ENABLE_SDAP, PARAMFLAG_BOOL,.iptr=NULL, .defintval=0, TYPE_INT, 0}, \
{GNB_CONFIG_STRING_DRBS, GNB_CONFIG_HLP_STRING_DRBS, 0, .iptr=NULL, .defintval=1, TYPE_INT, 0}, \
@@ -376,19 +376,16 @@ typedef enum {
#define GNB_CONFIG_E1_CU_TYPE_IDX 0
#define GNB_CONFIG_E1_IPV4_ADDRESS_CUCP 1
#define GNB_CONFIG_E1_IPV4_ADDRESS_CUUP 2
#define GNB_CONFIG_E1_CN_SUPPORT 3
#define GNB_CONFIG_STRING_E1_CU_TYPE "type"
#define GNB_CONFIG_STRING_E1_IPV4_ADDRESS_CUCP "ipv4_cucp"
#define GNB_CONFIG_STRING_E1_IPV4_ADDRESS_CUUP "ipv4_cuup"
#define GNB_CONFIG_STRING_E1_CN_SUPPORT "cn_support"
// clang-format off
#define GNBE1PARAMS_DESC { \
{GNB_CONFIG_STRING_E1_CU_TYPE, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \
{GNB_CONFIG_STRING_E1_IPV4_ADDRESS_CUCP, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \
{GNB_CONFIG_STRING_E1_IPV4_ADDRESS_CUUP, NULL, 0, .strptr=NULL, .defstrval=NULL, TYPE_STRING, 0}, \
{GNB_CONFIG_STRING_E1_CN_SUPPORT, NULL, 0, .uptr =NULL, .defintval=1L, TYPE_UINT, 0} \
}
// clang-format on
/* L1 configuration section names */
+1 -1
View File
@@ -96,7 +96,7 @@ NR_UE_MAC_INST_t * nr_l2_init_ue(NR_UE_RRC_INST_t* rrc_inst) {
fill_nr_noS1_bearer_config(&rbconfig, &rlc_rbconfig);
// set up PDCP, RLC, MAC
nr_pdcp_layer_init();
nr_pdcp_layer_init(false);
nr_pdcp_add_drbs(ENB_FLAG_NO, nr_ue_mac_inst->crnti, rbconfig->drb_ToAddModList, 0, NULL, NULL);
nr_rlc_add_drb(nr_ue_mac_inst->crnti, rbconfig->drb_ToAddModList->list.array[0]->drb_Identity, rlc_rbconfig);
struct NR_CellGroupConfig__rlc_BearerToAddModList rlc_toadd_list;
+1 -1
View File
@@ -16,7 +16,7 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
#ifndef MAC_RRC_UL_H
@@ -16,7 +16,7 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
#include "nr_mac_gNB.h"
+1 -1
View File
@@ -16,7 +16,7 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
#include <sys/socket.h>
+1 -1
View File
@@ -271,7 +271,7 @@ void mac_top_init_gNB(ngran_node_t node_type,
AssertFatal(rlc_module_init(1) == 0,"Could not initialize RLC layer\n");
// These should be out of here later
if (get_softmodem_params()->usim_test == 0 ) nr_pdcp_layer_init();
if (get_softmodem_params()->usim_test == 0 ) nr_pdcp_layer_init(false);
if(IS_SOFTMODEM_NOS1 && get_softmodem_params()->phy_test) {
// get default noS1 configuration
+280
View File
@@ -0,0 +1,280 @@
/*
* 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 "cucp_cuup_handler.h"
#include "NR_DRB-ToAddModList.h"
#include "platform_types.h"
#include "intertask_interface.h"
#include "openair2/COMMON/e1ap_messages_types.h"
#include "openair3/ocp-gtpu/gtp_itf.h"
#include "openair2/F1AP/f1ap_ids.h"
#include "nr_pdcp_oai_api.h"
#include "cuup_cucp_if.h"
#include "common/utils/oai_asn1.h"
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
#include "openair2/E1AP/e1ap_common.h"
#include "openair2/F1AP/f1ap_common.h"
static void fill_DRB_configList_e1(NR_DRB_ToAddModList_t *DRB_configList, const pdu_session_to_setup_t *pdu)
{
for (int i=0; i < pdu->numDRB2Setup; i++) {
const 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, id);
*id = drb->qosFlows[j].id;
}
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 == 2) { // Not Needed
asn1cCalloc(pdcp_config->ext1, ext1);
asn1cCallocOne(ext1->cipheringDisabled, NR_PDCP_Config__ext1__cipheringDisabled_true);
}
}
}
static int drb_gtpu_create(instance_t instance,
uint32_t ue_id,
int incoming_id,
int outgoing_id,
int qfi,
in_addr_t tlAddress, // only IPv4 now
teid_t outgoing_teid,
gtpCallback callBack,
gtpCallbackSDAP callBackSDAP,
gtpv1u_gnb_create_tunnel_resp_t *create_tunnel_resp)
{
gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0};
create_tunnel_req.incoming_rb_id[0] = incoming_id;
create_tunnel_req.pdusession_id[0] = outgoing_id;
memcpy(&create_tunnel_req.dst_addr[0].buffer, &tlAddress, sizeof(uint8_t) * 4);
create_tunnel_req.dst_addr[0].length = 32;
create_tunnel_req.outgoing_teid[0] = outgoing_teid;
create_tunnel_req.outgoing_qfi[0] = qfi;
create_tunnel_req.num_tunnels = 1;
create_tunnel_req.ue_id = ue_id;
// we use gtpv1u_create_ngu_tunnel because it returns the interface
// address and port of the interface; apart from that, we also might call
// newGtpuCreateTunnel() directly
return gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, create_tunnel_resp, callBack, callBackSDAP);
}
static instance_t get_n3_gtp_instance(void)
{
const e1ap_upcp_inst_t *inst = getCxtE1(0);
AssertFatal(inst != NULL, "need to have E1 instance\n");
return inst->gtpInstN3;
}
static instance_t get_f1_gtp_instance(void)
{
const f1ap_cudu_inst_t *inst = getCxt(0);
if (!inst)
return -1; // means no F1
return inst->gtpInst;
}
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req)
{
/* mirror the CU-CP UE ID for CU-UP */
uint32_t cu_up_ue_id = req->gNB_cu_cp_ue_id;
f1_ue_data_t ued = {.secondary_ue = req->gNB_cu_cp_ue_id};
cu_add_f1_ue_data(cu_up_ue_id, &ued);
LOG_I(E1AP, "adding UE with CU-CP UE ID %d and CU-UP UE ID %d\n", req->gNB_cu_cp_ue_id, cu_up_ue_id);
instance_t n3inst = get_n3_gtp_instance();
instance_t f1inst = get_f1_gtp_instance();
e1ap_bearer_setup_resp_t resp = {
.gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id,
.gNB_cu_up_ue_id = cu_up_ue_id,
};
resp.numPDUSessions = req->numPDUSessions;
for (int i = 0; i < resp.numPDUSessions; ++i) {
pdu_session_setup_t *resp_pdu = resp.pduSession + i;
const pdu_session_to_setup_t *req_pdu = req->pduSession + i;
resp_pdu->id = req_pdu->sessionId;
AssertFatal(req_pdu->numDRB2Modify == 0, "DRB modification not implemented\n");
AssertFatal(req_pdu->numDRB2Setup == 1, "can only handle one DRB per PDU session\n");
resp_pdu->numDRBSetup = req_pdu->numDRB2Setup;
const DRB_nGRAN_to_setup_t *req_drb = &req_pdu->DRBnGRanList[0];
DRB_nGRAN_setup_t *resp_drb = &resp_pdu->DRBnGRanList[0];
resp_drb->id = req_drb->id;
resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup;
for (int k = 0; k < resp_drb->numQosFlowSetup; k++)
resp_drb->qosFlows[k].id = req_drb->qosFlows[k].id;
// GTP tunnel for N3/to core
gtpv1u_gnb_create_tunnel_resp_t resp_n3 = {0};
int qfi = 0; // put PDU session marker
int ret = drb_gtpu_create(n3inst,
cu_up_ue_id,
req_drb->id,
req_pdu->sessionId,
qfi,
req_pdu->tlAddress,
req_pdu->teId,
nr_pdcp_data_req_drb,
sdap_data_req,
&resp_n3);
AssertFatal(ret >= 0, "Unable to create GTP Tunnel for NG-U\n");
AssertFatal(resp_n3.num_tunnels == req->numPDUSessions, "could not create all tunnels\n");
resp_pdu->teId = resp_n3.gnb_NGu_teid[i];
memcpy(&resp_pdu->tlAddress, &resp_n3.gnb_addr.buffer, 4);
// create PDCP bearers. This will also create SDAP bearers
NR_DRB_ToAddModList_t DRB_configList = {0};
fill_DRB_configList_e1(&DRB_configList, req_pdu);
nr_pdcp_add_drbs(true, // set this to notify PDCP that his not UE
cu_up_ue_id,
&DRB_configList,
(req->integrityProtectionAlgorithm << 4) | req->cipheringAlgorithm,
(uint8_t *)req->encryptionKey,
(uint8_t *)req->integrityProtectionKey);
if (f1inst >= 0) { /* we have F1(-U) */
teid_t dummy_teid = 0xffff; // we will update later with answer from DU
in_addr_t dummy_address = {0}; // IPv4, updated later with answer from DU
gtpv1u_gnb_create_tunnel_resp_t resp_f1 = {0};
int qfi = -1; // don't put PDU session marker in GTP
int ret = drb_gtpu_create(f1inst,
cu_up_ue_id,
req_drb->id,
req_drb->id,
qfi,
dummy_address,
dummy_teid,
cu_f1u_data_req,
NULL,
&resp_f1);
resp_drb->numUpParam = 1;
AssertFatal(ret >= 0, "Unable to create GTP Tunnel for F1-U\n");
memcpy(&resp_drb->UpParamList[0].tlAddress, &resp_f1.gnb_addr.buffer, 4);
resp_drb->UpParamList[0].teId = resp_f1.gnb_NGu_teid[0];
}
// We assume all DRBs to setup have been setup successfully, so we always
// send successful outcome in response and no failed DRBs
resp_pdu->numDRBFailed = 0;
}
get_e1_if()->bearer_setup_response(&resp);
}
void e1_bearer_context_modif(const e1ap_bearer_setup_req_t *req)
{
AssertFatal(req->numPDUSessionsMod > 0, "need at least one PDU session to modify\n");
e1ap_bearer_modif_resp_t modif = {
.gNB_cu_cp_ue_id = req->gNB_cu_cp_ue_id,
.gNB_cu_up_ue_id = req->gNB_cu_up_ue_id,
.numPDUSessionsMod = req->numPDUSessionsMod,
};
instance_t f1inst = get_f1_gtp_instance();
for (int i=0; i < req->numPDUSessionsMod; i++) {
LOG_I(E1AP,
"UE %d: updating PDU session ID %ld (%ld bearers)\n",
req->gNB_cu_up_ue_id,
req->pduSessionMod[i].sessionId,
req->pduSessionMod[i].numDRB2Modify);
modif.pduSessionMod[i].id = req->pduSessionMod[i].sessionId;
modif.pduSessionMod[i].numDRBModified = req->pduSessionMod[i].numDRB2Modify;
for (int j=0; j < req->pduSessionMod[i].numDRB2Modify; j++) {
const DRB_nGRAN_to_setup_t *to_modif = &req->pduSessionMod[i].DRBnGRanModList[j];
DRB_nGRAN_modified_t *modified = &modif.pduSessionMod[i].DRBnGRanModList[j];
modified->id = to_modif->id;
if (f1inst < 0) // no F1-U?
continue; // nothing to do
in_addr_t addr = {0};
memcpy(&addr, &to_modif->DlUpParamList[0].tlAddress, sizeof(in_addr_t));
GtpuUpdateTunnelOutgoingAddressAndTeid(f1inst, req->gNB_cu_cp_ue_id, to_modif->id, addr, to_modif->DlUpParamList[0].teId);
}
}
get_e1_if()->bearer_modif_response(&modif);
}
void e1_bearer_release_cmd(const e1ap_bearer_release_cmd_t *cmd)
{
instance_t n3inst = get_n3_gtp_instance();
instance_t f1inst = get_f1_gtp_instance();
LOG_I(E1AP, "releasing UE %d\n", cmd->gNB_cu_up_ue_id);
newGtpuDeleteAllTunnels(n3inst, cmd->gNB_cu_up_ue_id);
if (f1inst >= 0) // is there F1-U?
newGtpuDeleteAllTunnels(f1inst, cmd->gNB_cu_up_ue_id);
nr_pdcp_remove_UE(cmd->gNB_cu_up_ue_id);
cu_remove_f1_ue_data(cmd->gNB_cu_up_ue_id);
e1ap_bearer_release_cplt_t cplt = {
.gNB_cu_cp_ue_id = cmd->gNB_cu_cp_ue_id,
.gNB_cu_up_ue_id = cmd->gNB_cu_up_ue_id,
};
get_e1_if()->bearer_release_complete(&cplt);
}
@@ -9,8 +9,6 @@
*
* 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.
@@ -21,15 +19,17 @@
* contact@openairinterface.org
*/
#ifndef E1AP_API_H
#define E1AP_API_H
#ifndef CUCP_CUUP_HANDLER_H
#define CUCP_CUUP_HANDLER_H
#include "platform_types.h"
#include "openair2/COMMON/e1ap_messages_types.h"
#include "openair2/E1AP/e1ap_common.h"
void cuup_init_n3(instance_t instance);
void process_e1_bearer_context_setup_req(instance_t, e1ap_bearer_setup_req_t *const req);
void CUUP_process_bearer_context_mod_req(instance_t, e1ap_bearer_setup_req_t *const req);
#include <stdbool.h>
void CUUP_process_bearer_release_command(instance_t, e1ap_bearer_release_cmd_t *const cmd);
#endif
void nr_pdcp_e1_if_init(bool uses_e1);
struct e1ap_bearer_setup_req_s;
struct e1ap_bearer_release_cmd_s;
void e1_bearer_context_setup(const struct e1ap_bearer_setup_req_s *req);
void e1_bearer_context_modif(const struct e1ap_bearer_setup_req_s *req);
void e1_bearer_release_cmd(const struct e1ap_bearer_release_cmd_s *cmd);
#endif /* CUCP_CUUP_HANDLER_H */
@@ -0,0 +1,55 @@
/*
* 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 "cuup_cucp_if.h"
#include "e1ap_messages_types.h"
#include "intertask_interface.h"
static void bearer_setup_response_direct(const e1ap_bearer_setup_resp_t *resp)
{
MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, E1AP_BEARER_CONTEXT_SETUP_RESP);
e1ap_bearer_setup_resp_t *msg_resp = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg);
*msg_resp = *resp;
itti_send_msg_to_task(TASK_RRC_GNB, 0, msg);
}
static void bearer_modif_response_direct(const e1ap_bearer_modif_resp_t *resp)
{
MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, E1AP_BEARER_CONTEXT_MODIFICATION_RESP);
e1ap_bearer_modif_resp_t *msg_resp = &E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg);
*msg_resp = *resp;
itti_send_msg_to_task(TASK_RRC_GNB, 0, msg);
}
static void bearer_release_complete_direct(const e1ap_bearer_release_cplt_t *cplt)
{
MessageDef *msg = itti_alloc_new_message(TASK_MAC_GNB, 0, E1AP_BEARER_CONTEXT_RELEASE_CPLT);
e1ap_bearer_release_cplt_t *msg_cplt = &E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg);
*msg_cplt = *cplt;
itti_send_msg_to_task(TASK_RRC_GNB, 0, msg);
}
void cuup_cucp_init_direct(e1_if_t *iface)
{
iface->bearer_setup_response = bearer_setup_response_direct;
iface->bearer_modif_response = bearer_modif_response_direct;
iface->bearer_release_complete = bearer_release_complete_direct;
}
+55
View File
@@ -0,0 +1,55 @@
/*
* 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 "cuup_cucp_if.h"
#include "intertask_interface.h"
#include "e1ap_messages_types.h"
static void bearer_setup_response_e1ap(const e1ap_bearer_setup_resp_t *resp)
{
MessageDef *msg_p = itti_alloc_new_message(TASK_CUUP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_RESP);
e1ap_bearer_setup_resp_t *bearer_resp = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p);
*bearer_resp = *resp;
itti_send_msg_to_task (TASK_CUUP_E1, 0, msg_p);
}
static void bearer_modif_response_e1ap(const e1ap_bearer_modif_resp_t *resp)
{
MessageDef *msg_p = itti_alloc_new_message(TASK_CUUP_E1, 0, E1AP_BEARER_CONTEXT_MODIFICATION_RESP);
e1ap_bearer_modif_resp_t *modif_resp = &E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg_p);
*modif_resp = *resp;
itti_send_msg_to_task (TASK_CUUP_E1, 0, msg_p);
}
static void bearer_release_complete_e1ap(const e1ap_bearer_release_cplt_t *cplt)
{
MessageDef *msg_p = itti_alloc_new_message(TASK_CUUP_E1, 0, E1AP_BEARER_CONTEXT_RELEASE_CPLT);
e1ap_bearer_release_cplt_t *msg_cplt = &E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg_p);
*msg_cplt = *cplt;
itti_send_msg_to_task (TASK_CUUP_E1, 0, msg_p);
}
void cuup_cucp_init_e1ap(e1_if_t *iface)
{
iface->bearer_setup_response = bearer_setup_response_e1ap;
iface->bearer_modif_response = bearer_modif_response_e1ap;
iface->bearer_release_complete = bearer_release_complete_e1ap;
}
+37
View File
@@ -0,0 +1,37 @@
/*
* 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 "cuup_cucp_if.h"
static e1_if_t e1_if;
e1_if_t *get_e1_if(void)
{
return &e1_if;
}
void nr_pdcp_e1_if_init(bool uses_e1)
{
if (uses_e1)
cuup_cucp_init_e1ap(&e1_if);
else
cuup_cucp_init_direct(&e1_if);
}
+46
View File
@@ -0,0 +1,46 @@
/*
* 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 CUUP_CUCP_IF_H
#define CUUP_CUCP_IF_H
#include <stdbool.h>
struct e1ap_bearer_setup_resp_s;
struct e1ap_bearer_modif_resp_s;
struct e1ap_bearer_release_cplt_s;
typedef void (*e1_bearer_setup_response_func_t)(const struct e1ap_bearer_setup_resp_s *resp);
typedef void (*e1_bearer_modif_response_func_t)(const struct e1ap_bearer_modif_resp_s *resp);
typedef void (*e1_bearer_release_complete_func_t)(const struct e1ap_bearer_release_cplt_s *cplt);
typedef struct e1_if_t {
e1_bearer_setup_response_func_t bearer_setup_response;
e1_bearer_modif_response_func_t bearer_modif_response;
e1_bearer_release_complete_func_t bearer_release_complete;
} e1_if_t;
e1_if_t *get_e1_if(void);
void nr_pdcp_e1_if_init(bool uses_e1);
void cuup_cucp_init_direct(e1_if_t *iface);
void cuup_cucp_init_e1ap(e1_if_t *iface);
#endif /* CUUP_CUCP_IF_H */
-54
View File
@@ -1,54 +0,0 @@
/*
* 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 _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "nr_pdcp_e1_api.h"
void e1_add_drb(int is_gnb,
uint64_t ue_id,
struct NR_DRB_ToAddMod *s,
int ciphering_algorithm,
int integrity_algorithm,
unsigned char *ciphering_key,
unsigned char *integrity_key)
{
add_drb(is_gnb, ue_id, s, ciphering_algorithm, integrity_algorithm, ciphering_key, integrity_key);
LOG_I(PDCP, "%s:%s:%d: added DRB for UE ID %ld\n", __FILE__, __FUNCTION__, __LINE__, ue_id);
}
void nr_pdcp_e1_add_drbs(eNB_flag_t enb_flag,
uint64_t ue_id,
NR_DRB_ToAddModList_t *const drb2add_list,
const uint8_t security_modeP,
uint8_t *const kUPenc,
uint8_t *const kUPint) {
if (drb2add_list != NULL) {
for (int i = 0; i < drb2add_list->list.count; i++) {
e1_add_drb(enb_flag, ue_id, drb2add_list->list.array[i],
security_modeP & 0x0f, (security_modeP >> 4) & 0x0f,
kUPenc, kUPint);
}
} else
LOG_W(PDCP, "%s with void list\n", __FUNCTION__);
}
-53
View File
@@ -1,53 +0,0 @@
/*
* 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 _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "common/utils/oai_asn1.h"
#include "NR_RadioBearerConfig.h"
#include "nr_pdcp_oai_api.h"
#include "LAYER2/nr_rlc/nr_rlc_oai_api.h"
#include <openair3/ocp-gtpu/gtp_itf.h>
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
void e1_add_drb(int is_gnb,
uint64_t ue_id,
struct NR_DRB_ToAddMod *s,
int ciphering_algorithm,
int integrity_algorithm,
unsigned char *ciphering_key,
unsigned char *integrity_key);
void nr_pdcp_e1_add_drbs(eNB_flag_t enb_flag,
uint64_t ue_id,
NR_DRB_ToAddModList_t *const drb2add_list,
const uint8_t security_modeP,
uint8_t *const kUPenc,
uint8_t *const kUPint);
void add_drb_am(int is_gnb, ue_id_t rntiMaybeUEid, struct NR_DRB_ToAddMod *s,
int ciphering_algorithm,
int integrity_algorithm,
unsigned char *ciphering_key,
unsigned char *integrity_key);
+3 -2
View File
@@ -39,9 +39,9 @@
#include "openair2/F1AP/f1ap_ids.h"
#include <openair3/ocp-gtpu/gtp_itf.h>
#include "openair2/SDAP/nr_sdap/nr_sdap.h"
#include "nr_pdcp_e1_api.h"
#include "gnb_config.h"
#include "executables/softmodem-common.h"
#include "cuup_cucp_if.h"
#define TODO do { \
printf("%s:%d:%s: todo\n", __FILE__, __LINE__, __FUNCTION__); \
@@ -538,7 +538,7 @@ void pdcp_layer_init(void)
abort();
}
void nr_pdcp_layer_init(void)
void nr_pdcp_layer_init(bool uses_e1)
{
/* hack: be sure to initialize only once */
static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
@@ -559,6 +559,7 @@ void nr_pdcp_layer_init(void)
init_nr_rlc_data_req_queue();
}
nr_pdcp_e1_if_init(uses_e1);
init_nr_pdcp_data_ind_queue();
nr_pdcp_init_timer_thread(nr_pdcp_ue_manager);
}
+1 -1
View File
@@ -25,7 +25,7 @@
#include "pdcp.h"
#include "nr_pdcp_ue_manager.h"
void nr_pdcp_layer_init(void);
void nr_pdcp_layer_init(bool uses_e1);
uint64_t nr_pdcp_module_init(uint64_t _pdcp_optmask, int id);
void du_rlc_data_req(const protocol_ctxt_t *const ctxt_pP,
+1 -1
View File
@@ -16,7 +16,7 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
/*! \file RRC/LTE/defs.h
+14 -183
View File
@@ -16,204 +16,35 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@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 "openair3/SECU/key_nas_deriver.h"
#include "openair2/LAYER2/nr_pdcp/cucp_cuup_handler.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,
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;
in_addr_t addr = {0};
memcpy(&addr, &drb_p->DlUpParamList[0].tlAddress, sizeof(in_addr_t));
GtpuUpdateTunnelOutgoingAddressAndTeid(instance,
(ue_id & 0xFFFF),
(ebi_t)drb_p->id,
addr,
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,
instance_t instance)
static void cucp_cuup_bearer_context_setup_direct(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req)
{
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->rrc_ue_id;
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,
"drb_config_gtpu_create=>gtpv1u_create_ngu_tunnel failed, cannot set up GTP tunnel for data transmissions of UE %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[16] = {0};
uint8_t kRRCint[16] = {0};
uint8_t kUPenc[16] = {0};
uint8_t kUPint[16] = {0};
/* Derive the keys from kgnb */
if (DRB_configList != NULL) {
nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kUPenc);
nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, kUPint);
}
nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kRRCenc);
nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, kRRCint);
/* Refresh SRBs/DRBs */
LOG_D(NR_RRC, "Configuring PDCP DRBs for UE %x\n", UE->rnti);
nr_pdcp_add_drbs(ctxt_p->enb_flag,
UE->rrc_ue_id,
DRB_configList,
(UE->integrity_algorithm << 4) | UE->ciphering_algorithm,
kUPenc,
kUPint);
return ret;
AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id);
e1_bearer_context_setup(req);
}
static void cucp_cuup_bearer_context_setup_direct(e1ap_bearer_setup_req_t *const req, instance_t instance)
static void cucp_cuup_bearer_context_modif_direct(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req)
{
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], req->gNB_cu_cp_ue_id);
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->rrc_ue_id, 0, 0, 0);
e1ap_bearer_setup_resp_t resp = {0};
resp.numPDUSessions = req->numPDUSessions;
for (int i = 0; i < resp.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 *req_drb = req->pduSession[i].DRBnGRanList + j;
DRB_nGRAN_setup_t *resp_drb = resp.pduSession[i].DRBnGRanList + j;
resp_drb->id = req_drb->id;
resp_drb->numQosFlowSetup = req_drb->numQosFlow2Setup;
for (int k = 0; k < resp_drb->numQosFlowSetup; k++)
resp_drb->qosFlows[k].id = req_drb->qosFlows[k].id;
}
}
gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id];
// GTP tunnel for UL
NR_DRB_ToAddModList_t *DRB_configList = fill_DRB_configList(UE);
int ret = drb_config_gtpu_create(&ctxt, ue_context_p, req, DRB_configList, rrc->e1_inst);
if (ret < 0) AssertFatal(false, "Unable to configure DRB or to create GTP Tunnel\n");
// the code is very badly organized, it is not possible here to call freeDRBlist()
ASN_STRUCT_FREE(asn_DEF_NR_DRB_ToAddModList,DRB_configList );
// Used to store teids: if monolithic, will simply be NULL
if(!NODE_IS_CU(RC.nrrrc[ctxt.module_id]->node_type)) {
// intentionally empty
} else {
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(instance)->gtpInst;
// GTP tunnel for DL
fill_e1ap_bearer_setup_resp(&resp, req, gtpInst, UE->rrc_ue_id, remote_port, my_addr);
}
// actually, we should receive the corresponding context setup response
// message at the RRC and always react to this one. So in the following, we
// just call the corresponding message handler
prepare_and_send_ue_context_modification_f1(ue_context_p, &resp);
AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id);
e1_bearer_context_modif(req);
}
static void cucp_cuup_bearer_context_mod_direct(e1ap_bearer_setup_req_t *const req, instance_t instance)
static void cucp_cuup_bearer_context_release_cmd_direct(sctp_assoc_t assoc_id, const e1ap_bearer_release_cmd_t *cmd)
{
// only update GTP tunnels if it is really a CU
if (!NODE_IS_CU(RC.nrrrc[0]->node_type))
return;
instance_t gtpInst = getCxt(instance)->gtpInst;
CU_update_UP_DL_tunnel(req, gtpInst, req->gNB_cu_cp_ue_id);
AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id);
e1_bearer_release_cmd(cmd);
}
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;
rrc->cucp_cuup.bearer_context_mod = cucp_cuup_bearer_context_modif_direct;
rrc->cucp_cuup.bearer_context_release = cucp_cuup_bearer_context_release_cmd_direct;
}
+22 -17
View File
@@ -16,44 +16,49 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
#include "cucp_cuup_if.h"
#include <arpa/inet.h>
#include "platform_types.h"
#include "nr_rrc_defs.h"
#include "nr_rrc_proto.h"
#include "nr_rrc_extern.h"
#include "cucp_cuup_if.h"
#include "openair2/COMMON/e1ap_messages_types.h"
#include "openair3/SECU/secu_defs.h"
#include <openair2/RRC/NR/rrc_gNB_UE_context.h>
#include "common/ran_context.h"
extern RAN_CONTEXT_t RC;
static void cucp_cuup_bearer_context_setup_e1ap(e1ap_bearer_setup_req_t *const req, instance_t instance)
static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req)
{
MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, instance, E1AP_BEARER_CONTEXT_SETUP_REQ);
AssertFatal(assoc_id > 0, "illegal assoc_id %d\n", assoc_id);
MessageDef *msg_p = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_SETUP_REQ);
msg_p->ittiMsgHeader.originInstance = assoc_id;
e1ap_bearer_setup_req_t *bearer_req = &E1AP_BEARER_CONTEXT_SETUP_REQ(msg_p);
memcpy(bearer_req, req, sizeof(e1ap_bearer_setup_req_t));
itti_send_msg_to_task (TASK_CUCP_E1, instance, msg_p);
itti_send_msg_to_task (TASK_CUCP_E1, 0, msg_p);
}
static void cucp_cuup_bearer_context_mod_e1ap(e1ap_bearer_setup_req_t *const req, instance_t instance)
static void cucp_cuup_bearer_context_mod_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req)
{
MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, instance, E1AP_BEARER_CONTEXT_MODIFICATION_REQ);
AssertFatal(assoc_id > 0, "illegal assoc_id %d\n", assoc_id);
MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_MODIFICATION_REQ);
msg->ittiMsgHeader.originInstance = assoc_id;
e1ap_bearer_setup_req_t *req_msg = &E1AP_BEARER_CONTEXT_SETUP_REQ(msg);
memcpy(req_msg, req, sizeof(*req));
itti_send_msg_to_task(TASK_CUCP_E1, instance, msg);
itti_send_msg_to_task(TASK_CUCP_E1, 0, msg);
}
static void cucp_cuup_bearer_context_release_cmd_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_release_cmd_t *cmd)
{
AssertFatal(assoc_id > 0, "illegal assoc_id %d\n", assoc_id);
MessageDef *msg = itti_alloc_new_message(TASK_CUCP_E1, 0, E1AP_BEARER_CONTEXT_RELEASE_CMD);
msg->ittiMsgHeader.originInstance = assoc_id;
e1ap_bearer_release_cmd_t *cmd_msg = &E1AP_BEARER_CONTEXT_RELEASE_CMD(msg);
memcpy(cmd_msg, cmd, sizeof(*cmd));
itti_send_msg_to_task(TASK_CUCP_E1, 0, msg);
}
void cucp_cuup_message_transfer_e1ap_init(gNB_RRC_INST *rrc) {
rrc->cucp_cuup.bearer_context_setup = cucp_cuup_bearer_context_setup_e1ap;
rrc->cucp_cuup.bearer_context_mod = cucp_cuup_bearer_context_mod_e1ap;
rrc->cucp_cuup.bearer_context_release = cucp_cuup_bearer_context_release_cmd_e1ap;
}
+8 -9
View File
@@ -16,27 +16,26 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
#ifndef CUCP_CUUP_IF_H
#define CUCP_CUUP_IF_H
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/sctp.h>
#include "platform_types.h"
struct e1ap_bearer_setup_req_s;
struct e1ap_bearer_setup_resp_s;
typedef void (*cucp_cuup_bearer_context_setup_func_t)(struct e1ap_bearer_setup_req_s *const req, instance_t instance);
struct e1ap_bearer_release_cmd_s;
typedef void (*cucp_cuup_bearer_context_setup_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_setup_req_s *req);
typedef void (*cucp_cuup_bearer_context_release_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_release_cmd_s *cmd);
struct gNB_RRC_INST_s;
void cucp_cuup_message_transfer_direct_init(struct gNB_RRC_INST_s *rrc);
void cucp_cuup_message_transfer_e1ap_init(struct gNB_RRC_INST_s *rrc);
void fill_e1ap_bearer_setup_resp(struct e1ap_bearer_setup_resp_s *resp,
struct e1ap_bearer_setup_req_s *const req,
instance_t gtpInst,
ue_id_t ue_id,
int remote_port,
in_addr_t my_addr);
void CU_update_UP_DL_tunnel(struct e1ap_bearer_setup_req_s *const req, instance_t instance, ue_id_t ue_id);
#endif
+1 -1
View File
@@ -16,7 +16,7 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
#ifndef MAC_RRC_DL_H
+1 -1
View File
@@ -16,7 +16,7 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
#include "nr_rrc_defs.h"
+1 -1
View File
@@ -16,7 +16,7 @@
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* conmnc_digit_lengtht@openairinterface.org
* contact@openairinterface.org
*/
#include <stdlib.h>
+11 -23
View File
@@ -330,11 +330,6 @@ typedef struct {
uint8_t *SIB23;
uint8_t sizeof_SIB23;
NR_SIB2_t *sib2;
NR_SIB3_t *sib3;
NR_BCCH_DL_SCH_Message_t systemInformation; // SIB23
NR_CellGroupConfig_t *secondaryCellGroup[MAX_NR_RRC_UE_CONTEXTS];
} rrc_gNB_carrier_data_t;
//---------------------------------------------------
@@ -367,6 +362,7 @@ typedef struct nr_mac_rrc_dl_if_s {
typedef struct cucp_cuup_if_s {
cucp_cuup_bearer_context_setup_func_t bearer_context_setup;
cucp_cuup_bearer_context_setup_func_t bearer_context_mod;
cucp_cuup_bearer_context_release_func_t bearer_context_release;
} cucp_cuup_if_t;
typedef struct nr_rrc_du_container_t {
@@ -376,6 +372,14 @@ typedef struct nr_rrc_du_container_t {
NR_SIB1_t *sib1;
} nr_rrc_du_container_t;
typedef struct nr_rrc_cuup_container_t {
/* Tree-related data */
RB_ENTRY(nr_rrc_cuup_container_t) entries;
e1ap_setup_req_t *setup_req;
sctp_assoc_t assoc_id;
} nr_rrc_cuup_container_t;
//---NR---(completely change)---------------------
typedef struct gNB_RRC_INST_s {
@@ -396,24 +400,6 @@ typedef struct gNB_RRC_INST_s {
// gNB N3 GTPU instance
instance_t e1_inst;
// other PLMN parameters
/// Mobile country code
int mcc;
/// Mobile network code
int mnc;
/// number of mnc digits
int mnc_digit_length;
// other RAN parameters
int srb1_timer_poll_retransmit;
int srb1_poll_pdu;
int srb1_poll_byte;
int srb1_max_retx_threshold;
int srb1_timer_reordering;
int srb1_timer_status_prohibit;
int um_on_default_drb;
int srs_enable[MAX_NUM_CCs];
char *uecap_file;
// security configuration (preferred algorithms)
@@ -423,6 +409,8 @@ typedef struct gNB_RRC_INST_s {
cucp_cuup_if_t cucp_cuup;
nr_rrc_du_container_t *du;
RB_HEAD(rrc_cuup_tree, nr_rrc_cuup_container_t) cuups; // CU-UPs, indexed by assoc_id
size_t num_cuups;
} gNB_RRC_INST;
+4 -2
View File
@@ -132,6 +132,10 @@ rrc_gNB_generate_dedicatedRRCReconfiguration_release(
void rrc_gNB_generate_dedicatedRRCReconfiguration(const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP);
sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue);
sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd);
int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req);
void bearer_context_setup_direct(e1ap_bearer_setup_req_t *req,
instance_t instance);
@@ -144,8 +148,6 @@ void ue_cxt_mod_send_e1ap(MessageDef *msg,
void ue_cxt_mod_direct(MessageDef *msg,
instance_t instance);
NR_DRB_ToAddModList_t *fill_DRB_configList(gNB_RRC_UE_t *ue);
void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_context_p,
e1ap_bearer_setup_resp_t *e1ap_resp);
void nr_pdcp_add_srbs(eNB_flag_t enb_flag, ue_id_t rntiMaybeUEid, NR_SRB_ToAddModList_t *const srb2add_list, const uint8_t security_modeP, uint8_t *const kRRCenc, uint8_t *const kUPint);
+75 -67
View File
@@ -93,7 +93,6 @@
#include <openair3/SECU/key_nas_deriver.h>
#include <openair3/ocp-gtpu/gtp_itf.h>
#include <openair2/RRC/NR/nr_rrc_proto.h>
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h"
#include "openair2/F1AP/f1ap_common.h"
#include "openair2/F1AP/f1ap_ids.h"
#include "openair2/SDAP/nr_sdap/nr_sdap_entity.h"
@@ -337,6 +336,7 @@ void openair_rrc_gNB_configuration(gNB_RRC_INST *rrc, gNB_RrcConfigurationReq *c
rrc_gNB_CU_DU_init(rrc);
uid_linear_allocator_init(&rrc->uid_allocator);
RB_INIT(&rrc->rrc_ue_head);
RB_INIT(&rrc->cuups);
rrc->configuration = *configuration;
/// System Information INIT
init_NR_SI(rrc);
@@ -575,7 +575,6 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co
dedicatedNAS_MessageList,
ue_p->masterCellGroup);
AssertFatal(size > 0, "cannot encode RRCReconfiguration in %s()\n", __func__);
LOG_W(NR_RRC, "do_RRCReconfiguration(): size %d\n", size);
free_defaultMeasConfig(measconfig);
if (LOG_DEBUGFLAG(DEBUG_ASN1)) {
@@ -1041,6 +1040,7 @@ static void rrc_gNB_generate_RRCReestablishment(rrc_gNB_ue_context_t *ue_context
}
}
// TODO: should send E1 UE Bearer Modification with PDCP Reestablishment flag
nr_pdcp_reestablishment(ue_p->rrc_ue_id);
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id);
@@ -2033,8 +2033,6 @@ static void rrc_CU_process_ue_context_release_complete(MessageDef *msg_p)
}
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
nr_pdcp_remove_UE(UE->rrc_ue_id);
newGtpuDeleteAllTunnels(instance, UE->rrc_ue_id);
rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(instance, UE->rrc_ue_id);
LOG_I(NR_RRC, "removed UE CU UE ID %u/RNTI %04x \n", UE->rrc_ue_id, UE->rnti);
rrc_delete_ue_data(UE);
@@ -2055,10 +2053,13 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i
if (resp->drbs_to_be_setup_length > 0) {
e1ap_bearer_setup_req_t req = {0};
// TODO: bug: we receive the DRBs, but we don't associate to a PDU session
// -> we are not sure which PDU session this is, and fill "all"
req.numPDUSessionsMod = UE->nb_of_pdusessions;
req.gNB_cu_cp_ue_id = UE->rrc_ue_id;
req.gNB_cu_up_ue_id = UE->rrc_ue_id;
for (int i = 0; i < req.numPDUSessionsMod; i++) {
req.pduSessionMod[i].sessionId = UE->pduSession[i].param.pdusession_id;
req.pduSessionMod[i].numDRB2Modify = resp->drbs_to_be_setup_length;
for (int j = 0; j < resp->drbs_to_be_setup_length; j++) {
f1ap_drb_to_be_setup_t *drb_f1 = resp->drbs_to_be_setup + j;
@@ -2073,7 +2074,8 @@ static void rrc_CU_process_ue_context_modification_response(MessageDef *msg_p, i
// send the F1 response message up to update F1-U tunnel info
// it seems the rrc transaction id (xid) is not needed here
rrc->cucp_cuup.bearer_context_mod(&req, instance);
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE);
rrc->cucp_cuup.bearer_context_mod(assoc_id, &req);
}
if (resp->du_to_cu_rrc_information != NULL && resp->du_to_cu_rrc_information->cellGroupConfig != NULL) {
@@ -2314,47 +2316,42 @@ static int get_dl_mimo_layers(const f1ap_served_cell_info_t *cell_info, const NR
return(1);
}
int rrc_gNB_process_e1_setup_req(e1ap_setup_req_t *req, instance_t instance) {
AssertFatal(req->supported_plmns <= PLMN_LIST_MAX_SIZE, "Supported PLMNs is more than PLMN_LIST_MAX_SIZE\n");
gNB_RRC_INST *rrc = RC.nrrrc[0]; //TODO: remove hardcoding of RC index here
MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, instance, E1AP_SETUP_RESP);
e1ap_setup_resp_t *resp = &E1AP_SETUP_RESP(msg_p);
resp->transac_id = req->transac_id;
for (int i=0; i < req->supported_plmns; i++) {
if (rrc->configuration.mcc[i] == req->plmns[i].mcc &&
rrc->configuration.mnc[i] == req->plmns[i].mnc) {
LOG_E(NR_RRC, "PLMNs received from CUUP (mcc:%d, mnc:%d) did not match with PLMNs in RRC (mcc:%d, mnc:%d)\n",
req->plmns[i].mcc, req->plmns[i].mnc, rrc->configuration.mcc[i], rrc->configuration.mnc[i]);
return -1;
}
}
itti_send_msg_to_task(TASK_CUCP_E1, instance, msg_p);
return 0;
}
void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_context_p, e1ap_bearer_setup_resp_t *e1ap_resp)
void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp, instance_t instance)
{
/* Generate a UE context modification request message towards the DU to
* instruct the DU for SRB2 and DRB configuration and get the updates on
* master cell group config from the DU*/
gNB_RRC_INST *rrc = RC.nrrrc[0];
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, resp->gNB_cu_cp_ue_id);
AssertFatal(ue_context_p != NULL, "did not find UE with CU UE ID %d\n", resp->gNB_cu_cp_ue_id);
gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
// currently: we don't have "infrastructure" to save the CU-UP UE ID, so we
// assume (and below check) that CU-UP UE ID == CU-CP UE ID
AssertFatal(resp->gNB_cu_cp_ue_id == resp->gNB_cu_up_ue_id,
"cannot handle CU-UP UE ID different from CU-CP UE ID (%d vs %d)\n",
resp->gNB_cu_cp_ue_id,
resp->gNB_cu_up_ue_id);
// 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);
if (rrc_pdu == NULL) {
LOG_W(RRC, "E1: received setup for PDU session %ld, but has not been requested\n", e1_pdu->id);
continue;
}
rrc_pdu->param.gNB_teid_N3 = e1_pdu->teId;
memcpy(&rrc_pdu->param.gNB_addr_N3.buffer, &e1_pdu->tlAddress, sizeof(uint8_t) * 4);
rrc_pdu->param.gNB_addr_N3.length = sizeof(in_addr_t);
}
/* Instruction towards the DU for DRB configuration and tunnel creation */
int nb_drb = e1ap_resp->pduSession[0].numDRBSetup;
int nb_drb = resp->pduSession[0].numDRBSetup;
f1ap_drb_to_be_setup_t drbs[nb_drb];
for (int i = 0; i < nb_drb; i++) {
drbs[i].drb_id = e1ap_resp->pduSession[0].DRBnGRanList[i].id;
drbs[i].rlc_mode = rrc->um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM;
drbs[i].up_ul_tnl[0].tl_address = e1ap_resp->pduSession[0].DRBnGRanList[i].UpParamList[0].tlAddress;
drbs[i].drb_id = resp->pduSession[0].DRBnGRanList[i].id;
drbs[i].rlc_mode = rrc->configuration.um_on_default_drb ? RLC_MODE_UM : RLC_MODE_AM;
drbs[i].up_ul_tnl[0].tl_address = resp->pduSession[0].DRBnGRanList[i].UpParamList[0].tlAddress;
drbs[i].up_ul_tnl[0].port = rrc->eth_params_s.my_portd;
drbs[i].up_ul_tnl[0].teid = e1ap_resp->pduSession[0].DRBnGRanList[i].UpParamList[0].teId;
drbs[i].up_ul_tnl[0].teid = resp->pduSession[0].DRBnGRanList[i].UpParamList[0].teId;
drbs[i].up_ul_tnl_length = 1;
}
@@ -2368,6 +2365,7 @@ void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_contex
srbs[0].lcid = 2;
}
/* Gather UE capability if present */
cu_to_du_rrc_information_t cu2du = {0};
cu_to_du_rrc_information_t *cu2du_p = NULL;
if (UE->ue_cap_buffer.len > 0 && UE->ue_cap_buffer.buf != NULL) {
@@ -2394,36 +2392,29 @@ void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_contex
rrc->mac_rrc.ue_context_modification_request(&ue_context_modif_req);
}
void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp, instance_t instance) {
// Find the UE context from UE ID and send ITTI message to F1AP to send UE context modification message to DU
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], resp->gNB_cu_cp_ue_id);
AssertFatal(ue_context_p != NULL, "did not find UE with CU UE ID %d\n", resp->gNB_cu_cp_ue_id);
protocol_ctxt_t ctxt = {0};
PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, GNB_FLAG_YES, resp->gNB_cu_cp_ue_id, 0, 0, 0);
// currently: we don't have "infrastructure" to save the CU-UP UE ID, so we
// assume (and below check) that CU-UP UE ID == CU-CP UE ID
AssertFatal(resp->gNB_cu_cp_ue_id == resp->gNB_cu_up_ue_id,
"cannot handle CU-UP UE ID different from CU-CP UE ID (%d vs %d)\n",
resp->gNB_cu_cp_ue_id,
resp->gNB_cu_up_ue_id);
gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp={0};
create_tunnel_resp.num_tunnels = resp->numPDUSessions;
for (int i=0; i < resp->numPDUSessions; i++) {
create_tunnel_resp.pdusession_id[i] = resp->pduSession[i].id;
create_tunnel_resp.gnb_NGu_teid[i] = resp->pduSession[i].teId;
memcpy(create_tunnel_resp.gnb_addr.buffer,
&resp->pduSession[i].tlAddress,
sizeof(in_addr_t));
create_tunnel_resp.gnb_addr.length = sizeof(in_addr_t); // IPv4 byte length
void rrc_gNB_process_e1_bearer_context_modif_resp(const e1ap_bearer_modif_resp_t *resp)
{
gNB_RRC_INST *rrc = RC.nrrrc[0];
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(rrc, resp->gNB_cu_cp_ue_id);
if (ue_context_p == NULL) {
LOG_E(RRC, "no UE with CU-CP UE ID %d found\n", resp->gNB_cu_cp_ue_id);
return;
}
nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0);
// there is not really anything to do here as of now
for (int i = 0; i < resp->numPDUSessionsMod; ++i) {
const pdu_session_modif_t *pdu = &resp->pduSessionMod[i];
LOG_I(RRC, "UE %d: PDU session ID %ld modified %d bearers\n", resp->gNB_cu_cp_ue_id, pdu->id, pdu->numDRBModified);
}
}
// TODO: SV: combine e1ap_bearer_setup_req_t and e1ap_bearer_setup_resp_t and minimize assignments
prepare_and_send_ue_context_modification_f1(ue_context_p, resp);
void rrc_gNB_process_e1_bearer_context_release_cplt(const e1ap_bearer_release_cplt_t *cplt)
{
// there is not really anything to do here as of now
// note that we don't check for the UE: it does not exist anymore if the F1
// UE context release complete arrived from the DU first, after which we free
// the UE context
LOG_I(RRC, "UE %d: received bearer release complete\n", cplt->gNB_cu_cp_ue_id);
}
static void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id)
@@ -2698,11 +2689,20 @@ void *rrc_gnb_task(void *args_p) {
break;
case E1AP_SETUP_REQ:
rrc_gNB_process_e1_setup_req(&E1AP_SETUP_REQ(msg_p), instance);
rrc_gNB_process_e1_setup_req(msg_p->ittiMsgHeader.originInstance, &E1AP_SETUP_REQ(msg_p));
break;
case E1AP_BEARER_CONTEXT_SETUP_RESP:
rrc_gNB_process_e1_bearer_context_setup_resp(&E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p), instance);
break;
case E1AP_BEARER_CONTEXT_MODIFICATION_RESP:
rrc_gNB_process_e1_bearer_context_modif_resp(&E1AP_BEARER_CONTEXT_MODIFICATION_RESP(msg_p));
break;
case E1AP_BEARER_CONTEXT_RELEASE_CPLT:
rrc_gNB_process_e1_bearer_context_release_cplt(&E1AP_BEARER_CONTEXT_RELEASE_CPLT(msg_p));
break;
case NGAP_PAGING_IND:
rrc_gNB_process_PAGING_IND(msg_p, instance);
@@ -2855,6 +2855,13 @@ rrc_gNB_generate_RRCRelease(
deliver_ue_ctxt_release_data_t data = {.rrc = rrc, .release_cmd = &ue_context_release_cmd};
nr_pdcp_data_req_srb(ctxt_pP->rntiMaybeUEid, DCCH, rrc_gNB_mui++, size, buffer, rrc_deliver_ue_ctxt_release_cmd, &data);
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, UE);
e1ap_bearer_release_cmd_t cmd = {
.gNB_cu_cp_ue_id = UE->rrc_ue_id,
.gNB_cu_up_ue_id = UE->rrc_ue_id,
};
rrc->cucp_cuup.bearer_context_release(assoc_id, &cmd);
/* UE will be freed after UE context release complete */
}
@@ -2936,7 +2943,8 @@ void rrc_gNB_trigger_new_bearer(int rnti)
ue->xids[xid] = RRC_PDUSESSION_MODIFY;
ue->pduSession[0].xid = xid; // hack: fake xid for ongoing PDU session
LOG_W(RRC, "trigger new bearer %ld for UE %04x xid %d\n", drb->id, ue->rnti, xid);
rrc->cucp_cuup.bearer_context_setup(&bearer_req, 0);
sctp_assoc_t assoc_id = get_existing_cuup_for_ue(rrc, ue);
rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req);
}
void rrc_gNB_trigger_release_bearer(int rnti)
-32
View File
@@ -75,35 +75,3 @@ int rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(const protocol_ctxt_t *const ctxt_
return 0;
}
int nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(const protocol_ctxt_t *const ctxt_pP, const gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp_pP, int offset)
{
if (!create_tunnel_resp_pP) {
LOG_E(NR_RRC, "create_tunnel_resp_pP error\n");
return -1;
}
LOG_D(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT " RX CREATE_TUNNEL_RESP num tunnels %u \n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), create_tunnel_resp_pP->num_tunnels);
/* we look up by CU UE ID! Do NOT change back to RNTI! */
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[ctxt_pP->module_id], ctxt_pP->rntiMaybeUEid);
if (!ue_context_p) {
LOG_E(NR_RRC, "UE table error\n");
return -1;
}
for (int i = 0; i < create_tunnel_resp_pP->num_tunnels; i++) {
ue_context_p->ue_context.pduSession[i + offset].param.gNB_teid_N3 = create_tunnel_resp_pP->gnb_NGu_teid[i];
ue_context_p->ue_context.pduSession[i + offset].param.gNB_addr_N3 = create_tunnel_resp_pP->gnb_addr;
AssertFatal(ue_context_p->ue_context.pduSession[i + offset].param.pdusession_id == create_tunnel_resp_pP->pdusession_id[i], "");
LOG_I(NR_RRC,
PROTOCOL_NR_RRC_CTXT_UE_FMT
" nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP tunnel (%u) bearer UE context index %u, id %u, gtp addr len %d \n",
PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP),
create_tunnel_resp_pP->gnb_NGu_teid[i],
i,
create_tunnel_resp_pP->pdusession_id[i],
create_tunnel_resp_pP->gnb_addr.length);
}
return 0;
}
-2
View File
@@ -38,6 +38,4 @@ rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(
uint8_t *inde_list
);
int nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(const protocol_ctxt_t *const ctxt_pP, const gtpv1u_gnb_create_tunnel_resp_t *const create_tunnel_resp_pP, int offset_in_rrc);
#endif
+21 -3
View File
@@ -378,6 +378,9 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
uint8_t nb_pdusessions_tosetup = req->nb_of_pdusessions;
if (nb_pdusessions_tosetup) {
AssertFatal(false, "PDU sessions in Initial context setup request not handled by E1 yet\n");
/* this code should pass by E1: commenting here for future reference, but
* already handled in E1 for the "normal case" of a separate request for
* PDU session setup.
gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0};
for (int i = 0; i < nb_pdusessions_tosetup; i++) {
UE->nb_of_pdusessions++;
@@ -404,6 +407,7 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t
}
nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0);
*/
}
/* NAS PDU */
@@ -757,6 +761,8 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
UE->amf_ue_ngap_id = msg->amf_ue_ngap_id;
e1ap_bearer_setup_req_t bearer_req = {0};
e1ap_nssai_t cuup_nssai = {0};
for (int i = 0; i < msg->nb_pdusessions_tosetup; i++) {
rrc_pdu_session_param_t *pduSession = find_pduSession(UE, msg->pdusession_setup_params[i].pdusession_id, true);
pdusession_t *session = &pduSession->param;
@@ -775,7 +781,13 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions;
bearer_req.numPDUSessions++;
pdu->sessionId = session->pdusession_id;
pdu->sst = msg->allowed_nssai[i].sST;
ngap_allowed_NSSAI_t *nssai = &msg->allowed_nssai[i];
pdu->nssai.sst = nssai->sST;
pdu->nssai.sd = 0xffffff;
if (nssai->sD_flag)
pdu->nssai.sd = nssai->sD[0] << 16 | nssai->sD[1] << 8 | nssai->sD[2];
if (cuup_nssai.sst == 0)
cuup_nssai = pdu->nssai; /* for CU-UP selection below */
pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed;
pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed;
@@ -787,7 +799,7 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
drb->id = i + j + UE->nb_of_pdusessions;
drb->defaultDRB = E1AP_DefaultDRB_true;
drb->defaultDRB = true;
drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap);
drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap);
@@ -823,7 +835,13 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins
}
int xid = rrc_gNB_get_next_transaction_identifier(instance);
UE->xids[xid] = RRC_PDUSESSION_ESTABLISH;
rrc->cucp_cuup.bearer_context_setup(&bearer_req, instance);
/* Limitation: we assume one fixed CU-UP per UE. We base the selection on
* NSSAI, but the UE might have multiple PDU sessions with differing slices,
* in which we might need to select different CU-UPs. In this case, we would
* actually need to group the E1 bearer context setup for the different
* CU-UPs, and send them to the different CU-UPs. */
sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd);
rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req);
return;
}
+174
View File
@@ -0,0 +1,174 @@
/*
* 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 "common/ran_context.h"
#include "nr_rrc_defs.h"
#include "openair2/F1AP/f1ap_ids.h"
static int cuup_compare(const nr_rrc_cuup_container_t *a, const nr_rrc_cuup_container_t *b)
{
if (a->assoc_id > b->assoc_id)
return 1;
if (a->assoc_id == b->assoc_id)
return 0;
return -1; /* a->assoc_id < b->assoc_id */
}
/* Tree management functions */
RB_GENERATE/*_STATIC*/(rrc_cuup_tree, nr_rrc_cuup_container_t, entries, cuup_compare);
static const nr_rrc_cuup_container_t *select_cuup_slice(const struct rrc_cuup_tree *t, const gNB_RRC_UE_t *ue, int sst, int sd)
{
nr_rrc_cuup_container_t *second_best_match = NULL; /* if no NSSAI matches exactly */
nr_rrc_cuup_container_t *cuup = NULL;
RB_FOREACH(cuup, rrc_cuup_tree, (struct rrc_cuup_tree *)&t) {
e1ap_setup_req_t *sr = cuup->setup_req;
for (int p = 0; p < sr->supported_plmns; ++p) {
/* actually we should also check that the PLMN selected by the UE matches */
for (int s = 0; s < sr->plmn[p].supported_slices; ++s) {
e1ap_nssai_t *nssai = &sr->plmn[p].slice[s];
if (nssai->sst == sst && nssai->sd == sd) {
LOG_I(RRC, "selecting CU-UP ID %ld based on exact NSSAI match (%d:0x%06x)\n", sr->gNB_cu_up_id, sst, sd);
return cuup; /* exact match */
} else if (nssai->sst == sst && second_best_match == NULL) {
LOG_I(RRC, "second best match: CU-UP ID %ld matches SST %d\n", sr->gNB_cu_up_id, sst);
second_best_match = cuup; /* only the SST matches -> "good enough" */
}
}
}
}
return second_best_match;
}
static const nr_rrc_cuup_container_t *select_cuup_round_robin(size_t n_t, const struct rrc_cuup_tree *t, const gNB_RRC_UE_t *ue)
{
/* pick the CU-UP following a "round-robin" fashion: select CU-UP M = RRC UE
* ID % N with N number of CU-UPs */
int m = (ue->rrc_ue_id - 1) % n_t;
nr_rrc_cuup_container_t *cuup = NULL;
RB_FOREACH(cuup, rrc_cuup_tree, (struct rrc_cuup_tree *)&t) {
if (m == 0) {
LOG_I(RRC, "round-robin match: select CU-UP ID %ld (no NSSAI match)\n", cuup->setup_req->gNB_cu_up_id);
return cuup;
}
m--;
}
/* this should not happen: no CU-UP available? */
return NULL;
}
sctp_assoc_t get_existing_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue)
{
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id);
if (ue_data.e1_assoc_id == 0) {
LOG_W(RRC, "UE %d should be associated to CU-UP, but is not\n", ue->rrc_ue_id);
/* we could possibly check the SST/SD from the PDU session */
return get_new_cuup_for_ue(rrc, ue, 0, 0);
}
LOG_D(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id);
return ue_data.e1_assoc_id;
}
sctp_assoc_t get_new_cuup_for_ue(const gNB_RRC_INST *rrc, const gNB_RRC_UE_t *ue, int sst, int sd)
{
/* check if there is already a UE associated */
f1_ue_data_t ue_data = cu_get_f1_ue_data(ue->rrc_ue_id);
if (ue_data.e1_assoc_id != 0) {
LOG_I(RRC, "UE %d using CU-UP assoc_id %d\n", ue->rrc_ue_id, ue_data.e1_assoc_id);
return ue_data.e1_assoc_id;
}
/* it is zero -> no CUUP for this UE yet, get the (only) CU-UP that is
* connected */
if (RB_EMPTY(&rrc->cuups)) {
LOG_W(RRC, "no CU-UPs connected: UE %d cannot have a DRB\n", ue->rrc_ue_id);
return 0; /* no CUUP connected */
}
const nr_rrc_cuup_container_t *selected = NULL;
if (sst != 0) /* only do if there is slice information */
selected = select_cuup_slice(&rrc->cuups, ue, sst, sd);
if (selected == NULL) /* nothing found yet */
selected = select_cuup_round_robin(rrc->num_cuups, &rrc->cuups, ue);
if (selected == NULL) {
selected = RB_ROOT(&rrc->cuups);
}
AssertFatal(selected != NULL, "logic error: could not select CU-UP, is one connected?\n");
/* update the association for the UE so it will be picked up later */
ue_data.e1_assoc_id = selected->assoc_id;
cu_remove_f1_ue_data(ue->rrc_ue_id);
cu_add_f1_ue_data(ue->rrc_ue_id, &ue_data);
LOG_I(RRC, "UE %d associating to CU-UP assoc_id %d out of %ld CU-UPs\n", ue->rrc_ue_id, ue_data.e1_assoc_id, rrc->num_cuups);
return ue_data.e1_assoc_id;
}
int rrc_gNB_process_e1_setup_req(sctp_assoc_t assoc_id, e1ap_setup_req_t *req)
{
AssertFatal(req->supported_plmns <= PLMN_LIST_MAX_SIZE, "Supported PLMNs is more than PLMN_LIST_MAX_SIZE\n");
gNB_RRC_INST *rrc = RC.nrrrc[0];
nr_rrc_cuup_container_t *c = NULL;
RB_FOREACH(c, rrc_cuup_tree, &rrc->cuups) {
if (req->gNB_cu_up_id == c->setup_req->gNB_cu_up_id) {
LOG_E(NR_RRC,
"Connecting CU-UP ID %ld name %s (assoc_id %d) has same ID as existing CU-UP ID %ld name %s (assoc_id %d)\n",
req->gNB_cu_up_id,
req->gNB_cu_up_name,
assoc_id,
c->setup_req->gNB_cu_up_id,
c->setup_req->gNB_cu_up_name,
c->assoc_id);
return -1;
}
}
for (int i = 0; i < req->supported_plmns; i++) {
PLMN_ID_t *id = &req->plmn[i].id;
if (rrc->configuration.mcc[i] != id->mcc || rrc->configuration.mnc[i] != id->mnc) {
LOG_E(NR_RRC,
"PLMNs received from CUUP (mcc:%d, mnc:%d) did not match with PLMNs in RRC (mcc:%d, mnc:%d)\n",
id->mcc,
id->mnc,
rrc->configuration.mcc[i],
rrc->configuration.mnc[i]);
return -1;
}
}
LOG_I(RRC, "Accepting new CU-UP ID %ld name %s (assoc_id %d)\n", req->gNB_cu_up_id, req->gNB_cu_up_name, assoc_id);
nr_rrc_cuup_container_t *cuup = malloc(sizeof(*cuup));
AssertFatal(cuup, "out of memory\n");
cuup->setup_req = malloc(sizeof(*cuup->setup_req));
*cuup->setup_req = *req;
cuup->assoc_id = assoc_id;
RB_INSERT(rrc_cuup_tree, &rrc->cuups, cuup);
rrc->num_cuups++;
MessageDef *msg_p = itti_alloc_new_message(TASK_RRC_GNB, 0, E1AP_SETUP_RESP);
msg_p->ittiMsgHeader.originInstance = assoc_id;
e1ap_setup_resp_t *resp = &E1AP_SETUP_RESP(msg_p);
resp->transac_id = req->transac_id;
itti_send_msg_to_task(TASK_CUCP_E1, 0, msg_p);
return 0;
}