rrc_gNB_NGAP.c 62 KB
Newer Older
Xue Song's avatar
Xue Song committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * 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
 */

22 23 24 25 26 27 28 29 30
/*! \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) 
 */

Xue Song's avatar
Xue Song committed
31 32 33 34 35 36
#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"

37
#include "oai_asn1.h"
Xue Song's avatar
Xue Song committed
38
#include "intertask_interface.h"
39
#include "nr_pdcp/nr_pdcp_oai_api.h"
Xue Song's avatar
Xue Song committed
40
#include "pdcp_primitives.h"
41
#include "SDAP/nr_sdap/nr_sdap.h"
Xue Song's avatar
Xue Song committed
42

43
#include "openair3/ocp-gtpu/gtp_itf.h"
Laurent THOMAS's avatar
Laurent THOMAS committed
44
#include <openair3/ocp-gtpu/gtp_itf.h>
Xue Song's avatar
Xue Song committed
45
#include "RRC/LTE/rrc_eNB_GTPV1U.h"
46
#include "RRC/NR/rrc_gNB_GTPV1U.h"
Xue Song's avatar
Xue Song committed
47 48 49

#include "S1AP_NAS-PDU.h"
#include "executables/softmodem-common.h"
mir's avatar
mir committed
50 51
#include "openair3/SECU/key_nas_deriver.h"

52 53
#include "ngap_gNB_defs.h"
#include "ngap_gNB_ue_context.h"
Xue Song's avatar
Xue Song committed
54
#include "ngap_gNB_management_procedures.h"
55
#include "NR_ULInformationTransfer.h"
Xue Song's avatar
Xue Song committed
56
#include "RRC/NR/MESSAGES/asn1_msg.h"
57 58
#include "NR_UERadioAccessCapabilityInformation.h"
#include "NR_UE-CapabilityRAT-ContainerList.h"
59
#include "NGAP_CauseRadioNetwork.h"
60
#include "f1ap_messages_types.h"
61
#include "openair2/F1AP/f1ap_ids.h"
62
#include "openair2/E1AP/e1ap_asnc.h"
laurent's avatar
tmp  
laurent committed
63 64 65 66 67 68 69 70
#include "NGAP_asn_constant.h"
#include "NGAP_PDUSessionResourceSetupRequestTransfer.h"
#include "NGAP_PDUSessionResourceModifyRequestTransfer.h"
#include "NGAP_ProtocolIE-Field.h"
#include "NGAP_GTPTunnel.h"
#include "NGAP_QosFlowSetupRequestItem.h"
#include "NGAP_QosFlowAddOrModifyRequestItem.h"
#include "NGAP_NonDynamic5QIDescriptor.h"
71
#include "NGAP_Dynamic5QIDescriptor.h"
laurent's avatar
tmp  
laurent committed
72
#include "conversions.h"
73
#include "RRC/NR/rrc_gNB_radio_bearers.h"
74 75 76

#include "uper_encoder.h"

Xue Song's avatar
Xue Song committed
77 78
extern RAN_CONTEXT_t RC;

Xue Song's avatar
Xue Song committed
79 80 81 82 83 84 85 86 87 88 89 90
/* 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

laurent's avatar
tmp  
laurent committed
91
static 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);
92

Xue Song's avatar
Xue Song committed
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
/*! \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;
laurent's avatar
tmp  
laurent committed
109 110
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;

Xue Song's avatar
Xue Song committed
111
  /* Saves the security key */
laurent's avatar
tmp  
laurent committed
112 113 114
  memcpy(UE->kgnb, security_key_pP, SECURITY_KEY_LENGTH);
  memset(UE->nh, 0, SECURITY_KEY_LENGTH);
  UE->nh_ncc = -1;
Xue Song's avatar
Xue Song committed
115 116

  for (i = 0; i < 32; i++) {
laurent's avatar
tmp  
laurent committed
117
    sprintf(&ascii_buffer[2 * i], "%02X", UE->kgnb[i]);
Xue Song's avatar
Xue Song committed
118 119 120
  }

  ascii_buffer[2 * i] = '\0';
laurent's avatar
tmp  
laurent committed
121
  LOG_I(NR_RRC, "[gNB %d][UE %x] Saved security key %s\n", ctxt_pP->module_id, UE->rnti, ascii_buffer);
Xue Song's avatar
Xue Song committed
122 123
}

Xue Song's avatar
Xue Song committed
124 125 126 127 128
//------------------------------------------------------------------------------
void
nr_rrc_pdcp_config_security(
    const protocol_ctxt_t  *const ctxt_pP,
    rrc_gNB_ue_context_t   *const ue_context_pP,
129
    const uint8_t          enable_ciphering
Xue Song's avatar
Xue Song committed
130 131 132
)
//------------------------------------------------------------------------------
{
mir's avatar
mir committed
133 134 135
  uint8_t kRRCenc[16] = {0};
  uint8_t kRRCint[16] = {0};
  uint8_t kUPenc[16] = {0};
136
  //uint8_t                            *k_kdf  = NULL;
137
  static int                          print_keys= 1;
laurent's avatar
tmp  
laurent committed
138
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
Xue Song's avatar
Xue Song committed
139

140
  /* Derive the keys from kgnb */
laurent's avatar
tmp  
laurent committed
141
  if (UE->Srb[1].Active || UE->Srb[2].Active) {
mir's avatar
mir committed
142
    nr_derive_key(UP_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kUPenc);
143
  }
144

mir's avatar
mir committed
145 146 147
  nr_derive_key(RRC_ENC_ALG, UE->ciphering_algorithm, UE->kgnb, kRRCenc);
  nr_derive_key(RRC_INT_ALG, UE->integrity_algorithm, UE->kgnb, kRRCint);

148 149 150
  if (!IS_SOFTMODEM_IQPLAYER) {
    SET_LOG_DUMP(DEBUG_SECURITY) ;
  }
Xue Song's avatar
Xue Song committed
151 152


153 154 155
  if ( LOG_DUMPFLAG( DEBUG_SECURITY ) ) {
    if (print_keys == 1 ) {
      print_keys =0;
laurent's avatar
tmp  
laurent committed
156
      LOG_DUMPMSG(NR_RRC, DEBUG_SECURITY, UE->kgnb, 32, "\nKgNB:");
157 158
      LOG_DUMPMSG(NR_RRC, DEBUG_SECURITY, kRRCenc, 16,"\nKRRCenc:" );
      LOG_DUMPMSG(NR_RRC, DEBUG_SECURITY, kRRCint, 16,"\nKRRCint:" );
Xue Song's avatar
Xue Song committed
159
    }
160
  }
Xue Song's avatar
Xue Song committed
161

162 163 164
  uint8_t security_mode =
      enable_ciphering ? UE->ciphering_algorithm | (UE->integrity_algorithm << 4) : 0 | (UE->integrity_algorithm << 4);
  nr_pdcp_config_set_security(ctxt_pP->rntiMaybeUEid, DCCH, security_mode, kRRCenc, kRRCint, kUPenc);
Xue Song's avatar
Xue Song committed
165 166
}

Xue Song's avatar
Xue Song committed
167 168 169 170 171 172 173 174 175 176 177 178
//------------------------------------------------------------------------------
/*
* 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
)
//------------------------------------------------------------------------------
{
179 180
  // gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
  MessageDef         *message_p         = NULL;
laurent's avatar
tmp  
laurent committed
181
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
182

183
  message_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_NAS_FIRST_REQ);
laurent's avatar
tmp  
laurent committed
184 185 186
  ngap_nas_first_req_t *req = &NGAP_NAS_FIRST_REQ(message_p);
  memset(req, 0, sizeof(*req));

187
  req->gNB_ue_ngap_id = UE->rrc_ue_id;
Xue Song's avatar
Xue Song committed
188

189
  /* Assume that cause is coded in the same way in RRC and NGap, just check that the value is in NGap range */
laurent's avatar
tmp  
laurent committed
190 191 192
  AssertFatal(UE->establishment_cause < NGAP_RRC_CAUSE_LAST, "Establishment cause invalid (%jd/%d) for gNB %d!", UE->establishment_cause, NGAP_RRC_CAUSE_LAST, ctxt_pP->module_id);
  req->establishment_cause = UE->establishment_cause;

193
  /* Forward NAS message */
laurent's avatar
tmp  
laurent committed
194
  req->nas_pdu.length = rrcSetupComplete->dedicatedNAS_Message.size;
195 196 197
  req->nas_pdu.buffer = malloc(req->nas_pdu.length);
  AssertFatal(req->nas_pdu.buffer != NULL, "out of memory\n");
  memcpy(req->nas_pdu.buffer, rrcSetupComplete->dedicatedNAS_Message.buf, req->nas_pdu.length);
198 199 200 201 202
  // 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 */
laurent's avatar
tmp  
laurent committed
203
  req->ue_identity.presenceMask = NGAP_UE_IDENTITIES_NONE;
204
  /* Fill s-TMSI */
laurent's avatar
tmp  
laurent committed
205 206 207
  req->ue_identity.s_tmsi.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id;
  req->ue_identity.s_tmsi.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer;
  req->ue_identity.s_tmsi.m_tmsi = UE->Initialue_identity_5g_s_TMSI.fiveg_tmsi;
208 209 210

  /* selected_plmn_identity: IE is 1-based, convert to 0-based (C array) */
  int selected_plmn_identity = rrcSetupComplete->selectedPLMN_Identity - 1;
laurent's avatar
tmp  
laurent committed
211
  req->selected_plmn_identity = selected_plmn_identity;
212 213

  if (rrcSetupComplete->registeredAMF != NULL) {
214
      NR_RegisteredAMF_t *r_amf = rrcSetupComplete->registeredAMF;
laurent's avatar
tmp  
laurent committed
215
      req->ue_identity.presenceMask |= NGAP_UE_IDENTITIES_guami;
216 217 218 219

      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 */
laurent's avatar
tmp  
laurent committed
220 221
              req->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, req->ue_identity.guami.mcc, UE->rnti);
222
          }
Xue Song's avatar
Xue Song committed
223

224 225
          if (r_amf->plmn_Identity->mnc.list.count > 0) {
              /* Use first indicated PLMN MNC if it is defined */
laurent's avatar
tmp  
laurent committed
226 227
              req->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, req->ue_identity.guami.mnc, UE->rnti);
228 229 230
          }
      } else {
          /* TODO */
231
      }
Xue Song's avatar
Xue Song committed
232

233 234
      /* amf_Identifier */
      uint32_t amf_Id = BIT_STRING_to_uint32(&r_amf->amf_Identifier);
laurent's avatar
tmp  
laurent committed
235 236 237 238 239 240 241 242 243 244 245 246 247 248
      req->ue_identity.guami.amf_region_id = amf_Id >> 16;
      req->ue_identity.guami.amf_set_id = UE->Initialue_identity_5g_s_TMSI.amf_set_id;
      req->ue_identity.guami.amf_pointer = UE->Initialue_identity_5g_s_TMSI.amf_pointer;

      // fixme: illogical place to set UE values, should be in the function that call this one
      UE->ue_guami.mcc = req->ue_identity.guami.mcc;
      UE->ue_guami.mnc = req->ue_identity.guami.mnc;
      UE->ue_guami.mnc_len = req->ue_identity.guami.mnc_len;
      UE->ue_guami.amf_region_id = req->ue_identity.guami.amf_region_id;
      UE->ue_guami.amf_set_id = req->ue_identity.guami.amf_set_id;
      UE->ue_guami.amf_pointer = req->ue_identity.guami.amf_pointer;

      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",
249
            ctxt_pP->module_id,
laurent's avatar
tmp  
laurent committed
250 251 252
            req->ue_identity.guami.amf_set_id,
            req->ue_identity.guami.amf_region_id,
            UE->rnti);
253 254 255
  }

  itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, message_p);
256 257
}

258 259 260 261 262 263 264 265 266
static void fill_qos(NGAP_QosFlowSetupRequestList_t *qos, pdusession_t *session)
{
  DevAssert(qos->list.count > 0);
  DevAssert(qos->list.count <= NGAP_maxnoofQosFlows);
  for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) {
    NGAP_QosFlowSetupRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx];
    // Set the QOS informations
    session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier;
    NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters.qosCharacteristics;
267
    AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx);
268
    if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) {
269 270 271 272 273 274 275
      AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n");
      session->qos[qosIdx].fiveQI_type = non_dynamic;
      session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI;
    } else {
      AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n");
      session->qos[qosIdx].fiveQI_type = dynamic;
      session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI);
276 277 278 279 280 281 282 283 284 285 286 287
    }

    ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority;
    NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters.allocationAndRetentionPriority;
    tmp->priority_level = tmp2->priorityLevelARP;
    tmp->pre_emp_capability = tmp2->pre_emptionCapability;
    tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability;
  }
  session->nb_qos = qos->list.count;
}

static int decodePDUSessionResourceSetup(pdusession_t *session)
laurent's avatar
tmp  
laurent committed
288
{
289
  NGAP_PDUSessionResourceSetupRequestTransfer_t *pdusessionTransfer = NULL;
290
  asn_codec_ctx_t st = {.max_stack_size = 100 * 1000};
291
  asn_dec_rval_t dec_rval =
292
      aper_decode(&st, &asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer, (void **)&pdusessionTransfer, session->pdusessionTransfer.buffer, session->pdusessionTransfer.length, 0, 0);
laurent's avatar
tmp  
laurent committed
293 294

  if (dec_rval.code != RC_OK) {
295
    LOG_E(NR_RRC, "can not decode PDUSessionResourceSetupRequestTransfer\n");
laurent's avatar
tmp  
laurent committed
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
    return -1;
  }

  for (int i = 0; i < pdusessionTransfer->protocolIEs.list.count; i++) {
    NGAP_PDUSessionResourceSetupRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[i];
    switch (pdusessionTransfer_ies->id) {
        /* optional PDUSessionAggregateMaximumBitRate */
      case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate:
        break;

        /* mandatory UL-NGU-UP-TNLInformation */
      case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLInformation: {
        NGAP_GTPTunnel_t *gTPTunnel_p = pdusessionTransfer_ies->value.choice.UPTransportLayerInformation.choice.gTPTunnel;

        /* Set the transport layer address */
311
        memcpy(session->upf_addr.buffer, gTPTunnel_p->transportLayerAddress.buf, gTPTunnel_p->transportLayerAddress.size);
laurent's avatar
tmp  
laurent committed
312

313
        session->upf_addr.length = gTPTunnel_p->transportLayerAddress.size * 8 - gTPTunnel_p->transportLayerAddress.bits_unused;
laurent's avatar
tmp  
laurent committed
314 315

        /* GTP tunnel endpoint ID */
316
        OCTET_STRING_TO_INT32(&gTPTunnel_p->gTP_TEID, session->gtp_teid);
laurent's avatar
tmp  
laurent committed
317 318 319 320 321 322 323 324 325 326 327 328 329 330
      }

      break;

        /* optional AdditionalUL-NGU-UP-TNLInformation */
      case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation:
        break;

        /* optional DataForwardingNotPossible */
      case NGAP_ProtocolIE_ID_id_DataForwardingNotPossible:
        break;

        /* mandatory PDUSessionType */
      case NGAP_ProtocolIE_ID_id_PDUSessionType:
331
        session->pdu_session_type = (uint8_t)pdusessionTransfer_ies->value.choice.PDUSessionType;
332
        AssertFatal(session->pdu_session_type == PDUSessionType_ipv4 || session->pdu_session_type == PDUSessionType_ipv4v6, "To be developped: support not IPv4 sessions\n");
laurent's avatar
tmp  
laurent committed
333 334 335 336 337 338 339 340 341 342 343
        break;

        /* optional SecurityIndication */
      case NGAP_ProtocolIE_ID_id_SecurityIndication:
        break;

        /* optional NetworkInstance */
      case NGAP_ProtocolIE_ID_id_NetworkInstance:
        break;

        /* mandatory QosFlowSetupRequestList */
344 345 346
      case NGAP_ProtocolIE_ID_id_QosFlowSetupRequestList:
        fill_qos(&pdusessionTransfer_ies->value.choice.QosFlowSetupRequestList, session);
        break;
laurent's avatar
tmp  
laurent committed
347 348 349 350 351 352 353 354 355 356

        /* optional CommonNetworkInstance */
      case NGAP_ProtocolIE_ID_id_CommonNetworkInstance:
        break;

      default:
        LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id);
        return -1;
    }
  }
laurent's avatar
laurent committed
357
  ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NGAP_PDUSessionResourceSetupRequestTransfer,pdusessionTransfer );
358

laurent's avatar
tmp  
laurent committed
359 360 361
  return 0;
}

362
//------------------------------------------------------------------------------
laurent's avatar
tmp  
laurent committed
363
int rrc_gNB_process_NGAP_INITIAL_CONTEXT_SETUP_REQ(MessageDef *msg_p, instance_t instance)
364 365
//------------------------------------------------------------------------------
{
laurent's avatar
tmp  
laurent committed
366 367 368
  protocol_ctxt_t ctxt = {0};
  ngap_initial_context_setup_req_t *req = &NGAP_INITIAL_CONTEXT_SETUP_REQ(msg_p);

369
  rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], req->gNB_ue_ngap_id);
laurent's avatar
tmp  
laurent committed
370 371 372 373 374 375 376 377 378 379 380 381
  gNB_RRC_UE_t *UE = &ue_context_p->ue_context;

  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 (%u)\n", instance, req->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 = req->gNB_ue_ngap_id;
    // TODO add failure cause when defined!
    itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p);
    return (-1);
  }
382
  PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0);
laurent's avatar
tmp  
laurent committed
383 384
  UE->amf_ue_ngap_id = req->amf_ue_ngap_id;
  uint8_t nb_pdusessions_tosetup = req->nb_of_pdusessions;
385
  if (nb_pdusessions_tosetup) {
laurent's avatar
tmp  
laurent committed
386
    AssertFatal(false, "PDU sessions in Initial context setup request not handled by E1 yet\n");
387 388 389
    /* 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.
390 391 392
    gtpv1u_gnb_create_tunnel_req_t create_tunnel_req = {0};
    for (int i = 0; i < nb_pdusessions_tosetup; i++) {
      UE->nb_of_pdusessions++;
laurent's avatar
tmp  
laurent committed
393
      if(UE->pduSession[i].status >= PDU_SESSION_STATUS_DONE)
394
        continue;
laurent's avatar
tmp  
laurent committed
395
      UE->pduSession[i].status      = PDU_SESSION_STATUS_NEW;
396 397 398 399 400 401 402 403 404 405
      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]);
    }
406
    create_tunnel_req.ue_id = UE->rrc_ue_id;
407
    gtpv1u_gnb_create_tunnel_resp_t create_tunnel_resp = {0};
408
    int ret = gtpv1u_create_ngu_tunnel(instance, &create_tunnel_req, &create_tunnel_resp, nr_pdcp_data_req_drb, sdap_data_req);
409
    if (ret != 0) {
laurent's avatar
tmp  
laurent committed
410
      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);
411
      AssertFatal(false, "release timer not implemented\n");
412 413
      return (0);
    }
414

415
    nr_rrc_gNB_process_GTPV1U_CREATE_TUNNEL_RESP(&ctxt, &create_tunnel_resp, 0);
416
    */
laurent's avatar
tmp  
laurent committed
417
  }
418

laurent's avatar
tmp  
laurent committed
419 420 421
  /* NAS PDU */
  // this is malloced pointers, we pass it for later free()
  UE->nas_pdu = req->nas_pdu;
422

laurent's avatar
tmp  
laurent committed
423 424 425 426 427 428 429 430 431 432
  /* security */
  rrc_gNB_process_security(&ctxt, ue_context_p, &req->security_capabilities);
  process_gNB_security_key(&ctxt, ue_context_p, req->security_key);

  /* 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);

  return 0;
433
}
434 435

//------------------------------------------------------------------------------
laurent's avatar
tmp  
laurent committed
436
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)
437 438
//------------------------------------------------------------------------------
{
laurent's avatar
tmp  
laurent committed
439
  MessageDef *msg_p = NULL;
440 441
  int pdu_sessions_done = 0;
  int pdu_sessions_failed = 0;
442
  msg_p = itti_alloc_new_message (TASK_RRC_ENB, 0, NGAP_INITIAL_CONTEXT_SETUP_RESP);
laurent's avatar
tmp  
laurent committed
443 444 445
  ngap_initial_context_setup_resp_t *resp = &NGAP_INITIAL_CONTEXT_SETUP_RESP(msg_p);
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;

446
  resp->gNB_ue_ngap_id = UE->rrc_ue_id;
447

448
  for (int pdusession = 0; pdusession < UE->nb_of_pdusessions; pdusession++) {
laurent's avatar
tmp  
laurent committed
449 450
    rrc_pdu_session_param_t *session = &UE->pduSession[pdusession];
    if (session->status == PDU_SESSION_STATUS_DONE) {
451
      pdu_sessions_done++;
452
      resp->pdusessions[pdusession].pdusession_id = session->param.pdusession_id;
453 454 455 456 457
      resp->pdusessions[pdusession].gtp_teid = session->param.gNB_teid_N3;
      memcpy(resp->pdusessions[pdusession].gNB_addr.buffer,
             session->param.gNB_addr_N3.buffer,
             sizeof(resp->pdusessions[pdusession].gNB_addr.buffer));
      resp->pdusessions[pdusession].gNB_addr.length = 4; // Fixme: IPv4 hard coded here
laurent's avatar
tmp  
laurent committed
458 459 460 461
      resp->pdusessions[pdusession].nb_of_qos_flow = session->param.nb_qos;
      for (int qos_flow_index = 0; qos_flow_index < session->param.nb_qos; qos_flow_index++) {
        resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi;
        resp->pdusessions[pdusession].associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL;
462
      }
463
    } else {
464
      pdu_sessions_failed++;
laurent's avatar
tmp  
laurent committed
465
      resp->pdusessions_failed[pdusession].pdusession_id = session->param.pdusession_id;
466
      // TODO add cause when it will be integrated
laurent's avatar
laurent committed
467
      resp->pdusessions_failed[pdusession].cause = NGAP_CAUSE_RADIO_NETWORK;
laurent's avatar
tmp  
laurent committed
468
      resp->pdusessions_failed[pdusession].cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID;
469 470 471
    }
  }

laurent's avatar
tmp  
laurent committed
472 473
  resp->nb_of_pdusessions = pdu_sessions_done;
  resp->nb_of_pdusessions_failed = pdu_sessions_failed;
474 475 476
  itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p);
}

477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505
static NR_CipheringAlgorithm_t rrc_gNB_select_ciphering(
    const protocol_ctxt_t *const ctxt_pP,
    uint16_t algorithms)
{
  gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
  int i;
  /* preset nea0 as fallback */
  int ret = 0;

  /* Select ciphering algorithm based on gNB configuration file and
   * UE's supported algorithms.
   * We take the first from the list that is supported by the UE.
   * The ordering of the list comes from the configuration file.
   */
  for (i = 0; i < rrc->security.ciphering_algorithms_count; i++) {
    int nea_mask[4] = {
      0,
      NGAP_ENCRYPTION_NEA1_MASK,
      NGAP_ENCRYPTION_NEA2_MASK,
      NGAP_ENCRYPTION_NEA3_MASK
    };
    if (rrc->security.ciphering_algorithms[i] == 0) {
      /* nea0 */
      break;
    }
    if (algorithms & nea_mask[rrc->security.ciphering_algorithms[i]]) {
      ret = rrc->security.ciphering_algorithms[i];
      break;
    }
Xue Song's avatar
Xue Song committed
506 507
  }

508
  LOG_I(RRC, "selecting ciphering algorithm %d\n", ret);
Xue Song's avatar
Xue Song committed
509

510
  return ret;
511 512
}

513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541
static e_NR_IntegrityProtAlgorithm rrc_gNB_select_integrity(
    const protocol_ctxt_t *const ctxt_pP,
    uint16_t algorithms)
{
  gNB_RRC_INST *rrc = RC.nrrrc[ctxt_pP->module_id];
  int i;
  /* preset nia0 as fallback */
  int ret = 0;

  /* Select integrity algorithm based on gNB configuration file and
   * UE's supported algorithms.
   * We take the first from the list that is supported by the UE.
   * The ordering of the list comes from the configuration file.
   */
  for (i = 0; i < rrc->security.integrity_algorithms_count; i++) {
    int nia_mask[4] = {
      0,
      NGAP_INTEGRITY_NIA1_MASK,
      NGAP_INTEGRITY_NIA2_MASK,
      NGAP_INTEGRITY_NIA3_MASK
    };
    if (rrc->security.integrity_algorithms[i] == 0) {
      /* nia0 */
      break;
    }
    if (algorithms & nia_mask[rrc->security.integrity_algorithms[i]]) {
      ret = rrc->security.integrity_algorithms[i];
      break;
    }
Xue Song's avatar
Xue Song committed
542 543
  }

544
  LOG_I(RRC, "selecting integrity algorithm %d\n", ret);
545

546
  return ret;
547 548
}

laurent's avatar
tmp  
laurent committed
549 550
static 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)
{
551
  bool                                                  changed = false;
552 553
  NR_CipheringAlgorithm_t                               cipheringAlgorithm;
  e_NR_IntegrityProtAlgorithm                           integrityProtAlgorithm;
laurent's avatar
tmp  
laurent committed
554 555
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;

556
  /* Save security parameters */
laurent's avatar
tmp  
laurent committed
557
  UE->security_capabilities = *security_capabilities_pP;
558
  // translation
rmagueta's avatar
rmagueta committed
559
  LOG_D(NR_RRC,
Xue Song's avatar
Xue Song committed
560
        "[gNB %d] NAS security_capabilities.encryption_algorithms %u AS ciphering_algorithm %lu NAS security_capabilities.integrity_algorithms %u AS integrity_algorithm %u\n",
561
        ctxt_pP->module_id,
laurent's avatar
tmp  
laurent committed
562 563 564 565
        UE->security_capabilities.nRencryption_algorithms,
        (unsigned long)UE->ciphering_algorithm,
        UE->security_capabilities.nRintegrity_algorithms,
        UE->integrity_algorithm);
566
  /* Select relevant algorithms */
laurent's avatar
tmp  
laurent committed
567
  cipheringAlgorithm = rrc_gNB_select_ciphering(ctxt_pP, UE->security_capabilities.nRencryption_algorithms);
568

laurent's avatar
tmp  
laurent committed
569 570
  if (UE->ciphering_algorithm != cipheringAlgorithm) {
    UE->ciphering_algorithm = cipheringAlgorithm;
571
    changed = true;
572 573
  }

laurent's avatar
tmp  
laurent committed
574
  integrityProtAlgorithm = rrc_gNB_select_integrity(ctxt_pP, UE->security_capabilities.nRintegrity_algorithms);
575

laurent's avatar
tmp  
laurent committed
576 577
  if (UE->integrity_algorithm != integrityProtAlgorithm) {
    UE->integrity_algorithm = integrityProtAlgorithm;
578
    changed = true;
579 580
  }

laurent's avatar
tmp  
laurent committed
581 582 583 584 585 586 587 588
  LOG_I(NR_RRC,
        "[gNB %d][UE %x] Selected security algorithms (%p): %lx, %x, %s\n",
        ctxt_pP->module_id,
        UE->rnti,
        security_capabilities_pP,
        (unsigned long)cipheringAlgorithm,
        integrityProtAlgorithm,
        changed ? "changed" : "same");
589 590
  return changed;
}
Xue Song's avatar
Xue Song committed
591 592

//------------------------------------------------------------------------------
laurent's avatar
tmp  
laurent committed
593
int rrc_gNB_process_NGAP_DOWNLINK_NAS(MessageDef *msg_p, instance_t instance, mui_t *rrc_gNB_mui)
Xue Song's avatar
Xue Song committed
594 595
//------------------------------------------------------------------------------
{
laurent's avatar
tmp  
laurent committed
596
  uint32_t length;
597
  uint8_t buffer[4096];
laurent's avatar
tmp  
laurent committed
598 599
  protocol_ctxt_t ctxt = {0};
  ngap_downlink_nas_t *req = &NGAP_DOWNLINK_NAS(msg_p);
600
  rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], req->gNB_ue_ngap_id);
601

laurent's avatar
tmp  
laurent committed
602 603 604 605 606
  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(NR_RRC, "[gNB %ld] In NGAP_DOWNLINK_NAS: unknown UE from NGAP ids (%u)\n", instance, req->gNB_ue_ngap_id);
    msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_NAS_NON_DELIVERY_IND);
607 608 609 610
    ngap_nas_non_delivery_ind_t *msg = &NGAP_NAS_NON_DELIVERY_IND(msg_fail_p);
    msg->gNB_ue_ngap_id = req->gNB_ue_ngap_id;
    msg->nas_pdu.length = req->nas_pdu.length;
    msg->nas_pdu.buffer = req->nas_pdu.buffer;
laurent's avatar
tmp  
laurent committed
611 612 613
    // TODO add failure cause when defined!
    itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p);
    return (-1);
614
  }
615

616
  gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
617
  PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0);
618

619
  /* Create message for PDCP (DLInformationTransfer_t) */
620
  length = do_NR_DLInformationTransfer(buffer,
621 622 623 624
                                       sizeof(buffer),
                                       rrc_gNB_get_next_transaction_identifier(instance),
                                       req->nas_pdu.length,
                                       req->nas_pdu.buffer);
625 626 627 628
  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.
   */
629 630
  AssertFatal(!NODE_IS_DU(RC.nrrrc[ctxt.module_id]->node_type), "illegal node type DU: receiving NGAP messages at this node\n");
  /* Transfer data to PDCP */
631
  rb_id_t srb_id = UE->Srb[2].Active ? DCCH1 : DCCH;
632
  nr_rrc_transfer_protected_rrc_message(RC.nrrrc[instance], UE, srb_id, buffer, length);
633
  return 0;
Xue Song's avatar
Xue Song committed
634
}
635 636 637 638 639 640 641 642 643 644 645 646

//------------------------------------------------------------------------------
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
)
//------------------------------------------------------------------------------
{
    MessageDef *msg_p;
    NR_ULInformationTransfer_t *ulInformationTransfer = ul_dcch_msg->message.choice.c1->choice.ulInformationTransfer;
laurent's avatar
tmp  
laurent committed
647
    gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
648 649

    if (ulInformationTransfer->criticalExtensions.present == NR_ULInformationTransfer__criticalExtensions_PR_ulInformationTransfer) {
650 651 652 653
      NR_DedicatedNAS_Message_t *nas = ulInformationTransfer->criticalExtensions.choice.ulInformationTransfer->dedicatedNAS_Message;
        uint8_t *buf = malloc(nas->size);
        AssertFatal(buf != NULL, "out of memory\n");
        memcpy(buf, nas->buf, nas->size);
654
        msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_UPLINK_NAS);
655
        NGAP_UPLINK_NAS(msg_p).gNB_ue_ngap_id = UE->rrc_ue_id;
656 657
        NGAP_UPLINK_NAS (msg_p).nas_pdu.length = nas->size;
        NGAP_UPLINK_NAS (msg_p).nas_pdu.buffer = buf;
658 659 660 661
        // 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);
Robert Schmidt's avatar
Robert Schmidt committed
662
        LOG_D(NR_RRC,"Send RRC GNB UL Information Transfer \n");
663 664
    }
}
665 666 667 668 669 670 671 672 673 674 675 676 677 678

//------------------------------------------------------------------------------
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;

679
  msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_RESP);
laurent's avatar
tmp  
laurent committed
680 681
  ngap_pdusession_setup_resp_t *resp = &NGAP_PDUSESSION_SETUP_RESP(msg_p);
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
682
  resp->gNB_ue_ngap_id = UE->rrc_ue_id;
laurent's avatar
tmp  
laurent committed
683

684
  for (int pdusession = 0; pdusession < UE->nb_of_pdusessions; pdusession++) {
laurent's avatar
tmp  
laurent committed
685 686 687 688 689
    rrc_pdu_session_param_t *session = &UE->pduSession[pdusession];
    if (session->status == PDU_SESSION_STATUS_DONE) {
      pdusession_setup_t *tmp = &resp->pdusessions[pdu_sessions_done];
      tmp->pdusession_id = session->param.pdusession_id;
      tmp->nb_of_qos_flow = session->param.nb_qos;
690
      tmp->gtp_teid = session->param.gNB_teid_N3;
691
      tmp->pdu_session_type = session->param.pdu_session_type;
692 693
      tmp->gNB_addr.length = session->param.gNB_addr_N3.length;
      memcpy(tmp->gNB_addr.buffer, session->param.gNB_addr_N3.buffer, tmp->gNB_addr.length);
laurent's avatar
tmp  
laurent committed
694 695 696
      for (int qos_flow_index = 0; qos_flow_index < tmp->nb_of_qos_flow; qos_flow_index++) {
        tmp->associated_qos_flows[qos_flow_index].qfi = session->param.qos[qos_flow_index].qfi;
        tmp->associated_qos_flows[qos_flow_index].qos_flow_mapping_ind = QOSFLOW_MAPPING_INDICATION_DL;
697
      }
laurent's avatar
tmp  
laurent committed
698 699 700 701 702 703 704 705 706 707 708 709

      session->status = PDU_SESSION_STATUS_ESTABLISHED;
      LOG_I(NR_RRC,
            "msg index %d, pdu_sessions index %d, status %d, xid %d): nb_of_pdusessions %d,  pdusession_id %d, teid: %u \n ",
            pdu_sessions_done,
            pdusession,
            session->status,
            xid,
            UE->nb_of_pdusessions,
            tmp->pdusession_id,
            tmp->gtp_teid);
      pdu_sessions_done++;
710
    } else if (session->status != PDU_SESSION_STATUS_ESTABLISHED) {
laurent's avatar
tmp  
laurent committed
711 712 713 714 715 716 717
      session->status = PDU_SESSION_STATUS_FAILED;
      resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = session->param.pdusession_id;
      pdu_sessions_failed++;
      // TODO add cause when it will be integrated
    }
    resp->nb_of_pdusessions = pdu_sessions_done;
    resp->nb_of_pdusessions_failed = pdu_sessions_failed;
718 719
    // } else {
    //   LOG_D(NR_RRC,"xid does not corresponds  (context pdu_sessions index %d, status %d, xid %d/%d) \n ",
laurent's avatar
tmp  
laurent committed
720
    //         pdusession, UE->pdusession[pdusession].status, xid, UE->pdusession[pdusession].xid);
721 722 723
    // }
  }

laurent's avatar
tmp  
laurent committed
724 725
  if ((pdu_sessions_done > 0 || pdu_sessions_failed)) {
    LOG_I(NR_RRC, "NGAP_PDUSESSION_SETUP_RESP: sending the message\n");
726 727 728 729
    itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p);
  }

  for(int i = 0; i < NB_RB_MAX; i++) {
laurent's avatar
tmp  
laurent committed
730
    UE->pduSession[i].xid = -1;
731 732
  }

yaojie's avatar
yaojie committed
733
  return;
734 735 736
}

//------------------------------------------------------------------------------
laurent's avatar
tmp  
laurent committed
737
void rrc_gNB_process_NGAP_PDUSESSION_SETUP_REQ(MessageDef *msg_p, instance_t instance)
738 739
//------------------------------------------------------------------------------
{
740
  protocol_ctxt_t                 ctxt={0};
741 742

  ngap_pdusession_setup_req_t* msg=&NGAP_PDUSESSION_SETUP_REQ(msg_p);
743
  rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], msg->gNB_ue_ngap_id);
laurent's avatar
tmp  
laurent committed
744 745
  gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
  PROTOCOL_CTXT_SET_BY_MODULE_ID(&ctxt, 0, GNB_FLAG_YES, UE->rnti, 0, 0, 0);
746
  gNB_RRC_INST *rrc = RC.nrrrc[ctxt.module_id];
laurent's avatar
tmp  
laurent committed
747
  LOG_I(NR_RRC, "[gNB %ld] gNB_ue_ngap_id %u \n", instance, msg->gNB_ue_ngap_id);
748 749 750

  if (ue_context_p == NULL) {
    MessageDef *msg_fail_p = NULL;
laurent's avatar
tmp  
laurent committed
751
    LOG_W(NR_RRC, "[gNB %ld] In NGAP_PDUSESSION_SETUP_REQ: unknown UE from NGAP ids (%u)\n", instance, msg->gNB_ue_ngap_id);
752
    msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_SETUP_REQUEST_FAIL);
laurent's avatar
tmp  
laurent committed
753
    NGAP_PDUSESSION_SETUP_FAIL(msg_fail_p).gNB_ue_ngap_id = msg->gNB_ue_ngap_id;
754 755
    // TODO add failure cause when defined!
    itti_send_msg_to_task (TASK_NGAP, instance, msg_fail_p);
756 757
    return ;
  }
laurent's avatar
laurent committed
758

759
  UE->rrc_ue_id = msg->gNB_ue_ngap_id;
laurent's avatar
tmp  
laurent committed
760 761
  UE->amf_ue_ngap_id = msg->amf_ue_ngap_id;
  e1ap_bearer_setup_req_t bearer_req = {0};
762

763 764

  e1ap_nssai_t cuup_nssai = {0};
laurent's avatar
tmp  
laurent committed
765
  for (int i = 0; i < msg->nb_pdusessions_tosetup; i++) {
766 767 768
    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;
769
    LOG_I(NR_RRC, "Adding pdusession %d, total nb of sessions %d\n", session->pdusession_id, UE->nb_of_pdusessions);
770
    session->pdu_session_type = msg->pdusession_setup_params[i].pdu_session_type;
771 772
    session->nas_pdu = msg->pdusession_setup_params[i].nas_pdu;
    session->pdusessionTransfer = msg->pdusession_setup_params[i].pdusessionTransfer;
773
    session->nssai = msg->pdusession_setup_params[i].nssai;
774
    decodePDUSessionResourceSetup(session);
laurent's avatar
tmp  
laurent committed
775 776 777
    bearer_req.gNB_cu_cp_ue_id = msg->gNB_ue_ngap_id;
    bearer_req.cipheringAlgorithm = UE->ciphering_algorithm;
    bearer_req.integrityProtectionAlgorithm = UE->integrity_algorithm;
Cedric Roux's avatar
Cedric Roux committed
778 779
    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);
laurent's avatar
tmp  
laurent committed
780
    bearer_req.ueDlAggMaxBitRate = msg->ueAggMaxBitRateDownlink;
781
    pdu_session_to_setup_t *pdu = bearer_req.pduSession + bearer_req.numPDUSessions;
laurent's avatar
tmp  
laurent committed
782
    bearer_req.numPDUSessions++;
783
    pdu->sessionId = session->pdusession_id;
784
    pdu->nssai = msg->pdusession_setup_params[i].nssai;
785 786
    if (cuup_nssai.sst == 0)
      cuup_nssai = pdu->nssai; /* for CU-UP selection below */
laurent's avatar
tmp  
laurent committed
787 788 789
    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;
790 791
    pdu->teId = session->gtp_teid;
    memcpy(&pdu->tlAddress, session->upf_addr.buffer, 4); // Fixme: dirty IPv4 target
laurent's avatar
tmp  
laurent committed
792
    pdu->numDRB2Setup = 1; // One DRB per PDU Session. TODO: Remove hardcoding
793 794
    for (int j=0; j < pdu->numDRB2Setup; j++) {
      DRB_nGRAN_to_setup_t *drb = pdu->DRBnGRanList + j;
795

796
      drb->id = i + j + UE->nb_of_pdusessions;
797

798
      drb->defaultDRB = true;
799 800 801 802 803 804 805 806

      drb->sDAP_Header_UL = !(rrc->configuration.enable_sdap);
      drb->sDAP_Header_DL = !(rrc->configuration.enable_sdap);

      drb->pDCP_SN_Size_UL = E1AP_PDCP_SN_Size_s_18;
      drb->pDCP_SN_Size_DL = E1AP_PDCP_SN_Size_s_18;

      drb->discardTimer = E1AP_DiscardTimer_infinity;
807
      drb->reorderingTimer = E1AP_T_Reordering_ms100;
808 809 810 811 812 813 814 815 816 817

      drb->rLC_Mode = 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
      }

818
      drb->numQosFlow2Setup = session->nb_qos;
819
      for (int k=0; k < drb->numQosFlow2Setup; k++) {
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
        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;
839
      }
840
    }
841
  }
842 843
  int xid = rrc_gNB_get_next_transaction_identifier(instance);
  UE->xids[xid] = RRC_PDUSESSION_ESTABLISH;
844 845 846 847 848 849
  /* 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);
850
  rrc->cucp_cuup.bearer_context_setup(assoc_id, &bearer_req);
851
  return;
yaojie's avatar
yaojie committed
852
}
853

854
static void fill_qos2(NGAP_QosFlowAddOrModifyRequestList_t *qos, pdusession_t *session)
laurent's avatar
tmp  
laurent committed
855
{
856 857 858 859 860 861 862 863
  // we need to duplicate the function fill_qos because all data types are slightly different
  DevAssert(qos->list.count > 0);
  DevAssert(qos->list.count <= NGAP_maxnoofQosFlows);
  for (int qosIdx = 0; qosIdx < qos->list.count; qosIdx++) {
    NGAP_QosFlowAddOrModifyRequestItem_t *qosFlowItem_p = qos->list.array[qosIdx];
    // Set the QOS informations
    session->qos[qosIdx].qfi = (uint8_t)qosFlowItem_p->qosFlowIdentifier;
    NGAP_QosCharacteristics_t *qosChar = &qosFlowItem_p->qosFlowLevelQosParameters->qosCharacteristics;
864
    AssertFatal(qosChar, "Qos characteristics are not available for qos flow index %d\n", qosIdx);
865
    if (qosChar->present == NGAP_QosCharacteristics_PR_nonDynamic5QI) {
866 867 868 869 870 871 872
      AssertFatal(qosChar->choice.dynamic5QI, "Non-Dynamic 5QI is NULL\n");
      session->qos[qosIdx].fiveQI_type = non_dynamic;
      session->qos[qosIdx].fiveQI = (uint64_t)qosChar->choice.nonDynamic5QI->fiveQI;
    } else {
      AssertFatal(qosChar->choice.dynamic5QI, "Dynamic 5QI is NULL\n");
      session->qos[qosIdx].fiveQI_type = dynamic;
      session->qos[qosIdx].fiveQI = (uint64_t)(*qosChar->choice.dynamic5QI->fiveQI);
873
    }
laurent's avatar
tmp  
laurent committed
874

875 876 877 878 879 880 881 882 883 884 885
    ngap_allocation_retention_priority_t *tmp = &session->qos[qosIdx].allocation_retention_priority;
    NGAP_AllocationAndRetentionPriority_t *tmp2 = &qosFlowItem_p->qosFlowLevelQosParameters->allocationAndRetentionPriority;
    tmp->priority_level = tmp2->priorityLevelARP;
    tmp->pre_emp_capability = tmp2->pre_emptionCapability;
    tmp->pre_emp_vulnerability = tmp2->pre_emptionVulnerability;
  }
  session->nb_qos = qos->list.count;
}

static void decodePDUSessionResourceModify(pdusession_t *param, const ngap_pdu_t pdu)
{
886
  NGAP_PDUSessionResourceModifyRequestTransfer_t *pdusessionTransfer = NULL;
887
  asn_dec_rval_t dec_rval = aper_decode(NULL, &asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer, (void **)&pdusessionTransfer, pdu.buffer, pdu.length, 0, 0);
laurent's avatar
tmp  
laurent committed
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915

  if (dec_rval.code != RC_OK) {
    LOG_E(NR_RRC, "could not decode PDUSessionResourceModifyRequestTransfer\n");
    return;
  }

  for (int j = 0; j < pdusessionTransfer->protocolIEs.list.count; j++) {
    NGAP_PDUSessionResourceModifyRequestTransferIEs_t *pdusessionTransfer_ies = pdusessionTransfer->protocolIEs.list.array[j];
    switch (pdusessionTransfer_ies->id) {
        /* optional PDUSessionAggregateMaximumBitRate */
      case NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate:
        // TODO
        LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_PDUSessionAggregateMaximumBitRate\n");
        break;

        /* optional UL-NGU-UP-TNLModifyList */
      case NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList:
        // TODO
        LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_UL_NGU_UP_TNLModifyList\n");
        break;

        /* optional NetworkInstance */
      case NGAP_ProtocolIE_ID_id_NetworkInstance:
        // TODO
        LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_NetworkInstance\n");
        break;

        /* optional QosFlowAddOrModifyRequestList */
916 917 918
      case NGAP_ProtocolIE_ID_id_QosFlowAddOrModifyRequestList:
        fill_qos2(&pdusessionTransfer_ies->value.choice.QosFlowAddOrModifyRequestList, param);
        break;
laurent's avatar
tmp  
laurent committed
919 920 921 922

        /* optional QosFlowToReleaseList */
      case NGAP_ProtocolIE_ID_id_QosFlowToReleaseList:
        // TODO
923
        LOG_E(NR_RRC, "Can't handle NGAP_ProtocolIE_ID_id_QosFlowToReleaseList\n");
laurent's avatar
tmp  
laurent committed
924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
        break;

        /* optional AdditionalUL-NGU-UP-TNLInformation */
      case NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation:
        // TODO
        LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_AdditionalUL_NGU_UP_TNLInformation\n");
        break;

        /* optional CommonNetworkInstance */
      case NGAP_ProtocolIE_ID_id_CommonNetworkInstance:
        // TODO
        LOG_E(NR_RRC, "Cant' handle NGAP_ProtocolIE_ID_id_CommonNetworkInstance\n");
        break;

      default:
        LOG_E(NR_RRC, "could not found protocolIEs id %ld\n", pdusessionTransfer_ies->id);
        return;
    }
  }
943
    ASN_STRUCT_FREE(asn_DEF_NGAP_PDUSessionResourceModifyRequestTransfer,pdusessionTransfer );
laurent's avatar
tmp  
laurent committed
944 945
}

946
//------------------------------------------------------------------------------
laurent's avatar
tmp  
laurent committed
947
int rrc_gNB_process_NGAP_PDUSESSION_MODIFY_REQ(MessageDef *msg_p, instance_t instance)
948 949
//------------------------------------------------------------------------------
{
laurent's avatar
tmp  
laurent committed
950
  rrc_gNB_ue_context_t *ue_context_p = NULL;
951

laurent's avatar
tmp  
laurent committed
952 953
  protocol_ctxt_t ctxt;
  ngap_pdusession_modify_req_t *req = &NGAP_PDUSESSION_MODIFY_REQ(msg_p);
954

955
  ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], req->gNB_ue_ngap_id);
956
  if (ue_context_p == NULL) {
laurent's avatar
tmp  
laurent committed
957 958
    LOG_W(NR_RRC, "[gNB %ld] In NGAP_PDUSESSION_MODIFY_REQ: unknown UE from NGAP ids (%u)\n", instance, req->gNB_ue_ngap_id);
    // TO implement return setup failed
959
    return (-1);
960 961
  }
  gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
962
  PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0);
963
  ctxt.eNB_index = 0;
964
  bool all_failed = true;
965
  for (int i = 0; i < req->nb_pdusessions_tomodify; i++) {
966 967 968 969
    rrc_pdu_session_param_t *sess;
    const pdusession_t *sessMod = req->pdusession_modify_params + i;
    for (sess = UE->pduSession; sess < UE->pduSession + UE->nb_of_pdusessions; sess++)
      if (sess->param.pdusession_id == sessMod->pdusession_id)
970
        break;
971 972 973 974 975 976 977
    if (sess == UE->pduSession + UE->nb_of_pdusessions) {
      LOG_W(NR_RRC, "Requested modification of non-existing PDU session, refusing modification\n");
      UE->nb_of_pdusessions++;
      sess->status = PDU_SESSION_STATUS_FAILED;
      sess->param.pdusession_id = sessMod->pdusession_id;
      sess->cause = NGAP_CAUSE_RADIO_NETWORK;
      UE->pduSession[i].cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID;
978
    } else {
979 980 981 982 983 984 985 986 987 988
      all_failed = false;
      sess->status = PDU_SESSION_STATUS_NEW;
      sess->param.pdusession_id = sessMod->pdusession_id;
      sess->cause = NGAP_CAUSE_RADIO_NETWORK;
      sess->cause_value = NGAP_CauseRadioNetwork_multiple_PDU_session_ID_instances;
      sess->status = PDU_SESSION_STATUS_NEW;
      sess->param.pdusession_id = sessMod->pdusession_id;
      sess->cause = NGAP_CAUSE_NOTHING;
      if (sessMod->nas_pdu.buffer != NULL) {
        UE->pduSession[i].param.nas_pdu = sessMod->nas_pdu;
laurent's avatar
tmp  
laurent committed
989
      }
990
      // Save new pdu session parameters, qos, upf addr, teid
991 992 993
      decodePDUSessionResourceModify(&sess->param, UE->pduSession[i].param.pdusessionTransfer);
      sess->param.UPF_addr_N3 = sessMod->upf_addr;
      sess->param.UPF_teid_N3 = sessMod->gtp_teid;
994
    }
995
  }
996

997
  if (!all_failed) {
998 999
    LOG_D(NR_RRC, "generate RRCReconfiguration \n");
    rrc_gNB_modify_dedicatedRRCReconfiguration(&ctxt, ue_context_p);
1000 1001 1002 1003
  } else {
    LOG_I(NR_RRC,
          "pdu session modify failed, fill NGAP_PDUSESSION_MODIFY_RESP with the pdu session information that failed to modify \n");
    MessageDef *msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_PDUSESSION_MODIFY_RESP);
1004 1005 1006
    if (msg_fail_p == NULL) {
      LOG_E(NR_RRC, "itti_alloc_new_message failed, msg_fail_p is NULL \n");
      return (-1);
1007
    }
1008 1009 1010 1011
    ngap_pdusession_modify_resp_t *msg = &NGAP_PDUSESSION_MODIFY_RESP(msg_fail_p);
    msg->gNB_ue_ngap_id = req->gNB_ue_ngap_id;
    msg->nb_of_pdusessions = 0;

1012 1013 1014 1015 1016 1017
    for (int i = 0; i < UE->nb_of_pdusessions; i++) {
      if (UE->pduSession[i].status == PDU_SESSION_STATUS_FAILED) {
        msg->pdusessions_failed[i].pdusession_id = UE->pduSession[i].param.pdusession_id;
        msg->pdusessions_failed[i].cause = UE->pduSession[i].cause;
        msg->pdusessions_failed[i].cause_value = UE->pduSession[i].cause_value;
      }
1018 1019
    }
    itti_send_msg_to_task(TASK_NGAP, instance, msg_fail_p);
1020
  }
1021
  return (0);
1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032
}

//------------------------------------------------------------------------------
int
rrc_gNB_send_NGAP_PDUSESSION_MODIFY_RESP(
  const protocol_ctxt_t    *const ctxt_pP,
  rrc_gNB_ue_context_t     *const ue_context_pP,
  uint8_t                   xid
)
//------------------------------------------------------------------------------
{
laurent's avatar
tmp  
laurent committed
1033
  MessageDef *msg_p = NULL;
1034 1035
  uint8_t pdu_sessions_failed = 0;
  uint8_t pdu_sessions_done = 0;
laurent's avatar
tmp  
laurent committed
1036 1037
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;

1038 1039 1040 1041 1042
  msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_PDUSESSION_MODIFY_RESP);
  if (msg_p == NULL) {
    LOG_E(NR_RRC, "itti_alloc_new_message failed, msg_p is NULL \n");
    return (-1);
  }
laurent's avatar
tmp  
laurent committed
1043
  ngap_pdusession_modify_resp_t *resp = &NGAP_PDUSESSION_MODIFY_RESP(msg_p);
1044 1045
  LOG_I(NR_RRC, "send message NGAP_PDUSESSION_MODIFY_RESP \n");

1046
  resp->gNB_ue_ngap_id = UE->rrc_ue_id;
laurent's avatar
tmp  
laurent committed
1047

1048 1049 1050
  for (int i = 0; i < UE->nb_of_pdusessions; i++) {
    if (xid != UE->pduSession[i].xid) {
      LOG_W(NR_RRC, "xid does not correspond (context pdu session index %d, status %d, xid %d/%d) \n ", i, UE->pduSession[i].status, xid, UE->pduSession[i].xid);
1051 1052
      continue;
    }
1053 1054
    if (UE->pduSession[i].status == PDU_SESSION_STATUS_DONE) {
      rrc_pdu_session_param_t *pduSession = find_pduSession(UE, UE->pduSession[i].param.pdusession_id, false);
1055 1056 1057 1058 1059
      if (pduSession) {
        LOG_I(NR_RRC, "update pdu session %d \n", pduSession->param.pdusession_id);
        // Update UE->pduSession
        pduSession->status = PDU_SESSION_STATUS_ESTABLISHED;
        pduSession->cause = NGAP_CAUSE_NOTHING;
1060 1061
        for (int qos_flow_index = 0; qos_flow_index < UE->pduSession[i].param.nb_qos; qos_flow_index++) {
          pduSession->param.qos[qos_flow_index] = UE->pduSession[i].param.qos[qos_flow_index];
1062
        }
1063 1064 1065
        resp->pdusessions[pdu_sessions_done].pdusession_id = UE->pduSession[i].param.pdusession_id;
        for (int qos_flow_index = 0; qos_flow_index < UE->pduSession[i].param.nb_qos; qos_flow_index++) {
          resp->pdusessions[pdu_sessions_done].qos[qos_flow_index].qfi = UE->pduSession[i].param.qos[qos_flow_index].qfi;
1066
        }
1067 1068
        resp->pdusessions[pdu_sessions_done].pdusession_id = UE->pduSession[i].param.pdusession_id;
        resp->pdusessions[pdu_sessions_done].nb_of_qos_flow = UE->pduSession[i].param.nb_qos;
1069
        LOG_I(NR_RRC,
1070
              "Modify Resp (msg index %d, pdu session index %d, status %d, xid %d): nb_of_pduSessions %d,  pdusession_id %d \n ",
1071 1072
              pdu_sessions_done,
              i,
1073
              UE->pduSession[i].status,
1074
              xid,
1075
              UE->nb_of_pdusessions,
1076 1077 1078
              resp->pdusessions[pdu_sessions_done].pdusession_id);
        pdu_sessions_done++;
      } else {
1079 1080
        LOG_W(NR_RRC, "PDU SESSION modify of a not existing pdu session %d \n", UE->pduSession[i].param.pdusession_id);
        resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = UE->pduSession[i].param.pdusession_id;
1081 1082
        resp->pdusessions_failed[pdu_sessions_failed].cause = NGAP_CAUSE_RADIO_NETWORK;
        resp->pdusessions_failed[pdu_sessions_failed].cause_value = NGAP_CauseRadioNetwork_unknown_PDU_session_ID;
1083 1084
        pdu_sessions_failed++;
      }
1085
    } else if ((UE->pduSession[i].status == PDU_SESSION_STATUS_NEW) || (UE->pduSession[i].status == PDU_SESSION_STATUS_ESTABLISHED)) {
1086
      LOG_D(NR_RRC, "PDU SESSION is NEW or already ESTABLISHED\n");
1087 1088 1089 1090
    } else if (UE->pduSession[i].status == PDU_SESSION_STATUS_FAILED) {
      resp->pdusessions_failed[pdu_sessions_failed].pdusession_id = UE->pduSession[i].param.pdusession_id;
      resp->pdusessions_failed[pdu_sessions_failed].cause = UE->pduSession[i].cause;
      resp->pdusessions_failed[pdu_sessions_failed].cause_value = UE->pduSession[i].cause_value;
1091
      pdu_sessions_failed++;
1092
    }
1093 1094 1095
    else
      LOG_W(NR_RRC,
            "Modify pdu session %d, unknown state %d \n ",
1096 1097
            UE->pduSession[i].param.pdusession_id,
            UE->pduSession[i].status);
1098 1099
  }

laurent's avatar
tmp  
laurent committed
1100 1101
  resp->nb_of_pdusessions = pdu_sessions_done;
  resp->nb_of_pdusessions_failed = pdu_sessions_failed;
1102 1103

  if (pdu_sessions_done > 0 || pdu_sessions_failed > 0) {
1104
    LOG_D(NR_RRC, "NGAP_PDUSESSION_MODIFY_RESP: sending the message (total pdu session %d)\n", UE->nb_of_pdusessions);
1105 1106 1107 1108 1109 1110 1111 1112 1113
    itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p);
  } else {
    itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
  }

  return 0;
}

//------------------------------------------------------------------------------
1114
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)
1115 1116 1117 1118 1119
//------------------------------------------------------------------------------
{
  if (ue_context_pP == NULL) {
    LOG_E(RRC, "[gNB] In NGAP_UE_CONTEXT_RELEASE_REQ: invalid UE\n");
  } else {
laurent's avatar
tmp  
laurent committed
1120 1121 1122 1123
    const gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
    MessageDef *msg = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_REQ);
    ngap_ue_release_req_t *req = &NGAP_UE_CONTEXT_RELEASE_REQ(msg);
    memset(req, 0, sizeof(*req));
1124
    req->gNB_ue_ngap_id = UE->rrc_ue_id;
laurent's avatar
tmp  
laurent committed
1125 1126
    req->cause = causeP;
    req->cause_value = cause_valueP;
1127 1128
    for (int i = 0; i < UE->nb_of_pdusessions; i++) {
      req->pdusessions[i].pdusession_id = UE->pduSession[i].param.pdusession_id;
laurent's avatar
tmp  
laurent committed
1129
      req->nb_of_pdusessions++;
1130
    }
laurent's avatar
tmp  
laurent committed
1131
    itti_send_msg_to_task(TASK_NGAP, GNB_MODULE_ID_TO_INSTANCE(gnb_mod_idP), msg);
1132 1133 1134
  }
}
/*------------------------------------------------------------------------------*/
laurent's avatar
tmp  
laurent committed
1135
int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_REQ(MessageDef *msg_p, instance_t instance)
1136 1137 1138
{
  uint32_t gNB_ue_ngap_id;
  gNB_ue_ngap_id = NGAP_UE_CONTEXT_RELEASE_REQ(msg_p).gNB_ue_ngap_id;
1139
  rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], gNB_ue_ngap_id);
1140 1141 1142 1143

  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;
1144
    LOG_W(RRC, "[gNB %ld] In NGAP_UE_CONTEXT_RELEASE_REQ: unknown UE from gNB_ue_ngap_id (%u)\n",
1145 1146
          instance,
          gNB_ue_ngap_id);
1147
    msg_fail_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_RESP); /* TODO change message ID. */
1148 1149 1150 1151 1152 1153 1154
    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 */
1155 1156 1157 1158
    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);
1159 1160 1161 1162 1163 1164 1165 1166 1167
    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.
*/
laurent's avatar
tmp  
laurent committed
1168 1169
int rrc_gNB_process_NGAP_UE_CONTEXT_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance)
{
1170 1171 1172 1173
  //-----------------------------------------------------------------------------
  uint32_t gNB_ue_ngap_id = 0;
  protocol_ctxt_t ctxt;
  gNB_ue_ngap_id = NGAP_UE_CONTEXT_RELEASE_COMMAND(msg_p).gNB_ue_ngap_id;
1174
  rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], gNB_ue_ngap_id);
1175 1176 1177 1178

  if (ue_context_p == NULL) {
    /* Can not associate this message to an UE index */
    MessageDef *msg_complete_p = NULL;
1179
    LOG_W(NR_RRC, "[gNB %ld] In NGAP_UE_CONTEXT_RELEASE_COMMAND: unknown UE from gNB_ue_ngap_id (%u)\n",
1180 1181
          instance,
          gNB_ue_ngap_id);
1182
    msg_complete_p = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_COMPLETE);
1183 1184 1185 1186
    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);
    return -1;
  }
1187 1188

  gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
1189
  PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0);
1190 1191 1192
  ctxt.eNB_index = 0;
  rrc_gNB_generate_RRCRelease(&ctxt, ue_context_p);
  return 0;
1193
}
1194 1195 1196 1197 1198 1199 1200 1201 1202

void rrc_gNB_send_NGAP_UE_CONTEXT_RELEASE_COMPLETE(
  instance_t instance,
  uint32_t   gNB_ue_ngap_id) {
  MessageDef *msg = itti_alloc_new_message(TASK_RRC_GNB, 0, NGAP_UE_CONTEXT_RELEASE_COMPLETE);
  NGAP_UE_CONTEXT_RELEASE_COMPLETE(msg).gNB_ue_ngap_id = gNB_ue_ngap_id;
  itti_send_msg_to_task(TASK_NGAP, instance, msg);
}

1203 1204 1205
void rrc_gNB_send_NGAP_UE_CAPABILITIES_IND(const protocol_ctxt_t *const ctxt_pP,
                                           rrc_gNB_ue_context_t *const ue_context_pP,
                                           const NR_UECapabilityInformation_t *const ue_cap_info)
1206 1207
//------------------------------------------------------------------------------
{
1208 1209 1210 1211 1212
  NR_UE_CapabilityRAT_ContainerList_t *ueCapabilityRATContainerList =
      ue_cap_info->criticalExtensions.choice.ueCapabilityInformation->ue_CapabilityRAT_ContainerList;
  void *buf;
  NR_UERadioAccessCapabilityInformation_t rac = {0};
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
laurent's avatar
tmp  
laurent committed
1213

1214 1215
  if (ueCapabilityRATContainerList->list.count == 0) {
    LOG_W(RRC, "[gNB %d][UE %x] bad UE capabilities\n", ctxt_pP->module_id, UE->rnti);
1216
    }
1217 1218 1219 1220

    int ret = uper_encode_to_new_buffer(&asn_DEF_NR_UE_CapabilityRAT_ContainerList, NULL, ueCapabilityRATContainerList, &buf);
    AssertFatal(ret > 0, "fail to encode ue capabilities\n");

1221
    rac.criticalExtensions.present = NR_UERadioAccessCapabilityInformation__criticalExtensions_PR_c1;
1222 1223 1224 1225 1226 1227
    asn1cCalloc(rac.criticalExtensions.choice.c1, c1);
    c1->present = NR_UERadioAccessCapabilityInformation__criticalExtensions__c1_PR_ueRadioAccessCapabilityInformation;
    asn1cCalloc(c1->choice.ueRadioAccessCapabilityInformation, info);
    info->ue_RadioAccessCapabilityInfo.buf = buf;
    info->ue_RadioAccessCapabilityInfo.size = ret;
    info->nonCriticalExtension = NULL;
1228
    /* 8192 is arbitrary, should be big enough */
1229 1230
    void *buf2 = NULL;
    int encoded = uper_encode_to_new_buffer(&asn_DEF_NR_UERadioAccessCapabilityInformation, NULL, &rac, &buf2);
1231

1232 1233 1234
    AssertFatal(encoded > 0, "fail to encode ue capabilities\n");
    ;
    ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_NR_UERadioAccessCapabilityInformation, &rac);
1235
    MessageDef *msg_p;
1236
    msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_UE_CAPABILITIES_IND);
1237 1238
    ngap_ue_cap_info_ind_t *ind = &NGAP_UE_CAPABILITIES_IND(msg_p);
    memset(ind, 0, sizeof(*ind));
1239
    ind->gNB_ue_ngap_id = UE->rrc_ue_id;
1240 1241
    ind->ue_radio_cap.length = encoded;
    ind->ue_radio_cap.buffer = buf2;
1242 1243 1244 1245
    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");
}

1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256
//------------------------------------------------------------------------------
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;
laurent's avatar
tmp  
laurent committed
1257
  gNB_RRC_UE_t *UE = &ue_context_pP->ue_context;
1258
  msg_p = itti_alloc_new_message (TASK_RRC_GNB, 0, NGAP_PDUSESSION_RELEASE_RESPONSE);
1259 1260
  ngap_pdusession_release_resp_t *resp = &NGAP_PDUSESSION_RELEASE_RESPONSE(msg_p);
  memset(resp, 0, sizeof(*resp));
1261
  resp->gNB_ue_ngap_id = UE->rrc_ue_id;
1262

1263
  for (int i = 0; i < UE->nb_of_pdusessions; i++) {
laurent's avatar
tmp  
laurent committed
1264
    if (xid == UE->pduSession[i].xid) {
1265
      resp->pdusession_release[pdu_sessions_released].pdusession_id = UE->pduSession[i].param.pdusession_id;
1266 1267
      pdu_sessions_released++;
      //clear
laurent's avatar
tmp  
laurent committed
1268
      memset(&UE->pduSession[i], 0, sizeof(*UE->pduSession));
1269 1270
      UE->pduSession[i].status = PDU_SESSION_STATUS_RELEASED;
      LOG_W(NR_RRC, "Released pdu session, but code to finish to free memory\n");
1271 1272 1273
    }
  }

1274
  resp->nb_of_pdusessions_released = pdu_sessions_released;
1275
  resp->nb_of_pdusessions_failed = 0;
1276
  LOG_I(NR_RRC, "NGAP PDUSESSION RELEASE RESPONSE: rrc_ue_id %u release_pdu_sessions %d\n", resp->gNB_ue_ngap_id, pdu_sessions_released);
1277 1278 1279 1280
  itti_send_msg_to_task (TASK_NGAP, ctxt_pP->instance, msg_p);
}

//------------------------------------------------------------------------------
laurent's avatar
tmp  
laurent committed
1281
int rrc_gNB_process_NGAP_PDUSESSION_RELEASE_COMMAND(MessageDef *msg_p, instance_t instance)
1282 1283
//------------------------------------------------------------------------------
{
1284 1285 1286 1287 1288 1289
  uint32_t gNB_ue_ngap_id;
  protocol_ctxt_t ctxt;
  ngap_pdusession_release_command_t *cmd = &NGAP_PDUSESSION_RELEASE_COMMAND(msg_p);
  gNB_ue_ngap_id = cmd->gNB_ue_ngap_id;
  if (cmd->nb_pdusessions_torelease > NGAP_MAX_PDUSESSION) {
    LOG_E(NR_RRC, "incorrect number of pdu session do release %d\n", cmd->nb_pdusessions_torelease);
1290 1291
    return -1;
  }
1292
  rrc_gNB_ue_context_t *ue_context_p = rrc_gNB_get_ue_context(RC.nrrrc[instance], gNB_ue_ngap_id);
1293

1294 1295 1296 1297
  if (!ue_context_p) {
    LOG_E(NR_RRC, "[gNB %ld] not found ue context gNB_ue_ngap_id %u \n", instance, gNB_ue_ngap_id);
    return -1;
  }
1298

1299 1300
  LOG_I(NR_RRC, "[gNB %ld] gNB_ue_ngap_id %u \n", instance, gNB_ue_ngap_id);
  gNB_RRC_UE_t *UE = &ue_context_p->ue_context;
1301
  PROTOCOL_CTXT_SET_BY_INSTANCE(&ctxt, instance, GNB_FLAG_YES, UE->rrc_ue_id, 0, 0);
1302
  LOG_I(
1303
      NR_RRC, "PDU Session Release Command: AMF_UE_NGAP_ID %lu  rrc_ue_id %u release_pdusessions %d \n", cmd->amf_ue_ngap_id, gNB_ue_ngap_id, cmd->nb_pdusessions_torelease);
1304 1305 1306
  bool found = false;
  uint8_t xid = rrc_gNB_get_next_transaction_identifier(ctxt.module_id);
  UE->xids[xid] = RRC_PDUSESSION_RELEASE;
1307 1308 1309
  for (int pdusession = 0; pdusession < cmd->nb_pdusessions_torelease; pdusession++) {
    rrc_pdu_session_param_t *pduSession = find_pduSession(UE, cmd->pdusession_release_params[pdusession].pdusession_id, false);
    if (!pduSession) {
1310 1311 1312 1313 1314 1315
      LOG_I(NR_RRC, "no pdusession_id, AMF requested to close it id=%d\n", cmd->pdusession_release_params[pdusession].pdusession_id);
      int j=UE->nb_of_pdusessions++;
      UE->pduSession[j].status = PDU_SESSION_STATUS_FAILED;
      UE->pduSession[j].param.pdusession_id = cmd->pdusession_release_params[pdusession].pdusession_id;
      UE->pduSession[j].cause = NGAP_CAUSE_RADIO_NETWORK;
      UE->pduSession[j].cause_value = 30;
1316 1317 1318 1319 1320
      continue;
    }
    if (pduSession->status == PDU_SESSION_STATUS_FAILED) {
      pduSession->xid = xid;
      continue;
1321
    }
1322
    if (pduSession->status == PDU_SESSION_STATUS_ESTABLISHED) {
1323
      found = true;
1324 1325 1326 1327 1328
      LOG_I(NR_RRC, "RELEASE pdusession %d \n", pduSession->param.pdusession_id);
      pduSession->status = PDU_SESSION_STATUS_TORELEASE;
      pduSession->xid = xid;
    }
  }
1329

1330
  if (found) {
1331 1332 1333 1334 1335
    // TODO RRCReconfiguration To UE
    LOG_I(NR_RRC, "Send RRCReconfiguration To UE \n");
    rrc_gNB_generate_dedicatedRRCReconfiguration_release(&ctxt, ue_context_p, xid, cmd->nas_pdu.length, cmd->nas_pdu.buffer);
  } else {
    // gtp tunnel delete
1336
    LOG_I(NR_RRC, "gtp tunnel delete all tunnels for UE %04x\n", UE->rnti);
1337 1338 1339 1340 1341 1342
    gtpv1u_gnb_delete_tunnel_req_t req = {0};
    req.ue_id = UE->rnti;
    gtpv1u_delete_ngu_tunnel(instance, &req);
    // 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");
1343 1344 1345
  }
  return 0;
}
1346 1347 1348 1349 1350 1351 1352 1353 1354 1355

void nr_rrc_rx_tx(void) {
  // check timers

  // check if UEs are lost, to remove them from upper layers

  //

}

1356
/*------------------------------------------------------------------------------*/
laurent's avatar
tmp  
laurent committed
1357 1358
int rrc_gNB_process_PAGING_IND(MessageDef *msg_p, instance_t instance)
{
1359 1360 1361 1362 1363 1364 1365 1366 1367
  for (uint16_t tai_size = 0; tai_size < NGAP_PAGING_IND(msg_p).tai_size; tai_size++) {
    LOG_I(NR_RRC,"[gNB %ld] In NGAP_PAGING_IND: MCC %d, MNC %d, TAC %d\n", instance, NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc,
          NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc, NGAP_PAGING_IND(msg_p).tac[tai_size]);

    for (uint8_t j = 0; j < RC.nrrrc[instance]->configuration.num_plmn; j++) {
      if (RC.nrrrc[instance]->configuration.mcc[j] == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mcc
          && RC.nrrrc[instance]->configuration.mnc[j] == NGAP_PAGING_IND(msg_p).plmn_identity[tai_size].mnc
          && RC.nrrrc[instance]->configuration.tac == NGAP_PAGING_IND(msg_p).tac[tai_size]) {
        for (uint8_t CC_id = 0; CC_id < MAX_NUM_CCs; CC_id++) {
1368
          AssertFatal(false, "to be implemented properly\n");
1369 1370
          if (NODE_IS_CU(RC.nrrrc[instance]->node_type)) {
            MessageDef *m = itti_alloc_new_message(TASK_RRC_GNB, 0, F1AP_PAGING_IND);
1371 1372 1373
            F1AP_PAGING_IND(m).plmn.mcc = RC.nrrrc[j]->configuration.mcc[0];
            F1AP_PAGING_IND(m).plmn.mnc = RC.nrrrc[j]->configuration.mnc[0];
            F1AP_PAGING_IND(m).plmn.mnc_digit_length = RC.nrrrc[j]->configuration.mnc_digit_length[0];
1374 1375 1376 1377 1378 1379 1380
            F1AP_PAGING_IND (m).nr_cellid        = RC.nrrrc[j]->nr_cellid;
            F1AP_PAGING_IND (m).ueidentityindexvalue = (uint16_t)(NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi%1024);
            F1AP_PAGING_IND (m).fiveg_s_tmsi = NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi;
            F1AP_PAGING_IND (m).paging_drx = NGAP_PAGING_IND(msg_p).paging_drx;
            LOG_E(F1AP, "ueidentityindexvalue %u fiveg_s_tmsi %ld paging_drx %u\n", F1AP_PAGING_IND (m).ueidentityindexvalue, F1AP_PAGING_IND (m).fiveg_s_tmsi, F1AP_PAGING_IND (m).paging_drx);
            itti_send_msg_to_task(TASK_CU_F1, instance, m);
          } else {
1381
            //rrc_gNB_generate_pcch_msg(NGAP_PAGING_IND(msg_p).ue_paging_identity.s_tmsi.m_tmsi,(uint8_t)NGAP_PAGING_IND(msg_p).paging_drx, instance, CC_id);
1382 1383 1384 1385 1386 1387 1388 1389
          } // end of nodetype check
        } // end of cc loop
      } // end of mcc mnc check
    } // end of num_plmn
  } // end of tai size

  return 0;
}