Commit 380151fa authored by Robert Schmidt's avatar Robert Schmidt

E1 Bearer Context Setup Request: harmonize code

- harmonize monolithic and E1AP case
- use ITTI message to send bearer context setup response to RRC
parent 9546166e
......@@ -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)
......
......@@ -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})
......@@ -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);
......
/*
* 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__);
}
/*
* 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);
......
......@@ -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 */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment