461 lines
18 KiB
C
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);
|
|
}
|