Files
openairinterface5g/openair2/RRC/NR/rrc_gNB_NGAP.c
T

751 lines
33 KiB
C

/*
* 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 "RRC/LTE/rrc_eNB_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"
extern RAN_CONTEXT_t RC;
/* Value to indicate an invalid UE initial id */
static const uint16_t UE_INITIAL_ID_INVALID = 0;
/*! \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 %d] 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;
}
//------------------------------------------------------------------------------
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;
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) {
derive_key_up_enc(ue_context_pP->ue_context.ciphering_algorithm,
ue_context_pP->ue_context.kgnb,
&kUPenc);
}
derive_key_rrc_enc(ue_context_pP->ue_context.ciphering_algorithm,
ue_context_pP->ue_context.kgnb,
&kRRCenc);
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, 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;
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 %d] Received %s: ue_initial_id %d, gNB_ue_ngap_id %d \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 %d] In NGAP_INITIAL_CONTEXT_SETUP_REQ: unknown UE from NGAP ids (%d, %d)\n", instance, ue_initial_id, gNB_ue_ngap_id);
msg_fail_p = itti_alloc_new_message (TASK_RRC_GNB, 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;
/* NAS PDU */
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;
}
/* TODO security */
rrc_gNB_process_security(&ctxt, ue_context_p, &(NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p).security_capabilities));
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 e_rab;
int e_rabs_done = 0;
int e_rabs_failed = 0;
msg_p = itti_alloc_new_message (TASK_RRC_ENB, 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 (e_rab = 0; e_rab < ue_context_pP->ue_context.nb_of_e_rabs; e_rab++) {
if (ue_context_pP->ue_context.e_rab[e_rab].status == E_RAB_STATUS_DONE) {
e_rabs_done++;
NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions[e_rab].pdusession_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_id;
// TODO add other information from S1-U when it will be integrated
NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions[e_rab].gtp_teid = ue_context_pP->ue_context.gnb_gtp_teid[e_rab];
memcpy(NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions[e_rab].gNB_addr.buffer , ue_context_pP->ue_context.gnb_gtp_addrs[e_rab].buffer, 20);
NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions[e_rab].gNB_addr.length = 4;
ue_context_pP->ue_context.e_rab[e_rab].status = E_RAB_STATUS_ESTABLISHED;
} else {
e_rabs_failed++;
ue_context_pP->ue_context.e_rab[e_rab].status = E_RAB_STATUS_FAILED;
NGAP_INITIAL_CONTEXT_SETUP_RESP (msg_p).pdusessions_failed[e_rab].pdusession_id = ue_context_pP->ue_context.e_rab[e_rab].param.e_rab_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) {
//#warning "Forced return NR_CipheringAlgorithm_nea0, to be deleted in future"
return NR_CipheringAlgorithm_nea0;
}
static e_NR_IntegrityProtAlgorithm rrc_gNB_select_integrity(uint16_t algorithms) {
// to be continue
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,
"[eNB %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, "[eNB %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 %d] Received %s: ue_initial_id %d, gNB_ue_ngap_id %d\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 %d] In NGAP_DOWNLINK_NAS: unknown UE from NGAP ids (%d, %d)\n", instance, ue_initial_id, gNB_ue_ngap_id);
msg_fail_p = itti_alloc_new_message (TASK_RRC_GNB, 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_SIM, TASK_RRC_UE_SIM, length);
memcpy (message_buffer, buffer, length);
message_p = itti_alloc_new_message (TASK_RRC_GNB_SIM, 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, 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");
}
}