int s1ap_eNB_handle_overload_start(uint32_t               assoc_id,
                                   uint32_t               stream,
                                   struct s1ap_message_s *message_p)
{
  S1ap_OverloadStartIEs_t *overload_start_p;
  s1ap_eNB_mme_data_t     *mme_desc_p;

  DevAssert(message_p != NULL);

  overload_start_p = &message_p->msg.s1ap_OverloadStartIEs;

  DevCheck(overload_start_p->overloadResponse.present ==
           S1ap_OverloadResponse_PR_overloadAction,
           S1ap_OverloadResponse_PR_overloadAction, 0, 0);

  /* Non UE-associated signalling -> stream 0 */
  DevCheck(stream == 0, stream, 0, 0);

  if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
    /* No MME context associated */
    return -1;
  }

  /* Mark the MME as overloaded and set the overload state according to
   * the value received.
   */
  mme_desc_p->state = S1AP_ENB_OVERLOAD;
  mme_desc_p->overload_state =
    overload_start_p->overloadResponse.choice.overloadAction;

  return 0;
}
Example #2
0
int set_log(int component, int level, int interval)
{
  /* Checking parameters */
  DevCheck((component >= MIN_LOG_COMPONENTS) && (component < MAX_LOG_COMPONENTS),
           component, MIN_LOG_COMPONENTS, MAX_LOG_COMPONENTS);
  DevCheck((level <= LOG_TRACE) && (level >= LOG_EMERG), level, LOG_TRACE,
           LOG_EMERG);
  DevCheck((interval > 0) && (interval <= 0xFF), interval, 0, 0xFF);

  g_log->log_component[component].level = level;

  switch (level) {
  case LOG_TRACE:
    g_log->log_component[component].flag = LOG_MED ;
    break;

  case LOG_DEBUG:
    g_log->log_component[component].flag = LOG_MED ;
    break;

  case LOG_INFO:
    g_log->log_component[component].flag = LOG_LOW ;
    break;

  default:
    g_log->log_component[component].flag = LOG_NONE ;
    break;
  }

  g_log->log_component[component].interval = interval;

  return 0;
}
static inline
int s6a_parse_ip_address(struct avp_hdr *hdr, ip_address_t *ip_address)
{
    uint16_t ip_type;

    DevCheck(hdr->avp_value->os.len >= 2, hdr->avp_value->os.len, 2, 0);

    ip_type = (hdr->avp_value->os.data[0] << 8) | (hdr->avp_value->os.data[1]);

    if (ip_type == IANA_IPV4) {
        /* This is an IPv4 address */
        ip_address->pdn_type = IPv4;
        DevCheck(hdr->avp_value->os.len == 6, hdr->avp_value->os.len, 6, ip_type);
        memcpy(ip_address->address.ipv4_address, &hdr->avp_value->os.data[2], 4);
    } else if (ip_type == IANA_IPV6) {
        /* This is an IPv6 address */
        ip_address->pdn_type = IPv6;
        DevCheck(hdr->avp_value->os.len == 18, hdr->avp_value->os.len, 18, ip_type);
        memcpy(ip_address->address.ipv6_address, &hdr->avp_value->os.data[2], 16);
    } else {
        /* unhandled case... */
        return -1;
    }
    return 0;
}
Example #4
0
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB)
{
  s1ap_eNB_instance_t *new_instance;
  uint8_t index;
  
  DevAssert(s1ap_register_eNB != NULL);

  /* Look if the provided instance already exists */
  new_instance = s1ap_eNB_get_instance(instance);
  
 
  if (new_instance != NULL) { 
    /* Checks if it is a retry on the same eNB */
    DevCheck(new_instance->eNB_id == s1ap_register_eNB->eNB_id, new_instance->eNB_id, s1ap_register_eNB->eNB_id, 0);
    DevCheck(new_instance->cell_type == s1ap_register_eNB->cell_type, new_instance->cell_type, s1ap_register_eNB->cell_type, 0);
    DevCheck(new_instance->tac == s1ap_register_eNB->tac, new_instance->tac, s1ap_register_eNB->tac, 0);
    DevCheck(new_instance->mcc == s1ap_register_eNB->mcc, new_instance->mcc, s1ap_register_eNB->mcc, 0);
    DevCheck(new_instance->mnc == s1ap_register_eNB->mnc, new_instance->mnc, s1ap_register_eNB->mnc, 0);
    DevCheck(new_instance->mnc_digit_length == s1ap_register_eNB->mnc_digit_length, new_instance->mnc_digit_length, s1ap_register_eNB->mnc_digit_length, 0);
    DevCheck(new_instance->default_drx == s1ap_register_eNB->default_drx, new_instance->default_drx, s1ap_register_eNB->default_drx, 0);
  } else {
    new_instance = calloc(1, sizeof(s1ap_eNB_instance_t));
    DevAssert(new_instance != NULL);

    RB_INIT(&new_instance->s1ap_ue_head);
    RB_INIT(&new_instance->s1ap_mme_head);

    /* Copy usefull parameters */
    new_instance->instance         = instance;
    new_instance->eNB_name         = s1ap_register_eNB->eNB_name;
    new_instance->eNB_id           = s1ap_register_eNB->eNB_id;
    new_instance->cell_type        = s1ap_register_eNB->cell_type;
    new_instance->tac              = s1ap_register_eNB->tac;
    new_instance->mcc              = s1ap_register_eNB->mcc;
    new_instance->mnc              = s1ap_register_eNB->mnc;
    new_instance->mnc_digit_length = s1ap_register_eNB->mnc_digit_length;
    new_instance->default_drx      = s1ap_register_eNB->default_drx;

    /* Add the new instance to the list of eNB (meaningfull in virtual mode) */
    s1ap_eNB_insert_new_instance(new_instance);

    S1AP_INFO("Registered new eNB[%d] and %s eNB id %u\n",
               instance,
               s1ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
               s1ap_register_eNB->eNB_id);
  }

  DevCheck(s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS,
           S1AP_MAX_NB_MME_IP_ADDRESS, s1ap_register_eNB->nb_mme, 0);

  /* Trying to connect to provided list of MME ip address */
  for (index = 0; index < s1ap_register_eNB->nb_mme; index++) {
    s1ap_eNB_register_mme(new_instance,
    		          &s1ap_register_eNB->mme_ip_address[index],
                          &s1ap_register_eNB->enb_ip_address,
                          s1ap_register_eNB->sctp_in_streams,
                          s1ap_register_eNB->sctp_out_streams);
  }
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_common_abort()                                   **
 **                                                                        **
 ** Description: The ongoing EMM procedure has been aborted. The network   **
 **      performs required actions related to the EMM common pro-  **
 **      cedure previously initiated between the UE with the spe-  **
 **      cified identifier and the MME.                            **
 **                                                                        **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **      Others:    _emm_common_data                           **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int
emm_proc_common_abort (
  unsigned int ueid)
{
  emm_common_data_t                      *emm_common_data_ctx = NULL;
  emm_common_failure_callback_t           emm_callback;
  int                                     rc = RETURNerror;

  LOG_FUNC_IN;
#if NAS_BUILT_IN_EPC
  DevCheck (ueid > 0, ueid, 0, 0);
  emm_common_data_ctx = emm_common_data_context_get (&emm_common_data_head, ueid);
#else
  assert (ueid < EMM_DATA_NB_UE_MAX);
  emm_common_data_ctx = _emm_common_data[ueid];
#endif
  assert (emm_common_data_ctx != NULL);
  emm_callback = emm_common_data_ctx->abort;

  if (emm_callback) {
    struct emm_data_context_s              *ctx = NULL;

#if NAS_BUILT_IN_EPC
    ctx = emm_data_context_get (&_emm_data, ueid);
#else
    ctx = _emm_data.ctx[ueid];
#endif
    rc = (*emm_callback) (ctx);
  }

  _emm_common_cleanup (ueid);
  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_common_cleanup()                                 **
 **                                                                        **
 ** Description: Cleans EMM procedure callback functions upon completion   **
 **      of an EMM common procedure previously initiated within an **
 **      EMM procedure currently in progress between the network   **
 **      and the UE with the specified identifier.                 **
 **                                                                        **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    _emm_common_data                           **
 **                                                                        **
 ***************************************************************************/
static void
_emm_common_cleanup (
  unsigned int ueid)
{
  emm_common_data_t                      *emm_common_data_ctx = NULL;

#if NAS_BUILT_IN_EPC
  DevCheck (ueid > 0, ueid, 0, 0);
  emm_common_data_ctx = emm_common_data_context_get (&emm_common_data_head, ueid);
#else
  assert (ueid < EMM_DATA_NB_UE_MAX);
  emm_common_data_ctx = _emm_common_data[ueid];
#endif

  if (emm_common_data_ctx) {
    emm_common_data_ctx->ref_count -= 1;

    if (emm_common_data_ctx->ref_count == 0) {
      /*
       * Release the callback functions
       */
#if NAS_BUILT_IN_EPC
      RB_REMOVE (emm_common_data_map, &emm_common_data_head.emm_common_data_root, emm_common_data_ctx);
#endif
      free (emm_common_data_ctx);
      emm_common_data_ctx = NULL;
    }
  }
}
static inline
int s6a_parse_apn_configuration_profile(struct avp *avp_apn_conf_prof,
                                        apn_config_profile_t *apn_config_profile)
{
    struct avp *avp = NULL;
    struct avp_hdr *hdr;

    CHECK_FCT(fd_msg_browse(avp_apn_conf_prof, MSG_BRW_FIRST_CHILD, &avp, NULL));
    while(avp) {
        CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
        switch(hdr->avp_code) {
            case AVP_CODE_CONTEXT_IDENTIFIER:
                apn_config_profile->context_identifier = hdr->avp_value->u32;
                break;
            case AVP_CODE_ALL_APN_CONFIG_INC_IND:
                CHECK_FCT(s6a_parse_all_apn_conf_inc_ind(hdr, &apn_config_profile->all_apn_conf_ind));
                break;
            case AVP_CODE_APN_CONFIGURATION: {
                DevCheck(apn_config_profile->nb_apns < MAX_APN_PER_UE,
                         apn_config_profile->nb_apns, MAX_APN_PER_UE, 0);
                CHECK_FCT(s6a_parse_apn_configuration(
                    avp, &apn_config_profile->apn_configuration[apn_config_profile->nb_apns]));
                apn_config_profile->nb_apns++;
            } break;
        }
        /* Go to next AVP in the grouped AVP */
        CHECK_FCT(fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL));
    }
    return 0;
}
int s1ap_eNB_handle_overload_stop(uint32_t               assoc_id,
                                  uint32_t               stream,
                                  struct s1ap_message_s *message_p)
{
  /* We received Overload stop message, meaning that the MME is no more
   * overloaded. This is an empty message, with only message header and no
   * Information Element.
   */

  DevAssert(message_p != NULL);

  s1ap_eNB_mme_data_t *mme_desc_p;

  /* Non UE-associated signalling -> stream 0 */
  DevCheck(stream == 0, stream, 0, 0);

  if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
    /* No MME context associated */
    return -1;
  }

  mme_desc_p->state = S1AP_ENB_STATE_CONNECTED;
  mme_desc_p->overload_state = S1AP_NO_OVERLOAD;
  return 0;
}
static inline
int s6a_parse_pre_emp_vulnerability(struct avp_hdr *hdr, pre_emp_vulnerability_t *pre_emp_vulnerability)
{
    DevCheck(hdr->avp_value->u32 < PRE_EMPTION_VULNERABILITY_MAX, hdr->avp_value->u32,
             PRE_EMPTION_VULNERABILITY_MAX, 0);
    *pre_emp_vulnerability = hdr->avp_value->u32;
    return 0;
}
static inline
int s6a_parse_qci(struct avp_hdr *hdr, qci_t *qci)
{
    DevCheck(hdr->avp_value->u32 < QCI_MAX,
             hdr->avp_value->u32, QCI_MAX, 0);
    *qci = hdr->avp_value->u32;
    return 0;
}
static inline
int s6a_parse_pdn_type(struct avp_hdr *hdr, pdn_type_t *pdn_type)
{
    DevCheck(hdr->avp_value->u32 < IP_MAX,
             hdr->avp_value->u32, IP_MAX, 0);
    *pdn_type = hdr->avp_value->u32;
    return 0;
}
static inline
int s6a_parse_all_apn_conf_inc_ind(struct avp_hdr *hdr, all_apn_conf_ind_t *ptr)
{
    DevCheck(hdr->avp_value->u32 < ALL_APN_MAX,
             hdr->avp_value->u32, ALL_APN_MAX, 0);
    *ptr = hdr->avp_value->u32;
    return 0;
}
static inline
int s6a_parse_priority_level(struct avp_hdr *hdr, priority_level_t *priority_level)
{
    DevCheck(hdr->avp_value->u32 <= PRIORITY_LEVEL_MAX &&
             hdr->avp_value->u32 >= PRIORITY_LEVEL_MIN, hdr->avp_value->u32,
             PRIORITY_LEVEL_MAX, PRIORITY_LEVEL_MIN);
    *priority_level = (priority_level_t)hdr->avp_value->u32;
    return 0;
}
static inline
int s6a_parse_access_restriction_data(struct avp_hdr *hdr_access_restriction,
                                      access_restriction_t *access_restriction)
{
    DevCheck(hdr_access_restriction->avp_value->u32 < ARD_MAX,
             hdr_access_restriction->avp_value->u32, ARD_MAX, 0);
    *access_restriction = hdr_access_restriction->avp_value->u32;
    return 0;
}
static inline
int s6a_parse_service_selection(struct avp_hdr *hdr_service_selection,
                                char *service_selection, int *length)
{
    DevCheck(hdr_service_selection->avp_value->os.len <= APN_MAX_LENGTH,
             hdr_service_selection->avp_value->os.len, APN_MAX_LENGTH, 0);
    *length = sprintf(service_selection, "%*s",
                      (int)hdr_service_selection->avp_value->os.len,
                      hdr_service_selection->avp_value->os.data);
    return 0;
}
Example #16
0
int set_comp_log(int component, int level, int verbosity, int interval)
{
  /* Checking parameters */
  DevCheck((component >= MIN_LOG_COMPONENTS) && (component < MAX_LOG_COMPONENTS),
           component, MIN_LOG_COMPONENTS, MAX_LOG_COMPONENTS);
  DevCheck((level <= LOG_TRACE) && (level >= LOG_EMERG), level, LOG_TRACE,
           LOG_EMERG);
  DevCheck((interval > 0) && (interval <= 0xFF), interval, 0, 0xFF);

  if ((verbosity == LOG_NONE) || (verbosity == LOG_LOW) ||
      (verbosity == LOG_MED) || (verbosity == LOG_FULL) ||
      (verbosity == LOG_HIGH)) {
    g_log->log_component[component].flag = verbosity;
  }

  g_log->log_component[component].level = level;
  g_log->log_component[component].interval = interval;

  return 0;
}
static inline
int s6a_parse_subscriber_status(struct avp_hdr *hdr_sub_status,
                                subscriber_status_t *sub_status)
{
    DevCheck(hdr_sub_status->avp_value->u32 < SS_MAX,
             hdr_sub_status->avp_value->u32, SS_MAX, 0);

    *sub_status = hdr_sub_status->avp_value->u32;

    return 0;
}
Example #18
0
struct emm_data_context_s *emm_data_context_get(
    emm_data_t *emm_data, unsigned int _ueid)
{
    struct emm_data_context_s reference;

    DevAssert(emm_data != NULL);
    DevCheck(_ueid > 0, _ueid, 0, 0);

    memset(&reference, 0, sizeof(struct emm_data_context_s));
    reference.ueid = _ueid;
    return RB_FIND(emm_data_context_map, &emm_data->ctx_map, &reference);
}
static inline
int s6a_parse_network_access_mode(struct avp_hdr *hdr_network_am,
                                  network_access_mode_t *access_mode)
{
    DevCheck(hdr_network_am->avp_value->u32 < NAM_MAX &&
             hdr_network_am->avp_value->u32 != NAM_RESERVED,
             hdr_network_am->avp_value->u32, NAM_MAX, NAM_RESERVED);

    *access_mode = hdr_network_am->avp_value->u32;

    return 0;
}
Example #20
0
struct emm_common_data_s               *
emm_common_data_context_get (
  struct emm_common_data_head_s *root,
  unsigned int _ueid)
{
  struct emm_common_data_s                reference;

  DevAssert (root != NULL);
  DevCheck (_ueid > 0, _ueid, 0, 0);
  memset (&reference, 0, sizeof (struct emm_common_data_s));
  reference.ueid = _ueid;
  return RB_FIND (emm_common_data_map, &root->emm_common_data_root, &reference);
}
Example #21
0
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_common_get_args()                                **
 **                                                                        **
 ** Description: Returns pointer to the EMM common procedure argument pa-  **
 **      rameters allocated for the UE with the given identifier.  **
 **                                                                        **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **      Others:    _emm_common_data                           **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    pointer to the EMM common procedure argu-  **
 **             ment parameters                            **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
void                                   *
emm_proc_common_get_args (
  unsigned int ueid)
{
  emm_common_data_t                      *emm_common_data_ctx = NULL;

  LOG_FUNC_IN;
#if NAS_BUILT_IN_EPC
  DevCheck (ueid > 0, ueid, 0, 0);
  emm_common_data_ctx = emm_common_data_context_get (&emm_common_data_head, ueid);
#else
  assert (ueid < EMM_DATA_NB_UE_MAX);
  emm_common_data_ctx = _emm_common_data[ueid];
#endif
  assert (emm_common_data_ctx != NULL);
  LOG_FUNC_RETURN (emm_common_data_ctx->args);
}
static inline
int s6a_parse_msisdn(struct avp_hdr *hdr_msisdn, char *msisdn, uint8_t *length)
{
    int ret;

    DevCheck(hdr_msisdn->avp_value->os.len <= MSISDN_LENGTH,
             hdr_msisdn->avp_value->os.len, MSISDN_LENGTH, 0);

    if (hdr_msisdn->avp_value->os.len == 0)
        return 0;
    ret = sprintf(msisdn, "%*s", (int)hdr_msisdn->avp_value->os.len,
                  hdr_msisdn->avp_value->os.data);

    *length = ret;

    return 0;
}
void s1ap_handle_s1_setup_message(s1ap_eNB_mme_data_t *mme_desc_p, int sctp_shutdown)
{
  if (sctp_shutdown) {
    /* A previously connected MME has been shutdown */

    /* TODO check if it was used by some eNB and send a message to inform these eNB if there is no more associated MME */
    if (mme_desc_p->state == S1AP_ENB_STATE_CONNECTED) {
      mme_desc_p->state = S1AP_ENB_STATE_DISCONNECTED;

      if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb > 0) {
        /* Decrease associated MME number */
        mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb --;
      }

      /* If there are no more associated MME, inform eNB app */
      if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb == 0) {
        MessageDef                 *message_p;

        message_p = itti_alloc_new_message(TASK_S1AP, S1AP_DEREGISTERED_ENB_IND);
        S1AP_DEREGISTERED_ENB_IND(message_p).nb_mme = 0;
        itti_send_msg_to_task(TASK_ENB_APP, mme_desc_p->s1ap_eNB_instance->instance, message_p);
      }
    }
  } else {
    /* Check that at least one setup message is pending */
    DevCheck(mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb > 0, mme_desc_p->s1ap_eNB_instance->instance,
             mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb, 0);

    if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb > 0) {
      /* Decrease pending messages number */
      mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb --;
    }

    /* If there are no more pending messages, inform eNB app */
    if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb == 0) {
      MessageDef                 *message_p;

      message_p = itti_alloc_new_message(TASK_S1AP, S1AP_REGISTER_ENB_CNF);
      S1AP_REGISTER_ENB_CNF(message_p).nb_mme = mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb;
      itti_send_msg_to_task(TASK_ENB_APP, mme_desc_p->s1ap_eNB_instance->instance, message_p);
    }
  }
}
int s6a_parse_experimental_result(struct avp *avp, s6a_experimental_result_t *ptr)
{
  struct avp_hdr *hdr;
  struct avp *child_avp = NULL;

  if (!avp) {
    return EINVAL;
  }

  CHECK_FCT(fd_msg_avp_hdr(avp, &hdr));
  DevAssert(hdr->avp_code == AVP_CODE_EXPERIMENTAL_RESULT);
  CHECK_FCT(fd_msg_browse(avp, MSG_BRW_FIRST_CHILD, &child_avp, NULL));

  while(child_avp) {
    CHECK_FCT(fd_msg_avp_hdr(child_avp, &hdr));

    switch(hdr->avp_code) {
    case AVP_CODE_EXPERIMENTAL_RESULT_CODE:
      S6A_ERROR("Got experimental error %u:%s\n", hdr->avp_value->u32,
                experimental_retcode_2_string(hdr->avp_value->u32));

      if (ptr) {
        *ptr = (s6a_experimental_result_t)hdr->avp_value->u32;
      }

      break;

    case AVP_CODE_VENDOR_ID:
      DevCheck(hdr->avp_value->u32 == 10415, hdr->avp_value->u32,
               AVP_CODE_VENDOR_ID, 10415);
      break;

    default:
      return -1;
    }

    /* Go to next AVP in the grouped AVP */
    CHECK_FCT(fd_msg_browse(child_avp, MSG_BRW_NEXT, &child_avp, NULL));
  }

  return 0;
}
//------------------------------------------------------------------------------
int s1ap_eNB_handle_nas_first_req(
  instance_t instance, s1ap_nas_first_req_t *s1ap_nas_first_req_p)
//------------------------------------------------------------------------------
{
  s1ap_eNB_instance_t          *instance_p = NULL;
  struct s1ap_eNB_mme_data_s   *mme_desc_p = NULL;
  struct s1ap_eNB_ue_context_s *ue_desc_p  = NULL;

  s1ap_message message;

  S1ap_InitialUEMessageIEs_t *initial_ue_message_p = NULL;

  uint8_t  *buffer = NULL;
  uint32_t  length = 0;

  DevAssert(s1ap_nas_first_req_p != NULL);

  /* Retrieve the S1AP eNB instance associated with Mod_id */
  instance_p = s1ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);

  memset(&message, 0, sizeof(s1ap_message));

  message.direction     = S1AP_PDU_PR_initiatingMessage;
  message.procedureCode = S1ap_ProcedureCode_id_initialUEMessage;

  initial_ue_message_p = &message.msg.s1ap_InitialUEMessageIEs;

  /* Select the MME corresponding to the provided GUMMEI. */
  if (s1ap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_gummei) {
    mme_desc_p = s1ap_eNB_nnsf_select_mme_by_gummei(
                   instance_p,
                   s1ap_nas_first_req_p->establishment_cause,
                   s1ap_nas_first_req_p->ue_identity.gummei);
  }

  if (mme_desc_p == NULL) {
    /* Select the MME corresponding to the provided s-TMSI. */
    if (s1ap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_s_tmsi) {
      mme_desc_p = s1ap_eNB_nnsf_select_mme_by_mme_code(
                     instance_p,
                     s1ap_nas_first_req_p->establishment_cause,
                     s1ap_nas_first_req_p->ue_identity.s_tmsi.mme_code);
    }
  }

  if (mme_desc_p == NULL) {
    /*
     * If no MME corresponds to the GUMMEI or the s-TMSI, selects the MME with the
     * highest capacity.
     */
    mme_desc_p = s1ap_eNB_nnsf_select_mme(
                   instance_p,
                   s1ap_nas_first_req_p->establishment_cause);
  }

  if (mme_desc_p == NULL) {
    /*
     * In case eNB has no MME associated, the eNB should inform RRC and discard
     * this request.
     */

    S1AP_WARN("No MME is associated to the eNB\n");
    // TODO: Inform RRC
    return -1;
  }

  /* The eNB should allocate a unique eNB UE S1AP ID for this UE. The value
   * will be used for the duration of the connectivity.
   */
  ue_desc_p = s1ap_eNB_allocate_new_UE_context();
  DevAssert(ue_desc_p != NULL);

  /* Keep a reference to the selected MME */
  ue_desc_p->mme_ref       = mme_desc_p;
  ue_desc_p->ue_initial_id = s1ap_nas_first_req_p->ue_initial_id;
  ue_desc_p->eNB_instance  = instance_p;

  do {
    struct s1ap_eNB_ue_context_s *collision_p;

    /* Peek a random value for the eNB_ue_s1ap_id */
    ue_desc_p->eNB_ue_s1ap_id = (random() + random()) & 0x00ffffff;

    if ((collision_p = RB_INSERT(s1ap_ue_map, &instance_p->s1ap_ue_head, ue_desc_p))
        == NULL) {
      S1AP_DEBUG("Found usable eNB_ue_s1ap_id: 0x%06x %d(10)\n",
                 ue_desc_p->eNB_ue_s1ap_id,
                 ue_desc_p->eNB_ue_s1ap_id);
      /* Break the loop as the id is not already used by another UE */
      break;
    }
  } while(1);

  initial_ue_message_p->eNB_UE_S1AP_ID = ue_desc_p->eNB_ue_s1ap_id;
  /* Prepare the NAS PDU */
  initial_ue_message_p->nas_pdu.buf  = s1ap_nas_first_req_p->nas_pdu.buffer;
  initial_ue_message_p->nas_pdu.size = s1ap_nas_first_req_p->nas_pdu.length;

  /* Set the establishment cause according to those provided by RRC */
  DevCheck(s1ap_nas_first_req_p->establishment_cause < RRC_CAUSE_LAST,
           s1ap_nas_first_req_p->establishment_cause, RRC_CAUSE_LAST, 0);
  initial_ue_message_p->rrC_Establishment_Cause = s1ap_nas_first_req_p->establishment_cause;

  if (s1ap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_s_tmsi) {
    S1AP_DEBUG("S_TMSI_PRESENT\n");
    initial_ue_message_p->presenceMask |= S1AP_INITIALUEMESSAGEIES_S_TMSI_PRESENT;

    MME_CODE_TO_OCTET_STRING(s1ap_nas_first_req_p->ue_identity.s_tmsi.mme_code,
                             &initial_ue_message_p->s_tmsi.mMEC);
    M_TMSI_TO_OCTET_STRING(s1ap_nas_first_req_p->ue_identity.s_tmsi.m_tmsi,
                           &initial_ue_message_p->s_tmsi.m_TMSI);
  }

  if (s1ap_nas_first_req_p->ue_identity.presenceMask & UE_IDENTITIES_gummei) {
    S1AP_DEBUG("GUMMEI_ID_PRESENT\n");
    initial_ue_message_p->presenceMask |= S1AP_INITIALUEMESSAGEIES_GUMMEI_ID_PRESENT;

    MCC_MNC_TO_PLMNID(
      s1ap_nas_first_req_p->ue_identity.gummei.mcc,
      s1ap_nas_first_req_p->ue_identity.gummei.mnc,
      s1ap_nas_first_req_p->ue_identity.gummei.mnc_len,
      &initial_ue_message_p->gummei_id.pLMN_Identity);

    MME_GID_TO_OCTET_STRING(s1ap_nas_first_req_p->ue_identity.gummei.mme_group_id,
                            &initial_ue_message_p->gummei_id.mME_Group_ID);
    MME_CODE_TO_OCTET_STRING(s1ap_nas_first_req_p->ue_identity.gummei.mme_code,
                             &initial_ue_message_p->gummei_id.mME_Code);
  }

  /* Assuming TAI is the TAI from the cell */
  INT16_TO_OCTET_STRING(instance_p->tac, &initial_ue_message_p->tai.tAC);
  MCC_MNC_TO_PLMNID(instance_p->mcc,
                    instance_p->mnc,
                    instance_p->mnc_digit_length,
                    &initial_ue_message_p->tai.pLMNidentity);

  /* Set the EUTRAN CGI
   * The cell identity is defined on 28 bits but as we use macro enb id,
   * we have to pad.
   */
#warning "TODO get cell id from RRC"
  MACRO_ENB_ID_TO_CELL_IDENTITY(instance_p->eNB_id,
		  0, // Cell ID
          &initial_ue_message_p->eutran_cgi.cell_ID);
  MCC_MNC_TO_TBCD(instance_p->mcc,
                  instance_p->mnc,
                  instance_p->mnc_digit_length,
                  &initial_ue_message_p->eutran_cgi.pLMNidentity);

  if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
    /* Failed to encode message */
    DevMessage("Failed to encode initial UE message\n");
  }

  /* Update the current S1AP UE state */
  ue_desc_p->ue_state = S1AP_UE_WAITING_CSR;

  /* Assign a stream for this UE :
   * From 3GPP 36.412 7)Transport layers:
   *  Within the SCTP association established between one MME and eNB pair:
   *  - a single pair of stream identifiers shall be reserved for the sole use
   *      of S1AP elementary procedures that utilize non UE-associated signalling.
   *  - At least one pair of stream identifiers shall be reserved for the sole use
   *      of S1AP elementary procedures that utilize UE-associated signallings.
   *      However a few pairs (i.e. more than one) should be reserved.
   *  - A single UE-associated signalling shall use one SCTP stream and
   *      the stream should not be changed during the communication of the
   *      UE-associated signalling.
   */
  mme_desc_p->nextstream = (mme_desc_p->nextstream + 1) % mme_desc_p->out_streams;

  if ((mme_desc_p->nextstream == 0) && (mme_desc_p->out_streams > 1)) {
    mme_desc_p->nextstream += 1;
  }

  ue_desc_p->tx_stream = mme_desc_p->nextstream;

  MSC_LOG_TX_MESSAGE(
    MSC_S1AP_ENB,
    MSC_S1AP_MME,
    (const char *)NULL,
    0,
    MSC_AS_TIME_FMT" initialUEMessage initiatingMessage eNB_ue_s1ap_id %u",
    0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
    initial_ue_message_p->eNB_UE_S1AP_ID);

  /* Send encoded message over sctp */
  s1ap_eNB_itti_send_sctp_data_req(instance_p->instance, mme_desc_p->assoc_id,
                                   buffer, length, ue_desc_p->tx_stream);

  return 0;
}
//-----------------------------------------------------------------------------
int
pdcp_validate_security(
  const protocol_ctxt_t* const ctxt_pP,
  pdcp_t         * const pdcp_pP,
  const srb_flag_t     srb_flagP,
  const rb_id_t        rb_id,
  const uint8_t        pdcp_header_len,
  const uint16_t       current_sn,
  uint8_t       *const pdcp_pdu_buffer,
  const uint16_t       sdu_buffer_size
)
{
  uint8_t *buffer_decrypted = NULL;
  stream_cipher_t decrypt_params;

  DevAssert(pdcp_pP != NULL);

  DevAssert(pdcp_pdu_buffer != NULL);
  DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_IN);

  buffer_decrypted = (uint8_t*)&pdcp_pdu_buffer[pdcp_header_len];

  decrypt_params.direction  = (pdcp_pP->is_ue == 1) ? SECU_DIRECTION_DOWNLINK : SECU_DIRECTION_UPLINK ;
  decrypt_params.bearer     = rb_id - 1;
  decrypt_params.count      = pdcp_get_next_count_rx(pdcp_pP, srb_flagP, current_sn);
  decrypt_params.message    = &pdcp_pdu_buffer[pdcp_header_len];
  decrypt_params.blength    = (sdu_buffer_size - pdcp_header_len) << 3;
  decrypt_params.key_length = 16;

  if (srb_flagP) {
    LOG_D(PDCP, "[OSA][RB %d] %s Validating control-plane security\n",
          rb_id, (pdcp_pP->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
    decrypt_params.key = pdcp_pP->kRRCenc;// + 128;
  } else {
    LOG_D(PDCP, "[OSA][RB %d] %s Validating user-plane security\n",
          rb_id, (pdcp_pP->is_ue != 0) ? "eNB -> UE" : "UE -> eNB");
    decrypt_params.key = pdcp_pP->kUPenc;// + 128;
  }

  /* Uncipher the block */
  stream_decrypt(pdcp_pP->cipheringAlgorithm,
                 &decrypt_params,
                 &buffer_decrypted);

  if (srb_flagP) {
    /* Now check the integrity of the complete PDU */
    decrypt_params.message    = pdcp_pdu_buffer;
    decrypt_params.blength    = sdu_buffer_size << 3;
    decrypt_params.key        = pdcp_pP->kRRCint + 16;// 128;

    if (stream_check_integrity(pdcp_pP->integrityProtAlgorithm,
                               &decrypt_params,
                               &pdcp_pdu_buffer[sdu_buffer_size]) != 0) {
      MSC_LOG_EVENT(
    	  (ctxt_pP->enb_flag == ENB_FLAG_YES) ? MSC_PDCP_ENB:MSC_PDCP_UE,
    	  " Security: failed MAC-I Algo %X UE %"PRIx16" ",
    	  pdcp_pP->integrityProtAlgorithm,
    	  ctxt_pP->rnti);
      LOG_E(PDCP, "[OSA][RB %d] %s failed to validate MAC-I of incoming PDU\n",
            rb_id, (pdcp_pP->is_ue != 0) ? "UE" : "eNB");
      VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);
      return -1;
    }
  }

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_VALIDATE_SECURITY, VCD_FUNCTION_OUT);

  return 0;
}
//-----------------------------------------------------------------------------
int
pdcp_apply_security(
  const protocol_ctxt_t* const ctxt_pP,
  pdcp_t        *const pdcp_pP,
  const srb_flag_t     srb_flagP,
  const rb_id_t        rb_id,
  const uint8_t        pdcp_header_len,
  const uint16_t       current_sn,
  uint8_t       * const pdcp_pdu_buffer,
  const uint16_t      sdu_buffer_size
)
{
  uint8_t *buffer_encrypted = NULL;
  stream_cipher_t encrypt_params;

  DevAssert(pdcp_pP != NULL);
  DevAssert(pdcp_pdu_buffer != NULL);
  DevCheck(rb_id < NB_RB_MAX && rb_id >= 0, rb_id, NB_RB_MAX, 0);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_IN);

  encrypt_params.direction  = (pdcp_pP->is_ue == 1) ? SECU_DIRECTION_UPLINK : SECU_DIRECTION_DOWNLINK;
  encrypt_params.bearer     = rb_id - 1;
  encrypt_params.count      = pdcp_get_next_count_tx(pdcp_pP, srb_flagP, current_sn);
  encrypt_params.key_length = 16;

  if (srb_flagP) {
    /* SRBs */
    uint8_t *mac_i;

    LOG_D(PDCP, "[OSA][RB %d] %s Applying control-plane security %d \n",
          rb_id, (pdcp_pP->is_ue != 0) ? "UE -> eNB" : "eNB -> UE", pdcp_pP->integrityProtAlgorithm);

    encrypt_params.message    = pdcp_pdu_buffer;
    encrypt_params.blength    = (pdcp_header_len + sdu_buffer_size) << 3;
    encrypt_params.key        = pdcp_pP->kRRCint + 16; // + 128;

    mac_i = &pdcp_pdu_buffer[pdcp_header_len + sdu_buffer_size];

    /* Both header and data parts are integrity protected for
     * control-plane PDUs */
    stream_compute_integrity(pdcp_pP->integrityProtAlgorithm,
                             &encrypt_params,
                             mac_i);

    encrypt_params.key = pdcp_pP->kRRCenc;  // + 128  // bit key
  } else {
    LOG_D(PDCP, "[OSA][RB %d] %s Applying user-plane security\n",
          rb_id, (pdcp_pP->is_ue != 0) ? "UE -> eNB" : "eNB -> UE");

    encrypt_params.key = pdcp_pP->kUPenc;//  + 128;
  }

  encrypt_params.message    = &pdcp_pdu_buffer[pdcp_header_len];
  encrypt_params.blength    = sdu_buffer_size << 3;

  buffer_encrypted = &pdcp_pdu_buffer[pdcp_header_len];

  /* Apply ciphering if any requested */
  stream_encrypt(pdcp_pP->cipheringAlgorithm,
                 &encrypt_params,
                 &buffer_encrypted);

  VCD_SIGNAL_DUMPER_DUMP_FUNCTION_BY_NAME(VCD_SIGNAL_DUMPER_FUNCTIONS_PDCP_APPLY_SECURITY, VCD_FUNCTION_OUT);

  return 0;
}