/*******************************************************************************
OpenAirInterface
Copyright(c) 1999 - 2014 Eurecom
OpenAirInterface is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenAirInterface is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with OpenAirInterface.The full GNU General Public License is
included in this distribution in the file called "COPYING". If not,
see .
Contact Information
OpenAirInterface Admin: openair_admin@eurecom.fr
OpenAirInterface Tech : openair_tech@eurecom.fr
OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
*******************************************************************************/
/*****************************************************************************
Source esm_ebr_context.h
Version 0.1
Date 2013/05/28
Product NAS stack
Subsystem EPS Session Management
Author Frederic Maurel
Description Defines functions used to handle EPS bearer contexts.
*****************************************************************************/
#include // malloc, free
#include // memset
#include "commonDef.h"
#include "nas_log.h"
#include "emmData.h"
#include "esm_ebr.h"
#include "esm_ebr_context.h"
#include "emm_sap.h"
#if defined(ENABLE_ITTI)
# include "assertions.h"
#endif
#include
#include
#include
/****************************************************************************/
/**************** 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 *******************/
/****************************************************************************/
static int _esm_ebr_context_check_identifiers(const network_tft_t *,
const network_tft_t *);
static int _esm_ebr_context_check_precedence(const network_tft_t *,
const network_tft_t *);
/****************************************************************************/
/****************** E X P O R T E D F U N C T I O N S ******************/
/****************************************************************************/
/****************************************************************************
** **
** Name: esm_ebr_context_create() **
** **
** Description: Creates a new EPS bearer context to the PDN with the spe- **
** cified PDN connection identifier **
** **
** Inputs: ueid: UE identifier **
** pid: PDN connection identifier **
** ebi: EPS bearer identity **
** is_default: TRUE if the new bearer is a default EPS **
** bearer context **
** esm_qos: EPS bearer level QoS parameters **
** tft: Traffic flow template parameters **
** Others: _esm_data **
** **
** Outputs: None **
** Return: The EPS bearer identity of the default EPS **
** bearer associated to the new EPS bearer **
** context if successfully created; **
** UNASSIGN EPS bearer value otherwise. **
** Others: _esm_data **
** **
***************************************************************************/
int esm_ebr_context_create(
int pid, int ebi, int is_default,
const network_qos_t *qos, const network_tft_t *tft)
{
int bid = 0;
esm_data_context_t *esm_ctx = NULL;
esm_pdn_t *pdn = NULL;
//unsigned int ueid = 0;
LOG_FUNC_IN;
esm_ctx = &_esm_data;
bid = ESM_DATA_EPS_BEARER_MAX;
LOG_TRACE(INFO, "ESM-PROC - Create new %s EPS bearer context (ebi=%d) "
"for PDN connection (pid=%d)",
(is_default)? "default" : "dedicated", ebi, pid);
if (pid < ESM_DATA_PDN_MAX) {
if (pid != esm_ctx->pdn[pid].pid) {
LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier %d is "
"not valid", pid);
} else if (esm_ctx->pdn[pid].data == NULL) {
LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been "
"allocated", pid);
}
/* Check the total number of active EPS bearers */
else if (esm_ctx->n_ebrs > ESM_DATA_EPS_BEARER_TOTAL) {
LOG_TRACE(WARNING, "ESM-PROC - The total number of active EPS"
"bearers is exceeded");
} else {
/* Get the PDN connection entry */
pdn = esm_ctx->pdn[pid].data;
if (is_default) {
/* Default EPS bearer entry is defined at index 0 */
bid = 0;
if (pdn->bearer[bid] != NULL) {
LOG_TRACE(ERROR, "ESM-PROC - A default EPS bearer context "
"is already allocated");
LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED);
}
} else {
/* Search for an available EPS bearer context entry */
for (bid = 1; bid < ESM_DATA_EPS_BEARER_MAX; bid++) {
if (pdn->bearer[bid] != NULL) {
continue;
}
break;
}
}
}
}
if (bid < ESM_DATA_EPS_BEARER_MAX) {
/* Create new EPS bearer context */
esm_bearer_t *ebr = (esm_bearer_t *)malloc(sizeof(esm_bearer_t));
if (ebr != NULL) {
memset(ebr, 0 , sizeof(esm_bearer_t));
/* Increment the total number of active EPS bearers */
esm_ctx->n_ebrs += 1;
/* Increment the number of EPS bearer for this PDN connection */
pdn->n_bearers += 1;
/* Setup the EPS bearer data */
pdn->bearer[bid] = ebr;
ebr->bid = bid;
ebr->ebi = ebi;
if (qos != NULL) {
/* EPS bearer level QoS parameters */
ebr->qos = *qos;
}
if ( (tft != NULL) && (tft->n_pkfs < NET_PACKET_FILTER_MAX) ) {
int i;
/* Traffic flow template parameters */
for (i = 0; i < tft->n_pkfs; i++) {
ebr->tft.pkf[i] =
(network_pkf_t *)malloc(sizeof(network_pkf_t));
if (ebr->tft.pkf[i] != NULL) {
*(ebr->tft.pkf[i]) = *(tft->pkf[i]);
ebr->tft.n_pkfs += 1;
}
}
}
if (is_default) {
/* Set the PDN connection activation indicator */
esm_ctx->pdn[pid].is_active = TRUE;
/* Update the emergency bearer services indicator */
if (pdn->is_emergency) {
esm_ctx->emergency = TRUE;
}
// LG ADD TEMP
{
char *tmp = NULL;
char ipv4_addr[INET_ADDRSTRLEN];
//char ipv6_addr[INET6_ADDRSTRLEN];
char *netmask = NULL;
char broadcast[INET_ADDRSTRLEN];
struct in_addr in_addr;
char command_line[128];
int res;
switch (pdn->type) {
case NET_PDN_TYPE_IPV4V6:
//ipv6_addr[0] = pdn->ip_addr[4];
/* TODO? */
// etc
case NET_PDN_TYPE_IPV4:
// in_addr is in network byte order
in_addr.s_addr = pdn->ip_addr[0] << 24 |
((pdn->ip_addr[1] << 16) & 0x00FF0000) |
((pdn->ip_addr[2] << 8) & 0x0000FF00) |
( pdn->ip_addr[3] & 0x000000FF);
in_addr.s_addr = htonl(in_addr.s_addr);
tmp = inet_ntoa(in_addr);
//AssertFatal(tmp ,
// "error in PDN IPv4 address %x",
// in_addr.s_addr);
strcpy(ipv4_addr, tmp);
if (IN_CLASSA(ntohl(in_addr.s_addr))) {
netmask = "255.0.0.0";
in_addr.s_addr = pdn->ip_addr[0] << 24 |
((255 << 16) & 0x00FF0000) |
((255 << 8) & 0x0000FF00) |
( 255 & 0x000000FF);
in_addr.s_addr = htonl(in_addr.s_addr);
tmp = inet_ntoa(in_addr);
// AssertFatal(tmp ,
// "error in PDN IPv4 address %x",
// in_addr.s_addr);
strcpy(broadcast, tmp);
} else if (IN_CLASSB(ntohl(in_addr.s_addr))) {
netmask = "255.255.0.0";
in_addr.s_addr = pdn->ip_addr[0] << 24 |
((pdn->ip_addr[1] << 16) & 0x00FF0000) |
((255 << 8) & 0x0000FF00) |
( 255 & 0x000000FF);
in_addr.s_addr = htonl(in_addr.s_addr);
tmp = inet_ntoa(in_addr);
// AssertFatal(tmp ,
// "error in PDN IPv4 address %x",
// in_addr.s_addr);
strcpy(broadcast, tmp);
} else if (IN_CLASSC(ntohl(in_addr.s_addr))) {
netmask = "255.255.255.0";
in_addr.s_addr = pdn->ip_addr[0] << 24 |
((pdn->ip_addr[1] << 16) & 0x00FF0000) |
((pdn->ip_addr[2] << 8) & 0x0000FF00) |
( 255 & 0x000000FF);
in_addr.s_addr = htonl(in_addr.s_addr);
tmp = inet_ntoa(in_addr);
// AssertFatal(tmp ,
// "error in PDN IPv4 address %x",
// in_addr.s_addr);
strcpy(broadcast, tmp);
} else {
netmask = "255.255.255.255";
strcpy(broadcast, ipv4_addr);
}
res = sprintf(command_line,
"ifconfig oip1 %s netmask %s broadcast %s",
ipv4_addr, netmask, broadcast);
(void)res; /* avoid gcc warning "set but not used" */
// AssertFatal((res > 0) && (res < 128),
// "error in system command line");
LOG_TRACE(INFO, "ESM-PROC - executing %s ",
command_line);
if (system(command_line)) ; /* TODO: what to do? */
break;
case NET_PDN_TYPE_IPV6:
break;
default:
break;
}
}
// AssertFatal(0, "Forced stop in NAS UE");
}
/* Return the EPS bearer identity of the default EPS bearer
* associated to the new EPS bearer context */
LOG_FUNC_RETURN (pdn->bearer[0]->ebi);
}
LOG_TRACE(WARNING, "ESM-PROC - Failed to create new EPS bearer "
"context (ebi=%d)", ebi);
}
LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED);
}
/****************************************************************************
** **
** Name: esm_ebr_context_release() **
** **
** Description: Releases EPS bearer context entry previously allocated **
** to the EPS bearer with the specified EPS bearer identity **
** **
** Inputs: ueid: UE identifier **
** ebi: EPS bearer identity **
** Others: _esm_data **
** **
** Outputs: pid: Identifier of the PDN connection entry the **
** EPS bearer context belongs to **
** bid: Identifier of the released EPS bearer con- **
** text entry **
** Return: The EPS bearer identity associated to the **
** EPS bearer context if successfully relea- **
** sed; UNASSIGN EPS bearer value otherwise. **
** Others: _esm_data **
** **
***************************************************************************/
int esm_ebr_context_release(
int ebi, int *pid, int *bid)
{
int found = FALSE;
esm_pdn_t *pdn = NULL;
esm_data_context_t *esm_ctx;
//unsigned int ueid = 0;
LOG_FUNC_IN;
esm_ctx = &_esm_data;
if (ebi != ESM_EBI_UNASSIGNED) {
/*
* The identity of the EPS bearer to released is given;
* Release the EPS bearer context entry that match the specified EPS
* bearer identity
*/
/* Search for active PDN connection */
for (*pid = 0; *pid < ESM_DATA_PDN_MAX; (*pid)++) {
if ( !esm_ctx->pdn[*pid].is_active ) {
continue;
}
/* An active PDN connection is found */
if (esm_ctx->pdn[*pid].data != NULL) {
pdn = esm_ctx->pdn[*pid].data;
/* Search for the specified EPS bearer context entry */
for (*bid = 0; *bid < pdn->n_bearers; (*bid)++) {
if (pdn->bearer[*bid] != NULL) {
if (pdn->bearer[*bid]->ebi != ebi) {
continue;
}
/* The EPS bearer context entry is found */
found = TRUE;
break;
}
}
}
if (found) {
break;
}
}
} else {
/*
* The identity of the EPS bearer to released is not given;
* Release the EPS bearer context entry allocated with the EPS
* bearer context identifier (bid) to establish connectivity to
* the PDN identified by the PDN connection identifier (pid).
* Default EPS bearer to a given PDN is always identified by the
* first EPS bearer context entry at index bid = 0
*/
if (*pid < ESM_DATA_PDN_MAX) {
if (*pid != esm_ctx->pdn[*pid].pid) {
LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier %d "
"is not valid", *pid);
} else if (!esm_ctx->pdn[*pid].is_active) {
LOG_TRACE(WARNING,"ESM-PROC - PDN connection %d is not active",
*pid);
} else if (esm_ctx->pdn[*pid].data == NULL) {
LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been "
"allocated", *pid);
} else {
pdn = esm_ctx->pdn[*pid].data;
if (pdn->bearer[*bid] != NULL) {
ebi = pdn->bearer[*bid]->ebi;
found = TRUE;
}
}
}
}
if (found) {
int i, j;
/*
* Delete the specified EPS bearer context entry
*/
if (pdn->bearer[*bid]->bid != *bid) {
LOG_TRACE(ERROR, "ESM-PROC - EPS bearer identifier %d is "
"not valid", *bid);
LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED);
}
LOG_TRACE(WARNING, "ESM-PROC - Release EPS bearer context "
"(ebi=%d)", ebi);
/* Delete the TFT */
for (i = 0; i < pdn->bearer[*bid]->tft.n_pkfs; i++) {
free(pdn->bearer[*bid]->tft.pkf[i]);
}
/* Release the specified EPS bearer data */
free(pdn->bearer[*bid]);
pdn->bearer[*bid] = NULL;
/* Decrement the number of EPS bearer context allocated
* to the PDN connection */
pdn->n_bearers -= 1;
/* Decrement the total number of active EPS bearers */
esm_ctx->n_ebrs -= 1;
if (*bid == 0) {
/* 3GPP TS 24.301, section 6.4.4.3, 6.4.4.6
* If the EPS bearer identity is that of the default bearer to a
* PDN, the UE shall delete all EPS bearer contexts associated to
* that PDN connection.
*/
for (i = 1; pdn->n_bearers > 0; i++) {
if (pdn->bearer[i]) {
LOG_TRACE(WARNING, "ESM-PROC - Release EPS bearer context "
"(ebi=%d)", pdn->bearer[i]->ebi);
/* Delete the TFT */
for (j = 0; j < pdn->bearer[i]->tft.n_pkfs; j++) {
free(pdn->bearer[i]->tft.pkf[j]);
}
/* Set the EPS bearer context state to INACTIVE */
(void) esm_ebr_set_status(pdn->bearer[i]->ebi,
ESM_EBR_INACTIVE, TRUE);
/* Release EPS bearer data */
(void) esm_ebr_release(pdn->bearer[i]->ebi);
// esm_ebr_release()
/* Release dedicated EPS bearer data */
free(pdn->bearer[i]);
pdn->bearer[i] = NULL;
/* Decrement the number of EPS bearer context allocated
* to the PDN connection */
pdn->n_bearers -= 1;
/* Decrement the total number of active EPS bearers */
esm_ctx->n_ebrs -= 1;
}
}
/* Reset the PDN connection activation indicator */
esm_ctx->pdn[*pid].is_active = FALSE;
/* Update the emergency bearer services indicator */
if (pdn->is_emergency) {
esm_ctx->emergency = FALSE;
}
}
/* 3GPP TS 24.301, section 6.4.4.6
* If the UE locally deactivated all EPS bearer contexts, the UE
* shall perform a local detach and enter state EMM-DEREGISTERED.
*/
if (esm_ctx->n_ebrs == 0) {
emm_sap_t emm_sap;
emm_sap.primitive = EMMESM_ESTABLISH_CNF;
emm_sap.u.emm_esm.u.establish.is_attached = FALSE;
(void) emm_sap_send(&emm_sap);
}
/* 3GPP TS 24.301, section 6.4.4.3, 6.4.4.6
* If due to the EPS bearer context deactivation only the PDN
* connection for emergency bearer services remains established,
* the UE shall consider itself attached for emergency bearer
* services only.
*/
else if (esm_ctx->emergency && (esm_ctx->n_ebrs == 1) ) {
emm_sap_t emm_sap;
emm_sap.primitive = EMMESM_ESTABLISH_CNF;
emm_sap.u.emm_esm.u.establish.is_attached = TRUE;
emm_sap.u.emm_esm.u.establish.is_emergency = TRUE;
(void) emm_sap_send(&emm_sap);
}
LOG_FUNC_RETURN (ebi);
}
LOG_FUNC_RETURN (ESM_EBI_UNASSIGNED);
}
/****************************************************************************
** **
** Name: esm_ebr_context_get_pid() **
** **
** Description: Returns the identifier of the PDN connection entry the **
** default EPS bearer context with the specified EPS bearer **
** identity belongs to **
** **
** Inputs: ebi: The EPS bearer identity of the default EPS **
** bearer context **
** Others: _esm_data **
** **
** Outputs: None **
** Return: The identifier of the PDN connection entry **
** associated to the specified default EPS **
** bearer context if it exists; -1 otherwise. **
** Others: None **
** **
***************************************************************************/
int esm_ebr_context_get_pid(int ebi)
{
LOG_FUNC_IN;
int pid;
for (pid = 0; pid < ESM_DATA_PDN_MAX; pid++) {
if (_esm_data.pdn[pid].data == NULL) {
continue;
}
if (_esm_data.pdn[pid].data->bearer[0] == NULL) {
continue;
}
if (_esm_data.pdn[pid].data->bearer[0]->ebi == ebi) {
break;
}
}
if (pid < ESM_DATA_PDN_MAX) {
LOG_FUNC_RETURN (pid);
}
LOG_FUNC_RETURN (-1);
}
/****************************************************************************
** **
** Name: esm_ebr_context_check_tft() **
** **
** Description: Checks syntactical errors in packet filters associated to **
** the EPS bearer context with the specified EPS bearer **
** identity for the PDN connection entry with the given **
** identifier **
** **
** Inputs: pid: Identifier of the PDN connection entry the **
** EPS bearer context belongs to **
** ebi: The EPS bearer identity of the EPS bearer **
** context with associated packet filter list **
** tft: The traffic flow template (set of packet **
** filters) to be checked **
** operation: Traffic flow template operation **
** Others: _esm_data **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int esm_ebr_context_check_tft(int pid, int ebi,
const network_tft_t *tft,
esm_ebr_context_tft_t operation)
{
LOG_FUNC_IN;
int rc = RETURNerror;
int i;
if (pid < ESM_DATA_PDN_MAX) {
if (pid != _esm_data.pdn[pid].pid) {
LOG_TRACE(ERROR, "ESM-PROC - PDN connection identifier %d "
"is not valid", pid);
} else if (_esm_data.pdn[pid].data == NULL) {
LOG_TRACE(ERROR, "ESM-PROC - PDN connection %d has not been "
"allocated", pid);
} else if (operation == ESM_EBR_CONTEXT_TFT_CREATE) {
esm_pdn_t *pdn = _esm_data.pdn[pid].data;
/* For each EPS bearer context associated to the PDN connection */
for (i = 0; i < pdn->n_bearers; i++) {
if (pdn->bearer[i]) {
if (pdn->bearer[i]->ebi == ebi) {
/* Check the packet filter identifiers */
rc = _esm_ebr_context_check_identifiers(tft,
&pdn->bearer[i]->tft);
if (rc != RETURNok) {
break;
}
}
/* Check the packet filter precedence values */
rc = _esm_ebr_context_check_precedence(tft,
&pdn->bearer[i]->tft);
if (rc != RETURNok) {
break;
}
}
}
}
}
LOG_FUNC_RETURN (rc);
}
/****************************************************************************/
/********************* L O C A L F U N C T I O N S *********************/
/****************************************************************************/
/****************************************************************************
** **
** Name: _esm_ebr_context_check_identifiers() **
** **
** Description: Compares traffic flow templates to check whether two or **
** more packet filters have identical packet filter identi- **
** fiers **
** **
** Inputs: tft1: The first set of packet filters **
** tft2: The second set of packet filters **
** Others: None **
** **
** Outputs: None **
** Return: RETURNerror if at least one packet filter **
** has same identifier in both traffic flow **
** templates; RETURNok otherwise. **
** Others: None **
** **
***************************************************************************/
static int _esm_ebr_context_check_identifiers(const network_tft_t *tft1,
const network_tft_t *tft2)
{
int i;
int j;
if ( (tft1 == NULL) || (tft2 == NULL) ) {
return (RETURNok);
}
for (i = 0; i < tft1->n_pkfs; i++) {
for (j = 0; j < tft2->n_pkfs; j++) {
/* Packet filters should have been allocated */
if (tft1->pkf[i]->id == tft2->pkf[i]->id) {
/* 3GPP TS 24.301, section 6.4.2.5, abnormal cases d.1
* Packet filters have same identifier */
return (RETURNerror);
}
}
}
return (RETURNok);
}
/****************************************************************************
** **
** Name: _esm_ebr_context_check_precedence() **
** **
** Description: Compares traffic flow templates to check whether two or **
** more packet filters have identical precedence values **
** **
** Inputs: tft1: The first set of packet filters **
** tft2: The second set of packet filters **
** Others: None **
** **
** Outputs: None **
** Return: RETURNerror if at least one packet filter **
** has same precedence value in both traffic **
** flow templates; RETURNerror otherwise. **
** Others: None **
** **
***************************************************************************/
static int _esm_ebr_context_check_precedence(const network_tft_t *tft1,
const network_tft_t *tft2)
{
int i;
int j;
if ( (tft1 == NULL) || (tft2 == NULL) ) {
return (RETURNok);
}
for (i = 0; i < tft1->n_pkfs; i++) {
for (j = 0; j < tft2->n_pkfs; j++) {
/* Packet filters should have been allocated */
if (tft1->pkf[i]->precedence == tft2->pkf[i]->precedence) {
/* 3GPP TS 24.301, section 6.4.2.5, abnormal cases d.2
* Packet filters have same precedence value */
/* TODO: Actually if the old packet filters do not belong
* to the default EPS bearer context, the UE shall not
* diagnose an error (see 6.4.2.5, abnormal cases d.2) */
return (RETURNerror);
}
}
}
return (RETURNok);
}