/**************************************************************************** ** ** ** Name: _emm_attach_abnormal_cases_bcd() ** ** ** ** Description: Performs the abnormal case attach procedure. ** ** ** ** 3GPP TS 24.301, section 5.5.1.2.6, cases b, c and d ** ** The Timer T3410 shall be stopped if still running, the ** ** attach attempt counter shall be incremented and the UE ** ** shall proceed depending on whether the attach attempt ** ** counter reached its maximum value or not. ** ** ** ** Inputs: None ** ** Others: None ** ** ** ** Outputs: emm_sap: EMM service access point ** ** Return: None ** ** Others: _emm_data, _emm_attach_data, T3402, T3410, ** ** T3411 ** ** ** ***************************************************************************/ static void _emm_attach_abnormal_cases_bcd(emm_sap_t *emm_sap) { LOG_FUNC_IN; LOG_TRACE(WARNING, "EMM-PROC - Abnormal case, attach counter = %d", _emm_attach_data.attempt_count); /* Stop timer T3410 */ if (T3410.id != NAS_TIMER_INACTIVE_ID) { LOG_TRACE(INFO, "EMM-PROC - Stop timer T3410 (%d)", T3410.id); T3410.id = nas_timer_stop(T3410.id); } if (_emm_attach_data.attempt_count < EMM_ATTACH_COUNTER_MAX) { /* Increment the attach attempt counter */ _emm_attach_data.attempt_count += 1; /* Start T3411 timer */ T3411.id = nas_timer_start(T3411.sec, _emm_attach_t3411_handler, NULL); LOG_TRACE(INFO, "EMM-PROC - Timer T3411 (%d) expires in %ld seconds", T3411.id, T3411.sec); /* * Notify EMM that the attempt to attach for EPS services failed and * the attach attempt counter didn't reach its maximum value; network * attach procedure shall be restarted when timer T3411 expires. */ emm_sap->primitive = EMMREG_ATTACH_FAILED; } else { /* Delete the GUTI */ _emm_data.guti = NULL; /* Delete the TAI list */ _emm_data.ltai.n_tais = 0; /* Delete the last visited registered TAI */ _emm_data.tai = NULL; /* Delete the list of equivalent PLMNs */ _emm_data.nvdata.eplmn.n_plmns = 0; /* Delete the eKSI */ if (_emm_data.security) { _emm_data.security->type = EMM_KSI_NOT_AVAILABLE; } /* Set the EPS update status to EU2 NOT UPDATED */ _emm_data.status = EU2_NOT_UPDATED; /* Start T3402 timer */ T3402.id = nas_timer_start(T3402.sec, _emm_attach_t3402_handler, NULL); LOG_TRACE(INFO, "EMM-PROC - Timer T3402 (%d) expires in %ld seconds", T3402.id, T3402.sec); /* * Notify EMM that the attempt to attach for EPS services failed and * the attach attempt counter reached its maximum value. */ emm_sap->primitive = EMMREG_ATTACH_EXCEEDED; } LOG_FUNC_OUT; }
/**************************************************************************** ** ** ** 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: esm_pt_start_timer() ** ** ** ** Description: Start the timer of the specified procedure transaction to ** ** expire after a given time interval. Timer expiration will ** ** schedule execution of the callback function where stored ** ** ESM message should be re-transmit. ** ** ** ** Inputs: pti: The identity of the procedure transaction ** ** msg: The encoded ESM message to be stored ** ** sec: The value of the time interval in seconds ** ** cb: Function executed upon timer expiration ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: _esm_pt_data ** ** ** ***************************************************************************/ int esm_pt_start_timer(int pti, const OctetString *msg, long sec, nas_timer_callback_t cb) { LOG_FUNC_IN; if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) { LOG_FUNC_RETURN (RETURNerror); } /* Get procedure transaction data */ esm_pt_context_t *ctx = _esm_pt_data.context[pti - ESM_PTI_MIN]; if ( (ctx == NULL) || (ctx->pti != pti) ) { /* Procedure transaction not assigned */ LOG_FUNC_RETURN (RETURNerror); } if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) { if (ctx->args) { /* Re-start the retransmission timer */ ctx->timer.id = nas_timer_restart(ctx->timer.id); } } else { /* Setup the retransmission timer parameters */ ctx->args = (esm_pt_timer_data_t *)malloc(sizeof(esm_pt_timer_data_t)); if (ctx->args) { /* Set the EPS bearer identity */ ctx->args->pti = pti; /* Reset the retransmission counter */ ctx->args->count = 0; /* Set the ESM message to be re-transmited */ ctx->args->msg.value = (uint8_t *)malloc(msg->length); ctx->args->msg.length = 0; if (ctx->args->msg.value) { memcpy(ctx->args->msg.value, msg->value, msg->length); ctx->args->msg.length = msg->length; } /* Setup the retransmission timer to expire at the given * time interval */ ctx->timer.id = nas_timer_start(sec, cb, ctx->args); ctx->timer.sec = sec; } } if ( (ctx->args != NULL) && (ctx->timer.id != NAS_TIMER_INACTIVE_ID) ) { LOG_TRACE(INFO, "ESM-FSM - Retransmission timer %d expires in " "%ld seconds", ctx->timer.id, ctx->timer.sec); LOG_FUNC_RETURN (RETURNok); } LOG_FUNC_RETURN (RETURNerror); }
/**************************************************************************** ** ** ** 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: emm_proc_attach_failure() ** ** ** ** Description: Performs the attach procedure abnormal case upon receipt ** ** of transmission failure of Attach Request message or At- ** ** tach Complete message. ** ** ** ** 3GPP TS 24.301, section 5.5.1.2.6, cases h and i ** ** The UE shall restart the attach procedure when timer ** ** T3411 expires. ** ** ** ** Inputs: is_initial: TRUE if the NAS message that failed to be ** ** transfered is an initial NAS message (ESM ** ** message embedded within an Attach Request ** ** message) ** ** args: Not used ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: T3410, T3411 ** ** ** ***************************************************************************/ int emm_proc_attach_failure(int is_initial, void *args) { LOG_FUNC_IN; int rc = RETURNok; esm_sap_t esm_sap; LOG_TRACE(WARNING, "EMM-PROC - EPS attach failure"); /* Reset EMM procedure handler */ (void) emm_proc_lowerlayer_initialize(NULL, NULL, NULL, NULL); /* Stop timer T3410 if still running */ if (T3410.id != NAS_TIMER_INACTIVE_ID) { LOG_TRACE(INFO, "EMM-PROC - Stop timer T3410 (%d)", T3410.id); T3410.id = nas_timer_stop(T3410.id); } if (is_initial) { /* * Notify ESM that the PDN CONNECTIVITY REQUEST message contained * in the ESM message container IE of the ATTACH REQUEST has failed * to be transmitted */ esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ; esm_sap.is_standalone = FALSE; esm_sap.recv = NULL; } else { /* * Notify ESM that ACTIVATE DEFAULT EPS BEARER CONTEXT REQUEST message * contained in the ESM message container IE of the ATTACH COMPLETE * has failed to be transmitted */ esm_sap.primitive = ESM_DEFAULT_EPS_BEARER_CONTEXT_ACTIVATE_REJ; esm_sap.is_standalone = FALSE; esm_sap.recv = NULL; } rc = esm_sap_send(&esm_sap); if (rc != RETURNerror) { /* Start T3411 timer */ T3411.id = nas_timer_start(T3411.sec, _emm_attach_t3411_handler, NULL); LOG_TRACE(INFO, "EMM-PROC - Timer T3411 (%d) expires in %ld seconds", T3411.id, T3411.sec); } 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: emm_proc_attach() ** ** ** ** Description: Initiate EPS attach procedure to register a UE in PS mode ** ** of operation for EPS services only, or register a UE for ** ** emergency bearer services. ** ** ** ** 3GPP TS 24.301, section 5.5.1.2.2 ** ** In state EMM-DEREGISTERED, the UE initiates the attach ** ** procedure by sending an ATTACH REQUEST message to the MME,** ** starting timer T3410 and entering state EMM-REGISTERED- ** ** INITIATED. ** ** ** ** Inputs: type: Type of the requested attach ** ** Others: _emm_data ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: T3402, T3410, T3411 ** ** ** ***************************************************************************/ int emm_proc_attach(emm_proc_attach_type_t type) { LOG_FUNC_IN; emm_sap_t emm_sap; emm_as_establish_t *emm_as = &emm_sap.u.emm_as.u.establish; esm_sap_t esm_sap; int rc; LOG_TRACE(INFO, "EMM-PROC - Initiate EPS attach type = %s (%d)", _emm_attach_type_str[type], type); /* Update the emergency bearer service indicator */ if (type == EMM_ATTACH_TYPE_EMERGENCY) { _emm_data.is_emergency = TRUE; } /* Setup initial NAS information message to transfer */ emm_as->NASinfo = EMM_AS_NAS_INFO_ATTACH; /* Set the attach type */ emm_as->type = type; /* Set the RRC connection establishment cause */ if (_emm_data.is_emergency) { emm_as->RRCcause = NET_ESTABLISH_CAUSE_EMERGENCY; emm_as->RRCtype = NET_ESTABLISH_TYPE_EMERGENCY_CALLS; } else { emm_as->RRCcause = NET_ESTABLISH_CAUSE_MO_SIGNAL; emm_as->RRCtype = NET_ESTABLISH_TYPE_ORIGINATING_SIGNAL; } /* Set the PLMN identifier of the selected PLMN */ emm_as->plmnID = &_emm_data.splmn; /* * Process the EPS mobile identity */ emm_as->UEid.guti = NULL; emm_as->UEid.tai = NULL; emm_as->UEid.imsi = NULL; emm_as->UEid.imei = NULL; /* Check whether the UE is configured for "AttachWithIMSI" */ if (_emm_data.AttachWithImsi) { /* Check whether the selected PLMN is neither the registered PLMN * nor in the list of equivalent PLMNs */ if ( (!_emm_data.is_rplmn) && (!_emm_data.is_eplmn) ) { LOG_TRACE(INFO, "EMM-PROC - Initiate EPS attach with IMSI"); /* Include the IMSI */ emm_as->UEid.imsi = _emm_data.imsi; } else { LOG_TRACE(INFO, "EMM-PROC - Initiate EPS attach with NO IMSI, is registered PLMN %d, is equivalent PLMN %d", _emm_data.is_rplmn, _emm_data.is_eplmn); } } else if (_emm_data.guti) { LOG_TRACE(INFO, "EMM-PROC - Initiate EPS attach with GUTI"); /* Include a valid GUTI and the last visited registered TAI */ emm_as->UEid.guti = _emm_data.guti; emm_as->UEid.tai = _emm_data.tai; } else if (!_emm_data.is_emergency) { LOG_TRACE(INFO, "EMM-PROC - Initiate EPS attach with IMSI cause is no emergency and no GUTI"); /* Include the IMSI if no valid GUTI is available */ emm_as->UEid.imsi = _emm_data.imsi; } else { /* The UE is attaching for emergency bearer services and * does not hold a valid GUTI */ if (_emm_data.imsi) { /* Include the IMSI if valid (USIM is present) */ LOG_TRACE(INFO, "EMM-PROC - Initiate EPS attach with IMSI cause is emergency and no GUTI"); emm_as->UEid.imsi = _emm_data.imsi; } else { LOG_TRACE(INFO, "EMM-PROC - Initiate EPS attach with IMSI cause is emergency and no GUTI and no IMSI"); /* Include the IMEI if the IMSI is not valid */ emm_as->UEid.imei = _emm_data.imei; } } /* Setup EPS NAS security data */ emm_as_set_security_data(&emm_as->sctx, _emm_data.security, FALSE, FALSE); emm_as->ksi = EMM_AS_NO_KEY_AVAILABLE; if (_emm_data.security) { if (_emm_data.security->type != EMM_KSI_NOT_AVAILABLE) { emm_as->ksi = _emm_data.security->eksi; } LOG_TRACE(INFO, "EMM-PROC - eps_encryption 0x%X", _emm_data.security->capability.eps_encryption); LOG_TRACE(INFO, "EMM-PROC - eps_integrity 0x%X", _emm_data.security->capability.eps_integrity); emm_as->encryption = _emm_data.security->capability.eps_encryption; emm_as->integrity = _emm_data.security->capability.eps_integrity; } /* * Notify ESM that initiation of a PDN connectivity procedure * is requested to setup a default EPS bearer */ esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ; esm_sap.is_standalone = FALSE; esm_sap.data.pdn_connect.is_defined = TRUE; esm_sap.data.pdn_connect.cid = 1; /* TODO: PDN type should be set according to the IP capability of the UE */ esm_sap.data.pdn_connect.pdn_type = NET_PDN_TYPE_IPV4V6; esm_sap.data.pdn_connect.apn = NULL; esm_sap.data.pdn_connect.is_emergency = _emm_data.is_emergency; rc = esm_sap_send(&esm_sap); if (rc != RETURNerror) { /* Setup EMM procedure handler to be executed upon receiving * lower layer notification */ rc = emm_proc_lowerlayer_initialize(emm_proc_attach_request, emm_proc_attach_failure, emm_proc_attach_release, NULL); if (rc != RETURNok) { LOG_TRACE(WARNING, "Failed to initialize EMM procedure handler"); LOG_FUNC_RETURN (RETURNerror); } /* Start T3410 timer */ T3410.id = nas_timer_start(T3410.sec, _emm_attach_t3410_handler, NULL); LOG_TRACE(INFO,"EMM-PROC - Timer T3410 (%d) expires in %ld seconds", T3410.id, T3410.sec); /* Stop T3402 and T3411 timers if running */ T3402.id = nas_timer_stop(T3402.id); T3411.id = nas_timer_stop(T3411.id); /* * Notify EMM-AS SAP that a RRC connection establishment procedure * is requested from the Access-Stratum to send initial NAS message * attach request to the network */ emm_sap.primitive = EMMAS_ESTABLISH_REQ; /* Get the PDN connectivity request to transfer within the ESM * container of the initial attach request message */ emm_sap.u.emm_as.u.establish.NASmsg = esm_sap.send; rc = emm_sap_send(&emm_sap); } LOG_FUNC_RETURN(rc); }