//------------------------------------------------------------------------------
void mme_test_s1_start_test(instance_t instance)
//------------------------------------------------------------------------------
{
	s1ap_eNB_itti_send_sctp_data_req(instance,
			s1c_test.assoc_id,
			s1ap_scenarios[s1c_test.scenario_index][s1c_test.tx_next_message_index].buffer,
			s1ap_scenarios[s1c_test.scenario_index][s1c_test.tx_next_message_index].buf_len,
			s1ap_scenarios[s1c_test.scenario_index][s1c_test.tx_next_message_index].sctp_stream_id);
}
//------------------------------------------------------------------------------
int s1ap_eNB_ue_capabilities(instance_t instance,
                             s1ap_ue_cap_info_ind_t *ue_cap_info_ind_p)
//------------------------------------------------------------------------------
{
  s1ap_eNB_instance_t          *s1ap_eNB_instance_p;
  struct s1ap_eNB_ue_context_s *ue_context_p;

  S1ap_UECapabilityInfoIndicationIEs_t *ue_cap_info_ind_ies_p;

  s1ap_message  message;

  uint8_t  *buffer;
  uint32_t length;
  int      ret = -1;

  /* Retrieve the S1AP eNB instance associated with Mod_id */
  s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance);

  DevAssert(ue_cap_info_ind_p != NULL);
  DevAssert(s1ap_eNB_instance_p != NULL);

  if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p,
                      ue_cap_info_ind_p->eNB_ue_s1ap_id)) == NULL) {
    /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
    S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %u\n",
              ue_cap_info_ind_p->eNB_ue_s1ap_id);
    return -1;
  }

  /* UE capabilities message can occur either during an s1ap connected state
   * or during initial attach (for example: NAS authentication).
   */
  if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
        ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) {
    S1AP_WARN("You are attempting to send NAS data over non-connected "
              "eNB ue s1ap id: %u, current state: %d\n",
              ue_cap_info_ind_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
    return -1;
  }

  /* Prepare the S1AP message to encode */
  memset(&message, 0, sizeof(s1ap_message));

  message.direction     = S1AP_PDU_PR_initiatingMessage;
  message.procedureCode = S1ap_ProcedureCode_id_UECapabilityInfoIndication;

  ue_cap_info_ind_ies_p = &message.msg.s1ap_UECapabilityInfoIndicationIEs;

  ue_cap_info_ind_ies_p->ueRadioCapability.buf = ue_cap_info_ind_p->ue_radio_cap.buffer;
  ue_cap_info_ind_ies_p->ueRadioCapability.size = ue_cap_info_ind_p->ue_radio_cap.length;

  ue_cap_info_ind_ies_p->eNB_UE_S1AP_ID = ue_cap_info_ind_p->eNB_ue_s1ap_id;
  ue_cap_info_ind_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;

  if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
    /* Encode procedure has failed... */
    S1AP_ERROR("Failed to encode UE capabilities indication\n");
    return -1;
  }

  MSC_LOG_TX_MESSAGE(
    MSC_S1AP_ENB,
    MSC_S1AP_MME,
    (const char *)buffer,
    length,
    MSC_AS_TIME_FMT" UECapabilityInfoIndication initiatingMessage eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
    0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
    ue_cap_info_ind_ies_p->eNB_UE_S1AP_ID,
    ue_cap_info_ind_ies_p->mme_ue_s1ap_id);

  /* UE associated signalling -> use the allocated stream */
  s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
                                   ue_context_p->mme_ref->assoc_id, buffer,
                                   length, ue_context_p->tx_stream);

  return ret;
}
//------------------------------------------------------------------------------
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 s1ap_eNB_initial_ctxt_resp(
  instance_t instance, s1ap_initial_context_setup_resp_t *initial_ctxt_resp_p)
//------------------------------------------------------------------------------
{
  s1ap_eNB_instance_t          *s1ap_eNB_instance_p = NULL;
  struct s1ap_eNB_ue_context_s *ue_context_p        = NULL;

  S1ap_InitialContextSetupResponseIEs_t *initial_ies_p  = NULL;

  s1ap_message  message;

  uint8_t  *buffer  = NULL;
  uint32_t length;
  int      ret = -1;
  int      i;

  /* Retrieve the S1AP eNB instance associated with Mod_id */
  s1ap_eNB_instance_p = s1ap_eNB_get_instance(instance);

  DevAssert(initial_ctxt_resp_p != NULL);
  DevAssert(s1ap_eNB_instance_p != NULL);

  if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p,
                      initial_ctxt_resp_p->eNB_ue_s1ap_id)) == NULL) {
    /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
    S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: 0x%06x\n",
              initial_ctxt_resp_p->eNB_ue_s1ap_id);
    return -1;
  }

  /* Uplink NAS transport can occur either during an s1ap connected state
   * or during initial attach (for example: NAS authentication).
   */
  if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
        ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) {
    S1AP_WARN("You are attempting to send NAS data over non-connected "
              "eNB ue s1ap id: %06x, current state: %d\n",
              initial_ctxt_resp_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
    return -1;
  }

  /* Prepare the S1AP message to encode */
  memset(&message, 0, sizeof(s1ap_message));

  message.direction     = S1AP_PDU_PR_successfulOutcome;
  message.procedureCode = S1ap_ProcedureCode_id_InitialContextSetup;

  initial_ies_p = &message.msg.s1ap_InitialContextSetupResponseIEs;

  initial_ies_p->eNB_UE_S1AP_ID = initial_ctxt_resp_p->eNB_ue_s1ap_id;
  initial_ies_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;

  for (i = 0; i < initial_ctxt_resp_p->nb_of_e_rabs; i++) {
    S1ap_E_RABSetupItemCtxtSURes_t *new_item;

    new_item = calloc(1, sizeof(S1ap_E_RABSetupItemCtxtSURes_t));

    new_item->e_RAB_ID = initial_ctxt_resp_p->e_rabs[i].e_rab_id;
    GTP_TEID_TO_ASN1(initial_ctxt_resp_p->e_rabs[i].gtp_teid, &new_item->gTP_TEID);
    new_item->transportLayerAddress.buf = initial_ctxt_resp_p->e_rabs[i].eNB_addr.buffer;
    new_item->transportLayerAddress.size = initial_ctxt_resp_p->e_rabs[i].eNB_addr.length;
    new_item->transportLayerAddress.bits_unused = 0;

    ASN_SEQUENCE_ADD(&initial_ies_p->e_RABSetupListCtxtSURes.s1ap_E_RABSetupItemCtxtSURes,
                     new_item);
  }

  if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
    S1AP_ERROR("Failed to encode uplink NAS transport\n");
    /* Encode procedure has failed... */
    return -1;
  }

  MSC_LOG_TX_MESSAGE(
    MSC_S1AP_ENB,
    MSC_S1AP_MME,
    (const char *)buffer,
    length,
    MSC_AS_TIME_FMT" InitialContextSetup successfulOutcome eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
    0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
    initial_ies_p->eNB_UE_S1AP_ID,
    initial_ies_p->mme_ue_s1ap_id);

  /* UE associated signalling -> use the allocated stream */
  s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
                                   ue_context_p->mme_ref->assoc_id, buffer,
                                   length, ue_context_p->tx_stream);

  return ret;
}
//------------------------------------------------------------------------------
void s1ap_eNB_nas_non_delivery_ind(instance_t instance,
                                   s1ap_nas_non_delivery_ind_t *s1ap_nas_non_delivery_ind)
//------------------------------------------------------------------------------
{
  struct s1ap_eNB_ue_context_s *ue_context_p;
  s1ap_eNB_instance_t          *s1ap_eNB_instance_p;

  S1ap_NASNonDeliveryIndication_IEs_t *nas_non_delivery_p;

  s1ap_message  message;

  uint8_t  *buffer;
  uint32_t length;

  DevAssert(s1ap_nas_non_delivery_ind != NULL);

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

  if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p, s1ap_nas_non_delivery_ind->eNB_ue_s1ap_id)) == NULL) {
    /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
    S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %06x\n",
              s1ap_nas_non_delivery_ind->eNB_ue_s1ap_id);
    MSC_LOG_EVENT(
      MSC_S1AP_ENB,
      MSC_AS_TIME_FMT" Sent of NAS_NON_DELIVERY_IND to MME failed, no context for eNB_ue_s1ap_id %06x",
      s1ap_nas_non_delivery_ind->eNB_ue_s1ap_id);
    return;
  }

  /* Prepare the S1AP message to encode */
  memset(&message, 0, sizeof(s1ap_message));

  message.direction     = S1AP_PDU_PR_initiatingMessage;
  message.procedureCode = S1ap_ProcedureCode_id_NASNonDeliveryIndication;

  nas_non_delivery_p = &message.msg.s1ap_NASNonDeliveryIndication_IEs;
  nas_non_delivery_p->eNB_UE_S1AP_ID = ue_context_p->eNB_ue_s1ap_id;
  nas_non_delivery_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
  nas_non_delivery_p->nas_pdu.buf    = s1ap_nas_non_delivery_ind->nas_pdu.buffer;
  nas_non_delivery_p->nas_pdu.size   = s1ap_nas_non_delivery_ind->nas_pdu.length;

  /* Send a dummy cause */
  nas_non_delivery_p->cause.present = S1ap_Cause_PR_radioNetwork;
  nas_non_delivery_p->cause.choice.radioNetwork = S1ap_CauseRadioNetwork_radio_connection_with_ue_lost;

  if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
    S1AP_ERROR("Failed to encode NAS NON delivery indication\n");
    /* Encode procedure has failed... */
    MSC_LOG_EVENT(
      MSC_S1AP_ENB,
      MSC_AS_TIME_FMT" Sent of NAS_NON_DELIVERY_IND to MME failed (encoding)");
    return;
  }


  MSC_LOG_TX_MESSAGE(
    MSC_S1AP_ENB,
    MSC_S1AP_MME,
    (const char *)s1ap_nas_non_delivery_ind,
    sizeof(s1ap_nas_non_delivery_ind_t),
    MSC_AS_TIME_FMT" NASNonDeliveryIndication initiatingMessage eNB_ue_s1ap_id %u mme_ue_s1ap_id %u",
    0,0,//MSC_AS_TIME_ARGS(ctxt_pP),
    nas_non_delivery_p->eNB_UE_S1AP_ID,
    nas_non_delivery_p->mme_ue_s1ap_id);


  /* UE associated signalling -> use the allocated stream */
  s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
                                   ue_context_p->mme_ref->assoc_id, buffer,
                                   length, ue_context_p->tx_stream);
}
//------------------------------------------------------------------------------
int s1ap_eNB_nas_uplink(instance_t instance, s1ap_uplink_nas_t *s1ap_uplink_nas_p)
//------------------------------------------------------------------------------
{
  struct s1ap_eNB_ue_context_s *ue_context_p;
  s1ap_eNB_instance_t          *s1ap_eNB_instance_p;
  S1ap_UplinkNASTransportIEs_t *uplink_NAS_transport_p;

  s1ap_message  message;

  uint8_t  *buffer;
  uint32_t length;

  DevAssert(s1ap_uplink_nas_p != NULL);

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

  if ((ue_context_p = s1ap_eNB_get_ue_context(s1ap_eNB_instance_p, s1ap_uplink_nas_p->eNB_ue_s1ap_id)) == NULL) {
    /* The context for this eNB ue s1ap id doesn't exist in the map of eNB UEs */
    S1AP_WARN("Failed to find ue context associated with eNB ue s1ap id: %06x\n",
              s1ap_uplink_nas_p->eNB_ue_s1ap_id);
    return -1;
  }

  /* Uplink NAS transport can occur either during an s1ap connected state
   * or during initial attach (for example: NAS authentication).
   */
  if (!(ue_context_p->ue_state == S1AP_UE_CONNECTED ||
        ue_context_p->ue_state == S1AP_UE_WAITING_CSR)) {
    S1AP_WARN("You are attempting to send NAS data over non-connected "
              "eNB ue s1ap id: %u, current state: %d\n",
              s1ap_uplink_nas_p->eNB_ue_s1ap_id, ue_context_p->ue_state);
    return -1;
  }

  /* Prepare the S1AP message to encode */
  memset(&message, 0, sizeof(s1ap_message));

  message.direction     = S1AP_PDU_PR_initiatingMessage;
  message.procedureCode = S1ap_ProcedureCode_id_uplinkNASTransport;

  uplink_NAS_transport_p = &message.msg.s1ap_UplinkNASTransportIEs;

  uplink_NAS_transport_p->mme_ue_s1ap_id = ue_context_p->mme_ue_s1ap_id;
  uplink_NAS_transport_p->eNB_UE_S1AP_ID = ue_context_p->eNB_ue_s1ap_id;

  uplink_NAS_transport_p->nas_pdu.buf  = s1ap_uplink_nas_p->nas_pdu.buffer;
  uplink_NAS_transport_p->nas_pdu.size = s1ap_uplink_nas_p->nas_pdu.length;

  MCC_MNC_TO_PLMNID(
    s1ap_eNB_instance_p->mcc,
    s1ap_eNB_instance_p->mnc,
    s1ap_eNB_instance_p->mnc_digit_length,
    &uplink_NAS_transport_p->eutran_cgi.pLMNidentity);

#warning "TODO get cell id from RRC"
  MACRO_ENB_ID_TO_CELL_IDENTITY(s1ap_eNB_instance_p->eNB_id,
          0,
          &uplink_NAS_transport_p->eutran_cgi.cell_ID);

  /* MCC/MNC should be repeated in TAI and EUTRAN CGI */
  MCC_MNC_TO_PLMNID(
    s1ap_eNB_instance_p->mcc,
    s1ap_eNB_instance_p->mnc,
    s1ap_eNB_instance_p->mnc_digit_length,
    &uplink_NAS_transport_p->tai.pLMNidentity);

  TAC_TO_ASN1(s1ap_eNB_instance_p->tac, &uplink_NAS_transport_p->tai.tAC);

  if (s1ap_eNB_encode_pdu(&message, &buffer, &length) < 0) {
    S1AP_ERROR("Failed to encode uplink NAS transport\n");
    /* Encode procedure has failed... */
    return -1;
  }

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


  /* UE associated signalling -> use the allocated stream */
  s1ap_eNB_itti_send_sctp_data_req(s1ap_eNB_instance_p->instance,
                                   ue_context_p->mme_ref->assoc_id, buffer,
                                   length, ue_context_p->tx_stream);

  return 0;
}
示例#7
0
static int s1ap_eNB_generate_s1_setup_request(
  s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p)
{
  s1ap_message               message;

  S1ap_S1SetupRequestIEs_t *s1SetupRequest_p;
  S1ap_PLMNidentity_t       plmnIdentity;
  S1ap_SupportedTAs_Item_t  ta;

  uint8_t  *buffer;
  uint32_t  len;
  int       ret = 0;

  DevAssert(instance_p != NULL);
  DevAssert(s1ap_mme_data_p != NULL);

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

  message.direction     = S1AP_PDU_PR_initiatingMessage;
  message.procedureCode = S1ap_ProcedureCode_id_S1Setup;
  message.criticality   = S1ap_Criticality_reject;

  s1SetupRequest_p = &message.msg.s1ap_S1SetupRequestIEs;
  memset((void *)&plmnIdentity, 0, sizeof(S1ap_PLMNidentity_t));

  memset((void *)&ta, 0, sizeof(S1ap_SupportedTAs_Item_t));

  s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;

  s1SetupRequest_p->global_ENB_ID.eNB_ID.present = S1ap_ENB_ID_PR_macroENB_ID;
  MACRO_ENB_ID_TO_BIT_STRING(instance_p->eNB_id,
                             &s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID);
  MCC_MNC_TO_PLMNID(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length,
                    &s1SetupRequest_p->global_ENB_ID.pLMNidentity);

  S1AP_INFO("%d -> %02x%02x%02x\n", instance_p->eNB_id, s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[0], s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[1],
            s1SetupRequest_p->global_ENB_ID.eNB_ID.choice.macroENB_ID.buf[2]);

  INT16_TO_OCTET_STRING(instance_p->tac, &ta.tAC);
  MCC_MNC_TO_TBCD(instance_p->mcc, instance_p->mnc, instance_p->mnc_digit_length, &plmnIdentity);

  ASN_SEQUENCE_ADD(&ta.broadcastPLMNs.list, &plmnIdentity);
  ASN_SEQUENCE_ADD(&s1SetupRequest_p->supportedTAs.list, &ta);

  s1SetupRequest_p->defaultPagingDRX = instance_p->default_drx;

  if (instance_p->eNB_name != NULL) {
    s1SetupRequest_p->presenceMask |= S1AP_S1SETUPREQUESTIES_ENBNAME_PRESENT;
    OCTET_STRING_fromBuf(&s1SetupRequest_p->eNBname, instance_p->eNB_name,
                         strlen(instance_p->eNB_name));
  }

  if (s1ap_eNB_encode_pdu(&message, &buffer, &len) < 0) {
    S1AP_ERROR("Failed to encode S1 setup request\n");
    return -1;
  }

  /* Non UE-Associated signalling -> stream = 0 */
  s1ap_eNB_itti_send_sctp_data_req(instance_p->instance, s1ap_mme_data_p->assoc_id, buffer, len, 0);

  return ret;
}