/****************************************************************************
 **                                                                        **
 ** Name:    esm_proc_dedicated_eps_bearer_context_reject()            **
 **                                                                        **
 ** Description: Performs dedicated EPS bearer context activation proce-   **
 **      dure not accepted by the UE.                              **
 **                                                                        **
 **      3GPP TS 24.301, section 6.4.2.4                           **
 **      The UE rejects dedicated EPS bearer context activation by **
 **      sending ACTIVATE DEDICATED EPS BEARER CONTEXT REJECT mes- **
 **      sage.                                                     **
 **                                                                        **
 ** Inputs:  is_standalone: Not used                                   **
 **      ebi:       EPS bearer identity                        **
 **      msg:       Encoded ESM message to be sent             **
 **      ue_triggered:  Not used                                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int esm_proc_dedicated_eps_bearer_context_reject(int is_standalone, int ebi,
    OctetString *msg, int ue_triggered)
{
  LOG_FUNC_IN;

  int rc = RETURNok;

  LOG_TRACE(WARNING, "ESM-PROC  - Dedicated EPS bearer context activation "
            "not accepted by the UE (ebi=%d)", ebi);

  if ( !esm_ebr_is_not_in_use(ebi) ) {
    /* Release EPS bearer data currently in use */
    rc = esm_ebr_release(ebi);
  }

  if (rc != RETURNok) {
    LOG_TRACE(WARNING, "ESM-PROC  - Failed to release EPS bearer data");
  } else {
    emm_sap_t emm_sap;
    emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data;
    /*
     * Notity EMM that ESM PDU has to be forwarded to lower layers
     */
    emm_sap.primitive = EMMESM_UNITDATA_REQ;
    emm_sap.u.emm_esm.ueid = 0;
    emm_esm->msg.length = msg->length;
    emm_esm->msg.value = msg->value;
    rc = emm_sap_send(&emm_sap);
  }

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _authentication_reject()                                  **
 **                                                                        **
 ** Description: Sends AUTHENTICATION REJECT message                       **
 **                                                                        **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
static int _authentication_reject(unsigned int ueid)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;
  struct emm_data_context_s *emm_ctx;

  /*
   * Notify EMM-AS SAP that Authentication Reject message has to be sent
   * to the UE
   */
  emm_sap.primitive = EMMAS_SECURITY_REJ;
  emm_sap.u.emm_as.u.security.guti = NULL;
  emm_sap.u.emm_as.u.security.ueid = ueid;
  emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_AUTH;

#if defined(NAS_BUILT_IN_EPC)
  emm_ctx = emm_data_context_get(&_emm_data, ueid);
#else
  emm_ctx = _emm_data.ctx[ueid];
#endif
  /* Setup EPS NAS security data */
  emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx,
                           emm_ctx->security, FALSE, TRUE);
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN (rc);
}
/********************************************************************
 **                                                                **
 ** Name:    emm_proc_identification()                             **
 **                                                                **
 ** Description: Initiates an identification procedure.            **
 **                                                                **
 **              3GPP TS 24.301, section 5.4.4.2                   **
 **      The network initiates the identification procedure by     **
 **      sending an IDENTITY REQUEST message to the UE and star-   **
 **      ting the timer T3470. The IDENTITY REQUEST message speci- **
 **      fies the requested identification parameters in the Iden- **
 **      tity type information element.                            **
 **                                                                **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **      type:      Type of the requested identity                 **
 **      success:   Callback function executed when the identi-    **
 **             fication procedure successfully completes          **
 **      reject:    Callback function executed when the identi-    **
 **             fication procedure fails or is rejected            **
 **      failure:   Callback function executed whener a lower      **
 **             layer failure occured before the identifi-         **
 **             cation procedure completes                         **
 **      Others:    None                                           **
 **                                                                **
 ** Outputs:     None                                              **
 **      Return:    RETURNok, RETURNerror                          **
 **      Others:    _emm_data                                      **
 **                                                                **
 ********************************************************************/
int emm_proc_identification(unsigned int                   ueid,
                            emm_data_context_t            *emm_ctx,
                            emm_proc_identity_type_t       type,
                            emm_common_success_callback_t  success,
                            emm_common_reject_callback_t   reject,
                            emm_common_failure_callback_t  failure)
{
  LOG_FUNC_IN;

  int rc = RETURNerror;

  LOG_TRACE(INFO, "EMM-PROC  - Initiate identification type = %s (%d), ctx = %p",
            _emm_identity_type_str[type], type, emm_ctx);

  /* Allocate parameters of the retransmission timer callback */
  identification_data_t *data =
    (identification_data_t *)malloc(sizeof(identification_data_t));

  if (data != NULL) {
    /* Setup ongoing EMM procedure callback functions */
    rc = emm_proc_common_initialize(ueid, success, reject, failure,
                                    _identification_abort, data);

    if (rc != RETURNok) {
      LOG_TRACE(WARNING, "Failed to initialize EMM callback functions");
      free(data);
      LOG_FUNC_RETURN (RETURNerror);
    }

    /* Set the UE identifier */
    data->ueid = ueid;
    /* Reset the retransmission counter */
    data->retransmission_count = 0;
    /* Set the type of the requested identity */
    data->type = type;
    /* Set the failure notification indicator */
    data->notify_failure = FALSE;
    /* Send identity request message to the UE */
    rc = _identification_request(data);

    if (rc != RETURNerror) {
      /*
       * Notify EMM that common procedure has been initiated
       */
      MSC_LOG_TX_MESSAGE(
      		MSC_NAS_EMM_MME,
      	  	MSC_NAS_EMM_MME,
      	  	NULL,0,
      	  	"0 EMMREG_COMMON_PROC_REQ ue id "NAS_UE_ID_FMT" (identification)", ueid);

      emm_sap_t emm_sap;
      emm_sap.primitive = EMMREG_COMMON_PROC_REQ;
      emm_sap.u.emm_reg.ueid = ueid;
      emm_sap.u.emm_reg.ctx  = emm_ctx;
      rc = emm_sap_send(&emm_sap);
    }
  }

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _eps_bearer_deactivate()                                  **
 **                                                                        **
 ** Description: Sends DEACTIVATE EPS BEREAR CONTEXT REQUEST message and   **
 **      starts timer T3495                                        **
 **                                                                        **
 ** Inputs:  ueid:      UE local identifier                        **
 **      ebi:       EPS bearer identity                        **
 **      msg:       Encoded ESM message to be sent             **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    T3495                                      **
 **                                                                        **
 ***************************************************************************/
static int
_eps_bearer_deactivate (
  emm_data_context_t * ctx,
  int ebi,
  const OctetString * msg)
{
  LOG_FUNC_IN;
  emm_sap_t                               emm_sap;
  int                                     rc;

  /*
   * Notify EMM that a deactivate EPS bearer context request message
   * has to be sent to the UE
   */
  emm_esm_data_t                         *emm_esm = &emm_sap.u.emm_esm.u.data;

  emm_sap.primitive = EMMESM_UNITDATA_REQ;
  emm_sap.u.emm_esm.ueid = ctx->ueid;
  emm_sap.u.emm_esm.ctx = ctx;
  emm_esm->msg = *msg;
  rc = emm_sap_send (&emm_sap);

  if (rc != RETURNerror) {
    /*
     * Start T3495 retransmission timer
     */
    rc = esm_ebr_start_timer (ctx, ebi, msg, T3495_DEFAULT_VALUE, _eps_bearer_deactivate_t3495_handler);
  }

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _authentication_abort()                                   **
 **                                                                        **
 ** Description: Aborts the authentication procedure currently in progress **
 **                                                                        **
 ** Inputs:  args:      Authentication data to be released         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    T3460                                      **
 **                                                                        **
 ***************************************************************************/
static int
_authentication_abort (
  void *args)
{
  LOG_FUNC_IN;
  int                                     rc = RETURNerror;
  struct emm_data_context_s              *emm_ctx;
  authentication_data_t                  *data = (authentication_data_t *) (args);

  if (data) {
    unsigned int                            ueid = data->ueid;
    int                                     notify_failure = data->notify_failure;

    LOG_TRACE (WARNING, "EMM-PROC  - Abort authentication procedure " "(ueid=" NAS_UE_ID_FMT ")", ueid);
#if NAS_BUILT_IN_EPC
    emm_ctx = emm_data_context_get (&_emm_data, ueid);
#else
    emm_ctx = _emm_data.ctx[ueid];
#endif

    if (emm_ctx) {
      /*
       * Stop timer T3460
       */
      if (emm_ctx->T3460.id != NAS_TIMER_INACTIVE_ID) {
        LOG_TRACE (INFO, "EMM-PROC  - Stop timer T3460 (%d)", emm_ctx->T3460.id);
        emm_ctx->T3460.id = nas_timer_stop (emm_ctx->T3460.id);
        MSC_LOG_EVENT (MSC_NAS_EMM_MME, "0 T3460 stopped UE " NAS_UE_ID_FMT " ", data->ueid);
      }
    }

    /*
     * Release retransmission timer paramaters
     */
    if (data->rand.length > 0) {
      free (data->rand.value);
    }

    if (data->autn.length > 0) {
      free (data->autn.value);
    }

    free (data);

    /*
     * Notify EMM that the authentication procedure failed
     */
    if (notify_failure) {
      emm_sap_t                               emm_sap;

      emm_sap.primitive = EMMREG_COMMON_PROC_REJ;
      emm_sap.u.emm_reg.ueid = ueid;
      rc = emm_sap_send (&emm_sap);
    } else {
      rc = RETURNok;
    }
  }

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _authentication_request()                                 **
 **                                                                        **
 ** Description: Sends AUTHENTICATION REQUEST message and start timer T3460**
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    T3460                                      **
 **                                                                        **
 ***************************************************************************/
int _authentication_request(authentication_data_t *data)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;
  struct emm_data_context_s *emm_ctx;

  /*
   * Notify EMM-AS SAP that Authentication Request message has to be sent
   * to the UE
   */
  emm_sap.primitive = EMMAS_SECURITY_REQ;
  emm_sap.u.emm_as.u.security.guti = NULL;
  emm_sap.u.emm_as.u.security.ueid = data->ueid;
  emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_AUTH;
  emm_sap.u.emm_as.u.security.ksi = data->ksi;
  emm_sap.u.emm_as.u.security.rand = &data->rand;
  emm_sap.u.emm_as.u.security.autn = &data->autn;

  /* TODO: check for pointer validity */
#if defined(NAS_BUILT_IN_EPC)
  emm_ctx = emm_data_context_get(&_emm_data, data->ueid);
#else
  emm_ctx = _emm_data.ctx[data->ueid];
#endif

  /* Setup EPS NAS security data */
  emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx,
                           emm_ctx->security, FALSE, TRUE);

  MSC_LOG_TX_MESSAGE(
		  MSC_NAS_EMM_MME,
		  MSC_NAS_EMM_MME,
		  NULL,0,
		  "0 EMMAS_SECURITY_REQ ue id "NAS_UE_ID_FMT" ", data->ueid);

  rc = emm_sap_send(&emm_sap);

  if (rc != RETURNerror) {
	if (emm_ctx) {
	  if (emm_ctx->T3460.id != NAS_TIMER_INACTIVE_ID) {
        /* Re-start T3460 timer */
        emm_ctx->T3460.id = nas_timer_restart(emm_ctx->T3460.id);
        MSC_LOG_EVENT(MSC_NAS_EMM_MME, "0 T3460 restarted UE "NAS_UE_ID_FMT" ", data->ueid);
      } else {
        /* Start T3460 timer */
        emm_ctx->T3460.id = nas_timer_start(emm_ctx->T3460.sec, _authentication_t3460_handler,
                                 data);
        MSC_LOG_EVENT(MSC_NAS_EMM_MME, "0 T3460 started UE "NAS_UE_ID_FMT" ", data->ueid);
      }
    }

    LOG_TRACE(INFO,"EMM-PROC  - Timer T3460 (%d) expires in %ld seconds",
    		emm_ctx->T3460.id, emm_ctx->T3460.sec);
  }

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _identification_request()                                 **
 **                                                                        **
 ** Description: Sends IDENTITY REQUEST message and start timer T3470.     **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    T3470                                      **
 **                                                                        **
 ***************************************************************************/
int _identification_request(identification_data_t *data)
{
  emm_sap_t emm_sap;
  int rc;

  struct emm_data_context_s *emm_ctx = NULL;

  LOG_FUNC_IN;

  /*
   * Notify EMM-AS SAP that Identity Request message has to be sent
   * to the UE
   */
  MSC_LOG_TX_MESSAGE(
  		MSC_NAS_EMM_MME,
  	  	MSC_NAS_EMM_MME,
  	  	NULL,0,
  	  	"0 EMMAS_SECURITY_REQ ue id "NAS_UE_ID_FMT" ", data->ueid);

  emm_sap.primitive = EMMAS_SECURITY_REQ;
  emm_sap.u.emm_as.u.security.guti = NULL;
  emm_sap.u.emm_as.u.security.ueid = data->ueid;
  emm_sap.u.emm_as.u.security.msgType = EMM_AS_MSG_TYPE_IDENT;
  emm_sap.u.emm_as.u.security.identType = data->type;

#if defined(NAS_BUILT_IN_EPC)
  if (data->ueid > 0) {
    emm_ctx = emm_data_context_get(&_emm_data, data->ueid);
  }
#else
  if (data->ueid < EMM_DATA_NB_UE_MAX) {
    emm_ctx = _emm_data.ctx[data->ueid];
  }
#endif
  /* Setup EPS NAS security data */
  emm_as_set_security_data(&emm_sap.u.emm_as.u.security.sctx,
                           emm_ctx->security, FALSE, TRUE);
  rc = emm_sap_send(&emm_sap);

  if (rc != RETURNerror) {
    if (emm_ctx->T3470.id != NAS_TIMER_INACTIVE_ID) {
      /* Re-start T3470 timer */
    	emm_ctx->T3470.id = nas_timer_restart(emm_ctx->T3470.id);
      MSC_LOG_EVENT(MSC_NAS_EMM_MME, "0 T3470 restarted UE "NAS_UE_ID_FMT" ", data->ueid);
    } else {
      /* Start T3470 timer */
      emm_ctx->T3470.id = nas_timer_start(emm_ctx->T3470.sec, _identification_t3470_handler,
                                 data);
      MSC_LOG_EVENT(MSC_NAS_EMM_MME, "0 T3470 started UE "NAS_UE_ID_FMT" ", data->ueid);
    }

    LOG_TRACE(INFO,"EMM-PROC  - Timer T3470 (%d) expires in %ld seconds",
    		emm_ctx->T3470.id, emm_ctx->T3470.sec);
  }

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _emm_detach_t3421_handler()                               **
 **                                                                        **
 ** Description: T3421 timeout handler                                     **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.2.2.4 case c                  **
 **      On the first four expiries of the timer, the UE shall re- **
 **      transmit the DETACH REQUEST message and shall reset and   **
 **      restart timer T3421. On the fifth expiry of timer T3421,  **
 **      the detach procedure shall be aborted.                    **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    _emm_detach_data                           **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
void *_emm_detach_t3421_handler(void *args)
{
  LOG_FUNC_IN;

  int rc;

  /* Increment the retransmission counter */
  _emm_detach_data.count += 1;

  LOG_TRACE(WARNING, "EMM-PROC  - T3421 timer expired, "
            "retransmission counter = %d", _emm_detach_data.count);

  if (_emm_detach_data.count < EMM_DETACH_COUNTER_MAX) {
    /* Retransmit the Detach Request message */
    emm_sap_t emm_sap;
    emm_as_data_t *emm_as = &emm_sap.u.emm_as.u.data;

    /* Stop timer T3421 */
    T3421.id = nas_timer_stop(T3421.id);

    /* Setup NAS information message to transfer */
    emm_as->NASinfo = EMM_AS_NAS_INFO_DETACH;
    emm_as->NASmsg.length = 0;
    emm_as->NASmsg.value = NULL;
    /* Set the detach type */
    emm_as->type = _emm_detach_data.type;
    /* Set the switch-off indicator */
    emm_as->switch_off = _emm_detach_data.switch_off;
    /* Set the EPS mobile identity */
    emm_as->guti = _emm_data.guti;
    emm_as->ueid = 0;
    /* Setup EPS NAS security data */
    emm_as_set_security_data(&emm_as->sctx, _emm_data.security,
                             FALSE, TRUE);

    /*
     * Notify EMM-AS SAP that Detach Request message has to
     * be sent to the network
     */
    emm_sap.primitive = EMMAS_DATA_REQ;
    rc = emm_sap_send(&emm_sap);

    if (rc != RETURNerror) {
      /* Start T3421 timer */
      T3421.id = nas_timer_start(T3421.sec, _emm_detach_t3421_handler, NULL);
      LOG_TRACE(INFO, "EMM-PROC  - Timer T3421 (%d) expires in %ld "
                "seconds", T3421.id, T3421.sec);
    }
  } else {
    /* Abort the detach procedure */
    rc = _emm_detach_abort(_emm_detach_data.type);
  }

  LOG_FUNC_RETURN(NULL);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _identification_abort()                                   **
 **                                                                        **
 ** Description: Aborts the identification procedure currently in progress **
 **                                                                        **
 ** Inputs:  args:      Identification data to be released         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    T3470                                      **
 **                                                                        **
 ***************************************************************************/
static int _identification_abort(void *args)
{
  LOG_FUNC_IN;

  int rc = RETURNerror;

  identification_data_t *data = (identification_data_t *)(args);

  if (data) {
    unsigned int ueid = data->ueid;
    int notify_failure = data->notify_failure;
    struct emm_data_context_s *emm_ctx = NULL;
    /* Get the UE context */
  #if defined(NAS_BUILT_IN_EPC)
    if (ueid > 0) {
      emm_ctx = emm_data_context_get(&_emm_data, ueid);
    }
  #else
    if (ueid < EMM_DATA_NB_UE_MAX) {
      emm_ctx = _emm_data.ctx[ueid];
    }
  #endif
    LOG_TRACE(WARNING, "EMM-PROC  - Abort identification procedure "
              "(ueid="NAS_UE_ID_FMT")", ueid);

    /* Stop timer T3470 */
    if (emm_ctx->T3470.id != NAS_TIMER_INACTIVE_ID) {
      LOG_TRACE(INFO, "EMM-PROC  - Stop timer T3470 (%d)", emm_ctx->T3470.id);
      emm_ctx->T3470.id = nas_timer_stop(emm_ctx->T3470.id);
      MSC_LOG_EVENT(MSC_NAS_EMM_MME, "0 T3470 stopped UE "NAS_UE_ID_FMT" ", data->ueid);
    }

    /* Release retransmission timer paramaters */
    free(data);

    /*
     * Notify EMM that the identification procedure failed
     */
    if (notify_failure) {
      MSC_LOG_TX_MESSAGE(
    	  		MSC_NAS_EMM_MME,
    	  	  	MSC_NAS_EMM_MME,
    	  	  	NULL,0,
    	  	  	"0 EMMREG_COMMON_PROC_REJ ue id "NAS_UE_ID_FMT" ", ueid);
      emm_sap_t emm_sap;
      emm_sap.primitive = EMMREG_COMMON_PROC_REJ;
      emm_sap.u.emm_reg.ueid = ueid;
      rc = emm_sap_send(&emm_sap);
    } else {
      rc = RETURNok;
    }
  }

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    lowerlayer_failure()                                      **
 **                                                                        **
 ** Description: Notify the EPS Mobility Management entity that lower la-  **
 **      yers failed to deliver data to the network                **
 **                                                                        **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int lowerlayer_failure(unsigned int ueid)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  emm_sap.primitive = EMMREG_LOWERLAYER_FAILURE;
  emm_sap.u.emm_reg.ueid = ueid;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    lowerlayer_success()                                      **
 **                                                                        **
 ** Description: Notify the EPS Mobility Management entity that data have  **
 **      been successfully delivered to the network                **
 **                                                                        **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int lowerlayer_success(unsigned int ueid)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  emm_sap.primitive = EMMREG_LOWERLAYER_SUCCESS;
  emm_sap.u.emm_reg.ueid = ueid;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_detach()                                         **
 **                                                                        **
 ** Description: Initiates the detach procedure in order for the UE to de- **
 **      tach for EPS services.                                    **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.2.2.1                         **
 **      In state EMM-REGISTERED or EMM-REGISTERED-INITIATED, the  **
 **      UE initiates the detach procedure by sending a DETACH RE- **
 **      QUEST message to the network, starting timer T3421 and    **
 **      entering state EMM-DEREGISTERED-INITIATED.                **
 **                                                                        **
 ** Inputs:  type:      Type of the requested detach               **
 **      switch_off:    Indicates whether the detach is required   **
 **             because the UE is switched off or not      **
 **      Others:    _emm_data                                  **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    _emm_detach_data                           **
 **                                                                        **
 ***************************************************************************/
int emm_proc_detach(emm_proc_detach_type_t type, int switch_off)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  emm_as_data_t *emm_as = &emm_sap.u.emm_as.u.data;
  int rc;

  LOG_TRACE(INFO, "EMM-PROC  - Initiate EPS detach type = %s (%d)",
            _emm_detach_type_str[type], type);

  /* Initialize the detach procedure internal data */
  _emm_detach_data.count = 0;
  _emm_detach_data.switch_off = switch_off;
  _emm_detach_data.type = type;

  /* Setup EMM procedure handler to be executed upon receiving
   * lower layer notification */
  rc = emm_proc_lowerlayer_initialize(emm_proc_detach_request,
                                      emm_proc_detach_failure,
                                      emm_proc_detach_release, NULL);

  if (rc != RETURNok) {
    LOG_TRACE(WARNING, "Failed to initialize EMM procedure handler");
    LOG_FUNC_RETURN (RETURNerror);
  }

  /* Setup NAS information message to transfer */
  emm_as->NASinfo = EMM_AS_NAS_INFO_DETACH;
  emm_as->NASmsg.length = 0;
  emm_as->NASmsg.value = NULL;
  /* Set the detach type */
  emm_as->type = type;
  /* Set the switch-off indicator */
  emm_as->switch_off = switch_off;
  /* Set the EPS mobile identity */
  emm_as->guti = _emm_data.guti;
  emm_as->ueid = 0;
  /* Setup EPS NAS security data */
  emm_as_set_security_data(&emm_as->sctx, _emm_data.security, FALSE, TRUE);

  /*
   * Notify EMM-AS SAP that Detach Request message has to
   * be sent to the network
   */
  emm_sap.primitive = EMMAS_DATA_REQ;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_attach_request()                                 **
 **                                                                        **
 ** Description: Performs the attach procedure upon receipt of indication  **
 **      from lower layers that Attach Request message has been    **
 **      successfully delivered to the network.                    **
 **                                                                        **
 ** Inputs:  args:      Not used                                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int emm_proc_attach_request(void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  /*
   * Notify EMM that Attach Request has been sent to the network
   */
  emm_sap.primitive = EMMREG_ATTACH_REQ;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    lowerlayer_release()                                      **
 **                                                                        **
 ** Description: Notify the EPS Mobility Management entity that NAS signal-**
 **      ling connection has been released                         **
 **                                                                        **
 ** Inputs:  cause:     Release cause                              **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int lowerlayer_release(int cause)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  /* Update the EPS Connection Management status */
  _emm_data.ecm_status = ECM_IDLE;

  emm_sap.primitive = EMMREG_LOWERLAYER_RELEASE;
  emm_sap.u.emm_reg.ueid = 0;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_attach_release()                                 **
 **                                                                        **
 ** Description: Performs the attach procedure abnormal case upon receipt  **
 **      of NAS signalling connection release indication.          **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.1.2.6, case b                 **
 **      The attach procedure shall be aborted and the UE shall    **
 **      execute abnormal case attach procedure.                   **
 **                                                                        **
 ** Inputs:  args:      Not used                                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int emm_proc_attach_release(void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  LOG_TRACE(WARNING, "EMM-PROC  - NAS signalling connection released");

  /* Execute abnormal case attach procedure */
  _emm_attach_abnormal_cases_bcd(&emm_sap);

  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _authentication_t3460_handler()                           **
 **                                                                        **
 ** Description: T3460 timeout handler                                     **
 **      Upon T3460 timer expiration, the authentication request   **
 **      message is retransmitted and the timer restarted. When    **
 **      retransmission counter is exceed, the MME shall abort the **
 **      authentication procedure and any ongoing EMM specific     **
 **      procedure and release the NAS signalling connection.      **
 **                                                                        **
 **              3GPP TS 24.301, section 5.4.2.7, case b                   **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
static void                            *
_authentication_t3460_handler (
  void *args)
{
  LOG_FUNC_IN;
  int                                     rc;
  authentication_data_t                  *data = (authentication_data_t *) (args);

  /*
   * Increment the retransmission counter
   */
  data->retransmission_count += 1;
  LOG_TRACE (WARNING, "EMM-PROC  - T3460 timer expired, retransmission " "counter = %d", data->retransmission_count);

  if (data->retransmission_count < AUTHENTICATION_COUNTER_MAX) {
    /*
     * Send authentication request message to the UE
     */
    rc = _authentication_request (data);
  } else {
    unsigned int                            ueid = data->ueid;

    /*
     * Set the failure notification indicator
     */
    data->notify_failure = TRUE;
    /*
     * Abort the authentication procedure
     */
    rc = _authentication_abort (data);

    /*
     * Release the NAS signalling connection
     */
    if (rc != RETURNerror) {
      emm_sap_t                               emm_sap;

      emm_sap.primitive = EMMAS_RELEASE_REQ;
      emm_sap.u.emm_as.u.release.guti = NULL;
      emm_sap.u.emm_as.u.release.ueid = ueid;
      emm_sap.u.emm_as.u.release.cause = EMM_AS_CAUSE_AUTHENTICATION;
      rc = emm_sap_send (&emm_sap);
    }
  }

  LOG_FUNC_RETURN (NULL);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_attach_restart()                                 **
 **                                                                        **
 ** Description: Restarts the attach procedure                             **
 **                                                                        **
 ** Inputs:  None                                                      **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int emm_proc_attach_restart(void)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  LOG_TRACE(INFO, "EMM-PROC  - Restart EPS attach procedure");

  /*
   * Notify EMM that the attach procedure has to be restarted
   */
  emm_sap.primitive = EMMREG_ATTACH_INIT;
  emm_sap.u.emm_reg.u.attach.is_emergency = _emm_data.is_emergency;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_attach_set_detach()                              **
 **                                                                        **
 ** Description: Reset the network attachment indicator and enter state    **
 **      EMM-DEREGISTERED
 **                                                                        **
 ** Inputs:  None                                                      **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    _emm_data                                  **
 **                                                                        **
 ***************************************************************************/
int emm_proc_attach_set_detach(void)
{
  LOG_FUNC_IN;

  int rc;

  LOG_TRACE(WARNING,
            "EMM-PROC  - UE is now locally detached from the network");

  /* Reset the network attachment indicator */
  _emm_data.is_attached = FALSE;
  /*
   * Notify that the UE is locally detached from the network
   */
  emm_sap_t emm_sap;
  emm_sap.primitive = EMMREG_DETACH_CNF;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_attach_complete()                                **
 **                                                                        **
 ** Description: Terminates the attach procedure when Attach Complete mes- **
 **      sage has been successfully delivered to the MME.          **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.1.2.4                         **
 **      Upon successfully sending the ATTACH COMPLETE message,    **
 **      the UE shall reset the attach attempt counter and tra-    **
 **      cking area updating attempt counter, enter state EMM-     **
 **      REGISTERED and set the EPS update status to EU1-UPDATED.  **
 **                                                                        **
 ** Inputs:  args:      Not used                                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    _emm_data, _emm_attach_data                **
 **                                                                        **
 ***************************************************************************/
int emm_proc_attach_complete(void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  esm_sap_t esm_sap;
  int rc;

  LOG_TRACE(INFO, "EMM-PROC  - EPS attach complete");

  /* Reset EMM procedure handler */
  (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL);

  /* Reset the attach attempt counter */
  _emm_attach_data.attempt_count = 0;
  /* TODO: Reset the tracking area updating attempt counter */

  /* Set the EPS update status to EU1 UPDATED */
  _emm_data.status = EU1_UPDATED;
  _emm_data.is_attached = TRUE;

  /*
   * Notify EMM that network attach complete message has been delivered
   * to the network
   */
  emm_sap.primitive = EMMREG_ATTACH_CNF;
  rc = emm_sap_send(&emm_sap);

  if (rc != RETURNerror) {
    /*
     * Notify ESM that the Activate Default EPS Bearer Context Accept
     * message has been delivered to the network within the Attach
     * Complete message
     */
    esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_CNF;
    esm_sap.is_standalone = FALSE;
    rc = esm_sap_send(&esm_sap);
  }

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _emm_attach_t3411_handler()                               **
 **                                                                        **
 ** Description: T3411 timeout handler                                     **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.1.2.6                         **
 **      Upon T3411 timer expiration, the attach procedure shall   **
 **      be restarted, if still required by ESM sublayer.          **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    T3411                                      **
 **                                                                        **
 ***************************************************************************/
static void *_emm_attach_t3411_handler(void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;

  LOG_TRACE(WARNING, "EMM-PROC  - T3411 timer expired");

  /* Stop T3411 timer */
  T3411.id = nas_timer_stop(T3411.id);
  /*
   * Notify EMM that timer T3411 expired and attach procedure has to be
   * restarted
   */
  emm_sap.primitive = EMMREG_ATTACH_INIT;
  emm_sap.u.emm_reg.u.attach.is_emergency = _emm_data.is_emergency;

  (void) emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(NULL);
}
/****************************************************************************
 **                                                                        **
 ** Name:    esm_proc_pdn_disconnect_request()                         **
 **                                                                        **
 ** Description: Initiates PDN disconnection procedure in order to request **
 **      disconnection from a PDN.                                 **
 **                                                                        **
 **              3GPP TS 24.301, section 6.5.2.2                           **
 **      The UE requests PDN disconnection from a PDN by sending a **
 **      PDN DISCONNECT REQUEST message to the MME, starting timer **
 **      T3492 and entering state PROCEDURE TRANSACTION PENDING.   **
 **                                                                        **
 ** Inputs:  is_standalone: Should be always TRUE                      **
 **      pti:       Procedure transaction identity             **
 **      msg:       Encoded PDN disconnect request message to  **
 **             be sent                                    **
 **      sent_by_ue:    Not used                                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int esm_proc_pdn_disconnect_request(int is_standalone, int pti,
                                    OctetString *msg, int sent_by_ue)
{
  LOG_FUNC_IN;

  int rc = RETURNok;

  LOG_TRACE(INFO, "ESM-PROC  - Initiate PDN disconnection (pti=%d)", pti);

  if (is_standalone) {
    emm_sap_t emm_sap;
    emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data;
    /*
     * Notity EMM that ESM PDU has to be forwarded to lower layers
     */
    emm_sap.primitive = EMMESM_UNITDATA_REQ;
    emm_sap.u.emm_esm.ueid = 0;
    emm_esm->msg.length = msg->length;
    emm_esm->msg.value = msg->value;
    rc = emm_sap_send(&emm_sap);

    if (rc != RETURNerror) {
      /* Start T3482 retransmission timer */
      rc = esm_pt_start_timer(pti, msg, T3492_DEFAULT_VALUE,
                              _pdn_disconnect_t3492_handler);
    }
  }

  if (rc != RETURNerror) {
    /* Set the procedure transaction state to PENDING */
    rc = esm_pt_set_status(pti, ESM_PT_PENDING);

    if (rc != RETURNok) {
      /* The procedure transaction was already in PENDING state */
      LOG_TRACE(WARNING, "ESM-PROC  - PTI %d was already PENDING", pti);
    }
  }

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_detach_request()                                 **
 **                                                                        **
 ** Description: Performs the detach procedure upon receipt of indication  **
 **      from lower layers that Detach Request message has been    **
 **      successfully delivered to the network.                    **
 **                                                                        **
 ** Inputs:  args:      Not used                                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    T3421                                      **
 **                                                                        **
 ***************************************************************************/
int emm_proc_detach_request(void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  if ( !_emm_detach_data.switch_off ) {
    /* Start T3421 timer */
    T3421.id = nas_timer_start(T3421.sec, _emm_detach_t3421_handler, NULL);
    LOG_TRACE(INFO, "EMM-PROC  - Timer T3421 (%d) expires in %ld seconds",
              T3421.id, T3421.sec);
  }

  /*
   * Notify EMM that Detach Request has been sent to the network
   */
  emm_sap.primitive = EMMREG_DETACH_REQ;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    esm_proc_eps_bearer_context_deactivate_accept()           **
 **                                                                        **
 ** Description: Performs EPS bearer context deactivation procedure accep- **
 **      ted by the UE.                                            **
 **                                                                        **
 **      3GPP TS 24.301, section 6.4.4.3                           **
 **      The UE accepts EPS bearer context deactivation by sending **
 **      DEACTIVATE EPS BEARER CONTEXT ACCEPT message and entering **
 **      the state BEARER CONTEXT INACTIVE.                        **
 **                                                                        **
 ** Inputs:  is_standalone: Should be always TRUE                      **
 **      ebi:       EPS bearer identity                        **
 **      msg:       Encoded ESM message to be sent             **
 **      ue_triggered:  TRUE if the EPS bearer context procedure   **
 **             was triggered by the UE                    **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int esm_proc_eps_bearer_context_deactivate_accept(int is_standalone, int ebi,
    OctetString *msg, int ue_triggered)
{
  LOG_FUNC_IN;

  int rc = RETURNok;

  LOG_TRACE(INFO,"ESM-PROC  - EPS bearer context deactivation accepted");

  if (is_standalone) {
    emm_sap_t emm_sap;
    /*
     * Notity EMM that ESM PDU has to be forwarded to lower layers
     */
    emm_sap.primitive = EMMESM_UNITDATA_REQ;
    emm_sap.u.emm_esm.ueid = 0;
    emm_sap.u.emm_esm.u.data.msg.length = msg->length;
    emm_sap.u.emm_esm.u.data.msg.value = msg->value;
    rc = emm_sap_send(&emm_sap);
  }

  if (rc != RETURNerror) {
    /* Set the EPS bearer context state to INACTIVE */
    rc = esm_ebr_set_status(ebi, ESM_EBR_INACTIVE, ue_triggered);

    if (rc != RETURNok) {
      /* The EPS bearer context was already in INACTIVE state */
      LOG_TRACE(WARNING, "ESM-PROC  - EBI %d was already INACTIVE", ebi);
      /* Accept network retransmission of already accepted deactivate
       * EPS bearer context request */
      LOG_FUNC_RETURN (RETURNok);
    }

    /* Release EPS bearer data */
    rc = esm_ebr_release(ebi);
  }

  LOG_FUNC_RETURN (rc);
}
Exemple #24
0
/****************************************************************************
 **                                                                        **
 ** Name:    _identification_abort()                                   **
 **                                                                        **
 ** Description: Aborts the identification procedure currently in progress **
 **                                                                        **
 ** Inputs:  args:      Identification data to be released         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    T3470                                      **
 **                                                                        **
 ***************************************************************************/
static int _identification_abort(void *args)
{
    LOG_FUNC_IN;

    int rc = RETURNerror;

    identification_data_t *data = (identification_data_t *)(args);

    if (data) {
        unsigned int ueid = data->ueid;
        int notify_failure = data->notify_failure;

        LOG_TRACE(WARNING, "EMM-PROC  - Abort identification procedure "
                  "(ueid=%u)", ueid);

        /* Stop timer T3470 */
        if (T3470.id != NAS_TIMER_INACTIVE_ID) {
            LOG_TRACE(INFO, "EMM-PROC  - Stop timer T3470 (%d)", T3470.id);
            T3470.id = nas_timer_stop(T3470.id);
        }
        /* Release retransmission timer paramaters */
        free(data);

        /*
         * Notify EMM that the identification procedure failed
         */
        if (notify_failure) {
            emm_sap_t emm_sap;
            emm_sap.primitive = EMMREG_COMMON_PROC_REJ;
            emm_sap.u.emm_reg.ueid = ueid;
            rc = emm_sap_send(&emm_sap);
        } else {
            rc = RETURNok;
        }
    }

    LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _emm_attach_t3410_handler()                               **
 **                                                                        **
 ** Description: T3410 timeout handler                                     **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.1.2.6, case c                 **
 **      Upon T3410 timer expiration, the attach procedure shall   **
 **      be aborted and the UE shall execute abnormal case attach  **
 **      procedure.                                                **
 **      The NAS signalling connection shall be released locally.  **
 **                                                                        **
 ** Inputs:  args:      handler parameters                         **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    None                                       **
 **      Others:    T3410                                      **
 **                                                                        **
 ***************************************************************************/
void *_emm_attach_t3410_handler(void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  LOG_TRACE(WARNING, "EMM-PROC  - T3410 timer expired");

  /* Stop T3410 timer */
  T3410.id = nas_timer_stop(T3410.id);
  /* Execute abnormal case attach procedure */
  _emm_attach_abnormal_cases_bcd(&emm_sap);

  rc = emm_sap_send(&emm_sap);

  if (rc != RETURNerror) {
    /* Locally release the NAS signalling connection */
    _emm_data.ecm_status = ECM_IDLE;
  }

  LOG_FUNC_RETURN(NULL);
}
/****************************************************************************
 **                                                                        **
 ** Name:    lowerlayer_data_req()                                     **
 **                                                                        **
 ** Description: Notify the EPS Mobility Management entity that data have  **
 **      to be transfered to lower layers                          **
 **                                                                        **
 ** Inputs:  ueid:      UE lower layer identifier                  **
 **          data:      Data to be transfered to lower layers      **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int lowerlayer_data_req(unsigned int ueid, const OctetString *data)
{
  LOG_FUNC_IN;

  int rc;
  emm_sap_t emm_sap;
  emm_security_context_t    *sctx = NULL;
  struct emm_data_context_s *ctx  = NULL;

  emm_sap.primitive = EMMAS_DATA_REQ;
  emm_sap.u.emm_as.u.data.guti = _emm_data.guti;
  emm_sap.u.emm_as.u.data.ueid = 0;
  sctx = _emm_data.security;

  emm_sap.u.emm_as.u.data.NASinfo = 0;
  emm_sap.u.emm_as.u.data.NASmsg.length = data->length;
  emm_sap.u.emm_as.u.data.NASmsg.value = data->value;
  /* Setup EPS NAS security data */
  emm_as_set_security_data(&emm_sap.u.emm_as.u.data.sctx, sctx, FALSE, TRUE);
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    esm_proc_status()                                         **
 **                                                                        **
 ** Description: Initiates ESM status procedure.                           **
 **                                                                        **
 ** Inputs:  is_standalone: Not used - Always TRUE                     **
 **      ueid:      UE lower layer identifier                  **
 **      ebi:       Not used                                   **
 **      msg:       Encoded ESM status message to be sent      **
 **      ue_triggered:  Not used                                   **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int
esm_proc_status (
  int is_standalone,
  emm_data_context_t * ctx,
  int ebi,
  OctetString * msg,
  int ue_triggered)
{
  LOG_FUNC_IN;
  int                                     rc;
  emm_sap_t                               emm_sap;

  LOG_TRACE (INFO, "ESM-PROC  - ESM status procedure requested");
  /*
   * Notity EMM that ESM PDU has to be forwarded to lower layers
   */
  emm_sap.primitive = EMMESM_UNITDATA_REQ;
  emm_sap.u.emm_esm.ueid = ctx->ueid;
  emm_sap.u.emm_esm.ctx = ctx;
  emm_sap.u.emm_esm.u.data.msg.length = msg->length;
  emm_sap.u.emm_esm.u.data.msg.value = msg->value;
  rc = emm_sap_send (&emm_sap);
  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    emm_proc_detach_failure()                                 **
 **                                                                        **
 ** Description: Performs the detach procedure abnormal case upon receipt  **
 **          of transmission failure of Detach Request message.        **
 **                                                                        **
 **              3GPP TS 24.301, section 5.5.2.2.4, case h                 **
 **      The UE shall restart the detach procedure.                **
 **                                                                        **
 ** Inputs:  is_initial:    Not used                                   **
 **          args:      Not used                                   **
 **      Others:    _emm_detach_data                           **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int emm_proc_detach_failure(int is_initial, void *args)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc;

  LOG_TRACE(WARNING, "EMM-PROC  - Network detach failure");

  /* Reset EMM procedure handler */
  (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL);

  /* Stop timer T3421 */
  T3421.id = nas_timer_stop(T3421.id);

  /*
   * Notify EMM that detach procedure has to be restarted
   */
  emm_sap.primitive = EMMREG_DETACH_INIT;
  emm_sap.u.emm_reg.u.detach.switch_off = _emm_detach_data.switch_off;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN(rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    esm_proc_dedicated_eps_bearer_context_accept()            **
 **                                                                        **
 ** Description: Performs dedicated EPS bearer context activation proce-   **
 **      dure accepted by the UE.                                  **
 **                                                                        **
 **      3GPP TS 24.301, section 6.4.2.3                           **
 **      The UE accepts dedicated EPS bearer context activation by **
 **      sending ACTIVATE DEDICATED EPS BEARER CONTEXT ACCEPT mes- **
 **      sage and entering the state BEARER CONTEXT ACTIVE.        **
 **                                                                        **
 ** Inputs:  is_standalone: Not used                                   **
 **      ebi:       EPS bearer identity                        **
 **      msg:       Encoded ESM message to be sent             **
 **      ue_triggered:  TRUE if the EPS bearer context procedure   **
 **             was triggered by the UE                    **
 **      Others:    None                                       **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    None                                       **
 **                                                                        **
 ***************************************************************************/
int esm_proc_dedicated_eps_bearer_context_accept(int is_standalone, int ebi,
    OctetString *msg, int ue_triggered)
{
  LOG_FUNC_IN;

  int rc;

  LOG_TRACE(INFO,"ESM-PROC  - Dedicated EPS bearer context activation "
            "accepted by the UE (ebi=%d)", ebi);

  emm_sap_t emm_sap;
  emm_esm_data_t *emm_esm = &emm_sap.u.emm_esm.u.data;
  /*
   * Notity EMM that ESM PDU has to be forwarded to lower layers
   */
  emm_sap.primitive = EMMESM_UNITDATA_REQ;
  emm_sap.u.emm_esm.ueid = 0;
  emm_esm->msg.length = msg->length;
  emm_esm->msg.value = msg->value;
  rc = emm_sap_send(&emm_sap);

  if (rc != RETURNerror) {
    /* Set the EPS bearer context state to ACTIVE */
    rc = esm_ebr_set_status(ebi, ESM_EBR_ACTIVE, ue_triggered);

    if (rc != RETURNok) {
      /* The EPS bearer context was already in ACTIVE state */
      LOG_TRACE(WARNING, "ESM-PROC  - EBI %d was already ACTIVE", ebi);
      /* Accept network retransmission of already accepted activate
       * dedicated EPS bearer context request */
      LOG_FUNC_RETURN (RETURNok);
    }
  }

  LOG_FUNC_RETURN (rc);
}
/****************************************************************************
 **                                                                        **
 ** Name:    _emm_detach_abort()                                       **
 **                                                                        **
 ** Description: Aborts the detach procedure                               **
 **                                                                        **
 ** Inputs:  type:      not used                                   **
 **      Others:    _emm_detach_data                           **
 **                                                                        **
 ** Outputs:     None                                                      **
 **      Return:    RETURNok, RETURNerror                      **
 **      Others:    T3421                                      **
 **                                                                        **
 ***************************************************************************/
static int _emm_detach_abort(emm_proc_detach_type_t type)
{
  LOG_FUNC_IN;

  emm_sap_t emm_sap;
  int rc ;

  LOG_TRACE(WARNING, "EMM-PROC  - Abort the detach procedure");

  /* Reset EMM procedure handler */
  (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL);

  /* Stop timer T3421 */
  T3421.id = nas_timer_stop(T3421.id);

  /*
   * Notify EMM that detach procedure failed
   */
  emm_sap.primitive = EMMREG_DETACH_FAILED;
  emm_sap.u.emm_reg.u.detach.type = type;
  rc = emm_sap_send(&emm_sap);

  LOG_FUNC_RETURN (rc);
}