E1 Bearer Context Setup Request: harmonize code
- harmonize monolithic and E1AP case - use ITTI message to send bearer context setup response to RRC
This commit is contained in:
+1
-7
@@ -1450,12 +1450,6 @@ add_library(e1_if
|
||||
|
||||
target_link_libraries(e1_if PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs asn1_f1ap SECURITY ${OPENSSL_LIBRARIES} e1ap GTPV1U)
|
||||
|
||||
add_library(e1_pdcp_if
|
||||
${OPENAIR2_DIR}/LAYER2/nr_pdcp/nr_pdcp_e1_api.c
|
||||
)
|
||||
|
||||
target_link_libraries(e1_pdcp_if PRIVATE asn1_nr_rrc_hdrs asn1_lte_rrc_hdrs)
|
||||
|
||||
target_link_libraries(L2_NR PRIVATE f1ap x2ap s1ap ngap nr_rrc e1ap nr_rlc)
|
||||
if(E2_AGENT)
|
||||
target_link_libraries(L2_NR PUBLIC e2_agent e2_ran_func)
|
||||
@@ -2111,7 +2105,7 @@ add_executable(nr-cuup
|
||||
|
||||
target_link_libraries(nr-cuup PRIVATE
|
||||
CONFIG_LIB ITTI SCTP_CLIENT
|
||||
GTPV1U e1ap e1_pdcp_if f1ap SIMU_ETH
|
||||
GTPV1U e1ap f1ap SIMU_ETH
|
||||
z sctp dl pthread shlib_loader ${T_LIB})
|
||||
target_link_libraries(nr-cuup PRIVATE asn1_lte_rrc_hdrs asn1_nr_rrc_hdrs)
|
||||
|
||||
|
||||
+8
-14
@@ -95,12 +95,6 @@ void nr_rlc_add_drb(int rnti, int drb_id, const NR_RLC_BearerConfig_t *rlc_Beare
|
||||
abort();
|
||||
}
|
||||
|
||||
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_p, int offset)
|
||||
{
|
||||
abort();
|
||||
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)
|
||||
{
|
||||
abort();
|
||||
@@ -108,14 +102,14 @@ void prepare_and_send_ue_context_modification_f1(rrc_gNB_ue_context_t *ue_contex
|
||||
|
||||
f1ap_cudu_inst_t *getCxt(instance_t instanceP)
|
||||
{
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NR_DRB_ToAddModList_t *fill_DRB_configList(gNB_RRC_UE_t *ue)
|
||||
{
|
||||
abort();
|
||||
return NULL;
|
||||
// the E1 module uses F1's getCxt() to decide whether there is F1-U and if
|
||||
// so, what is the GTP instance. In the CU-UP, we don't start the F1 module,
|
||||
// and instead, E1 handles the GTP-U endpoint. In the following, we fake the
|
||||
// instance and put the right GTP-U instance number in.
|
||||
const e1ap_upcp_inst_t *e1inst = getCxtE1(instanceP);
|
||||
static f1ap_cudu_inst_t fake = {0};
|
||||
fake.gtpInst = e1inst->gtpInstF1U;
|
||||
return &fake;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
||||
@@ -108,6 +108,8 @@ void nr_rrc_ue_generate_RRCSetupRequest(module_id_t module_id, const uint8_t gNB
|
||||
return;
|
||||
}
|
||||
|
||||
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); }
|
||||
|
||||
int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -104,6 +104,8 @@ void nr_rrc_ue_generate_RRCSetupRequest(module_id_t module_id, const uint8_t gNB
|
||||
return;
|
||||
}
|
||||
|
||||
void e1_bearer_context_setup(const e1ap_bearer_setup_req_t *req) { abort(); }
|
||||
|
||||
int8_t nr_rrc_RA_succeeded(const module_id_t mod_id, const uint8_t gNB_index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3,5 +3,5 @@ add_subdirectory(MESSAGES)
|
||||
add_library(e1ap e1ap.c e1ap_common.c e1ap_api.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})
|
||||
|
||||
+17
-8
@@ -33,6 +33,7 @@
|
||||
#include "openair2/F1AP/f1ap_common.h"
|
||||
#include "e1ap_default_values.h"
|
||||
#include "gtp_itf.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h"
|
||||
|
||||
#define E1AP_NUM_MSG_HANDLERS 14
|
||||
typedef int (*e1ap_message_processing_t)(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *message_p);
|
||||
@@ -684,7 +685,7 @@ void e1apCUCP_send_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_bear
|
||||
e1ap_encode_send(CPtype, assoc_id, &pdu, 0, __func__);
|
||||
}
|
||||
|
||||
static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const resp, E1AP_E1AP_PDU_t *pdu)
|
||||
static void fill_BEARER_CONTEXT_SETUP_RESPONSE(const e1ap_bearer_setup_resp_t *resp, E1AP_E1AP_PDU_t *pdu)
|
||||
{
|
||||
/* Create */
|
||||
/* 0. pdu Type */
|
||||
@@ -750,7 +751,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r
|
||||
msgNGRAN->value.present = E1AP_NG_RAN_BearerContextSetupResponse__value_PR_PDU_Session_Resource_Setup_List;
|
||||
E1AP_PDU_Session_Resource_Setup_List_t *pduSetup = &msgNGRAN->value.choice.PDU_Session_Resource_Setup_List;
|
||||
|
||||
for (pdu_session_setup_t *i=resp->pduSession; i < resp->pduSession+resp->numPDUSessions; i++) {
|
||||
for (const pdu_session_setup_t *i=resp->pduSession; i < resp->pduSession+resp->numPDUSessions; i++) {
|
||||
asn1cSequenceAdd(pduSetup->list, E1AP_PDU_Session_Resource_Setup_Item_t, ieC3_1);
|
||||
ieC3_1->pDU_Session_ID = i->id;
|
||||
|
||||
@@ -759,11 +760,11 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r
|
||||
TRANSPORT_LAYER_ADDRESS_IPv4_TO_BIT_STRING(i->tlAddress, &gTPTunnel->transportLayerAddress);
|
||||
INT32_TO_OCTET_STRING(i->teId, &gTPTunnel->gTP_TEID);
|
||||
|
||||
for (DRB_nGRAN_setup_t *j=i->DRBnGRanList; j < i->DRBnGRanList+i->numDRBSetup; j++) {
|
||||
for (const DRB_nGRAN_setup_t *j=i->DRBnGRanList; j < i->DRBnGRanList+i->numDRBSetup; j++) {
|
||||
asn1cSequenceAdd(ieC3_1->dRB_Setup_List_NG_RAN.list, E1AP_DRB_Setup_Item_NG_RAN_t, ieC3_1_1);
|
||||
ieC3_1_1->dRB_ID = j->id;
|
||||
|
||||
for (up_params_t *k=j->UpParamList; k < j->UpParamList+j->numUpParam; k++) {
|
||||
for (const up_params_t *k=j->UpParamList; k < j->UpParamList+j->numUpParam; k++) {
|
||||
asn1cSequenceAdd(ieC3_1_1->uL_UP_Transport_Parameters.list, E1AP_UP_Parameters_Item_t, ieC3_1_1_1);
|
||||
ieC3_1_1_1->uP_TNL_Information.present = E1AP_UP_TNL_Information_PR_gTPTunnel;
|
||||
asn1cCalloc(ieC3_1_1_1->uP_TNL_Information.choice.gTPTunnel, gTPTunnel);
|
||||
@@ -771,7 +772,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r
|
||||
INT32_TO_OCTET_STRING(k->teId, &gTPTunnel->gTP_TEID);
|
||||
}
|
||||
|
||||
for (qos_flow_setup_t *k=j->qosFlows; k < j->qosFlows+j->numQosFlowSetup; k++) {
|
||||
for (const qos_flow_setup_t *k=j->qosFlows; k < j->qosFlows+j->numQosFlowSetup; k++) {
|
||||
asn1cSequenceAdd(ieC3_1_1->flow_Setup_List.list, E1AP_QoS_Flow_Item_t, ieC3_1_1_1);
|
||||
ieC3_1_1_1->qoS_Flow_Identifier = k->id;
|
||||
}
|
||||
@@ -780,7 +781,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r
|
||||
if (i->numDRBFailed > 0)
|
||||
ieC3_1->dRB_Failed_List_NG_RAN = calloc(1, sizeof(E1AP_DRB_Failed_List_NG_RAN_t));
|
||||
|
||||
for (DRB_nGRAN_failed_t *j=i->DRBnGRanFailedList; j < i->DRBnGRanFailedList+i->numDRBFailed; j++) {
|
||||
for (const DRB_nGRAN_failed_t *j=i->DRBnGRanFailedList; j < i->DRBnGRanFailedList+i->numDRBFailed; j++) {
|
||||
asn1cSequenceAdd(ieC3_1->dRB_Failed_List_NG_RAN->list, E1AP_DRB_Failed_Item_NG_RAN_t, ieC3_1_1);
|
||||
ieC3_1_1->dRB_ID = j->id;
|
||||
|
||||
@@ -811,7 +812,7 @@ static void fill_BEARER_CONTEXT_SETUP_RESPONSE(e1ap_bearer_setup_resp_t *const r
|
||||
}
|
||||
}
|
||||
|
||||
void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, e1ap_bearer_setup_resp_t *const resp)
|
||||
void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_bearer_setup_resp_t *resp)
|
||||
{
|
||||
E1AP_E1AP_PDU_t pdu = {0};
|
||||
fill_BEARER_CONTEXT_SETUP_RESPONSE(resp, &pdu);
|
||||
@@ -996,7 +997,8 @@ int e1apCUUP_handle_BEARER_CONTEXT_SETUP_REQUEST(sctp_assoc_t assoc_id, e1ap_upc
|
||||
|
||||
e1ap_bearer_setup_req_t bearerCxt = {0};
|
||||
extract_BEARER_CONTEXT_SETUP_REQUEST(pdu, &bearerCxt);
|
||||
process_e1_bearer_context_setup_req(e1_inst->instance, &bearerCxt);
|
||||
|
||||
e1_bearer_context_setup(&bearerCxt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1769,6 +1771,13 @@ void *E1AP_CUUP_task(void *arg) {
|
||||
e1apHandleTimer(myInstance);
|
||||
break;
|
||||
|
||||
case E1AP_BEARER_CONTEXT_SETUP_RESP: {
|
||||
const e1ap_bearer_setup_resp_t *resp = &E1AP_BEARER_CONTEXT_SETUP_RESP(msg);
|
||||
const e1ap_upcp_inst_t *inst = getCxtE1(myInstance);
|
||||
AssertFatal(inst != NULL, "no E1 instance found for instance %ld\n", myInstance);
|
||||
e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(inst->cuup.assoc_id, resp);
|
||||
} break;
|
||||
|
||||
default:
|
||||
LOG_E(E1AP, "Unknown message received in TASK_CUUP_E1\n");
|
||||
break;
|
||||
|
||||
@@ -42,7 +42,7 @@ int e1apCUCP_handle_BEARER_CONTEXT_SETUP_FAILURE(sctp_assoc_t assoc_id, e1ap_upc
|
||||
|
||||
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(sctp_assoc_t assoc_id, e1ap_bearer_setup_resp_t *const resp);
|
||||
void e1apCUUP_send_BEARER_CONTEXT_SETUP_RESPONSE(sctp_assoc_t assoc_id, const e1ap_bearer_setup_resp_t *resp);
|
||||
|
||||
int e1apCUUP_handle_BEARER_CONTEXT_RELEASE_COMMAND(sctp_assoc_t assoc_id, e1ap_upcp_inst_t *inst, const E1AP_E1AP_PDU_t *pdu);
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#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"
|
||||
@@ -35,146 +34,6 @@
|
||||
#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->net_config.localAddressF1U, &my_addr) != 1)
|
||||
LOG_E(E1AP, "can't use the F1-U local interface: %s\n", inst->net_config.localAddressF1U);
|
||||
fill_e1ap_bearer_setup_resp(resp, req, inst->gtpInstF1U, req->gNB_cu_cp_ue_id, inst->net_config.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->net_config.localAddressN3, &pduSetup->tlAddress) != 1)
|
||||
LOG_E(E1AP, "can't use the N3 local interface: %s\n", inst->net_config.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->cuup.assoc_id, 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);
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#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);
|
||||
|
||||
void CUUP_process_bearer_release_command(instance_t, e1ap_bearer_release_cmd_t *const cmd);
|
||||
|
||||
@@ -20,3 +20,202 @@
|
||||
*/
|
||||
|
||||
#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, 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_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);
|
||||
}
|
||||
|
||||
@@ -26,4 +26,7 @@
|
||||
|
||||
void nr_pdcp_e1_if_init(bool uses_e1);
|
||||
|
||||
struct e1ap_bearer_setup_req_s;
|
||||
void e1_bearer_context_setup(const struct e1ap_bearer_setup_req_s *req);
|
||||
|
||||
#endif /* CUCP_CUUP_HANDLER_H */
|
||||
|
||||
@@ -20,8 +20,18 @@
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
void cuup_cucp_init_direct(e1_if_t *iface)
|
||||
{
|
||||
(void) iface;
|
||||
iface->bearer_setup_response = bearer_setup_response_direct;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,18 @@
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
|
||||
void cuup_cucp_init_e1ap(e1_if_t *iface)
|
||||
{
|
||||
(void) iface;
|
||||
iface->bearer_setup_response = bearer_setup_response_e1ap;
|
||||
}
|
||||
|
||||
@@ -24,7 +24,11 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct e1ap_bearer_setup_resp_s;
|
||||
typedef void (*e1_bearer_setup_response_func_t)(const struct e1ap_bearer_setup_resp_s *resp);
|
||||
|
||||
typedef struct e1_if_t {
|
||||
e1_bearer_setup_response_func_t bearer_setup_response;
|
||||
} e1_if_t;
|
||||
|
||||
e1_if_t *get_e1_if(void);
|
||||
|
||||
@@ -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__);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#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"
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include "openair3/SECU/key_nas_deriver.h"
|
||||
|
||||
#include "nr_pdcp/nr_pdcp_entity.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/nr_pdcp_e1_api.h"
|
||||
#include "openair2/LAYER2/nr_pdcp/cucp_cuup_handler.h"
|
||||
#include <openair2/RRC/NR/rrc_gNB_UE_context.h>
|
||||
#include "openair3/ocp-gtpu/gtp_itf.h"
|
||||
#include "rrc_gNB_GTPV1U.h"
|
||||
@@ -42,42 +42,10 @@
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void cucp_cuup_bearer_context_setup_direct(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *req)
|
||||
{
|
||||
AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id);
|
||||
e1_bearer_context_setup(req);
|
||||
}
|
||||
|
||||
void CU_update_UP_DL_tunnel(e1ap_bearer_setup_req_t *const req, instance_t instance, ue_id_t ue_id) {
|
||||
@@ -97,114 +65,6 @@ void CU_update_UP_DL_tunnel(e1ap_bearer_setup_req_t *const req, instance_t insta
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
static void cucp_cuup_bearer_context_setup_direct(sctp_assoc_t assoc_id, e1ap_bearer_setup_req_t *const req)
|
||||
{
|
||||
AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id);
|
||||
rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[0], 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(0)->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);
|
||||
}
|
||||
|
||||
static void cucp_cuup_bearer_context_mod_direct(sctp_assoc_t assoc_id, e1ap_bearer_setup_req_t *const req)
|
||||
{
|
||||
AssertFatal(assoc_id == -1, "illegal assoc_id %d, impossible for integrated CU\n", assoc_id);
|
||||
|
||||
@@ -28,15 +28,8 @@
|
||||
#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(sctp_assoc_t assoc_id, e1ap_bearer_setup_req_t *const req)
|
||||
static void cucp_cuup_bearer_context_setup_e1ap(sctp_assoc_t assoc_id, const e1ap_bearer_setup_req_t *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);
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
struct e1ap_bearer_setup_req_s;
|
||||
struct e1ap_bearer_setup_resp_s;
|
||||
typedef void (*cucp_cuup_bearer_context_setup_func_t)(sctp_assoc_t assoc_id, struct e1ap_bearer_setup_req_s *const req);
|
||||
typedef void (*cucp_cuup_bearer_context_setup_func_t)(sctp_assoc_t assoc_id, const struct e1ap_bearer_setup_req_s *req);
|
||||
|
||||
struct gNB_RRC_INST_s;
|
||||
void cucp_cuup_message_transfer_direct_init(struct gNB_RRC_INST_s *rrc);
|
||||
|
||||
@@ -148,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);
|
||||
|
||||
+29
-42
@@ -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"
|
||||
@@ -2317,24 +2316,42 @@ static int get_dl_mimo_layers(const f1ap_served_cell_info_t *cell_info, const NR
|
||||
return(1);
|
||||
}
|
||||
|
||||
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].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 = e1ap_resp->pduSession[0].DRBnGRanList[i].UpParamList[0].tlAddress;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2348,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) {
|
||||
@@ -2374,38 +2392,6 @@ 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
|
||||
}
|
||||
|
||||
nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
static void rrc_CU_process_f1_lost_connection(gNB_RRC_INST *rrc, f1ap_lost_connection_t *lc, sctp_assoc_t assoc_id)
|
||||
{
|
||||
AssertFatal(rrc->du != NULL, "no DU connected, cannot received F1 lost connection\n");
|
||||
@@ -2683,6 +2669,7 @@ void *rrc_gnb_task(void *args_p) {
|
||||
|
||||
case E1AP_BEARER_CONTEXT_SETUP_RESP:
|
||||
rrc_gNB_process_e1_bearer_context_setup_resp(&E1AP_BEARER_CONTEXT_SETUP_RESP(msg_p), instance);
|
||||
break;
|
||||
|
||||
case NGAP_PAGING_IND:
|
||||
rrc_gNB_process_PAGING_IND(msg_p, instance);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user