559 lines
23 KiB
C
559 lines
23 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_pt.c
|
|
|
|
Version 0.1
|
|
|
|
Date 2013/01/03
|
|
|
|
Product NAS stack
|
|
|
|
Subsystem EPS Session Management
|
|
|
|
Author Frederic Maurel
|
|
|
|
Description Defines functions used to handle ESM procedure transactions.
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "esm_pt.h"
|
|
#include "esm_pt_defs.h"
|
|
#include "user_defs.h"
|
|
|
|
#include "commonDef.h"
|
|
#include "nas_log.h"
|
|
#include "utils.h"
|
|
|
|
#include <stdlib.h> // malloc, free
|
|
#include <string.h> // memcpy
|
|
|
|
/****************************************************************************/
|
|
/**************** 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 ESM procedure transaction status */
|
|
const char *esm_pt_state2str( int esmptstate){
|
|
static const char *_esm_pt_state_str[ESM_PT_STATE_MAX] = {
|
|
"PROCEDURE TRANSACTION INACTIVE",
|
|
"PROCEDURE TRANSACTION PENDING"
|
|
};
|
|
return _esm_pt_state_str[esmptstate];
|
|
}
|
|
|
|
/* Return the index of the next available entry in the list of procedure
|
|
* transaction data */
|
|
static int _esm_pt_get_available_entry(esm_pt_data_t *esm_pt_data);
|
|
|
|
/****************************************************************************/
|
|
/****************** E X P O R T E D F U N C T I O N S ******************/
|
|
/****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_initialize() **
|
|
** **
|
|
** Description: Initialize ESM procedure transaction data **
|
|
** **
|
|
** Inputs: None **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: None **
|
|
** **
|
|
***************************************************************************/
|
|
esm_pt_data_t *esm_pt_initialize(void)
|
|
{
|
|
LOG_FUNC_IN;
|
|
esm_pt_data_t *esm_pt_data = calloc_or_fail(1, sizeof(esm_pt_data_t));
|
|
int i;
|
|
|
|
esm_pt_data->index = 0;
|
|
|
|
for (i = 0; i < ESM_PT_DATA_SIZE + 1; i++) {
|
|
esm_pt_data->context[i] = NULL;
|
|
}
|
|
|
|
LOG_FUNC_OUT;
|
|
return esm_pt_data;
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_assign() **
|
|
** **
|
|
** Description: Assigns a new procedure transaction identity **
|
|
** **
|
|
** Inputs: None **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: The identity of the new procedure transac- **
|
|
** tion when successfully assigned; **
|
|
** the unassigned PTI (0) otherwise. **
|
|
** **
|
|
***************************************************************************/
|
|
int esm_pt_assign(esm_pt_data_t *esm_pt_data)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
/* Search for an available procedure transaction identity */
|
|
int i = _esm_pt_get_available_entry(esm_pt_data);
|
|
|
|
if (i < 0) {
|
|
LOG_FUNC_RETURN (ESM_PT_UNASSIGNED);
|
|
}
|
|
|
|
/* Assign new procedure transaction */
|
|
esm_pt_data->context[i] =
|
|
(esm_pt_context_t *)malloc(sizeof(esm_pt_context_t));
|
|
|
|
if (esm_pt_data->context[i] == NULL) {
|
|
LOG_FUNC_RETURN (ESM_PT_UNASSIGNED);
|
|
}
|
|
|
|
/* Store the index of the next available procedure transaction identity */
|
|
esm_pt_data->index = i + 1;
|
|
|
|
/* An available procedure transaction identity is found */
|
|
esm_pt_data->context[i]->pti = i + ESM_PTI_MIN;
|
|
/* Set the procedure transaction status to INACTIVE */
|
|
esm_pt_data->context[i]->status = ESM_PT_INACTIVE;
|
|
/* Disable the retransmission timer */
|
|
esm_pt_data->context[i]->timer.id = NAS_TIMER_INACTIVE_ID;
|
|
/* Setup retransmission timer parameters */
|
|
esm_pt_data->context[i]->args = NULL;
|
|
|
|
LOG_TRACE(INFO, "ESM-FSM - Procedure transaction identity %d assigned",
|
|
esm_pt_data->context[i]->pti);
|
|
LOG_FUNC_RETURN (esm_pt_data->context[i]->pti);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_release() **
|
|
** **
|
|
** Description: Release the given procedure transaction identity **
|
|
** **
|
|
** Inputs: pti: The identity of the procedure transaction **
|
|
** to release **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok if the procedure transaction iden-**
|
|
** tity has been successfully released; **
|
|
** RETURNerror otherwise. **
|
|
** **
|
|
***************************************************************************/
|
|
int esm_pt_release(esm_pt_data_t *esm_pt_data, int pti)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) {
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/* Get procedure transaction data */
|
|
esm_pt_context_t *ctx = esm_pt_data->context[pti - ESM_PTI_MIN];
|
|
|
|
if ( (ctx == NULL) || (ctx->pti != pti) ) {
|
|
/* Procedure transaction not assigned */
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/* Do not release active procedure transaction */
|
|
if (ctx->status != ESM_PT_INACTIVE) {
|
|
LOG_TRACE(ERROR, "ESM-FSM - Procedure transaction is not INACTIVE");
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/* Stop the retransmission timer if still running */
|
|
if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) {
|
|
LOG_TRACE(INFO, "ESM-FSM - Stop retransmission timer %d",
|
|
ctx->timer.id);
|
|
ctx->timer.id = nas_timer_stop(ctx->timer.id);
|
|
}
|
|
|
|
/* Release the retransmisison timer parameters */
|
|
if (ctx->args) {
|
|
if (ctx->args->msg.length > 0) {
|
|
free(ctx->args->msg.value);
|
|
}
|
|
|
|
free(ctx->args);
|
|
ctx->args = NULL;
|
|
}
|
|
|
|
/* Release transaction procedure data */
|
|
free(esm_pt_data->context[pti - ESM_PTI_MIN]);
|
|
esm_pt_data->context[pti - ESM_PTI_MIN] = NULL;
|
|
|
|
LOG_TRACE(INFO, "ESM-FSM - Procedure transaction %d released", pti);
|
|
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_start_timer() **
|
|
** **
|
|
** Description: Start the timer of the specified procedure transaction to **
|
|
** expire after a given time interval. Timer expiration will **
|
|
** schedule execution of the callback function where stored **
|
|
** ESM message should be re-transmit. **
|
|
** **
|
|
** Inputs: pti: The identity of the procedure transaction **
|
|
** msg: The encoded ESM message to be stored **
|
|
** sec: The value of the time interval in seconds **
|
|
** cb: Function executed upon timer expiration **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** **
|
|
***************************************************************************/
|
|
int esm_pt_start_timer(nas_user_t *user, int pti, const OctetString *msg,
|
|
long sec, nas_timer_callback_t cb)
|
|
{
|
|
LOG_FUNC_IN;
|
|
esm_pt_data_t *esm_pt_data = user->esm_pt_data;
|
|
|
|
if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) {
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/* Get procedure transaction data */
|
|
esm_pt_context_t *ctx = esm_pt_data->context[pti - ESM_PTI_MIN];
|
|
|
|
if ( (ctx == NULL) || (ctx->pti != pti) ) {
|
|
/* Procedure transaction not assigned */
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) {
|
|
if (ctx->args) {
|
|
/* Re-start the retransmission timer */
|
|
ctx->timer.id = nas_timer_restart(ctx->timer.id);
|
|
}
|
|
} else {
|
|
/* Setup the retransmission timer parameters */
|
|
ctx->args = (esm_pt_timer_data_t *)malloc(sizeof(esm_pt_timer_data_t));
|
|
|
|
if (ctx->args) {
|
|
ctx->args->user = user;
|
|
/* Set the EPS bearer identity */
|
|
ctx->args->pti = pti;
|
|
/* Reset the retransmission counter */
|
|
ctx->args->count = 0;
|
|
/* Set the ESM message to be re-transmited */
|
|
ctx->args->msg.value = (uint8_t *)malloc(msg->length);
|
|
ctx->args->msg.length = 0;
|
|
|
|
if (ctx->args->msg.value) {
|
|
memcpy(ctx->args->msg.value, msg->value, msg->length);
|
|
ctx->args->msg.length = msg->length;
|
|
}
|
|
|
|
/* Setup the retransmission timer to expire at the given
|
|
* time interval */
|
|
ctx->timer.id = nas_timer_start(sec, cb, ctx->args);
|
|
ctx->timer.sec = sec;
|
|
}
|
|
}
|
|
|
|
if ( (ctx->args != NULL) && (ctx->timer.id != NAS_TIMER_INACTIVE_ID) ) {
|
|
LOG_TRACE(INFO, "ESM-FSM - Retransmission timer %d expires in "
|
|
"%ld seconds", ctx->timer.id, ctx->timer.sec);
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_stop_timer() **
|
|
** **
|
|
** Description: Stop the timer previously started for the given procedure **
|
|
** transaction **
|
|
** **
|
|
** Inputs: pti: The identity of the procedure transaction **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** **
|
|
***************************************************************************/
|
|
int esm_pt_stop_timer(esm_pt_data_t *esm_pt_data, int pti)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) {
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/* Get procedure transaction data */
|
|
esm_pt_context_t *ctx = esm_pt_data->context[pti - ESM_PTI_MIN];
|
|
|
|
if ( (ctx == NULL) || (ctx->pti != pti) ) {
|
|
/* Procedure transaction not assigned */
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/* Stop the retransmission timer if still running */
|
|
if (ctx->timer.id != NAS_TIMER_INACTIVE_ID) {
|
|
LOG_TRACE(INFO, "ESM-FSM - Stop retransmission timer %d",
|
|
ctx->timer.id);
|
|
ctx->timer.id = nas_timer_stop(ctx->timer.id);
|
|
}
|
|
|
|
/* Release the retransmisison timer parameters */
|
|
if (ctx->args) {
|
|
if (ctx->args->msg.length > 0) {
|
|
free(ctx->args->msg.value);
|
|
}
|
|
|
|
free(ctx->args);
|
|
ctx->args = NULL;
|
|
}
|
|
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_set_status() **
|
|
** **
|
|
** Description: Set the status of the specified procedure transaction to **
|
|
** the given state **
|
|
** **
|
|
** Inputs: pti: The identity of the procedure transaction **
|
|
** status: The new ESM procedure transaction status **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** **
|
|
***************************************************************************/
|
|
int esm_pt_set_status(esm_pt_data_t *esm_pt_data, int pti, esm_pt_state status)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
esm_pt_state old_status;
|
|
|
|
if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) {
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/* Get procedure transaction data */
|
|
esm_pt_context_t *ctx = esm_pt_data->context[pti - ESM_PTI_MIN];
|
|
|
|
if ( (ctx == NULL) || (ctx->pti != pti) ) {
|
|
/* Procedure transaction not assigned */
|
|
LOG_TRACE(ERROR, "ESM-FSM - Procedure transaction not assigned "
|
|
"(pti=%d)", pti);
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
old_status = ctx->status;
|
|
|
|
if (status < ESM_PT_STATE_MAX) {
|
|
LOG_TRACE(INFO, "ESM-FSM - Status of procedure transaction %d changed:"
|
|
" %s ===> %s", pti,
|
|
esm_pt_state2str(old_status), esm_pt_state2str(status));
|
|
|
|
if (status != old_status) {
|
|
ctx->status = status;
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
}
|
|
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_get_status() **
|
|
** **
|
|
** Description: Get the current status value of the specified procedure **
|
|
** transaction **
|
|
** **
|
|
** Inputs: pti: The identity of the procedure transaction **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: The current value of the ESM procedure **
|
|
** transaction status **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
esm_pt_state esm_pt_get_status(esm_pt_data_t *esm_pt_data, int pti)
|
|
{
|
|
if ( (pti < ESM_PTI_MIN) || (pti > ESM_PTI_MAX) ) {
|
|
return (ESM_PT_INACTIVE);
|
|
}
|
|
|
|
if (esm_pt_data->context[pti - ESM_PTI_MIN] == NULL) {
|
|
/* Procedure transaction not allocated */
|
|
return (ESM_PT_INACTIVE);
|
|
}
|
|
|
|
if (esm_pt_data->context[pti - ESM_PTI_MIN]->pti != pti) {
|
|
/* Procedure transaction not assigned */
|
|
return (ESM_PT_INACTIVE);
|
|
}
|
|
|
|
return (esm_pt_data->context[pti - ESM_PTI_MIN]->status);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_get_pending_pti() **
|
|
** **
|
|
** Description: Returns the procedure transaction identity assigned to **
|
|
** the first PDN connection entry which is pending in the **
|
|
** given state **
|
|
** **
|
|
** Inputs: status: The PDN connection status **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: The procedure transaction identity of the **
|
|
** PDN connection entry if it exists; **
|
|
** the unassigned PTI (0) otherwise. **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
int esm_pt_get_pending_pti(esm_pt_data_t *esm_pt_data, esm_pt_state status)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < ESM_PT_DATA_SIZE; i++) {
|
|
if (esm_pt_data->context[i] == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if (esm_pt_data->context[i]->status != status) {
|
|
continue;
|
|
}
|
|
|
|
/* PDN connection entry found */
|
|
break;
|
|
}
|
|
|
|
if (i < ESM_PT_DATA_SIZE) {
|
|
LOG_FUNC_RETURN (esm_pt_data->context[i]->pti);
|
|
}
|
|
|
|
/* PDN connection entry not found */
|
|
LOG_FUNC_RETURN (ESM_PT_UNASSIGNED);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_is_not_in_use() **
|
|
** **
|
|
** Description: Check whether the given procedure transaction identity **
|
|
** does not match an assigned PTI value currently in use **
|
|
** **
|
|
** Inputs: pti: The identity of the procedure transaction **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: true, false **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
bool esm_pt_is_not_in_use(esm_pt_data_t *esm_pt_data, int pti)
|
|
{
|
|
return ( (pti == ESM_PT_UNASSIGNED) ||
|
|
(esm_pt_data->context[pti - ESM_PTI_MIN] == NULL) ||
|
|
(esm_pt_data->context[pti - ESM_PTI_MIN]->pti) != pti);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: esm_pt_is_reserved() **
|
|
** **
|
|
** Description: Check whether the given procedure transaction identity is **
|
|
** a reserved value **
|
|
** **
|
|
** Inputs: pti: The identity of the procedure transaction **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: true, false **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
bool esm_pt_is_reserved(int pti)
|
|
{
|
|
return ( (pti != ESM_PT_UNASSIGNED) && (pti > ESM_PTI_MAX) );
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/********************* L O C A L F U N C T I O N S *********************/
|
|
/****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _esm_pt_get_available_entry() **
|
|
** **
|
|
** Description: Returns the index of the next available entry in the list **
|
|
** of procedure transaction data **
|
|
** **
|
|
** Inputs: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: The index of the next available procedure **
|
|
** transaction data entry; -1 if no any entry **
|
|
** is available. **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _esm_pt_get_available_entry(esm_pt_data_t *esm_pt_data)
|
|
{
|
|
int i;
|
|
|
|
for (i = esm_pt_data->index; i < ESM_PT_DATA_SIZE; i++) {
|
|
if (esm_pt_data->context[i] != NULL) {
|
|
continue;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
for (i = 0; i < esm_pt_data->index; i++) {
|
|
if (esm_pt_data->context[i] != NULL) {
|
|
continue;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
/* No available PTI entry found */
|
|
return (-1);
|
|
}
|