diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c index b9ca19300a..bcf7c26ae6 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_direct.c @@ -69,7 +69,6 @@ static void f1_setup_request_direct(const f1ap_setup_req_t *req) static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) { DevAssert(req->drbs_to_be_setup_length == resp->drbs_to_be_setup_length); - AssertFatal(req->drbs_to_be_setup_length == 0, "not implemented\n"); (void) req; /* we don't need the request -- it is to set up GTP in F1 case */ MessageDef *msg = itti_alloc_new_message (TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_SETUP_RESP); @@ -85,6 +84,13 @@ static void ue_context_setup_response_direct(const f1ap_ue_context_setup_t *req, for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; } + if (resp->drbs_to_be_setup_length > 0) { + DevAssert(resp->drbs_to_be_setup != NULL); + f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); + for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) + f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; + } f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); diff --git a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c index 8e0a04cac8..fea829f61e 100644 --- a/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c +++ b/openair2/LAYER2/NR_MAC_gNB/mac_rrc_ul_f1ap.c @@ -103,7 +103,6 @@ static void f1_setup_request_f1ap(const f1ap_setup_req_t *req) static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, const f1ap_ue_context_setup_t *resp) { DevAssert(req->drbs_to_be_setup_length == resp->drbs_to_be_setup_length); - AssertFatal(req->drbs_to_be_setup_length == 0, "not implmented\n"); DevAssert(req->srbs_to_be_setup_length == resp->srbs_to_be_setup_length); MessageDef *msg = itti_alloc_new_message (TASK_MAC_GNB, 0, F1AP_UE_CONTEXT_SETUP_RESP); @@ -118,6 +117,13 @@ static void ue_context_setup_response_f1ap(const f1ap_ue_context_setup_t *req, c for (int i = 0; i < f1ap_msg->srbs_to_be_setup_length; ++i) f1ap_msg->srbs_to_be_setup[i] = resp->srbs_to_be_setup[i]; } + if (resp->drbs_to_be_setup_length > 0) { + DevAssert(resp->drbs_to_be_setup != NULL); + f1ap_msg->drbs_to_be_setup_length = resp->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup = calloc(f1ap_msg->drbs_to_be_setup_length, sizeof(*f1ap_msg->drbs_to_be_setup)); + for (int i = 0; i < f1ap_msg->drbs_to_be_setup_length; ++i) + f1ap_msg->drbs_to_be_setup[i] = resp->drbs_to_be_setup[i]; + } f1ap_msg->du_to_cu_rrc_information = malloc(sizeof(*resp->du_to_cu_rrc_information)); AssertFatal(f1ap_msg->du_to_cu_rrc_information != NULL, "out of memory\n"); diff --git a/openair2/RRC/NR/mac_rrc_dl_f1ap.c b/openair2/RRC/NR/mac_rrc_dl_f1ap.c index 891d5d94f1..e501dde45b 100644 --- a/openair2/RRC/NR/mac_rrc_dl_f1ap.c +++ b/openair2/RRC/NR/mac_rrc_dl_f1ap.c @@ -51,8 +51,20 @@ static void ue_context_setup_request_f1ap(sctp_assoc_t assoc_id, const f1ap_ue_c f1ap_ue_context_setup_t *f1ap_msg = &F1AP_UE_CONTEXT_SETUP_REQ(msg); *f1ap_msg = *req; AssertFatal(req->cu_to_du_rrc_information == NULL, "cu_to_du_rrc_information not supported yet\n"); - AssertFatal(req->drbs_to_be_setup == NULL, "drbs_to_be_setup not supported yet\n"); - AssertFatal(req->srbs_to_be_setup == NULL, "drbs_to_be_setup not supported yet\n"); + if (req->drbs_to_be_setup_length > 0) { + int n = req->drbs_to_be_setup_length; + f1ap_msg->drbs_to_be_setup_length = n; + f1ap_msg->drbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->drbs_to_be_setup)); + AssertFatal(f1ap_msg->drbs_to_be_setup != NULL, "out of memory\n"); + memcpy(f1ap_msg->drbs_to_be_setup, req->drbs_to_be_setup, n * sizeof(*f1ap_msg->drbs_to_be_setup)); + } + if (req->srbs_to_be_setup_length > 0) { + int n = req->srbs_to_be_setup_length; + f1ap_msg->srbs_to_be_setup_length = n; + f1ap_msg->srbs_to_be_setup = calloc(n, sizeof(*f1ap_msg->srbs_to_be_setup)); + AssertFatal(f1ap_msg->srbs_to_be_setup != NULL, "out of memory\n"); + memcpy(f1ap_msg->srbs_to_be_setup, req->srbs_to_be_setup, n * sizeof(*f1ap_msg->srbs_to_be_setup)); + } if (req->rrc_container_length > 0) { f1ap_msg->rrc_container = calloc(req->rrc_container_length, sizeof(*f1ap_msg->rrc_container)); AssertFatal(f1ap_msg->rrc_container != NULL, "out of memory\n"); diff --git a/openair2/RRC/NR/nr_rrc_proto.h b/openair2/RRC/NR/nr_rrc_proto.h index 7c2374acfa..e034005ceb 100644 --- a/openair2/RRC/NR/nr_rrc_proto.h +++ b/openair2/RRC/NR/nr_rrc_proto.h @@ -81,7 +81,9 @@ int parse_CG_ConfigInfo(gNB_RRC_INST *rrc, NR_CG_ConfigInfo_t *CG_ConfigInfo, x2 void rrc_gNB_generate_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *const ue_context_pP + rrc_gNB_ue_context_t *const ue_context_pP, + int n_drbs, + const f1ap_drb_to_be_setup_t *drbs ); unsigned int rrc_gNB_get_next_transaction_identifier(module_id_t gnb_mod_idP); diff --git a/openair2/RRC/NR/rrc_gNB.c b/openair2/RRC/NR/rrc_gNB.c index 1b0e5c1e1b..b054b2c58b 100644 --- a/openair2/RRC/NR/rrc_gNB.c +++ b/openair2/RRC/NR/rrc_gNB.c @@ -509,7 +509,6 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co { gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; gNB_RRC_UE_t *ue_p = &ue_context_pP->ue_context; - AssertFatal(ue_p->nb_of_pdusessions == 0, "logic bug: PDU sessions present before RRC Connection established\n"); uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt_pP->module_id); ue_p->xids[xid] = RRC_DEFAULT_RECONF; @@ -551,14 +550,16 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co uint32_t ssb_arfcn = get_ssb_arfcn(cell_info, du->mib, du->sib1); measconfig = get_defaultMeasConfig(ssb_arfcn, band, scs); } + NR_SRB_ToAddModList_t *SRBs = createSRBlist(ue_p, false); + NR_DRB_ToAddModList_t *DRBs = createDRBlist(ue_p, false); uint8_t buffer[RRC_BUF_SIZE] = {0}; int size = do_RRCReconfiguration(ue_p, buffer, RRC_BUF_SIZE, xid, - NULL, //*SRB_configList2, - NULL, //*DRB_configList, + SRBs, + DRBs, NULL, NULL, measconfig, @@ -566,6 +567,8 @@ static void rrc_gNB_generate_defaultRRCReconfiguration(const protocol_ctxt_t *co ue_p->masterCellGroup); AssertFatal(size > 0, "cannot encode RRCReconfiguration in %s()\n", __func__); free_defaultMeasConfig(measconfig); + freeSRBlist(SRBs); + freeDRBlist(DRBs); if (LOG_DEBUGFLAG(DEBUG_ASN1)) { xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, ue_p->masterCellGroup); @@ -1759,6 +1762,11 @@ static void rrc_CU_process_ue_context_setup_response(MessageDef *msg_p, instance if (LOG_DEBUGFLAG(DEBUG_ASN1)) xer_fprint(stdout, &asn_DEF_NR_CellGroupConfig, UE->masterCellGroup); + if (resp->drbs_to_be_setup_length > 0) { + AssertFatal(resp->srbs_to_be_setup_length > 0 && resp->srbs_to_be_setup[0].srb_id == 2, "logic bug: we set up DRBs, so need to have both SRB1&SRB2\n"); + e1_send_bearer_updates(rrc, UE, resp->drbs_to_be_setup_length, resp->drbs_to_be_setup); + } + /* at this point, we don't have to do anything: the UE context setup request * includes the Security Command, whose response will trigger the following * messages (UE capability, to be specific) */ @@ -2006,7 +2014,7 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp /* Instruction towards the DU for SRB2 configuration */ int nb_srb = 0; - f1ap_srb_to_be_setup_t srbs[1]; + f1ap_srb_to_be_setup_t srbs[1] = {0}; if (UE->Srb[2].Active == 0) { activate_srb(UE, 2); nb_srb = 1; @@ -2017,7 +2025,8 @@ void rrc_gNB_process_e1_bearer_context_setup_resp(e1ap_bearer_setup_resp_t *resp if (!UE->as_security_active) { /* no AS security active, need to send UE context setup req with security * command (and the bearers) */ - AssertFatal(false, "not implemented yet\n"); + protocol_ctxt_t ctxt = {.rntiMaybeUEid = UE->rrc_ue_id}; + rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p, nb_drb, drbs); return; } @@ -2387,7 +2396,9 @@ static void rrc_deliver_ue_ctxt_setup_req(void *deliver_pdu_data, ue_id_t ue_id, void rrc_gNB_generate_SecurityModeCommand( const protocol_ctxt_t *const ctxt_pP, - rrc_gNB_ue_context_t *const ue_context_pP + rrc_gNB_ue_context_t *const ue_context_pP, + int n_drbs, + const f1ap_drb_to_be_setup_t *drbs ) //----------------------------------------------------------------------------- { @@ -2413,6 +2424,16 @@ rrc_gNB_generate_SecurityModeCommand( cu2du.uE_CapabilityRAT_ContainerList_length = ue_p->ue_cap_buffer.len; } + int nb_srb = 0; + f1ap_srb_to_be_setup_t srb_buf[1] = {0}; + f1ap_srb_to_be_setup_t *srbs = 0; + if (n_drbs > 0) { + nb_srb = 1; + srb_buf[0].srb_id = 2; + srb_buf[0].lcid = 2; + srbs = srb_buf; + } + /* the callback will fill the UE context setup request and forward it */ f1_ue_data_t ue_data = cu_get_f1_ue_data(ue_p->rrc_ue_id); RETURN_IF_INVALID_ASSOC_ID(ue_data); @@ -2424,8 +2445,10 @@ rrc_gNB_generate_SecurityModeCommand( .plmn.mnc_digit_length = rrc->configuration.mnc_digit_length[0], .nr_cellid = rrc->nr_cellid, .servCellId = 0, /* TODO: correct value? */ - .srbs_to_be_setup = 0, /* no new SRBs */ - .drbs_to_be_setup = 0, /* no new DRBs */ + .srbs_to_be_setup_length = nb_srb, + .srbs_to_be_setup = srbs, + .drbs_to_be_setup_length = n_drbs, + .drbs_to_be_setup = (f1ap_drb_to_be_setup_t *) drbs, .cu_to_du_rrc_information = cu2du_p, }; deliver_ue_ctxt_setup_data_t data = {.rrc = rrc, .setup_req = &ue_context_setup_req, .assoc_id = ue_data.du_assoc_id }; diff --git a/openair2/RRC/NR/rrc_gNB_NGAP.c b/openair2/RRC/NR/rrc_gNB_NGAP.c index bc653a805c..e3e83610f2 100644 --- a/openair2/RRC/NR/rrc_gNB_NGAP.c +++ b/openair2/RRC/NR/rrc_gNB_NGAP.c @@ -362,6 +362,111 @@ static int decodePDUSessionResourceSetup(pdusession_t *session) return 0; } +static void trigger_bearer_setup(gNB_RRC_INST *rrc, gNB_RRC_UE_t *UE, int n, pdusession_t *sessions, uint64_t ueAggMaxBitRateDownlink) +{ + e1ap_bearer_setup_req_t bearer_req = {0}; + + e1ap_nssai_t cuup_nssai = {0}; + for (int i = 0; i < n; i++) { + rrc_pdu_session_param_t *pduSession = find_pduSession(UE, sessions[i].pdusession_id, true); + pdusession_t *session = &pduSession->param; + session->pdusession_id = sessions[i].pdusession_id; + LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); + session->pdu_session_type = sessions[i].pdu_session_type; + session->nas_pdu = sessions[i].nas_pdu; + session->pdusessionTransfer = sessions[i].pdusessionTransfer; + session->nssai = sessions[i].nssai; + decodePDUSessionResourceSetup(session); + bearer_req.gNB_cu_cp_ue_id = UE->rrc_ue_id; + bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; + bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; + nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); + nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); + bearer_req.ueDlAggMaxBitRate = ueAggMaxBitRateDownlink; + pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; + bearer_req.numPDUSessions++; + pdu->sessionId = session->pdusession_id; + pdu->nssai = sessions[i].nssai; + if (cuup_nssai.sst == 0) + cuup_nssai = pdu->nssai; /* for CU-UP selection below */ + + pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; + + pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; + pdu->teId = session->gtp_teid; + memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target + + /* we assume for the moment one DRB per PDU session. Activate the bearer, + * and configure in RRC. */ + int drb_id = get_next_available_drb_id(UE); + drb_t *rrc_drb = generateDRB(UE, + drb_id, + pduSession, + rrc->configuration.enable_sdap, + rrc->security.do_drb_integrity, + rrc->security.do_drb_ciphering); + + pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding + for (int j=0; j < pdu->numDRB2Setup; j++) { + DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; + + drb->id = rrc_drb->drb_id; + + struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; + drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; + drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; + drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; + + struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config; + drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL; + drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL; + drb->discardTimer = pdcp_config->discardTimer; + drb->reorderingTimer = pdcp_config->t_Reordering; + + drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; + + drb->numCellGroups = 1; // assume one cell group associated with a DRB + + for (int k=0; k < drb->numCellGroups; k++) { + cell_group_t *cellGroup = drb->cellGroupList + k; + cellGroup->id = 0; // MCG + } + + drb->numQosFlow2Setup = session->nb_qos; + for (int k=0; k < drb->numQosFlow2Setup; k++) { + qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; + pdusession_level_qos_parameter_t *qos_session = session->qos + k; + + qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; + qos_flow->qfi = qos_session->qfi; + qos_char->qos_type = qos_session->fiveQI_type; + if (qos_char->qos_type == dynamic) { + qos_char->dynamic.fiveqi = qos_session->fiveQI; + qos_char->dynamic.qos_priority_level = qos_session->qos_priority; + } else { + qos_char->non_dynamic.fiveqi = qos_session->fiveQI; + qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority; + } + + ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; + ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority; + rent_priority->priority_level = rent_priority_in->priority_level; + rent_priority->preemption_capability = rent_priority_in->pre_emp_capability; + rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability; + } + } + } + int xid = rrc_gNB_get_next_transaction_identifier(0); + UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; + /* Limitation: we assume one fixed CU-UP per UE. We base the selection on + * NSSAI, but the UE might have multiple PDU sessions with differing slices, + * in which we might need to select different CU-UPs. In this case, we would + * actually need to group the E1 bearer context setup for the different + * CU-UPs, and send them to the different CU-UPs. */ + sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd); + rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); +} + //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t instance) //------------------------------------------------------------------------------ @@ -384,40 +489,6 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t } PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0); UE->amf_ue_ngap_id = req->amf_ue_ngap_id; - 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++; - if(UE->pduSession[i].status >= PDU_SESSION_STATUS_DONE) - continue; - UE->pduSession[i].status = PDU_SESSION_STATUS_NEW; - UE->pduSession[i].param = req->pdusession_param[i]; - create_tunnel_req.num_tunnels++; - create_tunnel_req.pdusession_id[i] = req->pdusession_param[i].pdusession_id; - create_tunnel_req.outgoing_teid[i] = req->pdusession_param[i].gtp_teid; - // To be developped: hardcoded first flow - create_tunnel_req.outgoing_qfi[i] = req->pdusession_param[i].qos[0].qfi; - create_tunnel_req.dst_addr[i].length = req->pdusession_param[i].upf_addr.length; - memcpy(create_tunnel_req.dst_addr[i].buffer, req->pdusession_param[i].upf_addr.buffer, sizeof(create_tunnel_req.dst_addr[i].buffer)); - LOG_I(NR_RRC, "PDUSESSION SETUP: local index %d teid %u, pdusession id %d \n", i, create_tunnel_req.outgoing_teid[i], create_tunnel_req.pdusession_id[i]); - } - create_tunnel_req.ue_id = UE->rrc_ue_id; - gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp = {0}; - int ret = gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, &create_tunnel_resp, nr_pdcp_data_req_drb, sdap_data_req); - if (ret != 0) { - LOG_E(NR_RRC, "rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ : gtpv1u_create_ngu_tunnel failed,start to release UE %x\n", UE->rnti); - AssertFatal(false, "release timer not implemented\n"); - return (0); - } - - nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0); - */ - } /* NAS PDU */ // this is malloced pointers, we pass it for later free() @@ -430,7 +501,19 @@ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t /* configure only integrity, ciphering comes after receiving SecurityModeComplete */ nr_rrc_pdcp_config_security(&ctxt, ue_context_p, 0); - rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p); + uint8_t nb_pdusessions_tosetup = req->nb_of_pdusessions; + /* if there are PDU sessions to setup, first send them to the CU-UP, then + * send the UE Context setup with Security commend. Else go to the security + * command directly. */ + if (nb_pdusessions_tosetup > 0) { + trigger_bearer_setup(RC.nrrrc[instance], + UE, + req->nb_of_pdusessions, + req->pdusession_param, + /*req->ueAggMaxBitRateDownlink*/ 0); + } else { + rrc_gNB_generate_SecurityModeCommand(&ctxt, ue_context_p, 0, NULL); + } return 0; } @@ -762,109 +845,9 @@ void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t ins return ; } - UE->rrc_ue_id = msg->gNB_ue_ngap_id; + AssertFatal(UE->rrc_ue_id == msg->gNB_ue_ngap_id, "logic bug\n"); UE->amf_ue_ngap_id = msg->amf_ue_ngap_id; - e1ap_bearer_setup_req_t bearer_req = {0}; - - - e1ap_nssai_t cuup_nssai = {0}; - for (int i = 0; i < msg->nb_pdusessions_tosetup; i++) { - rrc_pdu_session_param_t *pduSession = find_pduSession(UE, msg->pdusession_setup_params[i].pdusession_id, true); - pdusession_t *session = &pduSession->param; - session->pdusession_id = msg->pdusession_setup_params[i].pdusession_id; - LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions); - session->pdu_session_type = msg->pdusession_setup_params[i].pdu_session_type; - session->nas_pdu = msg->pdusession_setup_params[i].nas_pdu; - session->pdusessionTransfer = msg->pdusession_setup_params[i].pdusessionTransfer; - session->nssai = msg->pdusession_setup_params[i].nssai; - decodePDUSessionResourceSetup(session); - bearer_req.gNB_cu_cp_ue_id = msg->gNB_ue_ngap_id; - bearer_req.cipheringAlgorithm = UE->ciphering_algorithm; - bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm; - nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, (uint8_t *)bearer_req.encryptionKey); - nr_derive_key(UP_INT_ALG, UE->integrity_algorithm, UE->kgnb, (uint8_t *)bearer_req.integrityProtectionKey); - bearer_req.ueDlAggMaxBitRate = msg->ueAggMaxBitRateDownlink; - pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions; - bearer_req.numPDUSessions++; - pdu->sessionId = session->pdusession_id; - pdu->nssai = msg->pdusession_setup_params[i].nssai; - if (cuup_nssai.sst == 0) - cuup_nssai = pdu->nssai; /* for CU-UP selection below */ - pdu->integrityProtectionIndication = rrc->security.do_drb_integrity ? E1AP_IntegrityProtectionIndication_required : E1AP_IntegrityProtectionIndication_not_needed; - - pdu->confidentialityProtectionIndication = rrc->security.do_drb_ciphering ? E1AP_ConfidentialityProtectionIndication_required : E1AP_ConfidentialityProtectionIndication_not_needed; - pdu->teId = session->gtp_teid; - memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target - - /* we assume for the moment one DRB per PDU session. Activate the bearer, - * and configure in RRC. */ - int drb_id = get_next_available_drb_id(UE); - drb_t *rrc_drb = generateDRB(UE, - drb_id, - pduSession, - rrc->configuration.enable_sdap, - rrc->security.do_drb_integrity, - rrc->security.do_drb_ciphering); - - pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding - for (int j=0; j < pdu->numDRB2Setup; j++) { - DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j; - - drb->id = rrc_drb->drb_id; - - struct sdap_config_s *sdap_config = &rrc_drb->cnAssociation.sdap_config; - drb->defaultDRB = sdap_config->defaultDRB ? E1AP_DefaultDRB_true : E1AP_DefaultDRB_false; - drb->sDAP_Header_UL = sdap_config->sdap_HeaderUL; - drb->sDAP_Header_DL = sdap_config->sdap_HeaderDL; - - struct pdcp_config_s *pdcp_config = &rrc_drb->pdcp_config; - drb->pDCP_SN_Size_UL = pdcp_config->pdcp_SN_SizeUL; - drb->pDCP_SN_Size_DL = pdcp_config->pdcp_SN_SizeDL; - drb->discardTimer = pdcp_config->discardTimer; - drb->reorderingTimer = pdcp_config->t_Reordering; - - drb->rLC_Mode = rrc->configuration.um_on_default_drb ? E1AP_RLC_Mode_rlc_um_bidirectional : E1AP_RLC_Mode_rlc_am; - - drb->numCellGroups = 1; // assume one cell group associated with a DRB - - for (int k=0; k < drb->numCellGroups; k++) { - cell_group_t *cellGroup = drb->cellGroupList + k; - cellGroup->id = 0; // MCG - } - - drb->numQosFlow2Setup = session->nb_qos; - for (int k=0; k < drb->numQosFlow2Setup; k++) { - qos_flow_to_setup_t *qos_flow = drb->qosFlows + k; - pdusession_level_qos_parameter_t *qos_session = session->qos + k; - - qos_characteristics_t *qos_char = &qos_flow->qos_params.qos_characteristics; - qos_flow->qfi = qos_session->qfi; - qos_char->qos_type = qos_session->fiveQI_type; - if (qos_char->qos_type == dynamic) { - qos_char->dynamic.fiveqi = qos_session->fiveQI; - qos_char->dynamic.qos_priority_level = qos_session->qos_priority; - } else { - qos_char->non_dynamic.fiveqi = qos_session->fiveQI; - qos_char->non_dynamic.qos_priority_level = qos_session->qos_priority; - } - - ngran_allocation_retention_priority_t *rent_priority = &qos_flow->qos_params.alloc_reten_priority; - ngap_allocation_retention_priority_t *rent_priority_in = &qos_session->allocation_retention_priority; - rent_priority->priority_level = rent_priority_in->priority_level; - rent_priority->preemption_capability = rent_priority_in->pre_emp_capability; - rent_priority->preemption_vulnerability = rent_priority_in->pre_emp_vulnerability; - } - } - } - int xid = rrc_gNB_get_next_transaction_identifier(instance); - UE->xids[xid] = RRC_PDUSESSION_ESTABLISH; - /* Limitation: we assume one fixed CU-UP per UE. We base the selection on - * NSSAI, but the UE might have multiple PDU sessions with differing slices, - * in which we might need to select different CU-UPs. In this case, we would - * actually need to group the E1 bearer context setup for the different - * CU-UPs, and send them to the different CU-UPs. */ - sctp_assoc_t assoc_id = get_new_cuup_for_ue(rrc, UE, cuup_nssai.sst, cuup_nssai.sd); - rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req); + trigger_bearer_setup(rrc, UE, msg->nb_pdusessions_tosetup, msg->pdusession_setup_params, msg->ueAggMaxBitRateDownlink); return; }