/******************************************************************************* 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 . 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 EmmCommon.h Version 0.1 Date 2013/04/19 Product NAS stack Subsystem EPS Mobility Management Author Frederic Maurel Description Defines callback functions executed within EMM common procedures by the Non-Access Stratum running at the network side. Following EMM common procedures can always be initiated by the network whilst a NAS signalling connection exists: GUTI reallocation authentication security mode control identification EMM information *****************************************************************************/ #include "EmmCommon.h" #include "commonDef.h" #include "nas_log.h" #include "emmData.h" #include // malloc, free #include #include #if defined(NAS_BUILT_IN_EPC) # include "assertions.h" #endif /****************************************************************************/ /**************** E X T E R N A L D E F I N I T I O N S ****************/ /****************************************************************************/ /****************************************************************************/ /******************* L O C A L D E F I N I T I O N S *******************/ /****************************************************************************/ /* EMM procedure callback cleanup function */ static void _emm_common_cleanup(unsigned int ueid); /* Ongoing EMM procedure callback functions */ typedef struct emm_common_data_s { unsigned int ueid; int ref_count; emm_common_success_callback_t success; emm_common_reject_callback_t reject; emm_common_failure_callback_t failure; emm_common_abort_callback_t abort; void *args; #if defined(NAS_BUILT_IN_EPC) RB_ENTRY(emm_common_data_s) entries; #endif } emm_common_data_t; #if defined(NAS_BUILT_IN_EPC) typedef struct emm_common_data_head_s { RB_HEAD(emm_common_data_map, emm_common_data_s) emm_common_data_root; } emm_common_data_head_t; emm_common_data_head_t emm_common_data_head = { RB_INITIALIZER() }; static inline int emm_common_data_compare_ueid(struct emm_common_data_s *p1, struct emm_common_data_s *p2); struct emm_common_data_s *emm_common_data_context_get( struct emm_common_data_head_s *root, unsigned int _ueid); RB_PROTOTYPE(emm_common_data_map, emm_common_data_s, entries, emm_common_data_compare_ueid); /* Generate functions used for the MAP */ RB_GENERATE(emm_common_data_map, emm_common_data_s, entries, emm_common_data_compare_ueid); static inline int emm_common_data_compare_ueid(struct emm_common_data_s *p1, struct emm_common_data_s *p2) { if (p1->ueid > p2->ueid) { return 1; } if (p1->ueid < p2->ueid) { return -1; } /* Matching reference -> return 0 */ return 0; } struct emm_common_data_s *emm_common_data_context_get( struct emm_common_data_head_s *root, unsigned int _ueid) { struct emm_common_data_s reference; DevAssert(root != NULL); DevCheck(_ueid > 0, _ueid, 0, 0); memset(&reference, 0, sizeof(struct emm_common_data_s)); reference.ueid = _ueid; return RB_FIND(emm_common_data_map, &root->emm_common_data_root, &reference); } #else static emm_common_data_t *_emm_common_data[EMM_DATA_NB_UE_MAX]; #endif /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: emm_proc_common_initialize() ** ** ** ** Description: Initialize EMM procedure callback functions executed for ** ** the UE with the given identifier ** ** ** ** Inputs: ueid: UE lower layer identifier ** ** success: EMM procedure executed upon successful EMM ** ** common procedure completion ** ** reject: EMM procedure executed if the EMM common ** ** procedure failed or is rejected ** ** failure: EMM procedure executed upon transmission ** ** failure reported by lower layer ** ** abort: EMM common procedure executed when the on- ** ** going EMM procedure is aborted ** ** args: EMM common procedure argument parameters ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: _emm_common_data ** ** ** ***************************************************************************/ int emm_proc_common_initialize(unsigned int ueid, emm_common_success_callback_t _success, emm_common_reject_callback_t _reject, emm_common_failure_callback_t _failure, emm_common_abort_callback_t _abort, void *args) { struct emm_common_data_s *emm_common_data_ctx = NULL; LOG_FUNC_IN; #if defined(NAS_BUILT_IN_EPC) assert(ueid > 0); emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); #else assert(ueid < EMM_DATA_NB_UE_MAX); #endif if (emm_common_data_ctx == NULL) { emm_common_data_ctx = (emm_common_data_t *)malloc(sizeof(emm_common_data_t)); emm_common_data_ctx->ueid = ueid; #if defined(NAS_BUILT_IN_EPC) RB_INSERT(emm_common_data_map, &emm_common_data_head.emm_common_data_root, emm_common_data_ctx); #endif if (emm_common_data_ctx) { emm_common_data_ctx->ref_count = 0; } } if (emm_common_data_ctx) { emm_common_data_ctx->ref_count += 1; emm_common_data_ctx->success = _success; emm_common_data_ctx->reject = _reject; emm_common_data_ctx->failure = _failure; emm_common_data_ctx->abort = _abort; emm_common_data_ctx->args = args; LOG_FUNC_RETURN(RETURNok); } LOG_FUNC_RETURN(RETURNerror); } /**************************************************************************** ** ** ** Name: emm_proc_common_success() ** ** ** ** Description: The EMM common procedure initiated between the UE with ** ** the specified identifier and the MME completed success- ** ** fully. The network performs required actions related to ** ** the ongoing EMM procedure. ** ** ** ** Inputs: ueid: UE lower layer identifier ** ** Others: _emm_common_data, _emm_data ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int emm_proc_common_success(unsigned int ueid) { emm_common_data_t *emm_common_data_ctx = NULL; emm_common_success_callback_t emm_callback; int rc = RETURNerror; LOG_FUNC_IN; #if defined(NAS_BUILT_IN_EPC) DevCheck(ueid > 0, ueid, 0, 0); emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); #else assert(ueid < EMM_DATA_NB_UE_MAX); emm_common_data_ctx = _emm_common_data[ueid]; #endif assert(emm_common_data_ctx != NULL); emm_callback = emm_common_data_ctx->success; if (emm_callback) { struct emm_data_context_s *ctx = NULL; #if defined(NAS_BUILT_IN_EPC) ctx = emm_data_context_get(&_emm_data, ueid); #else ctx = _emm_data.ctx[ueid]; #endif rc = (*emm_callback)(ctx); } _emm_common_cleanup(ueid); LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: emm_proc_common_reject() ** ** ** ** Description: The EMM common procedure initiated between the UE with ** ** the specified identifier and the MME failed or has been ** ** rejected. The network performs required actions related ** ** to the ongoing EMM procedure. ** ** ** ** Inputs: ueid: UE lower layer identifier ** ** Others: _emm_common_data, _emm_data ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int emm_proc_common_reject(unsigned int ueid) { emm_common_data_t *emm_common_data_ctx = NULL; int rc = RETURNerror; emm_common_reject_callback_t emm_callback; LOG_FUNC_IN; #if defined(NAS_BUILT_IN_EPC) DevCheck(ueid > 0, ueid, 0, 0); emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); #else assert(ueid < EMM_DATA_NB_UE_MAX); emm_common_data_ctx = _emm_common_data[ueid]; #endif assert(emm_common_data_ctx != NULL); emm_callback = emm_common_data_ctx->reject; if (emm_callback) { struct emm_data_context_s *ctx = NULL; #if defined(NAS_BUILT_IN_EPC) ctx = emm_data_context_get(&_emm_data, ueid); #else ctx = _emm_data.ctx[ueid]; #endif rc = (*emm_callback)(ctx); } _emm_common_cleanup(ueid); LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: emm_proc_common_failure() ** ** ** ** Description: The EMM common procedure has been initiated between the ** ** UE with the specified identifier and the MME, and a lower ** ** layer failure occurred before the EMM common procedure ** ** being completed. The network performs required actions ** ** related to the ongoing EMM procedure. ** ** ** ** Inputs: ueid: UE lower layer identifier ** ** Others: _emm_common_data, _emm_data ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int emm_proc_common_failure(unsigned int ueid) { emm_common_data_t *emm_common_data_ctx = NULL; emm_common_failure_callback_t emm_callback; int rc = RETURNerror; LOG_FUNC_IN; #if defined(NAS_BUILT_IN_EPC) DevCheck(ueid > 0, ueid, 0, 0); emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); #else assert(ueid < EMM_DATA_NB_UE_MAX); emm_common_data_ctx = _emm_common_data[ueid]; #endif assert(emm_common_data_ctx != NULL); emm_callback = emm_common_data_ctx->failure; if (emm_callback) { struct emm_data_context_s *ctx = NULL; #if defined(NAS_BUILT_IN_EPC) ctx = emm_data_context_get(&_emm_data, ueid); #else ctx = _emm_data.ctx[ueid]; #endif rc = (*emm_callback)(ctx); } _emm_common_cleanup(ueid); LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: emm_proc_common_abort() ** ** ** ** Description: The ongoing EMM procedure has been aborted. The network ** ** performs required actions related to the EMM common pro- ** ** cedure previously initiated between the UE with the spe- ** ** cified identifier and the MME. ** ** ** ** Inputs: ueid: UE lower layer identifier ** ** Others: _emm_common_data ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** Others: None ** ** ** ***************************************************************************/ int emm_proc_common_abort(unsigned int ueid) { emm_common_data_t *emm_common_data_ctx = NULL; emm_common_failure_callback_t emm_callback; int rc = RETURNerror; LOG_FUNC_IN; #if defined(NAS_BUILT_IN_EPC) DevCheck(ueid > 0, ueid, 0, 0); emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); #else assert(ueid < EMM_DATA_NB_UE_MAX); emm_common_data_ctx = _emm_common_data[ueid]; #endif assert(emm_common_data_ctx != NULL); emm_callback = emm_common_data_ctx->abort; if (emm_callback) { struct emm_data_context_s *ctx = NULL; #if defined(NAS_BUILT_IN_EPC) ctx = emm_data_context_get(&_emm_data, ueid); #else ctx = _emm_data.ctx[ueid]; #endif rc = (*emm_callback)(ctx); } _emm_common_cleanup(ueid); LOG_FUNC_RETURN(rc); } /**************************************************************************** ** ** ** Name: emm_proc_common_get_args() ** ** ** ** Description: Returns pointer to the EMM common procedure argument pa- ** ** rameters allocated for the UE with the given identifier. ** ** ** ** Inputs: ueid: UE lower layer identifier ** ** Others: _emm_common_data ** ** ** ** Outputs: None ** ** Return: pointer to the EMM common procedure argu- ** ** ment parameters ** ** Others: None ** ** ** ***************************************************************************/ void *emm_proc_common_get_args(unsigned int ueid) { emm_common_data_t *emm_common_data_ctx = NULL; LOG_FUNC_IN; #if defined(NAS_BUILT_IN_EPC) DevCheck(ueid > 0, ueid, 0, 0); emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); #else assert(ueid < EMM_DATA_NB_UE_MAX); emm_common_data_ctx = _emm_common_data[ueid]; #endif assert(emm_common_data_ctx != NULL); LOG_FUNC_RETURN(emm_common_data_ctx->args); } /****************************************************************************/ /********************* L O C A L F U N C T I O N S *********************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: emm_proc_common_cleanup() ** ** ** ** Description: Cleans EMM procedure callback functions upon completion ** ** of an EMM common procedure previously initiated within an ** ** EMM procedure currently in progress between the network ** ** and the UE with the specified identifier. ** ** ** ** Inputs: ueid: UE lower layer identifier ** ** Others: None ** ** ** ** Outputs: None ** ** Return: None ** ** Others: _emm_common_data ** ** ** ***************************************************************************/ static void _emm_common_cleanup(unsigned int ueid) { emm_common_data_t *emm_common_data_ctx = NULL; #if defined(NAS_BUILT_IN_EPC) DevCheck(ueid > 0, ueid, 0, 0); emm_common_data_ctx = emm_common_data_context_get(&emm_common_data_head, ueid); #else assert(ueid < EMM_DATA_NB_UE_MAX); emm_common_data_ctx = _emm_common_data[ueid]; #endif if (emm_common_data_ctx) { emm_common_data_ctx->ref_count -= 1; if (emm_common_data_ctx->ref_count == 0) { /* Release the callback functions */ #if defined(NAS_BUILT_IN_EPC) RB_REMOVE(emm_common_data_map, &emm_common_data_head.emm_common_data_root, emm_common_data_ctx); #endif free(emm_common_data_ctx); emm_common_data_ctx = NULL; } } }