/* * 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 */ /*! \file rrc_gNB_NGAP.h * \brief rrc NGAP procedures for gNB * \author Yoshio INOUE, Masayuki HARADA * \date 2020 * \version 0.1 * \email: yoshio.inoue@fujitsu.com,masayuki.harada@fujitsu.com * (yoshio.inoue%40fujitsu.com%2cmasayuki.harada%40fujitsu.com) */ #include "rrc_gNB_NGAP.h" #include "RRC/L2_INTERFACE/openair_rrc_L2_interface.h" #include "rrc_eNB_S1AP.h" #include "gnb_config.h" #include "common/ran_context.h" #include "gtpv1u.h" #include "asn1_conversions.h" #include "intertask_interface.h" #include "pdcp.h" #include "pdcp_primitives.h" #include "msc.h" #include "gtpv1u_eNB_task.h" #include "gtpv1u_gNB_task.h" #include "RRC/LTE/rrc_eNB_GTPV1U.h" #include "RRC/NR/rrc_gNB_GTPV1U.h" #include "S1AP_NAS-PDU.h" #include "executables/softmodem-common.h" #include "UTIL/OSA/osa_defs.h" #include "ngap_gNB_defs.h" #include "ngap_gNB_ue_context.h" #include "ngap_gNB_management_procedures.h" #include "NR_ULInformationTransfer.h" #include "RRC/NR/MESSAGES/asn1_msg.h" #include "NR_UERadioAccessCapabilityInformation.h" #include "NR_UE-CapabilityRAT-ContainerList.h" extern RAN_CONTEXT_t RC; /* Value to indicate an invalid UE initial id */ static const uint16_t UE_INITIAL_ID_INVALID = 0; /* Masks for NGAP Encryption algorithms, NEA0 is always supported (not coded) */ static const uint16_t NGAP_ENCRYPTION_NEA1_MASK = 0x8000; static const uint16_t NGAP_ENCRYPTION_NEA2_MASK = 0x4000; static const uint16_t NGAP_ENCRYPTION_NEA3_MASK = 0x2000; /* Masks for NGAP Integrity algorithms, NIA0 is always supported (not coded) */ static const uint16_t NGAP_INTEGRITY_NIA1_MASK = 0x8000; static const uint16_t NGAP_INTEGRITY_NIA2_MASK = 0x4000; static const uint16_t NGAP_INTEGRITY_NIA3_MASK = 0x2000; #define INTEGRITY_ALGORITHM_NONE NR_IntegrityProtAlgorithm_nia0 /*! \fn uint16_t get_next_ue_initial_id(uint8_t mod_id) *\brief provide an UE initial ID for NGAP initial communication. *\param mod_id Instance ID of gNB. *\return the UE initial ID. */ //------------------------------------------------------------------------------ static uint16_t get_next_ue_initial_id( const module_id_t mod_id ) //------------------------------------------------------------------------------ { static uint16_t ue_initial_id[NUMBER_OF_gNB_MAX]; ue_initial_id[mod_id]++; /* Never use UE_INITIAL_ID_INVALID this is the invalid id! */ if (ue_initial_id[mod_id] == UE_INITIAL_ID_INVALID) { ue_initial_id[mod_id]++; } return ue_initial_id[mod_id]; } //------------------------------------------------------------------------------ /* * Get the UE NG struct containing hashtables NG_id/UE_id. * Is also used to set the NG_id of the UE, depending on inputs. */ struct rrc_ue_ngap_ids_s * rrc_gNB_NGAP_get_ue_ids( gNB_RRC_INST *const rrc_instance_pP, const uint16_t ue_initial_id, const uint32_t gNB_ue_ngap_idP ) //------------------------------------------------------------------------------ { rrc_ue_ngap_ids_t *result = NULL; rrc_ue_ngap_ids_t *result2 = NULL; /*****************************/ instance_t instance = 0; ngap_gNB_instance_t *ngap_gNB_instance_p = NULL; ngap_gNB_ue_context_t *ue_desc_p = NULL; rrc_gNB_ue_context_t *ue_context_p = NULL; /*****************************/ hashtable_rc_t h_rc; if (ue_initial_id != UE_INITIAL_ID_INVALID) { h_rc = hashtable_get(rrc_instance_pP->initial_id2_ngap_ids, (hash_key_t)ue_initial_id, (void **)&result); if (h_rc == HASH_TABLE_OK) { if (gNB_ue_ngap_idP > 0) { h_rc = hashtable_get(rrc_instance_pP->ngap_id2_ngap_ids, (hash_key_t)gNB_ue_ngap_idP, (void **)&result2); if (h_rc != HASH_TABLE_OK) { // this case is equivalent to associate gNB_ue_ngap_idP and ue_initial_id result2 = malloc(sizeof(*result2)); if (NULL != result2) { *result2 = *result; result2->gNB_ue_ngap_id = gNB_ue_ngap_idP; result->gNB_ue_ngap_id = gNB_ue_ngap_idP; h_rc = hashtable_insert(rrc_instance_pP->ngap_id2_ngap_ids, (hash_key_t)gNB_ue_ngap_idP, result2); if (h_rc != HASH_TABLE_OK) { LOG_E(NGAP, "[gNB %ld] Error while hashtable_insert in ngap_id2_ngap_ids gNB_ue_ngap_idP %"PRIu32"\n", rrc_instance_pP - RC.nrrrc[0], gNB_ue_ngap_idP); } } } else { // here we should check that the association was done correctly if ((result->ue_initial_id != result2->ue_initial_id) || (result->gNB_ue_ngap_id != result2->gNB_ue_ngap_id)) { LOG_E(NGAP, "[gNB %ld] Error while hashtable_get, two rrc_ue_ngap_ids_t that should be equal, are not:\n \ ue_initial_id 1 = %"PRIu16",\n \ ue_initial_id 2 = %"PRIu16",\n \ gNB_ue_ngap_idP 1 = %"PRIu32",\n \ gNB_ue_ngap_idP 2 = %"PRIu32"\n", rrc_instance_pP - RC.nrrrc[0], result->ue_initial_id, result2->ue_initial_id, result->gNB_ue_ngap_id, result2->gNB_ue_ngap_id); // Still return *result } } } // end if if (gNB_ue_ngap_idP > 0) } else { // end if (h_rc == HASH_TABLE_OK) LOG_E(NGAP, "[gNB %ld] In hashtable_get, couldn't find in initial_id2_ngap_ids ue_initial_id %"PRIu16"\n", rrc_instance_pP - RC.nrrrc[0], ue_initial_id); return NULL; /* * At the moment this is written, this case shouldn't (cannot) happen and is equivalent to an error. * One could try to find the struct instance based on ngap_id2_ngap_ids and gNB_ue_ngap_idP (if > 0), * but this behavior is not expected at the moment. */ } // end else (h_rc != HASH_TABLE_OK) } else { // end if (ue_initial_id != UE_INITIAL_ID_INVALID) if (gNB_ue_ngap_idP > 0) { h_rc = hashtable_get(rrc_instance_pP->ngap_id2_ngap_ids, (hash_key_t)gNB_ue_ngap_idP, (void **)&result); if (h_rc != HASH_TABLE_OK) { /* * This case is uncommon, but can happen when: * -> if the first NAS message was a Detach Request (non exhaustiv), the UE RRC context exist * but is not associated with gNB_ue_ngap_id * -> ... (?) */ LOG_E(NGAP, "[gNB %ld] In hashtable_get, couldn't find in ngap_id2_ngap_ids gNB_ue_ngap_idP %"PRIu32", trying to find it through NGAP context\n", rrc_instance_pP - RC.nrrrc[0], gNB_ue_ngap_idP); instance = GNB_MODULE_ID_TO_INSTANCE(rrc_instance_pP - RC.nrrrc[0]); // get gNB instance ngap_gNB_instance_p = ngap_gNB_get_instance(instance); // get ngap_gNB_instance if (ngap_gNB_instance_p != NULL) { ue_desc_p = ngap_gNB_get_ue_context(ngap_gNB_instance_p, gNB_ue_ngap_idP); // get s1ap_eNB_ue_context } else { LOG_E(NGAP, "[gNB instance %ld] Couldn't find the gNB NGAP context\n", instance); return NULL; } if (ue_desc_p != NULL) { struct ngap_gNB_ue_context_s *ngap_ue_context_p = NULL; if ((ngap_ue_context_p = RB_REMOVE(ngap_ue_map, &ngap_gNB_instance_p->ngap_ue_head, ue_desc_p)) != NULL) { LOG_E(NR_RRC, "Removed UE context gNB_ue_ngap_id %u\n", ngap_ue_context_p->gNB_ue_ngap_id); ngap_gNB_free_ue_context(ngap_ue_context_p); } else { LOG_E(NR_RRC, "Removing UE context gNB_ue_ngap_id %u: did not find context\n",ue_desc_p->gNB_ue_ngap_id); } return NULL; //skip the operation below to avoid loop result = rrc_gNB_NGAP_get_ue_ids(rrc_instance_pP, ue_desc_p->ue_initial_id, gNB_ue_ngap_idP); if (ue_desc_p->ue_initial_id != UE_INITIAL_ID_INVALID) { result = rrc_gNB_NGAP_get_ue_ids(rrc_instance_pP, ue_desc_p->ue_initial_id, gNB_ue_ngap_idP); if (result != NULL) { ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[GNB_INSTANCE_TO_MODULE_ID(instance)], result->ue_rnti); if ((ue_context_p != NULL) && (ue_context_p->ue_context.gNB_ue_ngap_id == 0)) { ue_context_p->ue_context.gNB_ue_ngap_id = gNB_ue_ngap_idP; } else { LOG_E(NR_RRC, "[gNB %ld] Incoherence between RRC context and NGAP context (%d != %d) for UE RNTI %d or UE RRC context doesn't exist\n", rrc_instance_pP - RC.nrrrc[0], (ue_context_p==NULL)?99999:ue_context_p->ue_context.gNB_ue_ngap_id, gNB_ue_ngap_idP, result->ue_rnti); } } } else { LOG_E(NGAP, "[gNB %ld] NGAP context found but ue_initial_id is invalid (0)\n", rrc_instance_pP - RC.nrrrc[0]); return NULL; } } else { LOG_E(NGAP, "[gNB %ld] In hashtable_get, couldn't find in ngap_id2_ngap_ids gNB_ue_ngap_idP %"PRIu32", because ue_initial_id is invalid in NGAP context\n", rrc_instance_pP - RC.nrrrc[0], gNB_ue_ngap_idP); return NULL; } } // end if (h_rc != HASH_TABLE_OK) } // end if (gNB_ue_ngap_idP > 0) } // end else (ue_initial_id == UE_INITIAL_ID_INVALID) return result; } //------------------------------------------------------------------------------ static struct rrc_gNB_ue_context_s * rrc_gNB_get_ue_context_from_ngap_ids( const instance_t instanceP, const uint16_t ue_initial_idP, const uint32_t gNB_ue_ngap_idP ) //------------------------------------------------------------------------------ { rrc_ue_ngap_ids_t *temp = NULL; temp = rrc_gNB_NGAP_get_ue_ids(RC.nrrrc[GNB_INSTANCE_TO_MODULE_ID(instanceP)], ue_initial_idP, gNB_ue_ngap_idP); if (temp != NULL) { return rrc_gNB_get_ue_context(RC.nrrrc[GNB_INSTANCE_TO_MODULE_ID(instanceP)], temp->ue_rnti); } return NULL; } /*! \fn void process_gNB_security_key (const protocol_ctxt_t* const ctxt_pP, eNB_RRC_UE_t * const ue_context_pP, uint8_t *security_key) *\brief save security key. *\param ctxt_pP Running context. *\param ue_context_pP UE context. *\param security_key_pP The security key received from NGAP. */ //------------------------------------------------------------------------------ void process_gNB_security_key ( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, uint8_t *security_key_pP ) //------------------------------------------------------------------------------ { char ascii_buffer[65]; uint8_t i; /* Saves the security key */ memcpy (ue_context_pP->ue_context.kgnb, security_key_pP, SECURITY_KEY_LENGTH); memset (ue_context_pP->ue_context.nh, 0, SECURITY_KEY_LENGTH); ue_context_pP->ue_context.nh_ncc = -1; for (i = 0; i < 32; i++) { sprintf(&ascii_buffer[2 * i], "%02X", ue_context_pP->ue_context.kgnb[i]); } ascii_buffer[2 * i] = '\0'; LOG_I(NR_RRC, "[gNB %d][UE %x] Saved security key %s\n", ctxt_pP->module_id, ue_context_pP->ue_context.rnti, ascii_buffer); } //------------------------------------------------------------------------------ void nr_rrc_pdcp_config_security( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, const uint8_t send_security_mode_command ) //------------------------------------------------------------------------------ { NR_SRB_ToAddModList_t *SRB_configList = ue_context_pP->ue_context.SRB_configList; (void)SRB_configList; uint8_t *kRRCenc = NULL; uint8_t *kRRCint = NULL; uint8_t *kUPenc = NULL; pdcp_t *pdcp_p = NULL; static int print_keys= 1; hashtable_rc_t h_rc; hash_key_t key; #ifndef PHYSIM /* Derive the keys from kgnb */ if (SRB_configList != NULL) { nr_derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm, ue_context_pP->ue_context.kgnb, &kUPenc); } nr_derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm, ue_context_pP->ue_context.kgnb, &kRRCenc); nr_derive_key_rrc_int(ue_context_pP->ue_context.integrity_algorithm, ue_context_pP->ue_context.kgnb, &kRRCint); #endif if (!IS_SOFTMODEM_IQPLAYER) { SET_LOG_DUMP(DEBUG_SECURITY) ; } if ( LOG_DUMPFLAG( DEBUG_SECURITY ) ) { if (print_keys == 1 ) { print_keys =0; LOG_DUMPMSG(NR_RRC, DEBUG_SECURITY, ue_context_pP->ue_context.kgnb, 32,"\nKgNB:" ); LOG_DUMPMSG(NR_RRC, DEBUG_SECURITY, kRRCenc, 32,"\nKRRCenc:" ); LOG_DUMPMSG(NR_RRC, DEBUG_SECURITY, kRRCint, 32,"\nKRRCint:" ); } } key = PDCP_COLL_KEY_VALUE(ctxt_pP->module_id, ctxt_pP->rnti, ctxt_pP->enb_flag, DCCH, SRB_FLAG_YES); h_rc = hashtable_get(pdcp_coll_p, key, (void **)&pdcp_p); if (h_rc == HASH_TABLE_OK) { pdcp_config_set_security( ctxt_pP, pdcp_p, DCCH, DCCH+2, (send_security_mode_command == TRUE) ? 0 | (ue_context_pP->ue_context.integrity_algorithm << 4) : (ue_context_pP->ue_context.ciphering_algorithm ) | (ue_context_pP->ue_context.integrity_algorithm << 4), kRRCenc, kRRCint, kUPenc); } else { LOG_E(NR_RRC, PROTOCOL_NR_RRC_CTXT_UE_FMT"Could not get PDCP instance for SRB DCCH %u\n", PROTOCOL_NR_RRC_CTXT_UE_ARGS(ctxt_pP), DCCH); } } //------------------------------------------------------------------------------ /* * Initial UE NAS message on S1AP. */ void rrc_gNB_send_NGAP_NAS_FIRST_REQ( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *ue_context_pP, NR_RRCSetupComplete_IEs_t *rrcSetupComplete ) //------------------------------------------------------------------------------ { // gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id]; MessageDef *message_p = NULL; rrc_ue_ngap_ids_t *rrc_ue_ngap_ids_p = NULL; hashtable_rc_t h_rc; message_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_NAS_FIRST_REQ); memset(&message_p->ittiMsg.ngap_nas_first_req, 0, sizeof(ngap_nas_first_req_t)); ue_context_pP->ue_context.ue_initial_id = get_next_ue_initial_id(ctxt_pP->module_id); NGAP_NAS_FIRST_REQ(message_p).ue_initial_id = ue_context_pP->ue_context.ue_initial_id; rrc_ue_ngap_ids_p = malloc(sizeof(rrc_ue_ngap_ids_t)); rrc_ue_ngap_ids_p->ue_initial_id = ue_context_pP->ue_context.ue_initial_id; rrc_ue_ngap_ids_p->gNB_ue_ngap_id = UE_INITIAL_ID_INVALID; rrc_ue_ngap_ids_p->ue_rnti = ctxt_pP->rnti; h_rc = hashtable_insert(RC.nrrrc[ctxt_pP->module_id]->initial_id2_ngap_ids, (hash_key_t)ue_context_pP->ue_context.ue_initial_id, rrc_ue_ngap_ids_p); if (h_rc != HASH_TABLE_OK) { LOG_E(NGAP, "[gNB %d] Error while hashtable_insert in initial_id2_ngap_ids ue_initial_id %u\n", ctxt_pP->module_id, ue_context_pP->ue_context.ue_initial_id); } /* Assume that cause is coded in the same way in RRC and NGap, just check that the value is in NGap range */ AssertFatal(ue_context_pP->ue_context.establishment_cause < NGAP_RRC_CAUSE_LAST, "Establishment cause invalid (%jd/%d) for gNB %d!", ue_context_pP->ue_context.establishment_cause, NGAP_RRC_CAUSE_LAST, ctxt_pP->module_id); NGAP_NAS_FIRST_REQ(message_p).establishment_cause = ue_context_pP->ue_context.establishment_cause; /* Forward NAS message */ NGAP_NAS_FIRST_REQ(message_p).nas_pdu.buffer = rrcSetupComplete->dedicatedNAS_Message.buf; NGAP_NAS_FIRST_REQ(message_p).nas_pdu.length = rrcSetupComplete->dedicatedNAS_Message.size; // extract_imsi(NGAP_NAS_FIRST_REQ (message_p).nas_pdu.buffer, // NGAP_NAS_FIRST_REQ (message_p).nas_pdu.length, // ue_context_pP); /* Fill UE identities with available information */ NGAP_NAS_FIRST_REQ(message_p).ue_identity.presenceMask = NGAP_UE_IDENTITIES_NONE; /* Fill s-TMSI */ NGAP_NAS_FIRST_REQ(message_p).ue_identity.s_tmsi.amf_set_id = ue_context_pP->ue_context.Initialue_identity_5g_s_TMSI.amf_set_id; NGAP_NAS_FIRST_REQ(message_p).ue_identity.s_tmsi.amf_pointer = ue_context_pP->ue_context.Initialue_identity_5g_s_TMSI.amf_pointer; NGAP_NAS_FIRST_REQ(message_p).ue_identity.s_tmsi.m_tmsi = ue_context_pP->ue_context.Initialue_identity_5g_s_TMSI.fiveg_tmsi; /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */ int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1; NGAP_NAS_FIRST_REQ(message_p).selected_plmn_identity = selected_plmn_identity; if (rrcSetupComplete->registeredAMF != NULL) { NR_RegisteredAMF_t *r_amf = rrcSetupComplete->registeredAMF; NGAP_NAS_FIRST_REQ(message_p).ue_identity.presenceMask |= NGAP_UE_IDENTITIES_guami; if (r_amf->plmn_Identity != NULL) { if ((r_amf->plmn_Identity->mcc != NULL) && (r_amf->plmn_Identity->mcc->list.count > 0)) { /* Use first indicated PLMN MCC if it is defined */ NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.mcc = *r_amf->plmn_Identity->mcc->list.array[selected_plmn_identity]; LOG_I(NGAP, "[gNB %d] Build NGAP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI MCC %u ue %x\n", ctxt_pP->module_id, NGAP_NAS_FIRST_REQ (message_p).ue_identity.guami.mcc, ue_context_pP->ue_context.rnti); } if (r_amf->plmn_Identity->mnc.list.count > 0) { /* Use first indicated PLMN MNC if it is defined */ NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.mnc = *r_amf->plmn_Identity->mnc.list.array[selected_plmn_identity]; LOG_I(NGAP, "[gNB %d] Build NGAP_NAS_FIRST_REQ adding in s_TMSI: GUMMEI MNC %u ue %x\n", ctxt_pP->module_id, NGAP_NAS_FIRST_REQ (message_p).ue_identity.guami.mnc, ue_context_pP->ue_context.rnti); } } else { /* TODO */ } /* amf_Identifier */ uint32_t amf_Id = BIT_STRING_to_uint32(&r_amf->amf_Identifier); NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.amf_region_id = amf_Id >> 16; NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.amf_set_id = ue_context_pP->ue_context.Initialue_identity_5g_s_TMSI.amf_set_id; NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.amf_pointer = ue_context_pP->ue_context.Initialue_identity_5g_s_TMSI.amf_pointer; ue_context_pP->ue_context.ue_guami.mcc = NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.mcc; ue_context_pP->ue_context.ue_guami.mnc = NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.mnc; ue_context_pP->ue_context.ue_guami.mnc_len = NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.mnc_len; ue_context_pP->ue_context.ue_guami.amf_region_id = NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.amf_region_id; ue_context_pP->ue_context.ue_guami.amf_set_id = NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.amf_set_id; ue_context_pP->ue_context.ue_guami.amf_pointer = NGAP_NAS_FIRST_REQ(message_p).ue_identity.guami.amf_pointer; MSC_LOG_TX_MESSAGE(MSC_NGAP_GNB, MSC_NGAP_AMF, (const char *)&message_p->ittiMsg.ngap_nas_first_req, sizeof(ngap_nas_first_req_t), MSC_AS_TIME_FMT" NGAP_NAS_FIRST_REQ gNB %u UE %x", MSC_AS_TIME_ARGS(ctxt_pP), ctxt_pP->module_id, ctxt_pP->rnti); LOG_I(NGAP, "[gNB %d] Build NGAP_NAS_FIRST_REQ adding in s_TMSI: GUAMI amf_set_id %u amf_region_id %u ue %x\n", ctxt_pP->module_id, NGAP_NAS_FIRST_REQ (message_p).ue_identity.guami.amf_set_id, NGAP_NAS_FIRST_REQ (message_p).ue_identity.guami.amf_region_id, ue_context_pP->ue_context.rnti); } itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, message_p); } //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ( MessageDef *msg_p, const char *msg_name, instance_t instance ) //------------------------------------------------------------------------------ { uint16_t ue_initial_id; uint32_t gNB_ue_ngap_id; rrc_gNB_ue_context_t *ue_context_p = NULL; protocol_ctxt_t ctxt; uint8_t pdu_sessions_done = 0; ue_initial_id = NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).ue_initial_id; gNB_ue_ngap_id = NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).gNB_ue_ngap_id; ue_context_p = rrc_gNB_get_ue_context_from_ngap_ids(instance, ue_initial_id, gNB_ue_ngap_id); LOG_I(NR_RRC, "[gNB %ld] Received %s: ue_initial_id %d, gNB_ue_ngap_id %u \n", instance, msg_name, ue_initial_id, gNB_ue_ngap_id); if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to NGAP and discard it! */ MessageDef *msg_fail_p = NULL; LOG_W(NR_RRC, "[gNB %ld] In NGAP_INITIAL_CONTEXT_SETUP_REQ: unknown UE from NGAP ids (%d, %u)\n", instance, ue_initial_id, gNB_ue_ngap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_INITIAL_CONTEXT_SETUP_FAIL); NGAP_INITIAL_CONTEXT_SETUP_FAIL (msg_fail_p).gNB_ue_ngap_id = gNB_ue_ngap_id; // TODO add failure cause when defined! itti_send_msg_to_task (TASK_NGAP, instance, msg_fail_p); return (-1); } else { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); ue_context_p->ue_context.gNB_ue_ngap_id = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).gNB_ue_ngap_id; ue_context_p->ue_context.amf_ue_ngap_id = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).amf_ue_ngap_id; ue_context_p->ue_context.nas_pdu_flag = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).nas_pdu_flag; if (NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).nb_of_pdusessions != 0) { ue_context_p->ue_context.nb_of_pdusessions = NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).nb_of_pdusessions; for (int i = 0; i < NR_NB_RB_MAX - 3; i++) { if(ue_context_p->ue_context.pdusession[i].status >= PDU_SESSION_STATUS_DONE) continue; ue_context_p->ue_context.pdusession[i].status = PDU_SESSION_STATUS_NEW; ue_context_p->ue_context.pdusession[i].param = NGAP_INITIAL_CONTEXT_SETUP_REQ (msg_p).pdusession_param[pdu_sessions_done]; pdu_sessions_done++; // TODO establish PDU SESSION if(pdu_sessions_done >= NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).nb_of_pdusessions) { break; } } } /* NAS PDU */ ue_context_p->ue_context.nas_pdu_flag = NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).nas_pdu_flag; if (ue_context_p->ue_context.nas_pdu_flag == 1) { ue_context_p->ue_context.nas_pdu.length = NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).nas_pdu.length; ue_context_p->ue_context.nas_pdu.buffer = NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).nas_pdu.buffer; } /* security */ rrc_gNB_process_security(&ctxt, ue_context_p, &(NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_capabilities)); process_gNB_security_key ( &ctxt, ue_context_p, NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_key); uint8_t send_security_mode_command = TRUE; nr_rrc_pdcp_config_security( &ctxt, ue_context_p, send_security_mode_command); if (send_security_mode_command) { rrc_gNB_generate_SecurityModeCommand (&ctxt, ue_context_p); send_security_mode_command = FALSE; nr_rrc_pdcp_config_security( &ctxt, ue_context_p, send_security_mode_command); } else { /* rrc_gNB_generate_UECapabilityEnquiry */ rrc_gNB_generate_UECapabilityEnquiry(&ctxt, ue_context_p); } // in case, send the S1SP initial context response if it is not sent with the attach complete message if (ue_context_p->ue_context.Status == NR_RRC_RECONFIGURED) { LOG_I(NR_RRC, "Sending rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP, cause %ld\n", ue_context_p->ue_context.reestablishment_cause); rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP(&ctxt,ue_context_p); } return 0; } } //------------------------------------------------------------------------------ void rrc_gNB_send_NGAP_INITIAL_CONTEXT_SETUP_RESP( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP ) //------------------------------------------------------------------------------ { MessageDef *msg_p = NULL; int pdusession; int e_rabs_done = 0; int e_rabs_failed = 0; msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, NGAP_INITIAL_CONTEXT_SETUP_RESP); NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).gNB_ue_ngap_id = ue_context_pP->ue_context.gNB_ue_ngap_id; for (pdusession = 0; pdusession < ue_context_pP->ue_context.nb_of_pdusessions; pdusession++) { if (ue_context_pP->ue_context.pdusession[pdusession].status == E_RAB_STATUS_DONE) { e_rabs_done++; NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions[pdusession].pdusession_id = ue_context_pP->ue_context.pdusession[pdusession].param.pdusession_id; // TODO add other information from S1-U when it will be integrated NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions[pdusession].gtp_teid = ue_context_pP->ue_context.gnb_gtp_teid[pdusession]; memcpy(NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions[pdusession].gNB_addr.buffer , ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].buffer, 20); NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions[pdusession].gNB_addr.length = 4; ue_context_pP->ue_context.pdusession[pdusession].status = E_RAB_STATUS_ESTABLISHED; } else { e_rabs_failed++; ue_context_pP->ue_context.pdusession[pdusession].status = E_RAB_STATUS_FAILED; NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions_failed[pdusession].pdusession_id = ue_context_pP->ue_context.pdusession[pdusession].param.pdusession_id; // TODO add cause when it will be integrated } } MSC_LOG_TX_MESSAGE( MSC_RRC_GNB, MSC_S1AP_ENB, (const char *)&NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p), sizeof(ngap_initial_context_setup_resp_t), MSC_AS_TIME_FMT" INITIAL_CONTEXT_SETUP_RESP UE %X eNB_ue_s1ap_id %u e_rabs:%u succ %u fail", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_pP->ue_id_rnti, NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).gNB_ue_ngap_id, e_rabs_done, e_rabs_failed); NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).nb_of_pdusessions = e_rabs_done; NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).nb_of_pdusessions_failed = e_rabs_failed; itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p); } static NR_CipheringAlgorithm_t rrc_gNB_select_ciphering(uint16_t algorithms) { if (algorithms & NGAP_ENCRYPTION_NEA3_MASK) { return NR_CipheringAlgorithm_nea3; } if (algorithms & NGAP_ENCRYPTION_NEA2_MASK) { return NR_CipheringAlgorithm_nea2; } if (algorithms & NGAP_ENCRYPTION_NEA1_MASK) { return NR_CipheringAlgorithm_nea1; } return NR_CipheringAlgorithm_nea0; } static e_NR_IntegrityProtAlgorithm rrc_gNB_select_integrity(uint16_t algorithms) { if (algorithms & NGAP_INTEGRITY_NIA3_MASK) { return NR_IntegrityProtAlgorithm_nia3; } if (algorithms & NGAP_INTEGRITY_NIA2_MASK) { return NR_IntegrityProtAlgorithm_nia2; } if (algorithms & NGAP_INTEGRITY_NIA1_MASK) { return NR_IntegrityProtAlgorithm_nia1; } return NR_IntegrityProtAlgorithm_nia0; } int rrc_gNB_process_security( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, ngap_security_capabilities_t *security_capabilities_pP ) { boolean_t changed = FALSE; NR_CipheringAlgorithm_t cipheringAlgorithm; e_NR_IntegrityProtAlgorithm integrityProtAlgorithm; /* Save security parameters */ ue_context_pP->ue_context.security_capabilities = *security_capabilities_pP; // translation LOG_D(NR_RRC, "[gNB %d] NAS security_capabilities.encryption_algorithms %u AS ciphering_algorithm %lu NAS security_capabilities.integrity_algorithms %u AS integrity_algorithm %u\n", ctxt_pP->module_id, ue_context_pP->ue_context.security_capabilities.nRencryption_algorithms, (unsigned long)ue_context_pP->ue_context.ciphering_algorithm, ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms, ue_context_pP->ue_context.integrity_algorithm); /* Select relevant algorithms */ cipheringAlgorithm = rrc_gNB_select_ciphering (ue_context_pP->ue_context.security_capabilities.nRencryption_algorithms); if (ue_context_pP->ue_context.ciphering_algorithm != cipheringAlgorithm) { ue_context_pP->ue_context.ciphering_algorithm = cipheringAlgorithm; changed = TRUE; } integrityProtAlgorithm = rrc_gNB_select_integrity (ue_context_pP->ue_context.security_capabilities.nRintegrity_algorithms); if (ue_context_pP->ue_context.integrity_algorithm != integrityProtAlgorithm) { ue_context_pP->ue_context.integrity_algorithm = integrityProtAlgorithm; changed = TRUE; } LOG_I (NR_RRC, "[gNB %d][UE %x] Selected security algorithms (%p): %lx, %x, %s\n", ctxt_pP->module_id, ue_context_pP->ue_context.rnti, security_capabilities_pP, (unsigned long)cipheringAlgorithm, integrityProtAlgorithm, changed ? "changed" : "same"); return changed; } //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_DOWNLINK_NAS( MessageDef *msg_p, const char *msg_name, instance_t instance, mui_t *rrc_gNB_mui ) //------------------------------------------------------------------------------ { uint16_t ue_initial_id; uint32_t gNB_ue_ngap_id; uint32_t length; uint8_t *buffer; struct rrc_gNB_ue_context_s *ue_context_p = NULL; protocol_ctxt_t ctxt; memset(&ctxt, 0, sizeof(protocol_ctxt_t)); ue_initial_id = NGAP_DOWNLINK_NAS (msg_p).ue_initial_id; gNB_ue_ngap_id = NGAP_DOWNLINK_NAS (msg_p).gNB_ue_ngap_id; ue_context_p = rrc_gNB_get_ue_context_from_ngap_ids(instance, ue_initial_id, gNB_ue_ngap_id); LOG_I(NR_RRC, "[gNB %ld] Received %s: ue_initial_id %d, gNB_ue_ngap_id %u\n", instance, msg_name, ue_initial_id, gNB_ue_ngap_id); if (ue_context_p == NULL) { MSC_LOG_RX_MESSAGE( MSC_RRC_GNB, MSC_NGAP_GNB, NULL, 0, MSC_AS_TIME_FMT" DOWNLINK-NAS UE initial id %u gNB_ue_ngap_id %u", 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), ue_initial_id, gNB_ue_ngap_id); /* Can not associate this message to an UE index, send a failure to NGAP and discard it! */ MessageDef *msg_fail_p; LOG_W(NR_RRC, "[gNB %ld] In NGAP_DOWNLINK_NAS: unknown UE from NGAP ids (%d, %u)\n", instance, ue_initial_id, gNB_ue_ngap_id); msg_fail_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_NAS_NON_DELIVERY_IND); NGAP_NAS_NON_DELIVERY_IND (msg_fail_p).gNB_ue_ngap_id = gNB_ue_ngap_id; NGAP_NAS_NON_DELIVERY_IND (msg_fail_p).nas_pdu.length = NGAP_DOWNLINK_NAS (msg_p).nas_pdu.length; NGAP_NAS_NON_DELIVERY_IND (msg_fail_p).nas_pdu.buffer = NGAP_DOWNLINK_NAS (msg_p).nas_pdu.buffer; // TODO add failure cause when defined! MSC_LOG_TX_MESSAGE( MSC_RRC_ENB, MSC_NGAP_GNB, (const char *)NULL, 0, MSC_AS_TIME_FMT" NGAP_NAS_NON_DELIVERY_IND UE initial id %u gNB_ue_ngap_id %u (ue ctxt !found)", 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), ue_initial_id, gNB_ue_ngap_id); itti_send_msg_to_task (TASK_NGAP, instance, msg_fail_p); return (-1); } else { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); /* Is it the first income from NGAP ? */ if (ue_context_p->ue_context.gNB_ue_ngap_id == 0) { ue_context_p->ue_context.gNB_ue_ngap_id = NGAP_DOWNLINK_NAS (msg_p).gNB_ue_ngap_id; } MSC_LOG_RX_MESSAGE( MSC_RRC_GNB, MSC_NGAP_GNB, (const char *)NULL, 0, MSC_AS_TIME_FMT" DOWNLINK-NAS UE initial id %u gNB_ue_ngap_id %u", 0,0,//MSC_AS_TIME_ARGS(ctxt_pP), ue_initial_id, NGAP_DOWNLINK_NAS (msg_p).gNB_ue_ngap_id); /* Create message for PDCP (DLInformationTransfer_t) */ length = do_NR_DLInformationTransfer ( instance, &buffer, rrc_gNB_get_next_transaction_identifier (instance), NGAP_DOWNLINK_NAS (msg_p).nas_pdu.length, NGAP_DOWNLINK_NAS (msg_p).nas_pdu.buffer); LOG_DUMPMSG(NR_RRC, DEBUG_RRC, buffer, length, "[MSG] RRC DL Information Transfer\n"); /* * switch UL or DL NAS message without RRC piggybacked to SRB2 if active. */ #ifdef ITTI_SIM MessageDef *message_p; uint8_t *message_buffer; message_buffer = itti_malloc (TASK_RRC_GNB, TASK_RRC_UE_SIM, length); memcpy (message_buffer, buffer, length); message_p = itti_alloc_new_message (TASK_RRC_GNB, 0, GNB_RRC_DCCH_DATA_IND); GNB_RRC_DCCH_DATA_IND (message_p).rbid = DCCH; GNB_RRC_DCCH_DATA_IND (message_p).sdu = message_buffer; GNB_RRC_DCCH_DATA_IND (message_p).size = length; itti_send_msg_to_task (TASK_RRC_UE_SIM, instance, message_p); LOG_I(NR_RRC, "Send DL NAS message \n"); #else /* Transfer data to PDCP */ nr_rrc_data_req ( &ctxt, ue_context_p->ue_context.Srb2.Srb_info.Srb_id, (*rrc_gNB_mui)++, SDU_CONFIRM_NO, length, buffer, PDCP_TRANSMISSION_MODE_CONTROL); #endif return (0); } } //------------------------------------------------------------------------------ void rrc_gNB_send_NGAP_UPLINK_NAS( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, NR_UL_DCCH_Message_t *const ul_dcch_msg ) //------------------------------------------------------------------------------ { uint32_t pdu_length; uint8_t *pdu_buffer; MessageDef *msg_p; NR_ULInformationTransfer_t *ulInformationTransfer = ul_dcch_msg->message.choice.c1->choice.ulInformationTransfer; if (ulInformationTransfer->criticalExtensions.present == NR_ULInformationTransfer__criticalExtensions_PR_ulInformationTransfer) { pdu_length = ulInformationTransfer->criticalExtensions.choice.ulInformationTransfer->dedicatedNAS_Message->size; pdu_buffer = ulInformationTransfer->criticalExtensions.choice.ulInformationTransfer->dedicatedNAS_Message->buf; msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_UPLINK_NAS); NGAP_UPLINK_NAS (msg_p).gNB_ue_ngap_id = ue_context_pP->ue_context.gNB_ue_ngap_id; NGAP_UPLINK_NAS (msg_p).nas_pdu.length = pdu_length; NGAP_UPLINK_NAS (msg_p).nas_pdu.buffer = pdu_buffer; // extract_imsi(NGAP_UPLINK_NAS (msg_p).nas_pdu.buffer, // NGAP_UPLINK_NAS (msg_p).nas_pdu.length, // ue_context_pP); itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p); LOG_I(NR_RRC,"Send RRC GNB UL Information Transfer \n"); } } //------------------------------------------------------------------------------ void rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, uint8_t xid ) //------------------------------------------------------------------------------ { MessageDef *msg_p; int pdu_sessions_done = 0; int pdu_sessions_failed = 0; int pdusession; int qos_flow_index; msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_RESP); NGAP_PDUSESSION_SETUP_RESP(msg_p).gNB_ue_ngap_id = ue_context_pP->ue_context.gNB_ue_ngap_id; for (pdusession = 0; pdusession < ue_context_pP->ue_context.setup_pdu_sessions; pdusession++) { // if (xid == ue_context_pP->ue_context.pdusession[pdusession].xid) { if (ue_context_pP->ue_context.pdusession[pdusession].status == PDU_SESSION_STATUS_DONE) { NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].pdusession_id = ue_context_pP->ue_context.pdusession[pdusession].param.pdusession_id; // NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].pdusession_id = 1; NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].nb_of_qos_flow = ue_context_pP->ue_context.pdusession[pdusession].param.nb_qos; NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gtp_teid = ue_context_pP->ue_context.gnb_gtp_teid[pdusession]; NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.pdu_session_type = PDUSessionType_ipv4; NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.length = ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].length; memcpy(NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].gNB_addr.buffer, ue_context_pP->ue_context.gnb_gtp_addrs[pdusession].buffer, sizeof(uint8_t)*20); for (qos_flow_index = 0; qos_flow_index < NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].nb_of_qos_flow; qos_flow_index++) { NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = ue_context_pP->ue_context.pdusession[pdusession].param.qos[qos_flow_index].qfi; NGAP_PDUSESSION_SETUP_RESP(msg_p).pdusessions[pdusession].associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL; } ue_context_pP->ue_context.pdusession[pdusession].status = PDU_SESSION_STATUS_ESTABLISHED; LOG_I (NR_RRC,"gnb_gtp_addr (msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d, pdusession_id %d, teid: %u, addr: %d.%d.%d.%d \n ", pdu_sessions_done, pdusession, ue_context_pP->ue_context.pdusession[pdusession].status, xid, ue_context_pP->ue_context.nb_of_pdusessions, NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].pdusession_id, NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gtp_teid, NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[0], NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[1], NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[2], NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions[pdu_sessions_done].gNB_addr.buffer[3]); pdu_sessions_done++; } else if ((ue_context_pP->ue_context.pdusession[pdusession].status == PDU_SESSION_STATUS_NEW) || (ue_context_pP->ue_context.pdusession[pdusession].status == PDU_SESSION_STATUS_ESTABLISHED)) { LOG_D (NR_RRC,"PDU-SESSION is NEW or already ESTABLISHED\n"); } else { /* to be improved */ ue_context_pP->ue_context.pdusession[pdusession].status = PDU_SESSION_STATUS_FAILED; NGAP_PDUSESSION_SETUP_RESP (msg_p).pdusessions_failed[pdu_sessions_failed].pdusession_id = ue_context_pP->ue_context.pdusession[pdusession].param.pdusession_id; pdu_sessions_failed++; // TODO add cause when it will be integrated } NGAP_PDUSESSION_SETUP_RESP(msg_p).nb_of_pdusessions = pdu_sessions_done; NGAP_PDUSESSION_SETUP_RESP(msg_p).nb_of_pdusessions_failed = pdu_sessions_failed; // } else { // LOG_D(NR_RRC,"xid does not corresponds (context pdu_sessions index %d, status %d, xid %d/%d) \n ", // pdusession, ue_context_pP->ue_context.pdusession[pdusession].status, xid, ue_context_pP->ue_context.pdusession[pdusession].xid); // } } if ((pdu_sessions_done > 0) ) { LOG_I(NR_RRC,"NGAP_PDUSESSION_SETUP_RESP: sending the message: nb_of_pdusessions %d, total pdu_sessions %d, index %d\n", ue_context_pP->ue_context.nb_of_pdusessions, ue_context_pP->ue_context.setup_pdu_sessions, pdusession); MSC_LOG_TX_MESSAGE( MSC_RRC_GNB, MSC_NGAP_GNB, (const char *)&NGAP_PDUSESSION_SETUP_RESP (msg_p), sizeof(ngap_pdusession_setup_resp_t), MSC_AS_TIME_FMT" PDUSESSION_SETUP_RESP UE %X gNB_ue_ngap_id %u pdu_sessions:%u succ %u fail", MSC_AS_TIME_ARGS(ctxt_pP), ue_context_pP->ue_id_rnti, NGAP_PDUSESSION_SETUP_RESP (msg_p).gNB_ue_ngap_id, pdu_sessions_done, pdu_sessions_failed); itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p); } for(int i = 0; i < NB_RB_MAX; i++) { ue_context_pP->ue_context.pdusession[i].xid = -1; } return; } //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ( MessageDef *msg_p, const char *msg_name, instance_t instance ) //------------------------------------------------------------------------------ { uint16_t ue_initial_id; uint32_t gNB_ue_ngap_id; rrc_gNB_ue_context_t *ue_context_p = NULL; protocol_ctxt_t ctxt; gtpv1u_gnb_create_tunnel_req_t create_tunnel_req; gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp; uint8_t pdu_sessions_done; uint8_t inde_list[NR_NB_RB_MAX - 3]= {0}; int ret = 0; ue_initial_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).ue_initial_id; gNB_ue_ngap_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).gNB_ue_ngap_id; ue_context_p = rrc_gNB_get_ue_context_from_ngap_ids(instance, ue_initial_id, gNB_ue_ngap_id); LOG_I(NR_RRC, "[gNB %ld] Received %s: ue_initial_id %d, gNB_ue_ngap_id %u \n", instance, msg_name, ue_initial_id, gNB_ue_ngap_id); if (ue_context_p == NULL) { MessageDef *msg_fail_p = NULL; LOG_W(NR_RRC, "[gNB %ld] In NGAP_PDUSESSION_SETUP_REQ: unknown UE from NGAP ids (%d, %u)\n", instance, ue_initial_id, gNB_ue_ngap_id); msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQUEST_FAIL); NGAP_PDUSESSION_SETUP_REQ(msg_fail_p).gNB_ue_ngap_id = gNB_ue_ngap_id; // TODO add failure cause when defined! itti_send_msg_to_task (TASK_NGAP, instance, msg_fail_p); return (-1); } else { memset(&create_tunnel_req, 0, sizeof(gtpv1u_gnb_create_tunnel_req_t)); uint8_t nb_pdusessions_tosetup = NGAP_PDUSESSION_SETUP_REQ(msg_p).nb_pdusessions_tosetup; pdu_sessions_done = 0; PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); for (int i = 0; i < NR_NB_RB_MAX - 3; i++) { if(ue_context_p->ue_context.pdusession[i].status >= PDU_SESSION_STATUS_DONE) continue; ue_context_p->ue_context.pdusession[i].status = PDU_SESSION_STATUS_NEW; ue_context_p->ue_context.pdusession[i].param = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done]; create_tunnel_req.pdusession_id[pdu_sessions_done] = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].pdusession_id; create_tunnel_req.upf_NGu_teid[pdu_sessions_done] = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[pdu_sessions_done].gtp_teid; memcpy(create_tunnel_req.upf_addr[pdu_sessions_done].buffer, NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[i].upf_addr.buffer, sizeof(uint8_t)*20); create_tunnel_req.upf_addr[pdu_sessions_done].length = NGAP_PDUSESSION_SETUP_REQ(msg_p).pdusession_setup_params[i].upf_addr.length; LOG_I(NR_RRC,"NGAP PDUSESSION SETUP REQ: local index %d teid %u, pdusession id %d \n", i, create_tunnel_req.upf_NGu_teid[i], create_tunnel_req.pdusession_id[i]); inde_list[pdu_sessions_done] = i; pdu_sessions_done++; if(pdu_sessions_done >= nb_pdusessions_tosetup) { break; } } ue_context_p->ue_context.nb_of_pdusessions = NGAP_PDUSESSION_SETUP_REQ(msg_p).nb_pdusessions_tosetup; ue_context_p->ue_context.gNB_ue_ngap_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).gNB_ue_ngap_id; ue_context_p->ue_context.amf_ue_ngap_id = NGAP_PDUSESSION_SETUP_REQ(msg_p).amf_ue_ngap_id; create_tunnel_req.rnti = ue_context_p->ue_context.rnti; create_tunnel_req.num_tunnels = pdu_sessions_done; ret = gtpv1u_create_ngu_tunnel( instance, &create_tunnel_req, &create_tunnel_resp); if (ret != 0) { LOG_E(NR_RRC,"rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ : gtpv1u_create_ngu_tunnel failed,start to release UE %x\n",ue_context_p->ue_context.rnti); ue_context_p->ue_context.ue_release_timer_ng = 1; ue_context_p->ue_context.ue_release_timer_thres_ng = 100; ue_context_p->ue_context.ue_release_timer = 0; ue_context_p->ue_context.ue_reestablishment_timer = 0; ue_context_p->ue_context.ul_failure_timer = 20000; // set ul_failure to 20000 for triggering rrc_eNB_send_S1AP_UE_CONTEXT_RELEASE_REQ // rrc_gNB_free_UE(ctxt.module_id,ue_context_p); ue_context_p->ue_context.ul_failure_timer = 0; return (0); } nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP( &ctxt, &create_tunnel_resp, &inde_list[0]); ue_context_p->ue_context.setup_pdu_sessions += nb_pdusessions_tosetup; // TEST ue_context_p->ue_context.pdusession[0].status = PDU_SESSION_STATUS_DONE; rrc_gNB_send_NGAP_PDUSESSION_SETUP_RESP(&ctxt, ue_context_p, 0); return(0); } } void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_REQ( const module_id_t gnb_mod_idP, const rrc_gNB_ue_context_t *const ue_context_pP, const ngap_Cause_t causeP, const long cause_valueP) //------------------------------------------------------------------------------ { if (ue_context_pP == NULL) { LOG_E(RRC, "[gNB] In NGAP_UE_CONTEXT_RELEASE_REQ: invalid UE\n"); } else { MSC_LOG_TX_MESSAGE(MSC_RRC_GNB, MSC_NGAP_GNB, NULL, 0, "0 NGAP_UE_CONTEXT_RELEASE_REQ gNB_ue_ngap_id 0x%06"PRIX32" ", ue_context_pP->ue_context.gNB_ue_ngap_id); MessageDef *msg_context_release_req_p = NULL; msg_context_release_req_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_REQ); NGAP_UE_CONTEXT_RELEASE_REQ(msg_context_release_req_p).gNB_ue_ngap_id = ue_context_pP->ue_context.gNB_ue_ngap_id; NGAP_UE_CONTEXT_RELEASE_REQ(msg_context_release_req_p).cause = causeP; NGAP_UE_CONTEXT_RELEASE_REQ(msg_context_release_req_p).cause_value = cause_valueP; NGAP_UE_CONTEXT_RELEASE_REQ(msg_context_release_req_p).nb_of_pdusessions = ue_context_pP->ue_context.setup_pdu_sessions; for (int pdusession = 0; pdusession < ue_context_pP->ue_context.setup_pdu_sessions; pdusession++) { NGAP_UE_CONTEXT_RELEASE_REQ(msg_context_release_req_p).pdusessions[pdusession].pdusession_id = ue_context_pP->ue_context.pdusession[pdusession].param.pdusession_id; } itti_send_msg_to_task(TASK_NGAP, GNB_MODULE_ID_TO_INSTANCE(gnb_mod_idP), msg_context_release_req_p); } } /*------------------------------------------------------------------------------*/ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_REQ ( MessageDef *msg_p, const char *msg_name, instance_t instance) { uint32_t gNB_ue_ngap_id; struct rrc_gNB_ue_context_s *ue_context_p = NULL; gNB_ue_ngap_id = NGAP_UE_CONTEXT_RELEASE_REQ(msg_p).gNB_ue_ngap_id; ue_context_p = rrc_gNB_get_ue_context_from_ngap_ids(instance, UE_INITIAL_ID_INVALID, gNB_ue_ngap_id); if (ue_context_p == NULL) { /* Can not associate this message to an UE index, send a failure to ngAP and discard it! */ MessageDef *msg_fail_p; LOG_W(RRC, "[gNB %ld] In NGAP_UE_CONTEXT_RELEASE_REQ: unknown UE from gNB_ue_ngap_id (%u)\n", instance, gNB_ue_ngap_id); msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_RESP); /* TODO change message ID. */ NGAP_UE_CONTEXT_RELEASE_RESP(msg_fail_p).gNB_ue_ngap_id = gNB_ue_ngap_id; // TODO add failure cause when defined! itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p); return (-1); } else { /* TODO release context. */ /* Send the response */ { MessageDef *msg_resp_p; msg_resp_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_RESP); NGAP_UE_CONTEXT_RELEASE_RESP(msg_resp_p).gNB_ue_ngap_id = gNB_ue_ngap_id; itti_send_msg_to_task(TASK_NGAP, instance, msg_resp_p); } return (0); } } //----------------------------------------------------------------------------- /* * Process the NG command NGAP_UE_CONTEXT_RELEASE_COMMAND, sent by AMF. * The gNB should remove all pdu session, NG context, and other context of the UE. */ int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND( MessageDef *msg_p, const char *msg_name, instance_t instance) { //----------------------------------------------------------------------------- uint32_t gNB_ue_ngap_id = 0; protocol_ctxt_t ctxt; struct rrc_gNB_ue_context_s *ue_context_p = NULL; struct rrc_ue_ngap_ids_s *rrc_ue_ngap_ids = NULL; gNB_ue_ngap_id = NGAP_UE_CONTEXT_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id; ue_context_p = rrc_gNB_get_ue_context_from_ngap_ids(instance, UE_INITIAL_ID_INVALID, gNB_ue_ngap_id); if (ue_context_p == NULL) { /* Can not associate this message to an UE index */ MessageDef *msg_complete_p = NULL; LOG_W(NR_RRC, "[gNB %ld] In NGAP_UE_CONTEXT_RELEASE_COMMAND: unknown UE from gNB_ue_ngap_id (%u)\n", instance, gNB_ue_ngap_id); MSC_LOG_EVENT(MSC_RRC_GNB, "0 NGAP_UE_CONTEXT_RELEASE_COMPLETE gNB_ue_ngap_id 0x%06"PRIX32" context not found", gNB_ue_ngap_id); MSC_LOG_TX_MESSAGE(MSC_RRC_GNB, MSC_NGAP_GNB, NULL, 0, "0 NGAP_UE_CONTEXT_RELEASE_COMPLETE gNB_ue_ngap_id 0x%06"PRIX32" ", gNB_ue_ngap_id); msg_complete_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_COMPLETE); NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg_complete_p).gNB_ue_ngap_id = gNB_ue_ngap_id; itti_send_msg_to_task(TASK_NGAP, instance, msg_complete_p); rrc_ue_ngap_ids = rrc_gNB_NGAP_get_ue_ids(RC.nrrrc[instance], UE_INITIAL_ID_INVALID, gNB_ue_ngap_id); if (rrc_ue_ngap_ids != NULL) { rrc_gNB_NGAP_remove_ue_ids(RC.nrrrc[instance], rrc_ue_ngap_ids); } return -1; } else { ue_context_p->ue_context.ue_release_timer_ng = 0; PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); rrc_gNB_generate_RRCRelease(&ctxt, ue_context_p); return 0; } } //------------------------------------------------------------------------------ /* * Remove UE ids (ue_initial_id and ng_id) from hashtables. */ void rrc_gNB_NGAP_remove_ue_ids( gNB_RRC_INST *const rrc_instance_pP, struct rrc_ue_ngap_ids_s *const ue_ids_pP ) //------------------------------------------------------------------------------ { hashtable_rc_t h_rc; if (rrc_instance_pP == NULL) { LOG_E(NR_RRC, "Bad NR RRC instance\n"); return; } if (ue_ids_pP == NULL) { LOG_E(NR_RRC, "Trying to free a NULL NGAP UE IDs\n"); return; } const uint16_t ue_initial_id = ue_ids_pP->ue_initial_id; const uint32_t gNB_ue_ngap_id = ue_ids_pP->gNB_ue_ngap_id; if (gNB_ue_ngap_id > 0) { h_rc = hashtable_remove(rrc_instance_pP->ngap_id2_ngap_ids, (hash_key_t)gNB_ue_ngap_id); if (h_rc != HASH_TABLE_OK) { LOG_W(NR_RRC, "NGAP Did not find entry in hashtable ngap_id2_ngap_ids for gNB_ue_ngap_id %u\n", gNB_ue_ngap_id); } else { LOG_W(NR_RRC, "NGAP removed entry in hashtable ngap_id2_ngap_ids for gNB_ue_ngap_id %u\n", gNB_ue_ngap_id); } } if (ue_initial_id != UE_INITIAL_ID_INVALID) { h_rc = hashtable_remove(rrc_instance_pP->initial_id2_ngap_ids, (hash_key_t)ue_initial_id); if (h_rc != HASH_TABLE_OK) { LOG_W(NR_RRC, "NGAP Did not find entry in hashtable initial_id2_ngap_ids for ue_initial_id %u\n", ue_initial_id); } else { LOG_W(NR_RRC, "NGAP removed entry in hashtable initial_id2_ngap_ids for ue_initial_id %u\n", ue_initial_id); } } } void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, NR_UL_DCCH_Message_t *const ul_dcch_msg ) //------------------------------------------------------------------------------ { NR_UE_CapabilityRAT_ContainerList_t *ueCapabilityRATContainerList = ul_dcch_msg->message.choice.c1->choice.ueCapabilityInformation->criticalExtensions.choice.ueCapabilityInformation->ue_CapabilityRAT_ContainerList; /* 4096 is arbitrary, should be big enough */ unsigned char buf[4096]; unsigned char *buf2; NR_UERadioAccessCapabilityInformation_t rac; if (ueCapabilityRATContainerList->list.count == 0) { LOG_W(RRC, "[gNB %d][UE %x] bad UE capabilities\n", ctxt_pP->module_id, ue_context_pP->ue_context.rnti); } asn_enc_rval_t ret = uper_encode_to_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, NULL, ueCapabilityRATContainerList, buf, 4096); if (ret.encoded == -1) abort(); memset(&rac, 0, sizeof(NR_UERadioAccessCapabilityInformation_t)); rac.criticalExtensions.present = NR_UERadioAccessCapabilityInformation__criticalExtensions_PR_c1; rac.criticalExtensions.choice.c1 = calloc(1,sizeof(*rac.criticalExtensions.choice.c1)); rac.criticalExtensions.choice.c1->present = NR_UERadioAccessCapabilityInformation__criticalExtensions__c1_PR_ueRadioAccessCapabilityInformation; rac.criticalExtensions.choice.c1->choice.ueRadioAccessCapabilityInformation = calloc(1,sizeof(NR_UERadioAccessCapabilityInformation_IEs_t)); rac.criticalExtensions.choice.c1->choice.ueRadioAccessCapabilityInformation->ue_RadioAccessCapabilityInfo.buf = buf; rac.criticalExtensions.choice.c1->choice.ueRadioAccessCapabilityInformation->ue_RadioAccessCapabilityInfo.size = (ret.encoded+7)/8; rac.criticalExtensions.choice.c1->choice.ueRadioAccessCapabilityInformation->nonCriticalExtension = NULL; /* 8192 is arbitrary, should be big enough */ buf2 = malloc16(8192); if (buf2 == NULL) abort(); ret = uper_encode_to_buffer(&asn_DEF_NR_UERadioAccessCapabilityInformation, NULL, &rac, buf2, 8192); if (ret.encoded == -1) abort(); MessageDef *msg_p; msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_UE_CAPABILITIES_IND); NGAP_UE_CAPABILITIES_IND (msg_p).gNB_ue_ngap_id = ue_context_pP->ue_context.gNB_ue_ngap_id; NGAP_UE_CAPABILITIES_IND (msg_p).ue_radio_cap.length = (ret.encoded+7)/8; NGAP_UE_CAPABILITIES_IND (msg_p).ue_radio_cap.buffer = buf2; itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p); LOG_I(NR_RRC,"Send message to ngap: NGAP_UE_CAPABILITIES_IND\n"); } //------------------------------------------------------------------------------ void rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE( const protocol_ctxt_t *const ctxt_pP, rrc_gNB_ue_context_t *const ue_context_pP, uint8_t xid ) //------------------------------------------------------------------------------ { int pdu_sessions_released = 0; MessageDef *msg_p; msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_PDUSESSION_RELEASE_RESPONSE); NGAP_PDUSESSION_RELEASE_RESPONSE (msg_p).gNB_ue_ngap_id = ue_context_pP->ue_context.gNB_ue_ngap_id; for (int i = 0; i < NB_RB_MAX; i++) { if (xid == ue_context_pP->ue_context.pdusession[i].xid) { NGAP_PDUSESSION_RELEASE_RESPONSE (msg_p).pdusession_release[pdu_sessions_released].pdusession_id = ue_context_pP->ue_context.pdusession[i].param.pdusession_id; pdu_sessions_released++; //clear memset(&ue_context_pP->ue_context.pdusession[i], 0, sizeof(pdu_session_param_t)); } } NGAP_PDUSESSION_RELEASE_RESPONSE (msg_p).nb_of_pdusessions_released = pdu_sessions_released; NGAP_PDUSESSION_RELEASE_RESPONSE (msg_p).nb_of_pdusessions_failed = ue_context_pP->ue_context.nb_release_of_pdusessions; memcpy(&(NGAP_PDUSESSION_RELEASE_RESPONSE (msg_p).pdusessions_failed[0]), &ue_context_pP->ue_context.pdusessions_release_failed[0], sizeof(pdusession_failed_t)*ue_context_pP->ue_context.nb_release_of_pdusessions); ue_context_pP->ue_context.setup_pdu_sessions -= pdu_sessions_released; LOG_I(NR_RRC,"NGAP PDUSESSION RELEASE RESPONSE: GNB_UE_NGAP_ID %u release_pdu_sessions %d setup_pdu_sessions %d \n", NGAP_PDUSESSION_RELEASE_RESPONSE (msg_p).gNB_ue_ngap_id, pdu_sessions_released, ue_context_pP->ue_context.setup_pdu_sessions); itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p); //clear xid for(int i = 0; i < NB_RB_MAX; i++) { ue_context_pP->ue_context.pdusession[i].xid = -1; } //clear release pdusessions ue_context_pP->ue_context.nb_release_of_pdusessions = 0; memset(&ue_context_pP->ue_context.pdusessions_release_failed[0], 0, sizeof(pdusession_failed_t)*NGAP_MAX_PDUSESSION); } //------------------------------------------------------------------------------ int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND( MessageDef *msg_p, const char *msg_name, instance_t instance ) //------------------------------------------------------------------------------ { uint32_t gNB_ue_ngap_id; rrc_gNB_ue_context_t *ue_context_p = NULL; protocol_ctxt_t ctxt; pdusession_release_t pdusession_release_params[NGAP_MAX_PDUSESSION]; uint8_t nb_pdusessions_torelease; MessageDef *msg_delete_tunnels_p = NULL; uint8_t xid; int i, pdusession; uint8_t b_existed,is_existed; uint8_t pdusession_release_drb = 0; memcpy(&pdusession_release_params[0], &(NGAP_PDUSESSION_RELEASE_COMMAND (msg_p).pdusession_release_params[0]), sizeof(pdusession_release_t)*NGAP_MAX_PDUSESSION); gNB_ue_ngap_id = NGAP_PDUSESSION_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id; nb_pdusessions_torelease = NGAP_PDUSESSION_RELEASE_COMMAND(msg_p).nb_pdusessions_torelease; if (nb_pdusessions_torelease > NGAP_MAX_PDUSESSION) { return -1; } ue_context_p = rrc_gNB_get_ue_context_from_ngap_ids(instance, UE_INITIAL_ID_INVALID, gNB_ue_ngap_id); LOG_I(NR_RRC, "[gNB %ld] Received %s: gNB_ue_ngap_id %u \n", instance, msg_name, gNB_ue_ngap_id); if (ue_context_p != NULL) { PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, ue_context_p->ue_context.rnti, 0, 0); xid = rrc_gNB_get_next_transaction_identifier(ctxt.module_id); LOG_I(NR_RRC,"PDU Session Release Command: AMF_UE_NGAP_ID %lu GNB_UE_NGAP_ID %u release_pdusessions %d \n", NGAP_PDUSESSION_RELEASE_COMMAND (msg_p).amf_ue_ngap_id&0x000000FFFFFFFFFF, gNB_ue_ngap_id, nb_pdusessions_torelease); for (pdusession = 0; pdusession < nb_pdusessions_torelease; pdusession++) { b_existed = 0; is_existed = 0; for (i = pdusession-1; i >= 0; i--) { if (pdusession_release_params[pdusession].pdusession_id == pdusession_release_params[i].pdusession_id) { is_existed = 1; break; } } if(is_existed == 1) { // pdusession_id is existed continue; } for (i = 0; i < NR_NB_RB_MAX; i++) { if (pdusession_release_params[pdusession].pdusession_id == ue_context_p->ue_context.pdusession[i].param.pdusession_id) { b_existed = 1; break; } } if(b_existed == 0) { // no pdusession_id LOG_I(NR_RRC, "no pdusession_id \n"); ue_context_p->ue_context.pdusessions_release_failed[ue_context_p->ue_context.nb_release_of_pdusessions].pdusession_id = pdusession_release_params[pdusession].pdusession_id; ue_context_p->ue_context.pdusessions_release_failed[ue_context_p->ue_context.nb_release_of_pdusessions].cause = NGAP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.pdusessions_release_failed[ue_context_p->ue_context.nb_release_of_pdusessions].cause_value = 30; ue_context_p->ue_context.nb_release_of_pdusessions++; } else { if(ue_context_p->ue_context.pdusession[i].status == PDU_SESSION_STATUS_FAILED) { ue_context_p->ue_context.pdusession[i].xid = xid; continue; } else if(ue_context_p->ue_context.pdusession[i].status == PDU_SESSION_STATUS_ESTABLISHED) { LOG_I(NR_RRC, "RELEASE pdusession %d \n", ue_context_p->ue_context.pdusession[i].param.pdusession_id); ue_context_p->ue_context.pdusession[i].status = PDU_SESSION_STATUS_TORELEASE; ue_context_p->ue_context.pdusession[i].xid = xid; pdusession_release_drb++; } else { // pdusession_id status NG ue_context_p->ue_context.pdusessions_release_failed[ue_context_p->ue_context.nb_release_of_pdusessions].pdusession_id = pdusession_release_params[pdusession].pdusession_id; ue_context_p->ue_context.pdusessions_release_failed[ue_context_p->ue_context.nb_release_of_pdusessions].cause = NGAP_CAUSE_RADIO_NETWORK; ue_context_p->ue_context.pdusessions_release_failed[ue_context_p->ue_context.nb_release_of_pdusessions].cause_value = 0; ue_context_p->ue_context.nb_release_of_pdusessions++; } } } if(pdusession_release_drb > 0) { //TODO RRCReconfiguration To UE LOG_I(NR_RRC, "Send RRCReconfiguration To UE \n"); rrc_gNB_generate_dedicatedRRCReconfiguration_release(&ctxt, ue_context_p, xid, NGAP_PDUSESSION_RELEASE_COMMAND (msg_p).nas_pdu.length, NGAP_PDUSESSION_RELEASE_COMMAND (msg_p).nas_pdu.buffer); } else { //gtp tunnel delete LOG_I(NR_RRC, "gtp tunnel delete \n"); msg_delete_tunnels_p = itti_alloc_new_message(TASK_RRC_GNB, 0, GTPV1U_GNB_DELETE_TUNNEL_REQ); memset(>PV1U_GNB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p), 0, sizeof(GTPV1U_GNB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p))); GTPV1U_GNB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).rnti = ue_context_p->ue_context.rnti; for(i = 0; i < NB_RB_MAX; i++) { if(xid == ue_context_p->ue_context.pdusession[i].xid) { GTPV1U_GNB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).pdusession_id[GTPV1U_GNB_DELETE_TUNNEL_REQ(msg_delete_tunnels_p).num_pdusession++] = ue_context_p->ue_context.gnb_gtp_psi[i]; ue_context_p->ue_context.gnb_gtp_teid[i] = 0; memset(&ue_context_p->ue_context.gnb_gtp_addrs[i], 0, sizeof(ue_context_p->ue_context.gnb_gtp_addrs[i])); ue_context_p->ue_context.gnb_gtp_psi[i] = 0; } } itti_send_msg_to_task(TASK_GTPV1_U, instance, msg_delete_tunnels_p); //NGAP_PDUSESSION_RELEASE_RESPONSE rrc_gNB_send_NGAP_PDUSESSION_RELEASE_RESPONSE(&ctxt, ue_context_p, xid); LOG_I(NR_RRC, "Send PDU Session Release Response \n"); } } else { LOG_E(NR_RRC, "PDU Session Release Command: AMF_UE_NGAP_ID %lu GNB_UE_NGAP_ID %u Error ue_context_p NULL \n", NGAP_PDUSESSION_RELEASE_COMMAND (msg_p).amf_ue_ngap_id&0x000000FFFFFFFFFF, NGAP_PDUSESSION_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id); return -1; } return 0; } void nr_rrc_rx_tx(void) { // check timers // check if UEs are lost, to remove them from upper layers // }