/******************************************************************************* OpenAirInterface Copyright(c) 1999 - 2014 Eurecom OpenAirInterface is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenAirInterface is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenAirInterface.The full GNU General Public License is included in this distribution in the file called "COPYING". If not, see <http://www.gnu.org/licenses/>. Contact Information OpenAirInterface Admin: openair_admin@eurecom.fr OpenAirInterface Tech : openair_tech@eurecom.fr OpenAirInterface Dev : openair4g-devel@eurecom.fr Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France. *******************************************************************************/ /***************************************************************************** Source emm_cn.c Version 0.1 Date 2013/12/05 Product NAS stack Subsystem EPS Core Network Author Sebastien Roux, Lionel GAUTHIER Description *****************************************************************************/ #include <string.h> #if defined(NAS_BUILT_IN_EPC) #include "nas_log.h" #include "commonDef.h" #include "emm_cn.h" #include "emm_sap.h" #include "emm_proc.h" #include "emm_cause.h" #include "esm_send.h" // LG #include "esm_proc.h" // LG #include "esm_cause.h" // LG #include "assertions.h"// LG #include "emmData.h" // LG #include "esm_sap.h" // LG #include "EmmCommon.h" // LG extern int emm_cn_wrapper_attach_accept(emm_data_context_t *emm_ctx, void *data); /* * Internal data used for attach procedure */ typedef struct { unsigned int ueid; /* UE identifier */ #define ATTACH_COUNTER_MAX 5 unsigned int retransmission_count; /* Retransmission counter */ OctetString esm_msg; /* ESM message to be sent within * the Attach Accept message */ } attach_data_t; /* * String representation of EMMCN-SAP primitives */ static const char *_emm_cn_primitive_str[] = { "EMM_CN_AUTHENTICATION_PARAM_RES", "EMM_CN_AUTHENTICATION_PARAM_FAIL", "EMM_CN_DEREGISTER_UE", "EMM_CN_PDN_CONNECTIVITY_RES", "EMM_CN_PDN_CONNECTIVITY_FAIL", }; #define EMM_CN_SAP_BUFFER_SIZE 4096 static char _emm_cn_sap_buffer[EMM_CN_SAP_BUFFER_SIZE]; static int _emm_cn_authentication_res(const emm_cn_auth_res_t *msg) { emm_data_context_t *emm_ctx = NULL; int rc = RETURNerror; OctetString loc_rand; OctetString autn; /* We received security vector from HSS. Try to setup security with UE */ LOG_FUNC_IN; emm_ctx = emm_data_context_get(&_emm_data, msg->ue_id); if (emm_ctx == NULL) { LOG_TRACE(ERROR, "EMM-PROC - " "Failed to find UE associated to id "NAS_UE_ID_FMT"...", msg->ue_id); LOG_FUNC_RETURN (rc); } /* Copy provided vector to user context */ memcpy(emm_ctx->vector.kasme, msg->vector.kasme, AUTH_KASME_SIZE); memcpy(emm_ctx->vector.autn, msg->vector.autn, AUTH_AUTN_SIZE); memcpy(emm_ctx->vector.rand, msg->vector.rand, AUTH_RAND_SIZE); memcpy(emm_ctx->vector.xres, msg->vector.xres.data, msg->vector.xres.size); LOG_TRACE(INFO, "EMM-PROC - Received RAND ..: "RAND_FORMAT"\n", RAND_DISPLAY(msg->vector.rand)); LOG_TRACE(INFO, "EMM-PROC - Received AUTN ..: "AUTN_FORMAT"\n", AUTN_DISPLAY(msg->vector.autn)); LOG_TRACE(INFO, "EMM-PROC - Received KASME .: "KASME_FORMAT" "KASME_FORMAT"\n", KASME_DISPLAY_1(msg->vector.kasme), KASME_DISPLAY_2(msg->vector.kasme)); loc_rand.value = emm_ctx->vector.rand; loc_rand.length = AUTH_RAND_SIZE; autn.value = emm_ctx->vector.autn; autn.length = AUTH_AUTN_SIZE; emm_ctx->vector.xres_size = msg->vector.xres.size; /* 3GPP TS 24.401, Figure 5.3.2.1-1, point 5a * No EMM context exists for the UE in the network; authentication * and NAS security setup to activate integrity protection and NAS * ciphering are mandatory. */ rc = emm_proc_authentication(emm_ctx, emm_ctx->ueid, 0, // TODO: eksi != 0 &loc_rand, &autn, emm_attach_security, NULL, NULL); if (rc != RETURNok) { /* Failed to initiate the authentication procedure */ LOG_TRACE(WARNING, "EMM-PROC - " "Failed to initiate authentication procedure"); emm_ctx->emm_cause = EMM_CAUSE_ILLEGAL_UE; } LOG_FUNC_RETURN (rc); } static int _emm_cn_authentication_fail(const emm_cn_auth_fail_t *msg) { int rc = RETURNerror; LOG_FUNC_IN; rc = emm_proc_attach_reject(msg->ue_id, msg->cause); LOG_FUNC_RETURN (rc); } static int _emm_cn_deregister_ue(const uint32_t ue_id) { int rc = RETURNok; LOG_FUNC_IN; LOG_TRACE(WARNING, "EMM-PROC - " "TODO deregister UE "NAS_UE_ID_FMT", following procedure is a test", ue_id); emm_proc_detach_request(ue_id, EMM_DETACH_TYPE_EPS /* ??? emm_proc_detach_type_t*/, 1 /*switch_off*/, 0 /*native_ksi*/, 0 /*ksi*/, NULL /*guti*/, NULL /*imsi*/, NULL /*imei*/); LOG_FUNC_RETURN (rc); } static int _emm_cn_pdn_connectivity_res(const emm_cn_pdn_res_t *msg_pP) { int rc = RETURNok; struct emm_data_context_s *emm_ctx_p = NULL; esm_proc_pdn_type_t esm_pdn_type = ESM_PDN_TYPE_IPV4; esm_proc_data_t *esm_proc_data_p = NULL; ESM_msg esm_msg; EpsQualityOfService qos; ProtocolConfigurationOptions pco; unsigned int pco_in_index = 0; signed int length_in_pco = 0; uint16_t pi_or_ci = 0; // protocol identifier or container identifier; uint8_t length_pi_or_ci = 0; OctetString rsp = { 0, NULL}; int is_standalone = 0; // warning hardcoded int triggered_by_ue = 1; // warning hardcoded attach_data_t *data_p = NULL; int esm_cause = ESM_CAUSE_SUCCESS; int pid = 0; unsigned int new_ebi = 0; LOG_FUNC_IN; emm_ctx_p = emm_data_context_get(&_emm_data, msg_pP->ue_id); if (emm_ctx_p == NULL) { LOG_TRACE(ERROR, "EMMCN-SAP - " "Failed to find UE associated to id "NAS_UE_ID_FMT"...", msg_pP->ue_id); LOG_FUNC_RETURN (rc); } memset(&esm_msg, 0 , sizeof(ESM_msg)); switch (msg_pP->pdn_type) { case IPv4: LOG_TRACE(INFO, "EMM - esm_pdn_type = ESM_PDN_TYPE_IPV4"); esm_pdn_type = ESM_PDN_TYPE_IPV4; break; case IPv6: LOG_TRACE(INFO, "EMM - esm_pdn_type = ESM_PDN_TYPE_IPV6"); esm_pdn_type = ESM_PDN_TYPE_IPV6; break; case IPv4_AND_v6: LOG_TRACE(INFO, "EMM - esm_pdn_type = ESM_PDN_TYPE_IPV4V6"); esm_pdn_type = ESM_PDN_TYPE_IPV4V6; break; default: LOG_TRACE(INFO, "EMM - esm_pdn_type = ESM_PDN_TYPE_IPV4 (forced to default)"); esm_pdn_type = ESM_PDN_TYPE_IPV4; } LOG_TRACE(INFO, "EMM - qci = %u ", msg_pP->qci); LOG_TRACE(INFO, "EMM - qos.qci = %u ", msg_pP->qos.qci); LOG_TRACE(INFO, "EMM - qos.mbrUL = %u ", msg_pP->qos.mbrUL); LOG_TRACE(INFO, "EMM - qos.mbrDL = %u ", msg_pP->qos.mbrDL); LOG_TRACE(INFO, "EMM - qos.gbrUL = %u ", msg_pP->qos.gbrUL); LOG_TRACE(INFO, "EMM - qos.gbrDL = %u ", msg_pP->qos.gbrDL); qos.bitRatesPresent = 0; qos.bitRatesExtPresent = 0; #warning "Some work to do here about qos" qos.qci = msg_pP->qci; qos.bitRates.maxBitRateForUL = 0;//msg_pP->qos.mbrUL; qos.bitRates.maxBitRateForDL = 0;//msg_pP->qos.mbrDL; qos.bitRates.guarBitRateForUL = 0;//msg_pP->qos.gbrUL; qos.bitRates.guarBitRateForDL = 0;//msg_pP->qos.gbrDL; qos.bitRatesExt.maxBitRateForUL = 0; qos.bitRatesExt.maxBitRateForDL = 0; qos.bitRatesExt.guarBitRateForUL = 0; qos.bitRatesExt.guarBitRateForDL = 0; //-------------------------------------------------------------------------- // PCO processing //-------------------------------------------------------------------------- memset(&pco, 0, sizeof(ProtocolConfigurationOptions)); length_in_pco = msg_pP->pco.byte[1]; if ((length_in_pco+1+1) != msg_pP->pco.length) { LOG_TRACE(WARNING, "PCO: mismatch in lengths length_pco+1+1 %u != msg_pP->pco.length %u\n", length_in_pco+1+1, msg_pP->pco.length); } pco.configurationprotol = msg_pP->pco.byte[2] & 0x07; for (int i = 0; i < msg_pP->pco.length; i++) { LOG_TRACE(WARNING, "EMMCN_PDN_CONNECTIVITY_RES.pco.byte[%u] = 0x%x", i, msg_pP->pco.byte[i]); } if ((length_in_pco > 0) && (msg_pP->pco.byte[2] & 0x80)) { pco_in_index = PCO_MIN_LENGTH; while (length_in_pco >= 3) { pi_or_ci = (((uint16_t)msg_pP->pco.byte[pco_in_index]) << 8) | (uint16_t)msg_pP->pco.byte[pco_in_index+1]; pco_in_index += 2; length_pi_or_ci = msg_pP->pco.byte[pco_in_index++]; pco.protocolid[pco.num_protocol_id_or_container_id] = pi_or_ci; pco.lengthofprotocolid[pco.num_protocol_id_or_container_id] = length_pi_or_ci; pco.protocolidcontents[pco.num_protocol_id_or_container_id].value = malloc(length_pi_or_ci); pco.protocolidcontents[pco.num_protocol_id_or_container_id].length = length_pi_or_ci; memcpy(pco.protocolidcontents[pco.num_protocol_id_or_container_id].value, &msg_pP->pco.byte[pco_in_index], length_pi_or_ci); LOG_TRACE(WARNING, "PCO: Found pi_or_ci 0x%x length %u content %s\n", pi_or_ci, length_pi_or_ci, dump_octet_string(&pco.protocolidcontents[pco.num_protocol_id_or_container_id])); pco.num_protocol_id_or_container_id++; pco_in_index += length_pi_or_ci; length_in_pco = length_in_pco - (length_pi_or_ci + 2 + 1); } // while (length_in_pco >= 3) { } // if ((length_in_pco > 0) && (msg_pP->pco.byte[2] & 0x80)) { /*************************************************************************/ /* CODE THAT WAS IN esm_recv.c/esm_recv_pdn_connectivity_request() */ /*************************************************************************/ /* Execute the PDN connectivity procedure requested by the UE */ pid = esm_proc_pdn_connectivity_request( emm_ctx_p, msg_pP->pti, msg_pP->request_type, &msg_pP->apn, esm_pdn_type, &msg_pP->pdn_addr, NULL, &esm_cause); LOG_TRACE(INFO, "EMM - APN = %s ", (char *)(msg_pP->apn.value)); if (pid != RETURNerror) { /* Create local default EPS bearer context */ rc = esm_proc_default_eps_bearer_context( emm_ctx_p, pid, &new_ebi, &msg_pP->qos, &esm_cause); if (rc != RETURNerror) { esm_cause = ESM_CAUSE_SUCCESS; } } else { LOG_FUNC_RETURN (rc); } /**************************************************************************/ /* END OF CODE THAT WAS IN esm_recv.c/esm_recv_pdn_connectivity_request() */ /**************************************************************************/ LOG_TRACE(INFO, "EMM - APN = %s ", (char *)(msg_pP->apn.value)); /*************************************************************************/ /* CODE THAT WAS IN esm_sap.c/_esm_sap_recv() */ /*************************************************************************/ /* Return default EPS bearer context request message */ rc = esm_send_activate_default_eps_bearer_context_request( msg_pP->pti, new_ebi, //msg_pP->ebi, &esm_msg.activate_default_eps_bearer_context_request, &msg_pP->apn, &pco, esm_pdn_type, &msg_pP->pdn_addr, &qos, ESM_CAUSE_SUCCESS); if (rc != RETURNerror) { /* Encode the returned ESM response message */ int size = esm_msg_encode(&esm_msg, (uint8_t *)_emm_cn_sap_buffer, EMM_CN_SAP_BUFFER_SIZE); LOG_TRACE(INFO, "ESM encoded MSG size %d ", size); if (size > 0) { rsp.length = size; rsp.value = (uint8_t *)(_emm_cn_sap_buffer); } /* Complete the relevant ESM procedure */ rc = esm_proc_default_eps_bearer_context_request( is_standalone, emm_ctx_p, new_ebi, //0, //ESM_EBI_UNASSIGNED, //msg->ebi, &rsp, triggered_by_ue); if (rc != RETURNok) { /* Return indication that ESM procedure failed */ LOG_FUNC_RETURN (rc); } } else { LOG_TRACE(INFO, "ESM send activate_default_eps_bearer_context_request failed"); } /*************************************************************************/ /* END OF CODE THAT WAS IN esm_sap.c/_esm_sap_recv() */ /*************************************************************************/ LOG_TRACE(INFO, "EMM - APN = %s ", (char *)(msg_pP->apn.value)); data_p = (attach_data_t *)emm_proc_common_get_args(msg_pP->ue_id); /* Setup the ESM message container */ data_p->esm_msg.value = (uint8_t *)malloc(rsp.length); if (data_p->esm_msg.value) { data_p->esm_msg.length = rsp.length; LOG_TRACE(INFO, "EMM - copy ESM MSG %d bytes", data_p->esm_msg.length); memcpy(data_p->esm_msg.value, rsp.value, rsp.length); } else { data_p->esm_msg.length = 0; } /* Send attach accept message to the UE */ rc = emm_cn_wrapper_attach_accept(emm_ctx_p, data_p); if (rc != RETURNerror) { if (emm_ctx_p->guti_is_new && emm_ctx_p->old_guti) { /* Implicit GUTI reallocation; * Notify EMM that common procedure has been initiated */ emm_sap_t emm_sap; emm_sap.primitive = EMMREG_COMMON_PROC_REQ; emm_sap.u.emm_reg.ueid = msg_pP->ue_id; rc = emm_sap_send(&emm_sap); } } LOG_TRACE(INFO, "EMM - APN = %s ", (char *)(msg_pP->apn.value)); LOG_FUNC_RETURN (rc); } static int _emm_cn_pdn_connectivity_fail(const emm_cn_pdn_fail_t *msg) { int rc = RETURNok; LOG_FUNC_IN; LOG_FUNC_RETURN (rc); } int emm_cn_send(const emm_cn_t *msg) { int rc = RETURNerror; emm_cn_primitive_t primitive = msg->primitive; LOG_FUNC_IN; LOG_TRACE(INFO, "EMMCN-SAP - Received primitive %s (%d)", _emm_cn_primitive_str[primitive - _EMMCN_START - 1], primitive); switch (primitive) { case _EMMCN_AUTHENTICATION_PARAM_RES: rc = _emm_cn_authentication_res(msg->u.auth_res); break; case _EMMCN_AUTHENTICATION_PARAM_FAIL: rc = _emm_cn_authentication_fail(msg->u.auth_fail); break; case EMMCN_DEREGISTER_UE: rc = _emm_cn_deregister_ue(msg->u.deregister.UEid); break; case EMMCN_PDN_CONNECTIVITY_RES: rc = _emm_cn_pdn_connectivity_res(msg->u.emm_cn_pdn_res); break; case EMMCN_PDN_CONNECTIVITY_FAIL: rc = _emm_cn_pdn_connectivity_fail(msg->u.emm_cn_pdn_fail); break; default: /* Other primitives are forwarded to the Access Stratum */ rc = RETURNerror; break; } if (rc != RETURNok) { LOG_TRACE(ERROR, "EMMCN-SAP - Failed to process primitive %s (%d)", _emm_cn_primitive_str[primitive - _EMMCN_START - 1], primitive); } LOG_FUNC_RETURN (rc); } #endif