Ejemplo n.º 1
0
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
{
  s1ap_eNB_instance_t *instance_p;
  s1ap_eNB_mme_data_t *s1ap_mme_data_p;

  DevAssert(sctp_new_association_resp != NULL);

  instance_p = s1ap_eNB_get_instance(instance);
  DevAssert(instance_p != NULL);

  s1ap_mme_data_p = s1ap_eNB_get_MME(instance_p, -1,
                                     sctp_new_association_resp->ulp_cnx_id);
  DevAssert(s1ap_mme_data_p != NULL);

  if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
    S1AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
              sctp_new_association_resp->sctp_state,
              instance,
              sctp_new_association_resp->ulp_cnx_id);

    s1ap_handle_s1_setup_message(s1ap_mme_data_p, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);

    return;
  }

  /* Update parameters */
  s1ap_mme_data_p->assoc_id    = sctp_new_association_resp->assoc_id;
  s1ap_mme_data_p->in_streams  = sctp_new_association_resp->in_streams;
  s1ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams;

  /* Prepare new S1 Setup Request */
  s1ap_eNB_generate_s1_setup_request(instance_p, s1ap_mme_data_p);
}
static
int s1ap_eNB_handle_s1_setup_failure(uint32_t               assoc_id,
                                     uint32_t               stream,
                                     struct s1ap_message_s *message_p)
{
  S1ap_S1SetupFailureIEs_t   *s1_setup_failure_p;
  s1ap_eNB_mme_data_t        *mme_desc_p;

  DevAssert(message_p != NULL);

  s1_setup_failure_p = &message_p->msg.s1ap_S1SetupFailureIEs;

  /* S1 Setup Failure == Non UE-related procedure -> stream 0 */
  if (stream != 0) {
    S1AP_WARN("[SCTP %d] Received s1 setup failure on stream != 0 (%d)\n",
              assoc_id, stream);
  }

  if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
    S1AP_ERROR("[SCTP %d] Received S1 setup response for non existing "
               "MME context\n", assoc_id);
    return -1;
  }

  if ((s1_setup_failure_p->cause.present == S1ap_Cause_PR_misc) &&
      (s1_setup_failure_p->cause.choice.misc == S1ap_CauseMisc_unspecified)) {
    S1AP_WARN("Received s1 setup failure for MME... MME is not ready\n");
  } else {
    S1AP_ERROR("Received s1 setup failure for MME... please check your parameters\n");
  }

  mme_desc_p->state = S1AP_ENB_STATE_WAITING;
  s1ap_handle_s1_setup_message(mme_desc_p, 0);

  return 0;
}
//------------------------------------------------------------------------------
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;
}
Ejemplo n.º 8
0
static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
                                  net_ip_address_t    *mme_ip_address,
                                  net_ip_address_t    *local_ip_addr,
                                  uint16_t             in_streams,
                                  uint16_t             out_streams)
{
  MessageDef                 *message_p                   = NULL;
  sctp_new_association_req_t *sctp_new_association_req_p  = NULL;
  s1ap_eNB_mme_data_t        *s1ap_mme_data_p             = NULL;
  struct s1ap_eNB_mme_data_s *mme                         = NULL;
 
  DevAssert(instance_p != NULL);
  DevAssert(mme_ip_address != NULL);

  message_p = itti_alloc_new_message(TASK_S1AP, SCTP_NEW_ASSOCIATION_REQ);

  sctp_new_association_req_p = &message_p->ittiMsg.sctp_new_association_req;

  sctp_new_association_req_p->port = S1AP_PORT_NUMBER;
  sctp_new_association_req_p->ppid = S1AP_SCTP_PPID;

  sctp_new_association_req_p->in_streams  = in_streams;
  sctp_new_association_req_p->out_streams = out_streams;

  memcpy(&sctp_new_association_req_p->remote_address,
         mme_ip_address,
         sizeof(*mme_ip_address));

  memcpy(&sctp_new_association_req_p->local_address,
         local_ip_addr,
         sizeof(*local_ip_addr));
 
  S1AP_INFO("[eNB %d] check the mme registration state\n",instance_p->instance);
	      
  mme = s1ap_eNB_get_MME_from_instance(instance_p);

  if ( mme == NULL ) {
    
    /* Create new MME descriptor */
    s1ap_mme_data_p = calloc(1, sizeof(*s1ap_mme_data_p));
    DevAssert(s1ap_mme_data_p != NULL);
    
    s1ap_mme_data_p->cnx_id                = s1ap_eNB_fetch_add_global_cnx_id();
    sctp_new_association_req_p->ulp_cnx_id = s1ap_mme_data_p->cnx_id;
    
    s1ap_mme_data_p->assoc_id          = -1;
    s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
    
    STAILQ_INIT(&s1ap_mme_data_p->served_gummei);
  
    /* Insert the new descriptor in list of known MME
     * but not yet associated.
     */
    RB_INSERT(s1ap_mme_map, &instance_p->s1ap_mme_head, s1ap_mme_data_p);
    s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
    instance_p->s1ap_mme_nb ++;
    instance_p->s1ap_mme_pending_nb ++;
  } else if (mme->state == S1AP_ENB_STATE_WAITING) {
    instance_p->s1ap_mme_pending_nb ++;
    sctp_new_association_req_p->ulp_cnx_id = mme->cnx_id;

    S1AP_INFO("[eNB %d] MME already registered, retrive the data (state %d, cnx %d, mme_nb %d, mme_pending_nb %d)\n",
	      instance_p->instance, 
	      mme->state, mme->cnx_id,
	      instance_p->s1ap_mme_nb, instance_p->s1ap_mme_pending_nb);

    /*s1ap_mme_data_p->cnx_id                = mme->cnx_id;
    sctp_new_association_req_p->ulp_cnx_id = mme->cnx_id;
    
    s1ap_mme_data_p->assoc_id          = -1;
    s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
    */ 
  } else {
    
    S1AP_WARN("[eNB %d] MME already registered but not in the waiting state, retrive the data (state %d, cnx %d, mme_nb %d, mme_pending_nb %d)\n",
	      instance_p->instance, 
	      mme->state, mme->cnx_id, 
	      instance_p->s1ap_mme_nb, instance_p->s1ap_mme_pending_nb);
    
  }
    
  itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
}
static
int s1ap_eNB_handle_error_indication(uint32_t               assoc_id,
                                     uint32_t               stream,
                                     struct s1ap_message_s *message_p)
{
  S1ap_ErrorIndicationIEs_t   *s1_error_indication_p;
  s1ap_eNB_mme_data_t        *mme_desc_p;

  DevAssert(message_p != NULL);

  s1_error_indication_p = &message_p->msg.s1ap_ErrorIndicationIEs;

  /* S1 Setup Failure == Non UE-related procedure -> stream 0 */
  if (stream != 0) {
    S1AP_WARN("[SCTP %d] Received s1 Error indication on stream != 0 (%d)\n",
              assoc_id, stream);
  }

  if ((mme_desc_p = s1ap_eNB_get_MME(NULL, assoc_id, 0)) == NULL) {
    S1AP_ERROR("[SCTP %d] Received S1 Error indication for non existing "
               "MME context\n", assoc_id);
    return -1;
  }
  if ( s1_error_indication_p->presenceMask & S1AP_ERRORINDICATIONIES_MME_UE_S1AP_ID_PRESENT) {
	  	S1AP_WARN("Received S1 Error indication MME UE S1AP ID 0x%x\n", s1_error_indication_p->mme_ue_s1ap_id);
  }
  if ( s1_error_indication_p->presenceMask & S1AP_ERRORINDICATIONIES_ENB_UE_S1AP_ID_PRESENT) {
  	S1AP_WARN("Received S1 Error indication eNB UE S1AP ID 0x%x\n", s1_error_indication_p->eNB_UE_S1AP_ID);
  }

  if ( s1_error_indication_p->presenceMask & S1AP_ERRORINDICATIONIES_CAUSE_PRESENT) {
    switch(s1_error_indication_p->cause.present) {
      case S1ap_Cause_PR_NOTHING:
    	S1AP_WARN("Received S1 Error indication cause NOTHING\n");
      break;
      case S1ap_Cause_PR_radioNetwork:
      	switch (s1_error_indication_p->cause.choice.radioNetwork) {
	      case S1ap_CauseRadioNetwork_unspecified:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unspecified\n");
            break;
  	      case S1ap_CauseRadioNetwork_tx2relocoverall_expiry:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tx2relocoverall_expiry\n");
            break;
  	      case S1ap_CauseRadioNetwork_successful_handover:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_successful_handover\n");
            break;
  	      case S1ap_CauseRadioNetwork_release_due_to_eutran_generated_reason:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_release_due_to_eutran_generated_reason\n");
            break;
  	      case S1ap_CauseRadioNetwork_handover_cancelled:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_handover_cancelled\n");
            break;
  	      case S1ap_CauseRadioNetwork_partial_handover:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_partial_handover\n");
            break;
  	      case S1ap_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ho_failure_in_target_EPC_eNB_or_target_system\n");
            break;
  	      case S1ap_CauseRadioNetwork_ho_target_not_allowed:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ho_target_not_allowed\n");
            break;
  	      case S1ap_CauseRadioNetwork_tS1relocoverall_expiry:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tS1relocoverall_expiry\n");
            break;
  	      case S1ap_CauseRadioNetwork_tS1relocprep_expiry:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_tS1relocprep_expiry\n");
            break;
  	      case S1ap_CauseRadioNetwork_cell_not_available:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_cell_not_available\n");
            break;
  	      case S1ap_CauseRadioNetwork_unknown_targetID:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_targetID\n");
            break;
  	      case S1ap_CauseRadioNetwork_no_radio_resources_available_in_target_cell:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_no_radio_resources_available_in_target_cell\n");
            break;
  	      case S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_mme_ue_s1ap_id\n");
            break;
  	      case S1ap_CauseRadioNetwork_unknown_enb_ue_s1ap_id:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_enb_ue_s1ap_id\n");
            break;
  	      case S1ap_CauseRadioNetwork_unknown_pair_ue_s1ap_id:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_pair_ue_s1ap_id\n");
            break;
  	      case S1ap_CauseRadioNetwork_handover_desirable_for_radio_reason:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_handover_desirable_for_radio_reason\n");
            break;
  	      case S1ap_CauseRadioNetwork_time_critical_handover:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_time_critical_handover\n");
            break;
  	      case S1ap_CauseRadioNetwork_resource_optimisation_handover:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_resource_optimisation_handover\n");
            break;
  	      case S1ap_CauseRadioNetwork_reduce_load_in_serving_cell:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_reduce_load_in_serving_cell\n");
            break;
  	      case S1ap_CauseRadioNetwork_user_inactivity:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_user_inactivity\n");
            break;
  	      case S1ap_CauseRadioNetwork_radio_connection_with_ue_lost:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_radio_connection_with_ue_lost\n");
            break;
  	      case S1ap_CauseRadioNetwork_load_balancing_tau_required:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_load_balancing_tau_required\n");
            break;
  	      case S1ap_CauseRadioNetwork_cs_fallback_triggered:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_cs_fallback_triggered\n");
            break;
  	      case S1ap_CauseRadioNetwork_ue_not_available_for_ps_service:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_ue_not_available_for_ps_service\n");
            break;
  	      case S1ap_CauseRadioNetwork_radio_resources_not_available:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_radio_resources_not_available\n");
            break;
  	      case S1ap_CauseRadioNetwork_failure_in_radio_interface_procedure:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_failure_in_radio_interface_procedure\n");
            break;
  	      case S1ap_CauseRadioNetwork_invals1ap_id_qos_combination:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_invals1ap_id_qos_combination\n");
            break;
  	      case S1ap_CauseRadioNetwork_interrat_redirection:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_interrat_redirection\n");
            break;
  	      case S1ap_CauseRadioNetwork_interaction_with_other_procedure:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_interaction_with_other_procedure\n");
            break;
  	      case S1ap_CauseRadioNetwork_unknown_E_RAB_ID:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_unknown_E_RAB_ID\n");
            break;
  	      case S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_multiple_E_RAB_ID_instances\n");
            break;
  	      case S1ap_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_encryption_and_or_integrity_protection_algorithms_not_supported\n");
            break;
  	      case S1ap_CauseRadioNetwork_s1_intra_system_handover_triggered:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_s1_intra_system_handover_triggered\n");
            break;
  	      case S1ap_CauseRadioNetwork_s1_inter_system_handover_triggered:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_s1_inter_system_handover_triggered\n");
            break;
  	      case S1ap_CauseRadioNetwork_x2_handover_triggered:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_x2_handover_triggered\n");
            break;
  	      case S1ap_CauseRadioNetwork_redirection_towards_1xRTT:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_redirection_towards_1xRTT\n");
            break;
  	      case S1ap_CauseRadioNetwork_not_supported_QCI_value:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_not_supported_QCI_value\n");
            break;
  	      case S1ap_CauseRadioNetwork_invals1ap_id_CSG_Id:
            S1AP_WARN("Received S1 Error indication S1ap_CauseRadioNetwork_invals1ap_id_CSG_Id\n");
            break;
      	  default:
            S1AP_WARN("Received S1 Error indication cause radio network case not handled\n");
      	}
      break;

      case S1ap_Cause_PR_transport:
      	switch (s1_error_indication_p->cause.choice.transport) {
    	  case S1ap_CauseTransport_transport_resource_unavailable:
            S1AP_WARN("Received S1 Error indication S1ap_CauseTransport_transport_resource_unavailable\n");
            break;
    	  case S1ap_CauseTransport_unspecified:
            S1AP_WARN("Received S1 Error indication S1ap_CauseTransport_unspecified\n");
            break;
      	  default:
            S1AP_WARN("Received S1 Error indication cause transport case not handled\n");
      	}
      break;

      case S1ap_Cause_PR_nas:
      	switch (s1_error_indication_p->cause.choice.nas) {
    	  case S1ap_CauseNas_normal_release:
            S1AP_WARN("Received S1 Error indication S1ap_CauseNas_normal_release\n");
            break;
      	  case S1ap_CauseNas_authentication_failure:
            S1AP_WARN("Received S1 Error indication S1ap_CauseNas_authentication_failure\n");
            break;
      	  case S1ap_CauseNas_detach:
            S1AP_WARN("Received S1 Error indication S1ap_CauseNas_detach\n");
            break;
      	  case S1ap_CauseNas_unspecified:
            S1AP_WARN("Received S1 Error indication S1ap_CauseNas_unspecified\n");
            break;
      	  case S1ap_CauseNas_csg_subscription_expiry:
            S1AP_WARN("Received S1 Error indication S1ap_CauseNas_csg_subscription_expiry\n");
            break;
      	  default:
            S1AP_WARN("Received S1 Error indication cause nas case not handled\n");
      	}
      break;

      case S1ap_Cause_PR_protocol:
      	switch (s1_error_indication_p->cause.choice.protocol) {
      	  case S1ap_CauseProtocol_transfer_syntax_error:
            S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_transfer_syntax_error\n");
            break;
      	  case S1ap_CauseProtocol_abstract_syntax_error_reject:
            S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_reject\n");
            break;
      	  case S1ap_CauseProtocol_abstract_syntax_error_ignore_and_notify:
            S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_ignore_and_notify\n");
            break;
      	  case S1ap_CauseProtocol_message_not_compatible_with_receiver_state:
            S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_message_not_compatible_with_receiver_state\n");
            break;
      	  case S1ap_CauseProtocol_semantic_error:
            S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_semantic_error\n");
            break;
      	  case S1ap_CauseProtocol_abstract_syntax_error_falsely_constructed_message:
            S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_abstract_syntax_error_falsely_constructed_message\n");
            break;
      	  case S1ap_CauseProtocol_unspecified:
            S1AP_WARN("Received S1 Error indication S1ap_CauseProtocol_unspecified\n");
            break;
      	  default:
            S1AP_WARN("Received S1 Error indication cause protocol case not handled\n");
      	}
      break;

      case S1ap_Cause_PR_misc:
        switch (s1_error_indication_p->cause.choice.protocol) {
          case S1ap_CauseMisc_control_processing_overload:
            S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_control_processing_overload\n");
            break;
          case S1ap_CauseMisc_not_enough_user_plane_processing_resources:
        	S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_not_enough_user_plane_processing_resources\n");
        	break;
          case S1ap_CauseMisc_hardware_failure:
        	S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_hardware_failure\n");
        	break;
          case S1ap_CauseMisc_om_intervention:
        	S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_om_intervention\n");
        	break;
          case S1ap_CauseMisc_unspecified:
        	S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_unspecified\n");
        	break;
          case S1ap_CauseMisc_unknown_PLMN:
        	S1AP_WARN("Received S1 Error indication S1ap_CauseMisc_unknown_PLMN\n");
        	break;
          default:
            S1AP_WARN("Received S1 Error indication cause misc case not handled\n");
        }
      break;
    }
  }
  if ( s1_error_indication_p->presenceMask & S1AP_ERRORINDICATIONIES_CRITICALITYDIAGNOSTICS_PRESENT) {
    // TODO continue
  }
  // TODO continue

  return 0;
}