389 lines
17 KiB
C
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);
|
|
}
|
|
|