Files

389 lines
17 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_main.c
Version 0.1
Date 2012/12/04
Product NAS stack
Subsystem EPS Session Management
Author Frederic Maurel
Description Defines the EPS Session Management procedure call manager,
the main entry point for elementary ESM processing.
*****************************************************************************/
#include "esm_main.h"
#include "commonDef.h"
#include "nas_log.h"
#include "utils.h"
#include "emmData.h"
#include "esmData.h"
#include "esm_pt.h"
#include "esm_ebr.h"
#include "user_defs.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 *******************/
/****************************************************************************/
/****************************************************************************/
/****************** E X P O R T E D F U N C T I O N S ******************/
/****************************************************************************/
/****************************************************************************
** **
** Name: esm_main_initialize() **
** **
** Description: Initializes ESM internal data **
** **
** Inputs: cb: The user notification callback **
** Others: None **
** **
** Outputs: None **
** Return: None **
** **
***************************************************************************/
void esm_main_initialize(nas_user_t *user, esm_indication_callback_t cb)
{
LOG_FUNC_IN;
int i;
esm_data_t *esm_data = calloc_or_fail(1, sizeof(esm_data_t));
user->esm_data = esm_data;
default_eps_bearer_context_data_t *default_eps_bearer_context = calloc(1, sizeof(default_eps_bearer_context_data_t));
if ( default_eps_bearer_context == NULL ) {
LOG_TRACE(ERROR, "ESM-MAIN - Can't malloc default_eps_bearer_context");
exit(EXIT_FAILURE);
}
default_eps_bearer_context->ebi = ESM_EBI_UNASSIGNED;
user->default_eps_bearer_context_data = default_eps_bearer_context;
/* Total number of active EPS bearer contexts */
esm_data->n_ebrs = 0;
/* List of active PDN connections */
esm_data->n_pdns = 0;
for (i = 0; i < ESM_DATA_PDN_MAX + 1; i++) {
esm_data->pdn[i].pid = -1;
esm_data->pdn[i].is_active = false;
esm_data->pdn[i].data = NULL;
}
/* Emergency bearer services indicator */
esm_data->emergency = false;
/* Initialize the procedure transaction identity manager */
user->esm_pt_data = esm_pt_initialize();
/* Initialize the EPS bearer context manager */
user->esm_ebr_data = esm_ebr_initialize();
// FIXME only one callback for all user or many for many ?
esm_ebr_register_callback(cb);
LOG_FUNC_OUT;
}
/****************************************************************************
** **
** Name: esm_main_cleanup() **
** **
** Description: Performs the EPS Session Management clean up procedure **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: None **
** Others: None **
** **
***************************************************************************/
void esm_main_cleanup(esm_data_t *esm_data)
{
LOG_FUNC_IN;
{
int i;
int pid;
int bid;
/* De-activate EPS bearers and clean up PDN connections */
for (pid = 0; pid < ESM_DATA_PDN_MAX; pid++) {
if (esm_data->pdn[pid].data) {
esm_pdn_t *pdn = esm_data->pdn[pid].data;
if (pdn->apn.length > 0) {
free(pdn->apn.value);
}
/* Release EPS bearer contexts */
for (bid = 0; bid < pdn->n_bearers; bid++) {
if (pdn->bearer[bid]) {
LOG_TRACE(WARNING, "ESM-MAIN - Release EPS bearer "
"context (ebi=%d)", pdn->bearer[bid]->ebi);
/* Delete the TFT */
for (i = 0; i < pdn->bearer[bid]->tft.n_pkfs; i++) {
if (pdn->bearer[bid]->tft.pkf[i]) {
free(pdn->bearer[bid]->tft.pkf[i]);
}
}
free(pdn->bearer[bid]);
}
}
/* Release the PDN connection */
free(esm_data->pdn[pid].data);
}
}
}
LOG_FUNC_OUT;
}
/****************************************************************************
** **
** Name: esm_main_get_nb_pdn_max() **
** **
** Description: Get the maximum number of PDN connections that may be in **
** a defined state at the same time **
** **
** Inputs: None **
** **
** Outputs: None **
** Return: The maximum number of PDN connections that **
** may be defined **
** Others: None **
** **
***************************************************************************/
int esm_main_get_nb_pdns_max(esm_data_t *esm_data)
{
LOG_FUNC_IN;
LOG_FUNC_RETURN (ESM_DATA_PDN_MAX);
}
/****************************************************************************
** **
** Name: esm_main_get_nb_pdns() **
** **
** Description: Get the number of active PDN connections **
** **
** Inputs: None **
** **
** Outputs: None **
** Return: The number of active PDN connections **
** Others: None **
** **
***************************************************************************/
int esm_main_get_nb_pdns(esm_data_t *esm_data)
{
LOG_FUNC_IN;
LOG_FUNC_RETURN (esm_data->n_pdns);
}
/****************************************************************************
** **
** Name: esm_main_has_emergency() **
** **
** Description: Check whether a PDN connection for emergency bearer ser- **
** vices is established **
** **
** Inputs: None **
** **
** Outputs: None **
** Return: true if a PDN connection for emergency **
** bearer services is established **
** Others: None **
** **
***************************************************************************/
bool esm_main_has_emergency(esm_data_t *esm_data)
{
LOG_FUNC_IN;
LOG_FUNC_RETURN (esm_data->emergency);
}
/****************************************************************************
** **
** Name: esm_main_get_pdn_status() **
** **
** Description: Get the status of the specified PDN connection **
** **
** Inputs: cid: PDN connection identifier **
** **
** Outputs: state: true if the current state of the PDN con- **
** nection is ACTIVE; false otherwise. **
** Return: true if the specified PDN connection has a **
** PDN context defined; false if no any PDN **
** context has been defined for the specified **
** connection. **
** Others: None **
** **
***************************************************************************/
bool esm_main_get_pdn_status(nas_user_t *user, int cid, bool *state)
{
LOG_FUNC_IN;
unsigned int pid = cid - 1;
esm_data_t *esm_data = user->esm_data;
esm_ebr_data_t *esm_ebr_data = user-> esm_ebr_data;
if (pid >= ESM_DATA_PDN_MAX) {
return (false);
} else if (pid != esm_data->pdn[pid].pid) {
LOG_TRACE(WARNING, "ESM-MAIN - PDN connection %d is not defined", cid);
return (false);
} else if (esm_data->pdn[pid].data == NULL) {
LOG_TRACE(ERROR, "ESM-MAIN - PDN connection %d has not been allocated",
cid);
return (false);
}
if (esm_data->pdn[pid].data->bearer[0] != NULL) {
/* The status of a PDN connection is the status of the default EPS bearer
* that has been assigned to this PDN connection at activation time */
int ebi = esm_data->pdn[pid].data->bearer[0]->ebi;
*state = (esm_ebr_get_status(esm_ebr_data, ebi) == ESM_EBR_ACTIVE);
}
/* The PDN connection has not been activated yet */
LOG_FUNC_RETURN (true);
}
/****************************************************************************
** **
** Name: esm_main_get_pdn() **
** **
** Description: Get parameters defined for the specified PDN connection **
** **
** Inputs: cid: PDN connection identifier **
** **
** Outputs: type: PDN connection type (IPv4, IPv6, IPv4v6) **
** apn: Access Point logical Name in used **
** is_emergency: Emergency bearer services indicator **
** is_active: Active PDN connection indicator **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int esm_main_get_pdn(esm_data_t *esm_data, int cid, int *type, const char **apn,
bool *is_emergency, bool *is_active)
{
LOG_FUNC_IN;
unsigned int pid = cid - 1;
if (pid >= ESM_DATA_PDN_MAX) {
return (RETURNerror);
} else if (pid != esm_data->pdn[pid].pid) {
LOG_TRACE(WARNING, "ESM-MAIN - PDN connection %d is not defined", cid);
return (RETURNerror);
} else if (esm_data->pdn[pid].data == NULL) {
LOG_TRACE(ERROR, "ESM-MAIN - PDN connection %d has not been allocated",
cid);
return (RETURNerror);
}
/* Get the PDN type */
*type = esm_data->pdn[pid].data->type;
/* Get the Access Point Name */
if (esm_data->pdn[pid].data->apn.length > 0) {
*apn = (char *)(esm_data->pdn[pid].data->apn.value);
} else {
*apn = NULL;
}
/* Get the emergency bearer services indicator */
*is_emergency = esm_data->pdn[pid].data->is_emergency;
/* Get the active PDN connection indicator */
*is_active = esm_data->pdn[pid].is_active;
LOG_FUNC_RETURN (RETURNok);
}
/****************************************************************************
** **
** Name: esm_main_get_pdn_addr() **
** **
** Description: Get IP address(es) assigned to the specified PDN connec- **
** tion **
** **
** Inputs: cid: PDN connection identifier **
** **
** Outputs: ipv4adddr: IPv4 address **
** ipv6adddr: IPv6 address **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int esm_main_get_pdn_addr(esm_data_t *esm_data, int cid, const char **ipv4addr, const char **ipv6addr)
{
LOG_FUNC_IN;
unsigned int pid = cid - 1;
if (pid >= ESM_DATA_PDN_MAX) {
return (RETURNerror);
} else if (pid != esm_data->pdn[pid].pid) {
LOG_TRACE(WARNING, "ESM-MAIN - PDN connection %d is not defined", cid);
return (RETURNerror);
} else if (esm_data->pdn[pid].data == NULL) {
LOG_TRACE(ERROR, "ESM-MAIN - PDN connection %d has not been allocated",
cid);
return (RETURNerror);
} else if (!esm_data->pdn[pid].is_active) {
/* No any IP address has been assigned to this PDN connection */
return (RETURNok);
}
if (esm_data->pdn[pid].data->type == NET_PDN_TYPE_IPV4) {
/* Get IPv4 address */
*ipv4addr = esm_data->pdn[pid].data->ip_addr;
} else if (esm_data->pdn[pid].data->type == NET_PDN_TYPE_IPV6) {
/* Get IPv6 address */
*ipv6addr = esm_data->pdn[pid].data->ip_addr;
} else {
/* IPv4v6 dual-stack terminal */
*ipv4addr = esm_data->pdn[pid].data->ip_addr;
*ipv6addr = esm_data->pdn[pid].data->ip_addr+ESM_DATA_IPV4_ADDRESS_SIZE;
}
LOG_FUNC_RETURN (RETURNok);
}