Files
openairinterface5g/openair3/NAS/UE/nas_proc.c
T
2015-10-06 16:53:42 +00:00

1424 lines
61 KiB
C
Executable File

/*******************************************************************************
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 <http://www.gnu.org/licenses/>.
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 nas_proc.c
Version 0.1
Date 2012/09/20
Product NAS stack
Subsystem NAS main process
Author Frederic Maurel
Description NAS procedure call manager
*****************************************************************************/
#include "nas_proc.h"
#include "nas_log.h"
#include "emm_main.h"
#include "emm_sap.h"
#include "esm_main.h"
#include "esm_sap.h"
#include "msc.h"
#include <stdio.h> // sprintf
/****************************************************************************/
/**************** 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 *******************/
/****************************************************************************/
/*
* Signal strength/quality value not known or not detectable
*/
#define NAS_PROC_RSRQ_UNKNOWN 255
#define NAS_PROC_RSRP_UNKNOWN 255
/*
* Local NAS data
*/
static struct {
/* EPS capibility status */
int EPS_capability_status;
/* Reference signal received quality */
int rsrq;
/* Reference signal received power */
int rsrp;
} _nas_proc_data;
static int _nas_proc_activate(int cid, int apply_to_all);
static int _nas_proc_deactivate(int cid, int apply_to_all);
/****************************************************************************/
/****************** E X P O R T E D F U N C T I O N S ******************/
/****************************************************************************/
/****************************************************************************
** **
** Name: nas_proc_initialize() **
** **
** Description: **
** **
** Inputs: emm_cb: Mobility Management indication callback **
** esm_cb: Session Management indication callback **
** imei: The IMEI read from the UE's non-volatile **
** memory **
** Others: None **
** **
** Outputs: None **
** Return: None **
** Others: _nas_proc_data **
** **
***************************************************************************/
void nas_proc_initialize(emm_indication_callback_t emm_cb,
esm_indication_callback_t esm_cb, const char *imei)
{
LOG_FUNC_IN;
/* Initialize local NAS data */
_nas_proc_data.EPS_capability_status = FALSE;
_nas_proc_data.rsrq = NAS_PROC_RSRQ_UNKNOWN;
_nas_proc_data.rsrp = NAS_PROC_RSRP_UNKNOWN;
/* Initialize the EMM procedure manager */
emm_main_initialize(emm_cb, imei);
/* Initialize the ESM procedure manager */
esm_main_initialize(esm_cb);
LOG_FUNC_OUT;
}
/****************************************************************************
** **
** Name: nas_proc_cleanup() **
** **
** Description: Performs clean up procedure before the system is shutdown **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: None **
** Others: None **
** **
***************************************************************************/
void nas_proc_cleanup(void)
{
LOG_FUNC_IN;
/* Detach the UE from the EPS network */
int rc = nas_proc_detach(TRUE);
if (rc != RETURNok) {
LOG_TRACE(ERROR, "NAS-PROC - Failed to detach from the network");
}
/* Perform the EPS Mobility Manager's clean up procedure */
emm_main_cleanup();
/* Perform the EPS Session Manager's clean up procedure */
esm_main_cleanup();
LOG_FUNC_OUT;
}
/*
* --------------------------------------------------------------------------
* NAS procedures triggered by the user
* --------------------------------------------------------------------------
*/
/****************************************************************************
** **
** Name: nas_proc_enable_s1_mode() **
** **
** Description: Notify the EPS Mobility Manager that the UE can be **
** operated **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_enable_s1_mode(void)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that EPS capability
* of the UE is enabled
*/
_nas_proc_data.EPS_capability_status = TRUE;
emm_sap.primitive = EMMREG_S1_ENABLED;
rc = emm_sap_send(&emm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_disable_s1_mode() **
** **
** Description: Notify the EPS Mobility Manager that the S1 mode is no **
** longer activated **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_disable_s1_mode(void)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that EPS capability
* of the UE is disabled
*/
_nas_proc_data.EPS_capability_status = FALSE;
emm_sap.primitive = EMMREG_S1_DISABLED;
rc = emm_sap_send(&emm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_get_eps() **
** **
** Description: Get the current value of the EPS capability status **
** **
** Inputs: None **
** Others: _nas_proc_data **
** **
** Outputs: stat: The current value of the EPS capability **
** status **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_eps(int *stat)
{
LOG_FUNC_IN;
*stat = _nas_proc_data.EPS_capability_status;
LOG_FUNC_RETURN (RETURNok);
}
/****************************************************************************
** **
** Name: nas_proc_get_imsi() **
** **
** Description: Get the International Mobile Subscriber Identity number **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: imsi: The value of the IMSI **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_imsi(char *imsi_str)
{
LOG_FUNC_IN;
const imsi_t *imsi = emm_main_get_imsi();
if (imsi != NULL) {
int offset = 0;
offset += sprintf(imsi_str + offset, "%u%u%u%u%u",
imsi->u.num.digit1, imsi->u.num.digit2,
imsi->u.num.digit3, imsi->u.num.digit4,
imsi->u.num.digit5);
if (imsi->u.num.digit6 != 0xf) {
offset += sprintf(imsi_str + offset, "%u", imsi->u.num.digit6);
}
offset += sprintf(imsi_str + offset, "%u%u%u%u%u%u%u%u",
imsi->u.num.digit7, imsi->u.num.digit8,
imsi->u.num.digit9, imsi->u.num.digit10,
imsi->u.num.digit11, imsi->u.num.digit12,
imsi->u.num.digit13, imsi->u.num.digit14);
if (imsi->u.num.digit15 != 0xf) {
offset += sprintf(imsi_str + offset, "%u", imsi->u.num.digit15);
}
LOG_FUNC_RETURN (RETURNok);
}
LOG_FUNC_RETURN (RETURNerror);
}
/****************************************************************************
** **
** Name: nas_proc_get_msisdn() **
** **
** Description: Get the Mobile Subscriber dialing number **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: msisdn: The value of the subscriber dialing number **
** ton_npi: Type Of Number / Numbering Plan Indicator **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_msisdn(char *msisdn_str, int *ton_npi)
{
LOG_FUNC_IN;
const msisdn_t *msisdn = emm_main_get_msisdn();
if (msisdn != NULL) {
union {
struct {
Byte_t ext:1;
Byte_t ton:3;
Byte_t npi:4;
} ext_ton_npi;
Byte_t type;
} converter;
converter.ext_ton_npi.ext = msisdn->ext;
converter.ext_ton_npi.ton = msisdn->ton;
converter.ext_ton_npi.npi = msisdn->npi;
*ton_npi = converter.type;
sprintf(msisdn_str, "%u%u%u%u%u%u%u%u%u%u%u",
msisdn->digit[0].msb, msisdn->digit[0].lsb,
msisdn->digit[1].msb, msisdn->digit[1].lsb,
msisdn->digit[2].msb, msisdn->digit[2].lsb,
msisdn->digit[3].msb, msisdn->digit[3].lsb,
msisdn->digit[4].msb, msisdn->digit[4].lsb,
msisdn->digit[5].msb);
LOG_FUNC_RETURN (RETURNok);
}
LOG_FUNC_RETURN (RETURNerror);
}
/****************************************************************************
** **
** Name: nas_proc_get_signal_quality() **
** **
** Description: Get the signal strength/quality parameters **
** **
** Inputs: None **
** Others: _nas_proc_data **
** **
** Outputs: rsrq: Reference signal received quality value **
** rsrp: Reference signal received power value **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_signal_quality(int *rsrq, int *rsrp)
{
LOG_FUNC_IN;
*rsrq = _nas_proc_data.rsrq;
*rsrp = _nas_proc_data.rsrp;
LOG_FUNC_RETURN (RETURNok);
}
/****************************************************************************
** **
** Name: nas_proc_register() **
** **
** Description: Execute the network selection and registration procedure. **
** **
** Inputs: mode: Network selection mode of operation **
** format: Represention format of the operator iden- **
** tifier **
** oper: Identifier of the network operator to re- **
** gister **
** AcT: The selected Access Technology **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_register(int mode, int format, const network_plmn_t *oper, int AcT)
{
LOG_FUNC_IN;
int rc = RETURNerror;
/*
* Set the PLMN selection mode of operation
*/
int index = emm_main_set_plmn_selection_mode(mode, format, oper, AcT);
if ( !(index < 0) ) {
/*
* Notify the EMM procedure call manager that network (re)selection
* procedure has to be executed
*/
emm_sap_t emm_sap;
emm_sap.primitive = EMMREG_REGISTER_REQ;
emm_sap.u.emm_reg.u.regist.index = index;
rc = emm_sap_send(&emm_sap);
}
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_deregister() **
** **
** Description: Execute the network deregistration procedure. **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_deregister(void)
{
LOG_FUNC_IN;
/* TODO: Force an attempt to deregister from the network */
LOG_TRACE(ERROR, "NAS-PROC - Network deregistration procedure is "
"not implemented");
LOG_FUNC_RETURN (RETURNok);
}
/****************************************************************************
** **
** Name: nas_proc_get_reg_data() **
** **
** Description: Gets network registration data from EMM **
** **
** Inputs: format: Format of the representation of the net- **
** work operator identifier **
** Others: None **
** **
** Outputs: mode: The current network selection mode of ope- **
** ration **
** oper: The identifier of the selected network **
** operator **
** AcT: The access technology currently used **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_reg_data(int *mode, int *selected, int format,
network_plmn_t *oper, int *AcT)
{
LOG_FUNC_IN;
/* Get the PLMN selection mode of operation */
*mode = emm_main_get_plmn_selection_mode();
/* Get the currently selected operator */
const char *oper_name = emm_main_get_selected_plmn(oper, format);
if (oper_name != NULL) {
/* An operator is currently selected */
*selected = TRUE;
/* Get the supported Radio Access Technology */
*AcT = emm_main_get_plmn_rat();
} else {
/* No any operator is selected */
*selected = FALSE;
*AcT = NET_ACCESS_UNAVAILABLE;
}
LOG_FUNC_RETURN (RETURNok);
}
/****************************************************************************
** **
** Name: nas_proc_get_oper_list() **
** **
** Description: Gets the list of operators present in the network **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: oper_list: The list of operators **
** Return: The size of the list in bytes **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_oper_list(const char **oper_list)
{
LOG_FUNC_IN;
int size = emm_main_get_plmn_list(oper_list);
LOG_FUNC_RETURN (size);
}
/****************************************************************************
** **
** Name: nas_proc_get_reg_status() **
** **
** Description: Get the value of the network registration status which **
** shows whether the network has currently indicated the **
** registration of the UE **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: stat: The current network registration status **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_reg_status(int *stat)
{
LOG_FUNC_IN;
*stat = emm_main_get_plmn_status();
LOG_FUNC_RETURN (RETURNok);
}
/****************************************************************************
** **
** Name: nas_proc_get_loc_info() **
** **
** Description: Get the location information when the UE is registered in **
** the Network **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: tac: The code of the tracking area the registe- **
** red PLMN belongs to **
** ci: The identifier of the serving cell **
** AcT: The access technology in used **
** rac: The GPRS routing area code, if available **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_loc_info(char *tac, char *ci, int *AcT)
{
LOG_FUNC_IN;
sprintf(tac, "%.4x", emm_main_get_plmn_tac()); // two byte
sprintf(ci, "%.8x", emm_main_get_plmn_ci()); // four byte
*AcT = emm_main_get_plmn_rat(); // E-UTRAN
LOG_FUNC_RETURN (RETURNok);
}
/****************************************************************************
** **
** Name: nas_proc_detach() **
** **
** Description: Initiates a detach procedure **
** **
** Inputs: switch_off: TRUE if the detach is due to UE switch-off **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_detach(int switch_off)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc = RETURNok;
if ( emm_main_is_attached() ) {
/* Initiate an Detach procedure */
emm_sap.primitive = EMMREG_DETACH_INIT;
emm_sap.u.emm_reg.u.detach.switch_off = switch_off;
rc = emm_sap_send(&emm_sap);
}
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_attach() **
** **
** Description: Initiates an attach procedure **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_attach(void)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc = RETURNok;
if ( !emm_main_is_attached() ) {
/* Initiate an Attach procedure */
emm_sap.primitive = EMMREG_ATTACH_INIT;
emm_sap.u.emm_reg.u.attach.is_emergency = FALSE;
rc = emm_sap_send(&emm_sap);
}
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_get_attach_status() **
** **
** Description: Gets the current network attachment status **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: TRUE if the UE is currently attached to **
** the network **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_attach_status(void)
{
LOG_FUNC_IN;
int is_attached = emm_main_is_attached();
LOG_FUNC_RETURN (is_attached);
}
/****************************************************************************
** **
** Name: nas_proc_pdn_range() **
** **
** Description: Gets the maximum value of a PDN context identifier **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: The PDN context identifier maximum value **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_pdn_range(void)
{
LOG_FUNC_IN;
int max_pdn_id = esm_main_get_nb_pdns_max();
LOG_FUNC_RETURN (max_pdn_id);
}
/****************************************************************************
** **
** Name: nas_proc_get_pdn_status() **
** **
** Description: Gets the activation state of every defined PDN contexts **
** **
** Inputs: n_pdn_max: Maximum number of PDN contexts **
** Others: None **
** **
** Outputs: cids: List of PDN context identifiers **
** states: List of PDN context activation states **
** Return: The number of PDN contexts that are cur- **
** rently in a defined state **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_pdn_status(int *cids, int *states, int n_pdn_max)
{
LOG_FUNC_IN;
int cid;
int n_defined_pdn = 0;
/* Get the maximum number of supported PDN contexts */
int n_pdn = esm_main_get_nb_pdns_max();
/* For all PDN contexts */
for (cid = 1; (cid < n_pdn+1) && (n_defined_pdn < n_pdn_max); cid++) {
/* Get the status of this PDN */
int state = FALSE;
int is_defined = esm_main_get_pdn_status(cid, &state);
if (is_defined != FALSE) {
/* This PDN has been defined */
*(cids++) = cid;
*(states++) = state;
n_defined_pdn += 1;
}
}
LOG_FUNC_RETURN (n_defined_pdn);
}
/****************************************************************************
** **
** Name: nas_proc_get_pdn_param() **
** **
** Description: Gets the parameters of every defined PDN contexts **
** **
** Inputs: n_pdn_max: Maximum number of PDN contexts **
** Others: None **
** **
** Outputs: cids: List of PDN context identifiers **
** types: List of PDN types (IPv4, IPv6, IPv4v6) **
** apns: List of Access Point Names **
** Return: The number of PDN contexts that are cur- **
** rently in a defined state **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_pdn_param(int *cids, int *types, const char **apns,
int n_pdn_max)
{
LOG_FUNC_IN;
int cid;
int n_defined_pdn = 0;
/* Get the maximum number of supported PDN contexts */
int n_pdn = esm_main_get_nb_pdns_max();
/* For all PDN contexts */
for (cid = 1; (cid < n_pdn+1) && (n_defined_pdn < n_pdn_max); cid++) {
int emergency, active;
/* Get PDN connection parameters */
int rc = esm_main_get_pdn(cid, types, apns, &emergency, &active);
if (rc != RETURNerror) {
/* This PDN has been defined */
*(cids++) = cid;
types++;
apns++;
n_defined_pdn += 1;
}
}
LOG_FUNC_RETURN (n_defined_pdn);
}
/****************************************************************************
** **
** Name: nas_proc_get_pdn_addr() **
** **
** Description: When the cid parameter value is positive, gets the addres-**
** s(es) assigned to the specified PDN context. **
** When the cid parameter value is negative, gets the addres-**
** s(es) assigned to each defined PDN context. **
** When the cid parameter value is null, gets the list of **
** defined PDN contexts. **
** **
** Inputs: cid: PDN context identifier **
** n_pdn_max: Maximum number of PDN contexts **
** Others: None **
** **
** Outputs: cids: List of PDN context identifiers **
** addr1: List of IPv4 addresses **
** addr2: List of IPv6 addresses **
** Return: The number PDN contexts that have at least **
** one IP address assigned **
** Others: None **
** **
***************************************************************************/
int nas_proc_get_pdn_addr(int cid, int *cids, const char **addr1,
const char **addr2, int n_pdn_max)
{
LOG_FUNC_IN;
int rc;
int n_defined_pdn = 0;
if (cid > 0) {
/* Get addresses assigned to the specified PDN */
rc = esm_main_get_pdn_addr(cid, addr1, addr2);
if (rc != RETURNerror) {
*cids = cid;
n_defined_pdn = 1;
}
} else if (cid < 0) {
/* Get the maximum number of supported PDN contexts */
int n_pdn = esm_main_get_nb_pdns_max();
/* For all PDN contexts */
for (cid = 1; (cid < n_pdn+1) && (n_defined_pdn < n_pdn_max); cid++) {
/* Get PDN connection addresses */
rc = esm_main_get_pdn_addr(cid, addr1, addr2);
if (rc != RETURNerror) {
/* This PDN has been defined */
*(cids++) = cid;
addr1++;
addr2++;
n_defined_pdn += 1;
}
}
} else {
/* Get the list of defined PDN contexts */
}
LOG_FUNC_RETURN (n_defined_pdn);
}
/****************************************************************************
** **
** Name: nas_proc_set_pdn() **
** **
** Description: Setup parameters of a specified PDN context **
** **
** Inputs: cid: Identifier of the PDN context to setup **
** type: Type of PDN (IPv4, IPv6,IPv4v6) **
** apn: Access Point Name of the external network **
** to connect to **
** ipv4_addr: IPv4 address allocation (NAS, DHCP) **
** emergency: Emergency bearer support indication **
** p_cscf: Preference of P-CSCF address discovery **
** im_cn_signal: IM CN subsystem-related signalling indica- **
** tion parameter **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_set_pdn(int cid, int type, const char *apn, int ipv4_addr,
int emergency, int p_cscf, int im_cn_signal)
{
LOG_FUNC_IN;
int rc;
esm_sap_t esm_sap;
esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ;
esm_sap.is_standalone = TRUE;
esm_sap.data.pdn_connect.is_defined = FALSE;
esm_sap.data.pdn_connect.cid = cid;
esm_sap.data.pdn_connect.pdn_type = type;
esm_sap.data.pdn_connect.apn = apn;
esm_sap.data.pdn_connect.is_emergency = emergency;
/*
* Notify ESM that a new PDN context has to be defined for
* the specified APN
*/
rc = esm_sap_send(&esm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_reset_pdn() **
** **
** Description: Reset parameters of a specified PDN context **
** **
** Inputs: cid: Identifier of the PDN context to setup **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_reset_pdn(int cid)
{
LOG_FUNC_IN;
int rc;
esm_sap_t esm_sap;
esm_sap.primitive = ESM_PDN_CONNECTIVITY_REJ;
esm_sap.is_standalone = TRUE;
esm_sap.data.pdn_connect.is_defined = TRUE;
esm_sap.data.pdn_connect.cid = cid;
/*
* Notify ESM that the specified PDN context has to be undefined
*/
rc = esm_sap_send(&esm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_deactivate_pdn() **
** **
** Description: Deactivates specified PDN context or all PDN contexts if **
** specified cid is negative **
** **
** Inputs: cid: Identifier of the PDN context to be deac- **
** tivate **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_deactivate_pdn(int cid)
{
LOG_FUNC_IN;
int rc = RETURNok;
if (cid > 0) {
/* Deactivate only the specified PDN context */
rc = _nas_proc_deactivate(cid, FALSE);
} else {
/* Do not deactivate the PDN connection established during initial
* network attachment (identifier 1) */
cid = 2;
/* Deactivate all active PDN contexts */
while ((rc != RETURNerror) && (cid < esm_main_get_nb_pdns_max()+1)) {
rc = _nas_proc_deactivate(cid++, TRUE);
}
}
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_activate_pdn() **
** **
** Description: Activates specified PDN context or all PDN contexts if **
** specified cid is negative **
** **
** Inputs: cid: Identifier of the PDN context to be act- **
** tivate **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_activate_pdn(int cid)
{
LOG_FUNC_IN;
int rc = RETURNok;
if ( !emm_main_is_attached() ) {
/*
* If the UE is not attached to the network, perform EPS attach
* procedure prior to attempt to request any PDN connectivity
*/
LOG_TRACE(WARNING, "NAS-PROC - UE is not attached to the network");
rc = nas_proc_attach();
} else if (emm_main_is_emergency()) {
/* The UE is attached for emergency bearer services; It shall not
* request a PDN connection to any other PDN */
LOG_TRACE(WARNING,"NAS-PROC - Attached for emergency bearer services");
rc = RETURNerror;
}
if (rc != RETURNerror) {
if (cid > 0) {
/* Activate only the specified PDN context */
rc = _nas_proc_activate(cid, FALSE);
} else {
cid = 1;
/* Activate all defined PDN contexts */
while ((rc != RETURNerror) && (cid < esm_main_get_nb_pdns_max()+1)) {
rc = _nas_proc_activate(cid++, TRUE);
}
}
}
LOG_FUNC_RETURN (rc);
}
/*
* --------------------------------------------------------------------------
* NAS procedures triggered by the network
* --------------------------------------------------------------------------
*/
/****************************************************************************
** **
** Name: nas_proc_cell_info() **
** **
** Description: Processes the cell information received from the network **
** **
** Inputs: found: Indicates whether a suitable cell is found **
** for the selected PLMN to camp on **
** tac: The code of the tracking area the PLMN **
** belongs to **
** ci: The identifier of a cell serving this PLMN **
** AcT: The access technology supported by the **
** serving cell **
** rsrq: Reference signal received quality measure- **
** ment **
** rsrp: Reference signal received power measure- **
** ment **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: _nas_proc_data **
** **
***************************************************************************/
int nas_proc_cell_info(int found, tac_t tac, ci_t ci, AcT_t AcT,
uint8_t rsrq, uint8_t rsrp)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/* Store LTE signal strength/quality measurement data */
_nas_proc_data.rsrq = rsrq;
_nas_proc_data.rsrp = rsrp;
/*
* Notify the EMM procedure call manager that cell information
* have been received from the Access-Stratum sublayer
*/
emm_sap.primitive = EMMAS_CELL_INFO_RES;
emm_sap.u.emm_as.u.cell_info.found = found;
emm_sap.u.emm_as.u.cell_info.plmnIDs.n_plmns = 0;
emm_sap.u.emm_as.u.cell_info.rat = AcT;
emm_sap.u.emm_as.u.cell_info.tac = tac;
emm_sap.u.emm_as.u.cell_info.cellID = ci;
rc = emm_sap_send(&emm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_establish_cnf() **
** **
** Description: Processes the NAS signalling connection establishment **
** confirm message received from the network **
** **
** Inputs: data: The initial NAS message transfered within **
** the message **
** len: The length of the initial NAS message **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_establish_cnf(const Byte_t *data, uint32_t len)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that NAS signalling
* connection establishment confirm message has been received
* from the Access-Stratum sublayer
*/
emm_sap.primitive = EMMAS_ESTABLISH_CNF;
emm_sap.u.emm_as.u.establish.NASmsg.length = len;
emm_sap.u.emm_as.u.establish.NASmsg.value = (uint8_t *)data;
rc = emm_sap_send(&emm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_establish_rej() **
** **
** Description: Processes the NAS signalling connection establishment **
** confirm message received from the network while initial **
** NAS message has not been delivered to the NAS sublayer on **
** the receiver side. **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_establish_rej(void)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that transmission
* failure of initial NAS message indication has been received
* from lower layers
*/
emm_sap.primitive = EMMAS_ESTABLISH_REJ;
rc = emm_sap_send(&emm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_release_ind() **
** **
** Description: Processes the NAS signalling connection release indica- **
** tion message received from the network **
** **
** Inputs: cause: The release cause **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_release_ind(int cause)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that the NAS signalling
* connection has been terminated by the network
*/
emm_sap.primitive = EMMAS_RELEASE_IND;
emm_sap.u.emm_as.u.release.cause = cause;
rc = emm_sap_send(&emm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_ul_transfer_cnf() **
** **
** Description: Processes the uplink data transfer confirm message recei- **
** ved from the network while NAS message has been success- **
** fully delivered to the NAS sublayer on the receiver side. **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_ul_transfer_cnf(void)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that uplink NAS message
* has been successfully delivered to the NAS sublayer on the
* receiver side
*/
emm_sap.primitive = EMMAS_DATA_IND;
emm_sap.u.emm_as.u.data.ueid = 0;
emm_sap.u.emm_as.u.data.delivered = TRUE;
emm_sap.u.emm_as.u.data.NASmsg.length = 0;
rc = emm_sap_send(&emm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_ul_transfer_rej() **
** **
** Description: Processes the uplink data transfer confirm message recei- **
** ved from the network while NAS message has not been deli- **
** vered to the NAS sublayer on the receiver side. **
** **
** Inputs: None **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_ul_transfer_rej(void)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that transmission
* failure of uplink NAS message indication has been received
* from lower layers
*/
emm_sap.primitive = EMMAS_DATA_IND;
emm_sap.u.emm_as.u.data.ueid = 0;
emm_sap.u.emm_as.u.data.delivered = FALSE;
emm_sap.u.emm_as.u.data.NASmsg.length = 0;
rc = emm_sap_send(&emm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: nas_proc_dl_transfer_ind() **
** **
** Description: Processes downlink data transfer indication message re- **
** ceived from the network **
** **
** Inputs: data: The transfered NAS message **
** len: The length of the NAS message **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
int nas_proc_dl_transfer_ind(const Byte_t *data, uint32_t len)
{
LOG_FUNC_IN;
int rc = RETURNerror;
if (len > 0) {
emm_sap_t emm_sap;
/*
* Notify the EMM procedure call manager that data transfer
* indication has been received from the Access-Stratum sublayer
*/
emm_sap.primitive = EMMAS_DATA_IND;
emm_sap.u.emm_as.u.data.ueid = 0;
emm_sap.u.emm_as.u.data.delivered = TRUE;
emm_sap.u.emm_as.u.data.NASmsg.length = len;
emm_sap.u.emm_as.u.data.NASmsg.value = (uint8_t *)data;
rc = emm_sap_send(&emm_sap);
}
LOG_FUNC_RETURN (rc);
}
/****************************************************************************/
/********************* L O C A L F U N C T I O N S *********************/
/****************************************************************************/
/****************************************************************************
** **
** Name: _nas_proc_activate() **
** **
** Description: Initiates a PDN connectivity procedure **
** **
** Inputs: cid: Identifier of the PDN context used to es- **
** tablished connectivity to specified PDN **
** apply_to_all: TRUE if the PDN connectivity procedure is **
** initiated to establish connectivity to all **
** defined PDNs **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
static int _nas_proc_activate(int cid, int apply_to_all)
{
LOG_FUNC_IN;
int rc;
int active = FALSE;
esm_sap_t esm_sap;
/* Get PDN context parameters */
rc = esm_main_get_pdn(cid, &esm_sap.data.pdn_connect.pdn_type,
&esm_sap.data.pdn_connect.apn,
&esm_sap.data.pdn_connect.is_emergency, &active);
if (rc != RETURNok) {
/* No any context is defined for the specified PDN */
if (apply_to_all) {
/* Go ahead to activate next PDN context */
LOG_FUNC_RETURN (RETURNok);
}
/* Return an error */
LOG_FUNC_RETURN (RETURNerror);
}
if (active) {
/* The PDN context is already active */
LOG_TRACE(WARNING, "NAS-PROC - PDN connection %d is active", cid);
LOG_FUNC_RETURN (RETURNok);
}
if (esm_sap.data.pdn_connect.is_emergency) {
if (esm_main_has_emergency()) {
/* There is already a PDN connection for emergency
* bearer services established; the UE shall not
* request an additional PDN connection for emer-
* gency bearer services */
LOG_TRACE(WARNING, "NAS-PROC - PDN connection for emergency "
"bearer services is already established (cid=%d)", cid);
LOG_FUNC_RETURN (RETURNerror);
}
}
/*
* Notify ESM that a default EPS bearer has to be established
* for the specified PDN
*/
esm_sap.primitive = ESM_PDN_CONNECTIVITY_REQ;
esm_sap.is_standalone = TRUE;
esm_sap.data.pdn_connect.is_defined = TRUE;
esm_sap.data.pdn_connect.cid = cid;
rc = esm_sap_send(&esm_sap);
LOG_FUNC_RETURN (rc);
}
/****************************************************************************
** **
** Name: _nas_proc_deactivate() **
** **
** Description: Initiates a PDN disconnect procedure **
** **
** Inputs: cid: Identifier of the PDN context **
** apply_to_all: TRUE if the PDN disconnect procedure is **
** initiated to request disconnection from **
** all active PDNs **
** Others: None **
** **
** Outputs: None **
** Return: RETURNok, RETURNerror **
** Others: None **
** **
***************************************************************************/
static int _nas_proc_deactivate(int cid, int apply_to_all)
{
LOG_FUNC_IN;
int rc;
int pdn_type;
const char *apn;
int emergency = FALSE;
int active = FALSE;
/* Get PDN context parameters */
rc = esm_main_get_pdn(cid, &pdn_type, &apn, &emergency, &active);
if (rc != RETURNok) {
/* No any context is defined for the specified PDN */
if (apply_to_all) {
/* Go ahead to deactivate next PDN connection */
LOG_FUNC_RETURN (RETURNok);
}
LOG_FUNC_RETURN (RETURNerror);
}
if (!active) {
/* The PDN connection is already inactive */
LOG_TRACE(WARNING, "NAS-PROC - PDN connection %d is not active", cid);
LOG_FUNC_RETURN (RETURNok);
}
if (esm_main_get_nb_pdns() > 1) {
/*
* Notify ESM that all EPS bearers towards the specified PDN
* has to be released
*/
esm_sap_t esm_sap;
esm_sap.primitive = ESM_PDN_DISCONNECT_REQ;
esm_sap.data.pdn_disconnect.cid = cid;
rc = esm_sap_send(&esm_sap);
} else {
/* For EPS, if an attempt is made to disconnect the last PDN
* connection, then the MT responds with an error */
LOG_TRACE(WARNING,"NAS-PROC - "
"Attempt to disconnect from the last PDN is not allowed");
rc = RETURNerror;
}
LOG_FUNC_RETURN (rc);
}