/* * Licensed to the OpenAirInterface (OAI) Software Alliance under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The OpenAirInterface Software Alliance licenses this file to You under * the OAI Public License, Version 1.1 (the "License"); you may not use this file * except in compliance with the License. * You may obtain a copy of the License at * * http://www.openairinterface.org/?page_id=698 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *------------------------------------------------------------------------------- * For more information about the OpenAirInterface (OAI) Software Alliance: * contact@openairinterface.org */ /***************************************************************************** Source esm_ebr.c Version 0.1 Date 2013/01/29 Product NAS stack Subsystem EPS Session Management Author Frederic Maurel Description Defines functions used to handle state of EPS bearer contexts and manage ESM messages re-transmission. *****************************************************************************/ #include // malloc, free #include // memcpy #include "emmData.h" #include "esm_ebr.h" #include "commonDef.h" #include "nas_log.h" #include "utils.h" /****************************************************************************/ /**************** 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 *******************/ /****************************************************************************/ /* String representation of EPS bearer context status */ const char *esm_ebr_state2str(int esmebrstate) { static const char *_esm_ebr_state_str[ESM_EBR_STATE_MAX] = { "BEARER CONTEXT INACTIVE", "BEARER CONTEXT ACTIVE", }; return _esm_ebr_state_str[esmebrstate]; } /* * ---------------------- * User notification data * ---------------------- */ /* User notification callback executed whenever an EPS bearer context becomes * active or inactive */ static esm_indication_callback_t _esm_ebr_callback; /* PDN connection and EPS bearer status [NW/UE][Dedicated/Default][status] */ static const network_pdn_state_t _esm_ebr_pdn_state[2][2][2] = { /* Status modification triggerer by the network */ { /* Dedicated EPS bearer */ {NET_PDN_NW_DEDICATED_DEACT, NET_PDN_NW_DEDICATED_ACT}, /* Default EPS bearer */ {NET_PDN_NW_DEFAULT_DEACT, 0} }, /* Status modification triggered by the UE */ { /* Dedicated EPS bearer */ {NET_PDN_MT_DEDICATED_DEACT, NET_PDN_MT_DEDICATED_ACT}, /* Default EPS bearer */ {NET_PDN_MT_DEFAULT_DEACT, NET_PDN_MT_DEFAULT_ACT} } }; /* Returns the index of the next available entry in the list of EPS bearer * context data */ static int _esm_ebr_get_available_entry(esm_ebr_data_t *esm_ebr_data); /****************************************************************************/ /****************** E X P O R T E D F U N C T I O N S ******************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: esm_ebr_initialize() ** ** ** ** Description: Initialize EPS bearer context data ** ** ** ** Inputs: cb: User notification callback ** ** Others: None ** ** ** ** Outputs: None ** ** Return: None ** ** ** ***************************************************************************/ esm_ebr_data_t *esm_ebr_initialize(void) { LOG_FUNC_IN; int i; esm_ebr_data_t *esm_ebr_data = calloc_or_fail(1, sizeof(esm_ebr_data_t)); esm_ebr_data->index = 0; /* Initialize EPS bearer context data */ for (i = 0; i < ESM_EBR_DATA_SIZE + 1; i++) { esm_ebr_data->context[i] = NULL; } LOG_FUNC_OUT; return esm_ebr_data; } void esm_ebr_register_callback(esm_indication_callback_t cb) { LOG_FUNC_IN; /* Initialize the user notification callback */ _esm_ebr_callback = *cb; LOG_FUNC_OUT; } /**************************************************************************** ** ** ** Name: esm_ebr_assign() ** ** ** ** Description: Assigns a new EPS bearer context ** ** ** ** ebi: Identity of the new EPS bearer context ** ** cid: Identifier of the PDN context the EPS bea- ** ** rer context is associated to ** ** default_ebr bool if the new bearer context is associa- ** ** ted to a default EPS bearer ** ** Others: None ** ** ** ** Outputs: None ** ** Return: The identity of the new EPS bearer context ** ** if successfully assigned; ** ** the not assigned EBI (0) otherwise. ** ** ** ***************************************************************************/ int esm_ebr_assign(esm_ebr_data_t *esm_ebr_data, int ebi, int cid, bool default_ebr) { esm_ebr_context_t *ebr_ctx = NULL; int i; LOG_FUNC_IN; ebr_ctx = esm_ebr_data->context[ebi - ESM_EBI_MIN]; if (ebi != ESM_EBI_UNASSIGNED) { if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); } else if (ebr_ctx != NULL) { LOG_TRACE(WARNING, "ESM-FSM - EPS bearer context already " "assigned (ebi=%d)", ebi); LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED); } /* The specified EPS bearer context is available */ i = ebi - ESM_EBI_MIN; } else { /* Search for an available EPS bearer identity */ i = _esm_ebr_get_available_entry(esm_ebr_data); if (i < 0) { LOG_FUNC_RETURN(ESM_EBI_UNASSIGNED); } /* An available EPS bearer context is found */ ebi = i + ESM_EBI_MIN; } /* Assign new EPS bearer context */ ebr_ctx = (esm_ebr_context_t *)malloc(sizeof(esm_ebr_context_t)); if (ebr_ctx == NULL) { LOG_FUNC_RETURN(ESM_EBI_UNASSIGNED); } esm_ebr_data->context[ebi - ESM_EBI_MIN] = ebr_ctx; /* Store the index of the next available EPS bearer identity */ esm_ebr_data->index = i + 1; /* Set the EPS bearer identity */ ebr_ctx->ebi = ebi; /* Set the EPS bearer context status to INACTIVE */ ebr_ctx->status = ESM_EBR_INACTIVE; /* Set the default EPS bearer indicator */ ebr_ctx->is_default_ebr = default_ebr; /* Set the identifier of the PDN context the EPS bearer is assigned to */ ebr_ctx->cid = cid; LOG_TRACE(INFO, "ESM-FSM - EPS bearer context %d assigned", ebi); LOG_FUNC_RETURN(ebr_ctx->ebi); } /**************************************************************************** ** ** ** Name: esm_ebr_release() ** ** ** ** Description: Release the given EPS bearer identity ** ** ** ** Inputs: ** ** ebi: The identity of the EPS bearer context to ** ** be released ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok if the EPS bearer context has ** ** been successfully released; ** ** RETURNerror otherwise. ** ** ** ***************************************************************************/ int esm_ebr_release(esm_ebr_data_t *esm_ebr_data, int ebi) { esm_ebr_context_t *ebr_ctx; LOG_FUNC_IN; if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { LOG_FUNC_RETURN (RETURNerror); } /* Get EPS bearer context data */ ebr_ctx = esm_ebr_data->context[ebi - ESM_EBI_MIN]; if ( (ebr_ctx == NULL) || (ebr_ctx->ebi != ebi) ) { /* EPS bearer context not assigned */ LOG_FUNC_RETURN (RETURNerror); } /* Do not release active EPS bearer context */ if (ebr_ctx->status != ESM_EBR_INACTIVE) { LOG_TRACE(ERROR, "ESM-FSM - EPS bearer context is not INACTIVE"); LOG_FUNC_RETURN (RETURNerror); } /* Release EPS bearer context data */ free(ebr_ctx); ebr_ctx = NULL; LOG_TRACE(INFO, "ESM-FSM - EPS bearer context %d released", ebi); LOG_FUNC_RETURN (RETURNok); } /**************************************************************************** ** ** ** Name: esm_ebr_set_status() ** ** ** ** Description: Set the status of the specified EPS bearer context to the ** ** given state ** ** ** ** ebi: The identity of the EPS bearer ** ** status: The new EPS bearer context status ** ** ue_requested: true/false if the modification of the EPS ** ** bearer context status was requested by the ** ** UE/network ** ** Others: None ** ** ** ** Outputs: None ** ** Return: RETURNok, RETURNerror ** ** ** ***************************************************************************/ int esm_ebr_set_status(user_api_id_t *user_api_id, esm_ebr_data_t *esm_ebr_data, int ebi, esm_ebr_state status, bool ue_requested) { esm_ebr_context_t *ebr_ctx; esm_ebr_state old_status; LOG_FUNC_IN; if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { LOG_FUNC_RETURN (RETURNerror); } /* Get EPS bearer context data */ ebr_ctx = esm_ebr_data->context[ebi - ESM_EBI_MIN]; if ( (ebr_ctx == NULL) || (ebr_ctx->ebi != ebi) ) { /* EPS bearer context not assigned */ LOG_TRACE(ERROR, "ESM-FSM - EPS bearer context not assigned " "(ebi=%d)", ebi); LOG_FUNC_RETURN (RETURNerror); } old_status = ebr_ctx->status; if (status < ESM_EBR_STATE_MAX) { LOG_TRACE(INFO, "ESM-FSM - Status of EPS bearer context %d changed:" " %s ===> %s", ebi, esm_ebr_state2str(old_status), esm_ebr_state2str(status)); if (status != old_status) { ebr_ctx->status = status; /* * Notify the user that the state of the EPS bearer has changed */ (*_esm_ebr_callback)(user_api_id, ebr_ctx->cid, _esm_ebr_pdn_state[ue_requested][ebr_ctx->is_default_ebr][status]); LOG_FUNC_RETURN (RETURNok); } } LOG_FUNC_RETURN (RETURNerror); } /**************************************************************************** ** ** ** Name: esm_ebr_get_status() ** ** ** ** Description: Get the current status value of the specified EPS bearer ** ** context ** ** ** ** ebi: The identity of the EPS bearer ** ** ** ** Outputs: None ** ** Return: The current value of the EPS bearer con- ** ** text status ** ** Others: None ** ** ** ***************************************************************************/ esm_ebr_state esm_ebr_get_status(esm_ebr_data_t *esm_ebr_data, int ebi) { if ( (ebi < ESM_EBI_MIN) || (ebi > ESM_EBI_MAX) ) { return (ESM_EBR_INACTIVE); } if (esm_ebr_data->context[ebi - ESM_EBI_MIN] == NULL) { /* EPS bearer context not allocated */ return (ESM_EBR_INACTIVE); } if (esm_ebr_data->context[ebi - ESM_EBI_MIN]->ebi != ebi) { /* EPS bearer context not assigned */ return (ESM_EBR_INACTIVE); } return (esm_ebr_data->context[ebi - ESM_EBI_MIN]->status); } /**************************************************************************** ** ** ** Name: esm_ebr_is_reserved() ** ** ** ** Description: Check whether the given EPS bearer identity is a reserved ** ** value ** ** ** ** Inputs: ebi: The identity of the EPS bearer ** ** Others: None ** ** ** ** Outputs: None ** ** Return: true, false ** ** Others: None ** ** ** ***************************************************************************/ bool esm_ebr_is_reserved(esm_ebr_data_t *esm_ebr_data, int ebi) { return ( (ebi != ESM_EBI_UNASSIGNED) && (ebi < ESM_EBI_MIN) ); } /**************************************************************************** ** ** ** Name: esm_ebr_is_not_in_use() ** ** ** ** Description: Check whether the given EPS bearer identity does not ** ** match an assigned EBI value currently in use ** ** ** ** ebi: The identity of the EPS bearer ** ** ** ** Outputs: None ** ** Return: true, false ** ** Others: None ** ** ** ***************************************************************************/ bool esm_ebr_is_not_in_use(esm_ebr_data_t *esm_ebr_data, int ebi) { return ( (ebi == ESM_EBI_UNASSIGNED) || (esm_ebr_data->context[ebi - ESM_EBI_MIN] == NULL) || (esm_ebr_data->context[ebi - ESM_EBI_MIN]->ebi) != ebi); } /****************************************************************************/ /********************* L O C A L F U N C T I O N S *********************/ /****************************************************************************/ /**************************************************************************** ** ** ** Name: _esm_ebr_get_available_entry() ** ** ** ** Description: Returns the index of the next available entry in the list ** ** of EPS bearer context data ** ** ** ** ** ** Outputs: None ** ** Return: The index of the next available EPS bearer ** ** context data entry; -1 if no any entry is ** ** available. ** ** Others: None ** ** ** ***************************************************************************/ static int _esm_ebr_get_available_entry(esm_ebr_data_t *esm_ebr_data) { int i; for (i = esm_ebr_data->index; i < ESM_EBR_DATA_SIZE; i++) { if (esm_ebr_data->context[i] != NULL) { continue; } return i; } for (i = 0; i < esm_ebr_data->index; i++) { if (esm_ebr_data->context[i] != NULL) { continue; } return i; } /* No available EBI entry found */ return (-1); }