| /* |
| * Copyright 2019-present Infosys Limited |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| /****************************************************************************** |
| * |
| * This file has both generated and manual code. |
| * |
| * File template used for code generation: |
| * <TOP-DIR/scripts/SMCodeGen/templates/stateMachineTmpls/actionHandlers.cpp.tt> |
| * |
| ******************************************************************************/ |
| |
| #include <3gpp_24008.h> |
| #include <typeinfo> |
| #include "actionHandlers/actionHandlers.h" |
| #include "controlBlock.h" |
| #include "msgType.h" |
| #include "contextManager/subsDataGroupManager.h" |
| #include "contextManager/dataBlocks.h" |
| #include "procedureStats.h" |
| #include "log.h" |
| #include "secUtils.h" |
| #include "state.h" |
| #include <string.h> |
| #include <sstream> |
| #include <smTypes.h> |
| #include <cstring> |
| #include <event.h> |
| #include <ipcTypes.h> |
| #include <tipcTypes.h> |
| #include <msgBuffer.h> |
| #include <interfaces/mmeIpcInterface.h> |
| #include <utils/mmeCommonUtils.h> |
| #include <utils/mmeContextManagerUtils.h> |
| |
| using namespace SM; |
| using namespace mme; |
| using namespace cmn::utils; |
| |
| extern MmeIpcInterface* mmeIpcIf_g; |
| |
| ActStatus ActionHandlers::validate_imsi_in_ue_context(ControlBlock& cb) |
| { |
| UEContext* ueCtxt_p = static_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ueCtxt_p == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_identity_request_to_ue: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| if (ueCtxt_p->getImsi().isValid()) |
| { |
| SM::Event evt(Event_e::IMSI_VALIDATION_SUCCESS, NULL); |
| cb.addEventToProcQ(evt); |
| } |
| else |
| { |
| // TODO: If known GUTI, IMSI_VALIDATION_FAILURE_KNOWN_GUTI to trigger id req to UE |
| // If unknown GUTI, IMSI_VALIDATION_FAILURE_UNKNOWN_GUTI to query old mme |
| // when s10 is supported in MME |
| SM::Event evt(Event_e::IMSI_VALIDATION_FAILURE, NULL); |
| cb.addEventToProcQ(evt); |
| } |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::send_identity_request_to_ue(ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside send_identity_request_to_ue \n"); |
| |
| UEContext* ueCtxt_p = static_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ueCtxt_p == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_identity_request_to_ue: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| struct attachIdReq_info idReqMsg; |
| idReqMsg.msg_type = id_request; |
| idReqMsg.enb_fd = ueCtxt_p->getEnbFd(); |
| idReqMsg.s1ap_enb_ue_id = ueCtxt_p->getS1apEnbUeId(); |
| idReqMsg.ue_idx = ueCtxt_p->getContextID(); |
| idReqMsg.ue_type = ID_IMSI; |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s1apAppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &idReqMsg, sizeof(idReqMsg), destAddr); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::process_identity_response(ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside process_identity_response \n"); |
| |
| UEContext *ueCtxt_p = static_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ueCtxt_p == NULL) |
| { |
| log_msg(LOG_DEBUG, "process_identity_response: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MsgBuffer* msgBuf = static_cast<MsgBuffer*>(cb.getMsgData()); |
| if (msgBuf == NULL) |
| { |
| log_msg(LOG_DEBUG, "process_identity_response: msgBuf is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| const s1_incoming_msg_data_t* s1_msg_data = static_cast<const s1_incoming_msg_data_t*>(msgBuf->getDataPointer()); |
| if (s1_msg_data == NULL) |
| { |
| log_msg(LOG_DEBUG, "process_identity_response: s1MsgData is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| const struct identityResp_Q_msg &id_resp = s1_msg_data->msg_data.identityResp_Q_msg_m; |
| if(SUCCESS != id_resp.status) |
| { |
| log_msg(LOG_DEBUG, "process_identity_response: ID Response Failure NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| uint8_t imsi[BINARY_IMSI_LEN] = {0}; |
| memcpy( imsi, id_resp.IMSI, BINARY_IMSI_LEN ); |
| |
| // Only upper nibble of first octect in imsi need to be considered |
| // Changing the lower nibble to 0x0f for handling |
| uint8_t first = imsi[0] >> 4; |
| imsi[0] = (uint8_t)(( first << 4 ) | 0x0f ); |
| |
| DigitRegister15 IMSIInfo; |
| IMSIInfo.convertFromBcdArray(imsi); |
| ueCtxt_p->setImsi(IMSIInfo); |
| |
| SubsDataGroupManager::Instance()->addimsikey(ueCtxt_p->getImsi(), ueCtxt_p->getContextID()); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| |
| ActStatus ActionHandlers::send_air_to_hss(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside send_air_to_hss \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_air_to_hss: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| s6a_Q_msg s6a_req; |
| |
| memset(s6a_req.imsi, '\0', sizeof(s6a_req.imsi)); |
| ue_ctxt->getImsi().getImsiDigits(s6a_req.imsi); |
| |
| memcpy(&(s6a_req.tai), &(ue_ctxt->getTai().tai_m), sizeof(struct TAI)); |
| |
| s6a_req.ue_idx = ue_ctxt->getContextID(); |
| s6a_req.msg_type = auth_info_request; |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s6AppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &s6a_req, sizeof(s6a_req), destAddr); |
| |
| ProcedureStats::num_of_air_sent ++; |
| log_msg(LOG_DEBUG, "Leaving send_air_to_hss \n"); |
| |
| return ActStatus::PROCEED; |
| |
| } |
| |
| ActStatus ActionHandlers::send_ulr_to_hss(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside send_ulr_to_hss \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_ulr_to_hss: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| s6a_Q_msg s6a_req; |
| |
| memset(s6a_req.imsi, '\0', sizeof(s6a_req.imsi)); |
| ue_ctxt->getImsi().getImsiDigits(s6a_req.imsi); |
| |
| memcpy(&(s6a_req.tai), &(ue_ctxt->getTai().tai_m), sizeof(struct TAI)); |
| |
| s6a_req.ue_idx = ue_ctxt->getContextID(); |
| s6a_req.msg_type = update_loc_request; |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s6AppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &s6a_req, sizeof(s6a_req), destAddr); |
| |
| ProcedureStats::num_of_ulr_sent ++; |
| log_msg(LOG_DEBUG, "Leaving send_ulr_to_hss \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| |
| ActStatus ActionHandlers::process_aia(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside handle_aia \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "handle_aia: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MsgBuffer* msgBuf = static_cast<MsgBuffer*>(cb.getMsgData()); |
| |
| if (msgBuf == NULL) |
| return ActStatus::HALT; |
| |
| const s6_incoming_msg_data_t* msgData_p = static_cast<const s6_incoming_msg_data_t*>(msgBuf->getDataPointer()); |
| |
| ue_ctxt->setAiaSecInfo(E_utran_sec_vector(msgData_p->msg_data.aia_Q_msg_m.sec)); |
| |
| ProcedureStats::num_of_processed_aia ++; |
| log_msg(LOG_DEBUG, "Leaving handle_aia \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::process_ula(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside handle_ula \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "handle_ula: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| SessionContext* sessionCtxt = ue_ctxt->getSessionContext(); |
| if( sessionCtxt == NULL ) |
| { |
| log_msg(LOG_ERROR, "Failed to retrieve Session Context for UE IDX %d\n", cb.getCBIndex()); |
| return ActStatus::HALT; |
| } |
| |
| MsgBuffer* msgBuf = static_cast<MsgBuffer*>(cb.getMsgData()); |
| |
| if (msgBuf == NULL) |
| return ActStatus::HALT; |
| |
| const s6_incoming_msg_data_t* s6_msg_data = static_cast<const s6_incoming_msg_data_t*>(msgBuf->getDataPointer()); |
| const struct ula_Q_msg &ula_msg = s6_msg_data->msg_data.ula_Q_msg_m; |
| |
| sessionCtxt->setApnConfigProfileCtxId(ula_msg.apn_config_profile_ctx_id); |
| DigitRegister15 ueMSISDN; |
| ueMSISDN.convertFromBcdArray( reinterpret_cast<const uint8_t*>( ula_msg.MSISDN )); |
| ue_ctxt->setMsisdn(ueMSISDN); |
| ue_ctxt->setRauTauTimer(ula_msg.RAU_TAU_timer); |
| ue_ctxt->setSubscriptionStatus(ula_msg.subscription_status); |
| ue_ctxt->setNetAccessMode(ula_msg.net_access_mode); |
| ue_ctxt->setAccessRestrictionData(ula_msg.access_restriction_data); |
| |
| struct AMBR ambr; |
| ambr.max_requested_bw_dl = ula_msg.max_requested_bw_dl; |
| ambr.max_requested_bw_ul = ula_msg.max_requested_bw_ul; |
| |
| ue_ctxt->setAmbr(Ambr(ambr)); |
| |
| ProcedureStats::num_of_processed_ula ++; |
| log_msg(LOG_DEBUG, "Leaving handle_ula_v \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::auth_req_to_ue(SM::ControlBlock& cb) |
| { |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "auth_req_to_ue: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| authreq_info authreq; |
| authreq.msg_type = auth_request; |
| authreq.ue_idx = ue_ctxt->getContextID(); |
| authreq.enb_fd = ue_ctxt->getEnbFd(); |
| authreq.enb_s1ap_ue_id = ue_ctxt->getS1apEnbUeId(); |
| |
| ue_ctxt->setDwnLnkSeqNo(0); |
| |
| E_UTRAN_sec_vector *secVect = const_cast<E_UTRAN_sec_vector*>(ue_ctxt->getAiaSecInfo().AiaSecInfo_mp); |
| |
| secinfo& secInfo = const_cast<secinfo&>(ue_ctxt->getUeSecInfo().secinfo_m); |
| |
| SecUtils::create_integrity_key(secVect->kasme.val, secInfo.int_key); |
| |
| memcpy(&(authreq.rand), &(secVect->rand.val), NAS_RAND_SIZE); |
| memcpy(&(authreq.autn), &(secVect->autn.val), NAS_AUTN_SIZE); |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s1apAppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &authreq, sizeof(authreq), destAddr); |
| |
| |
| ProcedureStats::num_of_auth_req_to_ue_sent ++; |
| log_msg(LOG_DEBUG, "Leaving auth_req_to_ue_v \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::auth_response_validate(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside auth_response_validate \n"); |
| SM::ControlBlock* controlBlk_p = SubsDataGroupManager::Instance()->findControlBlock(cb.getCBIndex()); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "auth_response_validate: ue context or procedure ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MsgBuffer* msgBuf = static_cast<MsgBuffer*>(cb.getMsgData()); |
| |
| if (msgBuf == NULL) |
| return ActStatus::HALT; |
| |
| const s1_incoming_msg_data_t* s1_msg_data = static_cast<const s1_incoming_msg_data_t*>(msgBuf->getDataPointer()); |
| const struct authresp_Q_msg &auth_resp = s1_msg_data->msg_data.authresp_Q_msg_m; |
| |
| /*Check the state*/ |
| if(SUCCESS != auth_resp.status) { |
| log_msg(LOG_ERROR, "eNB authentication failure for UE-%d.\n", ue_ctxt->getContextID()); |
| if(auth_resp.auts.len == 0) |
| { |
| log_msg(LOG_ERROR,"No AUTS.Not Synch Failure\n"); |
| SM::Event evt(Event_e::AUTH_RESP_FAILURE,NULL); |
| controlBlk_p->addEventToProcQ(evt); |
| } |
| else |
| { |
| log_msg(LOG_INFO,"AUTS recvd. Synch failure. send AIR\n"); |
| SM::Event evt(Event_e::AUTH_RESP_SYNC_FAILURE,NULL); |
| controlBlk_p->addEventToProcQ(evt); |
| } |
| } |
| else{ |
| log_msg(LOG_INFO,"Auth response validation success. Proceeding to Sec mode Command\n"); |
| SM::Event evt(Event_e::AUTH_RESP_SUCCESS,NULL); |
| controlBlk_p->addEventToProcQ(evt); |
| |
| } |
| //TODO: XRES comparison |
| #if 0 |
| log_msg(LOG_ERROR, "stage 3 processing memcmp - %d, %d, %d", &(ue_ctxt->getaiaSecInfo().AiaSecInfo_mp->xres.val), |
| &(auth_resp->res.val), |
| auth_resp->res.len); |
| if(memcmp(&(ue_ctxt->getaiaSecInfo().AiaSecInfo_mp->xres.val), |
| &(auth_resp->res.val), |
| auth_resp->res.len) != 0) { |
| log_msg(LOG_ERROR, "Invalid auth result received for UE %d", |
| auth_resp->ue_idx); |
| return E_FAIL;//report failure |
| } |
| #endif |
| |
| ProcedureStats::num_of_processed_auth_response ++; |
| log_msg(LOG_DEBUG, "Leaving auth_response_validate \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::send_auth_reject(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside send_auth_reject \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_auth_reject: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| return ActStatus::HALT; |
| } |
| |
| |
| ActStatus ActionHandlers::sec_mode_cmd_to_ue(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside sec_mode_cmd_to_ue \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "sec_mode_cmd_to_ue: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| sec_mode_Q_msg sec_mode_msg; |
| sec_mode_msg.msg_type = sec_mode_command; |
| sec_mode_msg.ue_idx = ue_ctxt->getContextID(); |
| sec_mode_msg.enb_fd = ue_ctxt->getEnbFd(); |
| sec_mode_msg.enb_s1ap_ue_id = ue_ctxt->getS1apEnbUeId(); |
| |
| memcpy(&(sec_mode_msg.ue_network), &(ue_ctxt->getUeNetCapab().ue_net_capab_m), |
| sizeof(struct UE_net_capab)); |
| |
| memcpy(&(sec_mode_msg.ms_net_capab), &(ue_ctxt->getMsNetCapab().ms_net_capab_m), |
| sizeof(struct MS_net_capab)); |
| |
| memcpy(&(sec_mode_msg.key), &(ue_ctxt->getAiaSecInfo().AiaSecInfo_mp->kasme), |
| sizeof(struct KASME)); |
| |
| memcpy(&(sec_mode_msg.int_key), &(ue_ctxt->getUeSecInfo().secinfo_m.int_key), |
| NAS_INT_KEY_SIZE); |
| |
| sec_mode_msg.dl_seq_no = ue_ctxt->getDwnLnkSeqNo(); |
| ue_ctxt->setDwnLnkSeqNo(sec_mode_msg.dl_seq_no + 1); |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s1apAppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &sec_mode_msg, sizeof(sec_mode_msg), destAddr); |
| |
| ProcedureStats::num_of_sec_mode_cmd_to_ue_sent ++; |
| log_msg(LOG_DEBUG, "Leaving sec_mode_cmd_to_ue \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| |
| ActStatus ActionHandlers::process_sec_mode_resp(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside handle_sec_mode_resp \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "handle_sec_mode_resp: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MsgBuffer* msgBuf = static_cast<MsgBuffer*>(cb.getMsgData()); |
| |
| if (msgBuf == NULL) |
| return ActStatus::HALT; |
| |
| const s1_incoming_msg_data_t* s1_msg_data = static_cast<const s1_incoming_msg_data_t*>(msgBuf->getDataPointer()); |
| const secmode_resp_Q_msg &secmode_resp = s1_msg_data->msg_data.secmode_resp_Q_msg_m; |
| if(SUCCESS == secmode_resp.status) |
| { |
| log_msg(LOG_INFO, "Sec mode complete rcv. UE - %d.\n", |
| ue_ctxt->getContextID()); |
| |
| } |
| else |
| { |
| log_msg(LOG_INFO, "Sec mode failed. UE %d", ue_ctxt->getContextID()); |
| } |
| |
| ProcedureStats::num_of_processed_sec_mode_resp ++; |
| log_msg(LOG_DEBUG, "Leaving handle_sec_mode_resp \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::check_esm_info_req_required(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside check_esm_info_req_required \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "check_esm_info_req_required: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MmeProcedureCtxt* procedure_p = dynamic_cast<MmeProcedureCtxt*>(cb.getTempDataBlock()); |
| if (procedure_p == NULL) |
| { |
| log_msg(LOG_DEBUG, "check_esm_info_req_required: procedure context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| SessionContext* sessionCtxt = SubsDataGroupManager::Instance()->getSessionContext(); |
| if( sessionCtxt == NULL ) |
| { |
| log_msg(LOG_ERROR, "Failed to allocate Session Context for UE IDX %d\n", cb.getCBIndex()); |
| |
| return ActStatus::HALT; |
| } |
| BearerContext* bearerCtxt_p = SubsDataGroupManager::Instance()->getBearerContext(); |
| if( bearerCtxt_p == NULL ) |
| { |
| log_msg(LOG_ERROR, "Failed to allocate Bearer context for UE IDx %d\n", cb.getCBIndex()); |
| |
| return ActStatus::HALT; |
| } |
| |
| bearerCtxt_p->setBearerId(5); |
| sessionCtxt->setPti(procedure_p->getPti()); |
| sessionCtxt->setBearerContext( bearerCtxt_p ); |
| ue_ctxt->setSessionContext(sessionCtxt); |
| |
| if (procedure_p->getEsmInfoTxRequired() == false) |
| { |
| // hardcoding APN, if ESM info request is not to be sent |
| std::string apnName = "apn1"; |
| struct apn_name apn = {0}; |
| apn.len = apnName.length() + 1; |
| apn.val[0] = apnName.length(); |
| memcpy(&(apn.val[1]), apnName.c_str(), apnName.length()); |
| |
| sessionCtxt->setAccessPtName(Apn_name(apn)); |
| |
| SM::Event evt(Event_e::ESM_INFO_NOT_REQUIRED, NULL); |
| cb.addEventToProcQ(evt); |
| } |
| else |
| { |
| SM::Event evt(Event_e::ESM_INFO_REQUIRED, NULL); |
| cb.addEventToProcQ(evt); |
| } |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::send_esm_info_req_to_ue(SM::ControlBlock& cb) |
| { |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_esm_info_req_to_ue: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| SessionContext *sessionCtxt = ue_ctxt->getSessionContext(); |
| esm_req_Q_msg esmreq; |
| esmreq.msg_type = esm_info_request; |
| esmreq.ue_idx = ue_ctxt->getContextID(); |
| esmreq.enb_fd = ue_ctxt->getEnbFd(); |
| esmreq.enb_s1ap_ue_id = ue_ctxt->getS1apEnbUeId(); |
| esmreq.pti = sessionCtxt->getPti(); |
| esmreq.dl_seq_no = ue_ctxt->getDwnLnkSeqNo(); |
| memcpy(&(esmreq.int_key), &((ue_ctxt->getUeSecInfo().secinfo_m).int_key), |
| NAS_INT_KEY_SIZE); |
| ue_ctxt->setDwnLnkSeqNo(esmreq.dl_seq_no+1); |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s1apAppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &esmreq, sizeof(esmreq), destAddr); |
| |
| log_msg(LOG_DEBUG, "Leaving send_esm_info_req_to_ue \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::process_esm_info_resp(SM::ControlBlock& cb) |
| { |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "handle_ula: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| SessionContext* sessionCtxt = ue_ctxt->getSessionContext(); |
| if( sessionCtxt == NULL ) |
| { |
| log_msg(LOG_ERROR, "Failed to allocate Session " |
| "Context for UE IDX %d\n", cb.getCBIndex()); |
| return ActStatus::HALT; |
| } |
| |
| MsgBuffer* msgBuf = static_cast<MsgBuffer*>(cb.getMsgData()); |
| |
| if (msgBuf == NULL) |
| return ActStatus::HALT; |
| |
| const s1_incoming_msg_data_t* s1_msg_data = static_cast<const s1_incoming_msg_data_t*>(msgBuf->getDataPointer()); |
| const struct esm_resp_Q_msg &esm_res =s1_msg_data->msg_data.esm_resp_Q_msg_m; |
| |
| sessionCtxt->setAccessPtName(Apn_name(esm_res.apn)); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::cs_req_to_sgw(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside cs_req_to_sgw \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| MmeProcedureCtxt *procCtxt = dynamic_cast<MmeProcedureCtxt*>(cb.getTempDataBlock()); |
| if (ue_ctxt == NULL || procCtxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "handle_ula: UE context or Procedure Context is NULL \n"); |
| |
| return ActStatus::HALT; |
| } |
| |
| SessionContext* sessionCtxt = ue_ctxt->getSessionContext(); |
| if( sessionCtxt == NULL ) |
| { |
| log_msg(LOG_ERROR, "Failed to allocate Session Context for UE IDX %d\n", cb.getCBIndex()); |
| |
| return ActStatus::HALT; |
| } |
| |
| BearerContext* bearerCtxt_p = sessionCtxt->getBearerContext(); |
| if( bearerCtxt_p == NULL ) |
| { |
| log_msg(LOG_ERROR, "Failed to allocate Bearer context for UE IDx %d\n", cb.getCBIndex()); |
| |
| return ActStatus::HALT; |
| } |
| |
| struct CS_Q_msg cs_msg; |
| cs_msg.msg_type = create_session_request; |
| cs_msg.ue_idx = ue_ctxt->getContextID(); |
| |
| const DigitRegister15& ueImsi = ue_ctxt->getImsi(); |
| ueImsi.convertToBcdArray( cs_msg.IMSI ); |
| |
| /*uint8_t plmn_id[3] = {0}; |
| memcpy(plmn_id, ue_ctxt->gettai().tai_m.plmn_id.idx, 3); |
| if ((plmn_id[1] & 0xF0) == 0xF0) |
| plmn_id[1] = plmn_id[1] & 0x0F; |
| |
| const Apn_name &apnName = sessionCtxt->getaccessPtName(); |
| std::string apnStr((const char *)apnName.apnname_m.val, apnName.apnname_m.len); |
| |
| stringstream formattedApn; |
| formattedApn << apnStr << |
| "\x6" << "mnc" << |
| ((plmn_id[1] & 0xF0) >> 4) << |
| (plmn_id[2] & 0x0F) << |
| ((plmn_id[2] & 0xF0) >> 4) << |
| "\x6" << "mcc" << |
| (plmn_id[0] & 0x0F) << |
| ((plmn_id[0] & 0xF0) >> 4) << |
| ((plmn_id[1] & 0x0F)) << |
| "\x4" << "gprs"; |
| |
| uint32_t formattedApnLen = formattedApn.str().length(); |
| cs_msg.apn.len = formattedApnLen + 1; |
| cs_msg.apn.val[0] = apnStr.length(); |
| memcpy(&cs_msg.apn.val[1], formattedApn.str().c_str(), |
| formattedApn.str().length()); */ |
| |
| const Apn_name &apnName = sessionCtxt->getAccessPtName(); |
| memcpy(&(cs_msg.apn), &(apnName.apnname_m), sizeof(struct apn_name)); |
| memcpy(&(cs_msg.tai), &(ue_ctxt->getTai().tai_m), sizeof(struct TAI)); |
| memcpy(&(cs_msg.utran_cgi), &(ue_ctxt->getUtranCgi().cgi_m), sizeof(struct CGI)); |
| memcpy(&(cs_msg.pco_options[0]), procCtxt->getPcoOptions(),sizeof(cs_msg.pco_options)); |
| |
| const AMBR& ambr = ue_ctxt->getAmbr().ambr_m; |
| |
| cs_msg.max_requested_bw_dl = ambr.max_requested_bw_dl; |
| cs_msg.max_requested_bw_ul = ambr.max_requested_bw_ul; |
| |
| memset(cs_msg.MSISDN, 0, BINARY_IMSI_LEN); |
| |
| const DigitRegister15& ueMSISDN = ue_ctxt->getMsisdn(); |
| ueMSISDN.convertToBcdArray(cs_msg.MSISDN); |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s11AppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &cs_msg, sizeof(cs_msg), destAddr); |
| |
| ProcedureStats::num_of_cs_req_to_sgw_sent ++; |
| log_msg(LOG_DEBUG, "Leaving cs_req_to_sgw \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::process_cs_resp(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Entering handle_cs_resp \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "handle_cs_resp: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| SessionContext* sessionCtxt = ue_ctxt->getSessionContext(); |
| if (sessionCtxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "handle_cs_resp: session ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MsgBuffer* msgBuf = static_cast<MsgBuffer*>(cb.getMsgData()); |
| |
| if (msgBuf == NULL) |
| return ActStatus::HALT; |
| |
| const gtp_incoming_msg_data_t* gtp_msg_data= static_cast<const gtp_incoming_msg_data_t*>(msgBuf->getDataPointer()); |
| const struct csr_Q_msg& csr_info = gtp_msg_data->msg_data.csr_Q_msg_m; |
| |
| BearerContext* bearerCtxt = sessionCtxt->getBearerContext(); |
| if( bearerCtxt == NULL ) |
| { |
| log_msg(LOG_ERROR, "Failed to retrive Bearer context for UE IDx %d\n", cb.getCBIndex()); |
| |
| return ActStatus::HALT; |
| } |
| |
| sessionCtxt->setS11SgwCtrlFteid(Fteid(csr_info.s11_sgw_fteid)); |
| sessionCtxt->setS5S8PgwCtrlFteid(Fteid(csr_info.s5s8_pgwc_fteid)); |
| |
| bearerCtxt->setS1uSgwUserFteid(Fteid(csr_info.s1u_sgw_fteid)); |
| bearerCtxt->setS5S8PgwUserFteid(Fteid(csr_info.s5s8_pgwu_fteid)); |
| |
| sessionCtxt->setPdnAddr(Paa(csr_info.pdn_addr)); |
| |
| ProcedureStats::num_of_processed_cs_resp ++; |
| log_msg(LOG_DEBUG, "Leaving handle_cs_resp \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::send_init_ctxt_req_to_ue(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside send_init_ctxt_req_to_ue \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL ) |
| { |
| log_msg(LOG_DEBUG, "send_init_ctxt_req_to_ue: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MmeProcedureCtxt* procedure_p = dynamic_cast<MmeProcedureCtxt*>(cb.getTempDataBlock()); |
| if (procedure_p == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_init_ctxt_req_to_ue: procedure context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| if (procedure_p->getAttachType() == imsiAttach_c || |
| procedure_p->getAttachType() == unknownGutiAttach_c) |
| { |
| uint32_t mTmsi = MmeCommonUtils::allocateMtmsi(); |
| if (mTmsi == 0) |
| { |
| log_msg(LOG_DEBUG, "send_init_ctxt_req_to_ue: Failed to allocate mTmsi \n"); |
| return ActStatus::HALT; |
| } |
| |
| ue_ctxt->setMtmsi(mTmsi); |
| |
| // TODO: Should this be done here or attach_done method |
| SubsDataGroupManager::Instance()->addmTmsikey(mTmsi, ue_ctxt->getContextID()); |
| } |
| |
| SessionContext* sessionCtxt = ue_ctxt->getSessionContext(); |
| if (sessionCtxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_init_ctxt_req_to_ue: session ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| unsigned int nas_count = 0; |
| E_UTRAN_sec_vector* secVect = const_cast<E_UTRAN_sec_vector*>(ue_ctxt->getAiaSecInfo().AiaSecInfo_mp); |
| secinfo& secInfo = const_cast<secinfo&>(ue_ctxt->getUeSecInfo().secinfo_m); |
| |
| SecUtils::create_kenb_key(secVect->kasme.val, secInfo.kenb_key, nas_count); |
| |
| init_ctx_req_Q_msg icr_msg; |
| icr_msg.msg_type = init_ctxt_request; |
| icr_msg.ue_idx = ue_ctxt->getContextID(); |
| icr_msg.enb_fd = ue_ctxt->getEnbFd(); |
| icr_msg.enb_s1ap_ue_id = ue_ctxt->getS1apEnbUeId(); |
| |
| icr_msg.exg_max_dl_bitrate = (ue_ctxt->getAmbr().ambr_m).max_requested_bw_dl; |
| icr_msg.exg_max_ul_bitrate = (ue_ctxt->getAmbr().ambr_m).max_requested_bw_ul; |
| BearerContext* bearerCtxt = sessionCtxt->getBearerContext(); |
| if( bearerCtxt == NULL ) |
| { |
| log_msg(LOG_ERROR, "Failed to retrive Bearer context for UE IDx %d\n", cb.getCBIndex()); |
| |
| return ActStatus::HALT; |
| } |
| |
| icr_msg.bearer_id = bearerCtxt->getBearerId(); |
| |
| icr_msg.dl_seq_no = ue_ctxt->getDwnLnkSeqNo(); |
| memcpy(&(icr_msg.tai), &(ue_ctxt->getTai().tai_m), sizeof(struct TAI)); |
| memcpy(&(icr_msg.gtp_teid), &(bearerCtxt->getS1uSgwUserFteid().fteid_m), sizeof(struct fteid)); |
| memcpy(&(icr_msg.apn), &(sessionCtxt->getAccessPtName().apnname_m), sizeof(struct apn_name)); |
| memcpy(&(icr_msg.pdn_addr), &(sessionCtxt->getPdnAddr().paa_m), sizeof(struct PAA)); |
| memcpy(&(icr_msg.int_key), &((ue_ctxt->getUeSecInfo().secinfo_m).int_key), |
| NAS_INT_KEY_SIZE); |
| memcpy(&(icr_msg.sec_key), &((ue_ctxt->getUeSecInfo().secinfo_m).kenb_key), |
| KENB_SIZE); |
| icr_msg.pti = sessionCtxt->getPti(); |
| icr_msg.m_tmsi = ue_ctxt->getMtmsi(); |
| ue_ctxt->setDwnLnkSeqNo(icr_msg.dl_seq_no+1); |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s1apAppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &icr_msg, sizeof(icr_msg), destAddr); |
| |
| ProcedureStats::num_of_init_ctxt_req_to_ue_sent ++; |
| log_msg(LOG_DEBUG, "Leaving send_init_ctxt_req_to_ue_v \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::process_init_ctxt_resp(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside process_init_ctxt_resp \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| MmeProcedureCtxt *procCtxt = dynamic_cast<MmeProcedureCtxt*>(cb.getTempDataBlock()); |
| |
| if (ue_ctxt == NULL || procCtxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "process_init_ctxt_resp: ue context or procedure ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| SessionContext* sessionCtxt = ue_ctxt->getSessionContext(); |
| if (sessionCtxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "process_init_ctxt_resp: session ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MsgBuffer* msgBuf = static_cast<MsgBuffer*>(cb.getMsgData()); |
| |
| if (msgBuf == NULL) |
| return ActStatus::HALT; |
| |
| const s1_incoming_msg_data_t* s1_msg_data = static_cast<const s1_incoming_msg_data_t*>(msgBuf->getDataPointer()); |
| const struct initctx_resp_Q_msg &ics_res =s1_msg_data->msg_data.initctx_resp_Q_msg_m; |
| |
| fteid S1uEnbUserFteid; |
| S1uEnbUserFteid.header.iface_type = 0; |
| S1uEnbUserFteid.header.v4 = 1; |
| S1uEnbUserFteid.header.teid_gre = ics_res.gtp_teid; |
| S1uEnbUserFteid.ip.ipv4 = *(struct in_addr*)&ics_res.transp_layer_addr; |
| |
| BearerContext* bearerCtxt = sessionCtxt->getBearerContext(); |
| if (bearerCtxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "process_init_ctxt_resp: bearer ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| bearerCtxt->setS1uEnbUserFteid(Fteid(S1uEnbUserFteid)); |
| |
| ProcedureStats::num_of_processed_init_ctxt_resp ++; |
| log_msg(LOG_DEBUG, "Leaving process_init_ctxt_resp \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::send_mb_req_to_sgw(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside send_mb_req_to_sgw \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_mb_req_to_sgw: ue context or procedure ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| SessionContext* sessionCtxt = ue_ctxt->getSessionContext(); |
| if (sessionCtxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_mb_req_to_sgw: session ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| struct MB_Q_msg mb_msg; |
| mb_msg.msg_type = modify_bearer_request; |
| mb_msg.ue_idx = ue_ctxt->getContextID(); |
| |
| memset(mb_msg.indication, 0, S11_MB_INDICATION_FLAG_SIZE); /*TODO : future*/ |
| BearerContext* bearerCtxt = sessionCtxt->getBearerContext(); |
| if (bearerCtxt == NULL) |
| { |
| log_msg(LOG_DEBUG, "send_mb_req_to_sgw: bearer ctxt is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| mb_msg.bearer_id = bearerCtxt->getBearerId(); |
| |
| memcpy(&(mb_msg.s11_sgw_c_fteid), &(sessionCtxt->getS11SgwCtrlFteid().fteid_m), |
| sizeof(struct fteid)); |
| |
| memcpy(&(mb_msg.s1u_enb_fteid), &(bearerCtxt->getS1uEnbUserFteid().fteid_m), |
| sizeof(struct fteid)); |
| |
| |
| cmn::ipc::IpcAddress destAddr; |
| destAddr.u32 = TipcServiceInstance::s11AppInstanceNum_c; |
| |
| mmeIpcIf_g->dispatchIpcMsg((char *) &mb_msg, sizeof(mb_msg), destAddr); |
| |
| ProcedureStats::num_of_mb_req_to_sgw_sent ++; |
| log_msg(LOG_DEBUG, "Leaving send_mb_req_to_sgw \n"); |
| |
| return ActStatus::PROCEED; |
| |
| } |
| |
| ActStatus ActionHandlers::process_attach_cmp_from_ue(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside handle_attach_cmp_from_ue \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_ERROR, "attach_done: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| ue_ctxt->setUpLnkSeqNo(ue_ctxt->getUpLnkSeqNo()+1); |
| |
| ProcedureStats::num_of_processed_attach_cmp_from_ue ++; |
| log_msg(LOG_DEBUG, "Leaving handle_attach_cmp_from_ue \n"); |
| |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::process_mb_resp(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside handle_mb_resp \n"); |
| ProcedureStats::num_of_processed_mb_resp ++; |
| return ActStatus::PROCEED; |
| } |
| |
| ActStatus ActionHandlers::attach_done(SM::ControlBlock& cb) |
| { |
| log_msg(LOG_DEBUG, "Inside attach_done \n"); |
| |
| UEContext *ue_ctxt = dynamic_cast<UEContext*>(cb.getPermDataBlock()); |
| if (ue_ctxt == NULL) |
| { |
| log_msg(LOG_ERROR, "attach_done: ue context is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| MmContext* mmCtxt = ue_ctxt->getMmContext(); |
| if (mmCtxt == NULL) |
| { |
| log_msg(LOG_ERROR, "attach_done: MMcontext is NULL \n"); |
| return ActStatus::HALT; |
| } |
| |
| mmCtxt->setMmState(EpsAttached); |
| |
| MmeContextManagerUtils::deallocateProcedureCtxt(cb, attach_c); |
| |
| ProcedureStats::num_of_attach_done++; |
| ProcedureStats::num_of_subscribers_attached ++; |
| |
| log_msg(LOG_DEBUG,"Leaving attach done\n"); |
| |
| return ActStatus::PROCEED; |
| } |