Files
openairinterface5g/openair3/NAS/UE/nas_proc.c
T

1419 lines
62 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.0 (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 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 "nas_user.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
static int _nas_proc_activate(nas_user_t *user, int cid, int apply_to_all);
static int _nas_proc_deactivate(nas_user_t *user, 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(nas_user_t *user, emm_indication_callback_t emm_cb,
esm_indication_callback_t esm_cb, const char *imei)
{
LOG_FUNC_IN;
/* Initialize local NAS data */
user->proc.EPS_capability_status = FALSE;
user->proc.rsrq = NAS_PROC_RSRQ_UNKNOWN;
user->proc.rsrp = NAS_PROC_RSRP_UNKNOWN;
user->authentication_data = calloc(1, sizeof(authentication_data_t));
if ( user->authentication_data == NULL ) {
LOG_TRACE(ERROR, "NAS-PROC - Failed to alloc authentication_data");
// FIXME stop here
}
user->security_data = calloc(1, sizeof(security_data_t));
if ( user->security_data == NULL ) {
LOG_TRACE(ERROR, "NAS-PROC - Failed to alloc security_data");
// FIXME stop here
}
/* Initialize the EMM procedure manager */
emm_main_initialize(user, emm_cb, imei);
/* Initialize the ESM procedure manager */
esm_main_initialize(user, 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(nas_user_t *user)
{
LOG_FUNC_IN;
/* Detach the UE from the EPS network */
int rc = nas_proc_detach(user, 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(user->emm_data);
/* Perform the EPS Session Manager's clean up procedure */
esm_main_cleanup(user->esm_data);
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(nas_user_t *user)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that EPS capability
* of the UE is enabled
*/
user->proc.EPS_capability_status = TRUE;
emm_sap.primitive = EMMREG_S1_ENABLED;
rc = emm_sap_send(user, &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(nas_user_t *user)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc;
/*
* Notify the EMM procedure call manager that EPS capability
* of the UE is disabled
*/
user->proc.EPS_capability_status = FALSE;
emm_sap.primitive = EMMREG_S1_DISABLED;
rc = emm_sap_send(user, &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(nas_user_t *user, int *stat)
{
LOG_FUNC_IN;
*stat = user->proc.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(emm_data_t *emm_data, char *imsi_str)
{
LOG_FUNC_IN;
const imsi_t *imsi = emm_main_get_imsi(emm_data);
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(nas_user_t *user, char *msisdn_str, int *ton_npi)
{
LOG_FUNC_IN;
const msisdn_t *msisdn = emm_main_get_msisdn(user);
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(nas_user_t *user, int *rsrq, int *rsrp)
{
LOG_FUNC_IN;
*rsrq = user->proc.rsrq;
*rsrp = user->proc.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(nas_user_t *user, 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(user, 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(user, &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(nas_user_t *user)
{
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(nas_user_t *user, 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(user->emm_data);
/* Get the currently selected operator */
const char *oper_name = emm_main_get_selected_plmn(user->emm_plmn_list, user->emm_data, 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(user->emm_data);
} 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(nas_user_t *user, const char **oper_list)
{
LOG_FUNC_IN;
int size = emm_main_get_plmn_list(user->emm_plmn_list, user->emm_data, 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(nas_user_t *user, int *stat)
{
LOG_FUNC_IN;
*stat = emm_main_get_plmn_status(user->emm_data);
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(nas_user_t *user, char *tac, char *ci, int *AcT)
{
LOG_FUNC_IN;
sprintf(tac, "%.4x", emm_main_get_plmn_tac(user->emm_data)); // two byte
sprintf(ci, "%.8x", emm_main_get_plmn_ci(user->emm_data)); // four byte
*AcT = emm_main_get_plmn_rat(user->emm_data); // 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(nas_user_t *user, int switch_off)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc = RETURNok;
if ( emm_main_is_attached(user->emm_data) ) {
/* 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(user, &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(nas_user_t *user)
{
LOG_FUNC_IN;
emm_sap_t emm_sap;
int rc = RETURNok;
if ( !emm_main_is_attached(user->emm_data) ) {
/* Initiate an Attach procedure */
emm_sap.primitive = EMMREG_ATTACH_INIT;
emm_sap.u.emm_reg.u.attach.is_emergency = FALSE;
rc = emm_sap_send(user, &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(nas_user_t *user)
{
LOG_FUNC_IN;
int is_attached = emm_main_is_attached(user->emm_data);
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(esm_data_t *esm_data)
{
LOG_FUNC_IN;
int max_pdn_id = esm_main_get_nb_pdns_max(esm_data);
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(nas_user_t *user, 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(user->esm_data);
/* 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(user, 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(esm_data_t *esm_data, 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(esm_data);
/* 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(esm_data, 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(nas_user_t *user, 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(user->esm_data, 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(user->esm_data);
/* 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(user->esm_data, 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(nas_user_t *user, 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(user, &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(nas_user_t *user, 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(user, &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(nas_user_t *user, int cid)
{
LOG_FUNC_IN;
int rc = RETURNok;
if (cid > 0) {
/* Deactivate only the specified PDN context */
rc = _nas_proc_deactivate(user, 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(user->esm_data)+1)) {
rc = _nas_proc_deactivate(user, 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(nas_user_t *user, int cid)
{
LOG_FUNC_IN;
int rc = RETURNok;
if ( !emm_main_is_attached(user->emm_data) ) {
/*
* 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(user);
} else if (emm_main_is_emergency(user->emm_data)) {
/* 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(user, cid, FALSE);
} else {
cid = 1;
/* Activate all defined PDN contexts */
while ((rc != RETURNerror) && (cid < esm_main_get_nb_pdns_max(user->esm_data)+1)) {
rc = _nas_proc_activate(user, 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(nas_user_t *user, 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 */
user->proc.rsrq = rsrq;
user->proc.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(user, &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(nas_user_t *user, 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(user, &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(nas_user_t *user)
{
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(user, &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(nas_user_t *user, 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(user, &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(nas_user_t *user)
{
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(user, &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(nas_user_t *user)
{
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(user, &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(nas_user_t *user, 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(user, &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(nas_user_t *user, 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(user->esm_data, 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(user->esm_data)) {
/* 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(user, &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(nas_user_t *user, 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(user->esm_data, 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(user->esm_data) > 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(user, &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);
}