Files

461 lines
18 KiB
C

/*
* 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 <stdlib.h> // malloc, free
#include <string.h> // 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);
}