Surprisingly, it touches every part of openair3, and most of the prototype. Moreover, a special attention have been put to callback review. However, there are still places to fix or review indicated by FIXME
1480 lines
56 KiB
C
1480 lines
56 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 emm_as.c
|
|
|
|
Version 0.1
|
|
|
|
Date 2012/10/16
|
|
|
|
Product NAS stack
|
|
|
|
Subsystem EPS Mobility Management
|
|
|
|
Author Frederic Maurel
|
|
|
|
Description Defines the EMMAS Service Access Point that provides
|
|
services to the EPS Mobility Management for NAS message
|
|
transfer to/from the Access Stratum sublayer.
|
|
|
|
*****************************************************************************/
|
|
|
|
#include "emm_as.h"
|
|
#include "emm_recv.h"
|
|
#include "emm_send.h"
|
|
#include "emmData.h"
|
|
#include "commonDef.h"
|
|
#include "nas_log.h"
|
|
|
|
#include "TLVDecoder.h"
|
|
#include "as_message.h"
|
|
#include "nas_message.h"
|
|
|
|
#include "emm_cause.h"
|
|
#include "LowerLayer.h"
|
|
|
|
#include <string.h> // memset
|
|
#include <stdlib.h> // malloc, free
|
|
|
|
#if defined(NAS_BUILT_IN_UE)
|
|
# include "nas_itti_messaging.h"
|
|
#endif
|
|
#include "msc.h"
|
|
|
|
/****************************************************************************/
|
|
/**************** E X T E R N A L D E F I N I T I O N S ****************/
|
|
/****************************************************************************/
|
|
|
|
extern int emm_proc_plmn_selection_end(int found, tac_t tac, ci_t ci, AcT_t rat);
|
|
|
|
extern int emm_proc_status(unsigned int ueid, int emm_cause);
|
|
|
|
/****************************************************************************/
|
|
/******************* L O C A L D E F I N I T I O N S *******************/
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* String representation of EMMAS-SAP primitives
|
|
*/
|
|
static const char *_emm_as_primitive_str[] = {
|
|
"EMMAS_SECURITY_REQ",
|
|
"EMMAS_SECURITY_IND",
|
|
"EMMAS_SECURITY_RES",
|
|
"EMMAS_SECURITY_REJ",
|
|
"EMMAS_ESTABLISH_REQ",
|
|
"EMMAS_ESTABLISH_CNF",
|
|
"EMMAS_ESTABLISH_REJ",
|
|
"EMMAS_RELEASE_REQ",
|
|
"EMMAS_RELEASE_IND",
|
|
"EMMAS_DATA_REQ",
|
|
"EMMAS_DATA_IND",
|
|
"EMMAS_PAGE_IND",
|
|
"EMMAS_STATUS_IND",
|
|
"EMMAS_CELL_INFO_REQ",
|
|
"EMMAS_CELL_INFO_RES",
|
|
"EMMAS_CELL_INFO_IND",
|
|
};
|
|
|
|
/*
|
|
* Functions executed to process EMM procedures upon receiving
|
|
* data from the network
|
|
*/
|
|
static int _emm_as_recv(nas_user_t *user, unsigned int ueid, const char *msg, int len,
|
|
int *emm_cause);
|
|
|
|
static int _emm_as_establish_cnf(nas_user_t *user, const emm_as_establish_t *msg, int *emm_cause);
|
|
static int _emm_as_establish_rej(nas_user_t *user);
|
|
static int _emm_as_release_ind(nas_user_t *user, const emm_as_release_t *msg);
|
|
static int _emm_as_page_ind(const emm_as_page_t *msg);
|
|
|
|
|
|
static int _emm_as_cell_info_res(const emm_as_cell_info_t *msg);
|
|
static int _emm_as_cell_info_ind(const emm_as_cell_info_t *msg);
|
|
|
|
static int _emm_as_data_ind(nas_user_t *user, const emm_as_data_t *msg, int *emm_cause);
|
|
|
|
/*
|
|
* Functions executed to send data to the network when requested
|
|
* within EMM procedure processing
|
|
*/
|
|
static EMM_msg *_emm_as_set_header(nas_message_t *msg,
|
|
const emm_as_security_data_t *security);
|
|
static int
|
|
_emm_as_encode(
|
|
as_nas_info_t *info,
|
|
nas_message_t *msg,
|
|
int length,
|
|
emm_security_context_t *emm_security_context);
|
|
|
|
static int _emm_as_encrypt(
|
|
as_nas_info_t *info,
|
|
const nas_message_security_header_t *header,
|
|
const char *buffer,
|
|
int length,
|
|
emm_security_context_t *emm_security_context);
|
|
|
|
static int _emm_as_send(const nas_user_t *user, const emm_as_t *msg);
|
|
|
|
static int _emm_as_security_res(const emm_as_security_t *,
|
|
ul_info_transfer_req_t *);
|
|
static int _emm_as_establish_req(const emm_as_establish_t *,
|
|
nas_establish_req_t *);
|
|
|
|
|
|
static int _emm_as_cell_info_req(const emm_as_cell_info_t *, cell_info_req_t *);
|
|
|
|
static int _emm_as_data_req(const emm_as_data_t *msg, ul_info_transfer_req_t *);
|
|
static int _emm_as_status_ind(const emm_as_status_t *, ul_info_transfer_req_t *);
|
|
static int _emm_as_release_req(const emm_as_release_t *, nas_release_req_t *);
|
|
|
|
/****************************************************************************/
|
|
/****************** E X P O R T E D F U N C T I O N S ******************/
|
|
/****************************************************************************/
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: emm_as_initialize() **
|
|
** **
|
|
** Description: Initializes the EMMAS Service Access Point **
|
|
** **
|
|
** Inputs: None **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: None **
|
|
** Others: NONE **
|
|
** **
|
|
***************************************************************************/
|
|
void emm_as_initialize(nas_user_t *user)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
/* TODO: Initialize the EMMAS-SAP */
|
|
|
|
LOG_FUNC_OUT;
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: emm_as_send() **
|
|
** **
|
|
** Description: Processes the EMMAS Service Access Point primitive. **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
int emm_as_send(nas_user_t *user, const emm_as_t *msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int rc;
|
|
int emm_cause = EMM_CAUSE_SUCCESS;
|
|
emm_as_primitive_t primitive = msg->primitive;
|
|
|
|
uint32_t ueid = 0;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received primitive %s (%d)",
|
|
_emm_as_primitive_str[primitive - _EMMAS_START - 1], primitive);
|
|
|
|
switch (primitive) {
|
|
case _EMMAS_DATA_IND:
|
|
rc = _emm_as_data_ind(user, &msg->u.data, &emm_cause);
|
|
ueid = msg->u.data.ueid;
|
|
break;
|
|
|
|
|
|
case _EMMAS_ESTABLISH_CNF:
|
|
rc = _emm_as_establish_cnf(user, &msg->u.establish, &emm_cause);
|
|
break;
|
|
|
|
case _EMMAS_ESTABLISH_REJ:
|
|
rc = _emm_as_establish_rej(user);
|
|
break;
|
|
|
|
case _EMMAS_RELEASE_IND:
|
|
rc = _emm_as_release_ind(user, &msg->u.release);
|
|
break;
|
|
|
|
case _EMMAS_PAGE_IND:
|
|
rc = _emm_as_page_ind(&msg->u.page);
|
|
break;
|
|
|
|
case _EMMAS_CELL_INFO_RES:
|
|
rc = _emm_as_cell_info_res(&msg->u.cell_info);
|
|
break;
|
|
|
|
case _EMMAS_CELL_INFO_IND:
|
|
rc = _emm_as_cell_info_ind(&msg->u.cell_info);
|
|
break;
|
|
|
|
default:
|
|
/* Other primitives are forwarded to the Access Stratum */
|
|
rc = _emm_as_send(user, msg);
|
|
|
|
if (rc != RETURNok) {
|
|
LOG_TRACE(ERROR, "EMMAS-SAP - "
|
|
"Failed to process primitive %s (%d)",
|
|
_emm_as_primitive_str[primitive - _EMMAS_START - 1],
|
|
primitive);
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
/* Handle decoding errors */
|
|
if (emm_cause != EMM_CAUSE_SUCCESS) {
|
|
/* Ignore received message that is too short to contain a complete
|
|
* message type information element */
|
|
if (rc == TLV_DECODE_BUFFER_TOO_SHORT) {
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
/* Ignore received message that contains not supported protocol
|
|
* discriminator */
|
|
else if (rc == TLV_DECODE_PROTOCOL_NOT_SUPPORTED) {
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
} else if (rc == TLV_DECODE_WRONG_MESSAGE_TYPE) {
|
|
emm_cause = EMM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
/* EMM message processing failed */
|
|
LOG_TRACE(WARNING, "EMMAS-SAP - Received EMM message is not valid "
|
|
"(cause=%d)", emm_cause);
|
|
/* Return an EMM status message */
|
|
rc = emm_proc_status(ueid, emm_cause);
|
|
}
|
|
|
|
if (rc != RETURNok) {
|
|
LOG_TRACE(ERROR, "EMMAS-SAP - Failed to process primitive %s (%d)",
|
|
_emm_as_primitive_str[primitive - _EMMAS_START - 1],
|
|
primitive);
|
|
}
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
/****************************************************************************/
|
|
/********************* L O C A L F U N C T I O N S *********************/
|
|
/****************************************************************************/
|
|
|
|
/*
|
|
* --------------------------------------------------------------------------
|
|
* Functions executed to process EMM procedures upon receiving data from the
|
|
* network
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_recv() **
|
|
** **
|
|
** Description: Decodes and processes the EPS Mobility Management message **
|
|
** received from the Access Stratum **
|
|
** **
|
|
** Inputs: ueid: UE lower layer identifier **
|
|
** msg: The EMM message to process **
|
|
** len: The length of the EMM message **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: emm_cause: EMM cause code **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_recv(nas_user_t *user, unsigned int ueid, const char *msg, int len,
|
|
int *emm_cause)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int decoder_rc;
|
|
int rc = RETURNerror;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received EMM message (length=%d)", len);
|
|
|
|
nas_message_t nas_msg;
|
|
memset(&nas_msg, 0 , sizeof(nas_message_t));
|
|
|
|
emm_security_context_t *security = NULL; /* Current EPS NAS security context */
|
|
|
|
security = _emm_data.security;
|
|
|
|
/* Decode the received message */
|
|
decoder_rc = nas_message_decode(msg, &nas_msg, len, security);
|
|
|
|
if (decoder_rc < 0) {
|
|
LOG_TRACE(WARNING, "EMMAS-SAP - Failed to decode NAS message "
|
|
"(err=%d)", decoder_rc);
|
|
*emm_cause = EMM_CAUSE_PROTOCOL_ERROR;
|
|
LOG_FUNC_RETURN (decoder_rc);
|
|
}
|
|
|
|
/* Process NAS message */
|
|
EMM_msg *emm_msg = &nas_msg.plain.emm;
|
|
|
|
switch (emm_msg->header.message_type) {
|
|
case EMM_STATUS:
|
|
rc = emm_recv_status(ueid, &emm_msg->emm_status, emm_cause);
|
|
break;
|
|
|
|
case IDENTITY_REQUEST:
|
|
rc = emm_recv_identity_request(user, &emm_msg->identity_request,
|
|
emm_cause);
|
|
break;
|
|
|
|
case AUTHENTICATION_REQUEST:
|
|
rc = emm_recv_authentication_request(user,
|
|
&emm_msg->authentication_request,
|
|
emm_cause);
|
|
break;
|
|
|
|
case AUTHENTICATION_REJECT:
|
|
rc = emm_recv_authentication_reject(user,
|
|
&emm_msg->authentication_reject,
|
|
emm_cause);
|
|
break;
|
|
|
|
case SECURITY_MODE_COMMAND:
|
|
rc = emm_recv_security_mode_command(user,
|
|
&emm_msg->security_mode_command,
|
|
emm_cause);
|
|
break;
|
|
|
|
case DETACH_ACCEPT:
|
|
rc = emm_recv_detach_accept(user, &emm_msg->detach_accept, emm_cause);
|
|
break;
|
|
|
|
|
|
case TRACKING_AREA_UPDATE_ACCEPT:
|
|
case TRACKING_AREA_UPDATE_REJECT:
|
|
case SERVICE_REJECT:
|
|
case GUTI_REALLOCATION_COMMAND:
|
|
case EMM_INFORMATION:
|
|
case DOWNLINK_NAS_TRANSPORT:
|
|
case CS_SERVICE_NOTIFICATION:
|
|
/* TODO */
|
|
break;
|
|
|
|
default:
|
|
LOG_TRACE(WARNING, "EMMAS-SAP - EMM message 0x%x is not valid",
|
|
emm_msg->header.message_type);
|
|
*emm_cause = EMM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE;
|
|
break;
|
|
}
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_data_ind() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP data transfer indication **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - AS->EMM: DATA_IND - Data transfer procedure **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: emm_cause: EMM cause code **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_data_ind(nas_user_t *user, const emm_as_data_t *msg, int *emm_cause)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int rc = RETURNerror;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received AS data transfer indication "
|
|
"(ueid=%u, delivered=%s, length=%d)", msg->ueid,
|
|
(msg->delivered)? "TRUE" : "FALSE", msg->NASmsg.length);
|
|
|
|
if (msg->delivered) {
|
|
if (msg->NASmsg.length > 0) {
|
|
/* Process the received NAS message */
|
|
char *plain_msg = (char *)malloc(msg->NASmsg.length);
|
|
|
|
if (plain_msg) {
|
|
nas_message_security_header_t header;
|
|
emm_security_context_t *security = NULL; /* Current EPS NAS security context */
|
|
|
|
memset(&header, 0, sizeof(header));
|
|
/* Decrypt the received security protected message */
|
|
|
|
security = _emm_data.security;
|
|
int bytes = nas_message_decrypt((char *)(msg->NASmsg.value),
|
|
plain_msg,
|
|
&header,
|
|
msg->NASmsg.length,
|
|
security
|
|
);
|
|
|
|
if (bytes < 0) {
|
|
/* Failed to decrypt the message */
|
|
*emm_cause = EMM_CAUSE_PROTOCOL_ERROR;
|
|
LOG_FUNC_RETURN (bytes);
|
|
} else if (header.protocol_discriminator ==
|
|
EPS_MOBILITY_MANAGEMENT_MESSAGE) {
|
|
/* Process EMM data */
|
|
rc = _emm_as_recv(user, msg->ueid, plain_msg, bytes, emm_cause);
|
|
} else if (header.protocol_discriminator ==
|
|
EPS_SESSION_MANAGEMENT_MESSAGE) {
|
|
const OctetString data = {bytes, (uint8_t *)plain_msg};
|
|
/* Foward ESM data to EPS session management */
|
|
rc = lowerlayer_data_ind(user, msg->ueid, &data);
|
|
}
|
|
|
|
free(plain_msg);
|
|
}
|
|
} else {
|
|
/* Process successfull lower layer transfer indication */
|
|
rc = lowerlayer_success(user, msg->ueid);
|
|
}
|
|
} else {
|
|
/* Process lower layer transmission failure of NAS message */
|
|
rc = lowerlayer_failure(user, msg->ueid);
|
|
}
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_establish_cnf() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP connection establish confirmation **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - AS->EMM: ESTABLISH_CNF - NAS signalling connection **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: emm_cause: EMM cause code **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_establish_cnf(nas_user_t *user, const emm_as_establish_t *msg,
|
|
int *emm_cause)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int decoder_rc;
|
|
int rc = RETURNerror;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received AS connection establish confirm");
|
|
|
|
if (msg->NASmsg.length > 0) {
|
|
/* The NAS signalling connection is established */
|
|
(void) lowerlayer_establish(user);
|
|
} else {
|
|
/* The initial NAS message has been successfully delivered to
|
|
* lower layers */
|
|
rc = lowerlayer_success(user, 0);
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
nas_message_t nas_msg;
|
|
memset(&nas_msg, 0 , sizeof(nas_message_t));
|
|
|
|
/* Decode initial NAS message */
|
|
decoder_rc = nas_message_decode((char *)(msg->NASmsg.value),
|
|
&nas_msg,
|
|
msg->NASmsg.length,
|
|
_emm_data.security);
|
|
|
|
if (decoder_rc < 0) {
|
|
LOG_TRACE(WARNING, "EMMAS-SAP - Failed to decode initial NAS message"
|
|
"(err=%d)", decoder_rc);
|
|
*emm_cause = EMM_CAUSE_PROTOCOL_ERROR;
|
|
LOG_FUNC_RETURN (decoder_rc);
|
|
}
|
|
|
|
/* Process initial NAS message */
|
|
EMM_msg *emm_msg = &nas_msg.plain.emm;
|
|
|
|
switch (emm_msg->header.message_type) {
|
|
case ATTACH_ACCEPT:
|
|
rc = emm_recv_attach_accept(user, &emm_msg->attach_accept, emm_cause);
|
|
break;
|
|
|
|
case ATTACH_REJECT:
|
|
rc = emm_recv_attach_reject(user, &emm_msg->attach_reject, emm_cause);
|
|
break;
|
|
|
|
case DETACH_ACCEPT:
|
|
break;
|
|
|
|
case TRACKING_AREA_UPDATE_ACCEPT:
|
|
break;
|
|
|
|
default:
|
|
LOG_TRACE(WARNING, "EMMAS-SAP - Initial NAS message 0x%x is "
|
|
"not valid", emm_msg->header.message_type);
|
|
*emm_cause = EMM_CAUSE_MESSAGE_TYPE_NOT_COMPATIBLE;
|
|
break;
|
|
}
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_establish_rej() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP connection establish reject **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - AS->EMM: ESTABLISH_REJ - NAS signalling connection **
|
|
** **
|
|
** Inputs: None **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_establish_rej(nas_user_t *user)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int rc;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received AS initial NAS message transmission "
|
|
"failure");
|
|
|
|
/* Process lower layer transmission failure of initial NAS message */
|
|
rc = lowerlayer_failure(user, 0);
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_release_ind() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP connection release indication **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - AS->EMM: RELEASE_IND - NAS signalling release procedure **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_release_ind(nas_user_t *user, const emm_as_release_t *msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int rc = RETURNok;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received AS connection release indication "
|
|
"(cause=%d)", msg->cause);
|
|
|
|
/* Process NAS signalling connection release indication */
|
|
rc = lowerlayer_release(user, msg->cause);
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_page_ind() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP paging data indication primitive **
|
|
** **
|
|
** EMMAS-SAP - AS->EMM: PAGE_IND - Paging data procedure **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_page_ind(const emm_as_page_t *msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int rc = RETURNok;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received AS paging data indication");
|
|
|
|
/* TODO */
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_cell_info_res() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP cell information response **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - AS->EMM: CELL_INFO_RES - PLMN and cell selection procedure **
|
|
** The NAS received a response to cell selection request pre- **
|
|
** viously sent to the Access-Startum. If a suitable cell is **
|
|
** found to serve the selected PLMN with associated Radio Ac- **
|
|
** cess Technologies, this cell is selected to camp on. **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_cell_info_res(const emm_as_cell_info_t *msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int rc = RETURNok;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received AS cell information response");
|
|
|
|
int AcT = NET_ACCESS_EUTRAN;
|
|
|
|
if (msg->found == TRUE) {
|
|
/* Get the first supported access technology */
|
|
while (AcT != NET_ACCESS_UNAVAILABLE) {
|
|
if (msg->rat & (1 << AcT)) {
|
|
break;
|
|
}
|
|
|
|
AcT -= 1;
|
|
}
|
|
}
|
|
|
|
/* Notify EMM that a cell has been found */
|
|
rc = emm_proc_plmn_selection_end(msg->found, msg->tac, msg->cellID, AcT);
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_cell_info_ind() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP cell information indication **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - AS->EMM: CELL_INFO_IND - PLMN and cell selection procedure **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_cell_info_ind(const emm_as_cell_info_t *msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int rc = RETURNok;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Received AS cell information indication");
|
|
|
|
/* TODO */
|
|
|
|
LOG_FUNC_RETURN (rc);
|
|
}
|
|
|
|
/*
|
|
* --------------------------------------------------------------------------
|
|
* Functions executed to send data to the network when requested within EMM
|
|
* procedure processing
|
|
* --------------------------------------------------------------------------
|
|
*/
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_set_header() **
|
|
** **
|
|
** Description: Setup the security header of the given NAS message **
|
|
** **
|
|
** Inputs: security: The NAS security data to use **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: msg: The NAS message **
|
|
** Return: Pointer to the plain NAS message to be se- **
|
|
** curity protected if setting of the securi- **
|
|
** ty header succeed; **
|
|
** NULL pointer otherwise **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static EMM_msg *_emm_as_set_header(nas_message_t *msg,
|
|
const emm_as_security_data_t *security)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
msg->header.protocol_discriminator = EPS_MOBILITY_MANAGEMENT_MESSAGE;
|
|
|
|
if ( security && (security->ksi != EMM_AS_NO_KEY_AVAILABLE) ) {
|
|
/* A valid EPS security context exists */
|
|
if (security->is_new) {
|
|
/* New EPS security context is taken into use */
|
|
if (security->k_int) {
|
|
if (security->k_enc) {
|
|
/* NAS integrity and cyphering keys are available */
|
|
msg->header.security_header_type =
|
|
SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED_NEW;
|
|
} else {
|
|
/* NAS integrity key only is available */
|
|
msg->header.security_header_type =
|
|
SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_NEW;
|
|
}
|
|
|
|
LOG_FUNC_RETURN (&msg->security_protected.plain.emm);
|
|
}
|
|
} else if (security->k_int) {
|
|
if (security->k_enc) {
|
|
/* NAS integrity and cyphering keys are available */
|
|
msg->header.security_header_type =
|
|
SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED_CYPHERED;
|
|
} else {
|
|
/* NAS integrity key only is available */
|
|
msg->header.security_header_type =
|
|
SECURITY_HEADER_TYPE_INTEGRITY_PROTECTED;
|
|
}
|
|
|
|
LOG_FUNC_RETURN (&msg->security_protected.plain.emm);
|
|
} else {
|
|
/* No valid EPS security context exists */
|
|
msg->header.security_header_type = SECURITY_HEADER_TYPE_NOT_PROTECTED;
|
|
LOG_FUNC_RETURN (&msg->plain.emm);
|
|
}
|
|
} else {
|
|
/* No valid EPS security context exists */
|
|
msg->header.security_header_type = SECURITY_HEADER_TYPE_NOT_PROTECTED;
|
|
LOG_FUNC_RETURN (&msg->plain.emm);
|
|
}
|
|
|
|
/* A valid EPS security context exists but NAS integrity key
|
|
* is not available */
|
|
LOG_FUNC_RETURN (NULL);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_encode() **
|
|
** **
|
|
** Description: Encodes NAS message into NAS information container **
|
|
** **
|
|
** Inputs: msg: The NAS message to encode **
|
|
** length: The maximum length of the NAS message **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: info: The NAS information container **
|
|
** msg: The NAS message to encode **
|
|
** Return: The number of bytes successfully encoded **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int
|
|
_emm_as_encode(
|
|
as_nas_info_t *info,
|
|
nas_message_t *msg,
|
|
int length,
|
|
emm_security_context_t *emm_security_context)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int bytes = 0;
|
|
|
|
if (msg->header.security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) {
|
|
emm_msg_header_t *header = &msg->security_protected.plain.emm.header;
|
|
/* Expand size of protected NAS message */
|
|
length += NAS_MESSAGE_SECURITY_HEADER_SIZE;
|
|
/* Set header of plain NAS message */
|
|
header->protocol_discriminator = EPS_MOBILITY_MANAGEMENT_MESSAGE;
|
|
header->security_header_type = SECURITY_HEADER_TYPE_NOT_PROTECTED;
|
|
}
|
|
|
|
/* Allocate memory to the NAS information container */
|
|
info->data = (Byte_t *)malloc(length * sizeof(Byte_t));
|
|
|
|
if (info->data != NULL) {
|
|
/* Encode the NAS message */
|
|
bytes = nas_message_encode(
|
|
(char *)(info->data),
|
|
msg,
|
|
length,
|
|
emm_security_context);
|
|
|
|
if (bytes > 0) {
|
|
info->length = bytes;
|
|
} else {
|
|
free(info->data);
|
|
info->length = 0;
|
|
info->data = NULL;
|
|
}
|
|
}
|
|
|
|
LOG_FUNC_RETURN (bytes);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_encrypt() **
|
|
** **
|
|
** Description: Encryts NAS message into NAS information container **
|
|
** **
|
|
** Inputs: header: The Security header in used **
|
|
** msg: The NAS message to encrypt **
|
|
** length: The maximum length of the NAS message **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: info: The NAS information container **
|
|
** Return: The number of bytes successfully encrypted **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int
|
|
_emm_as_encrypt(
|
|
as_nas_info_t *info,
|
|
const nas_message_security_header_t *header,
|
|
const char *msg,
|
|
int length,
|
|
emm_security_context_t *emm_security_context)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int bytes = 0;
|
|
|
|
if (header->security_header_type != SECURITY_HEADER_TYPE_NOT_PROTECTED) {
|
|
/* Expand size of protected NAS message */
|
|
length += NAS_MESSAGE_SECURITY_HEADER_SIZE;
|
|
}
|
|
|
|
/* Allocate memory to the NAS information container */
|
|
info->data = (Byte_t *)malloc(length * sizeof(Byte_t));
|
|
|
|
if (info->data != NULL) {
|
|
/* Encrypt the NAS information message */
|
|
bytes = nas_message_encrypt(
|
|
msg,
|
|
(char *)(info->data),
|
|
header,
|
|
length,
|
|
emm_security_context);
|
|
|
|
if (bytes > 0) {
|
|
info->length = bytes;
|
|
} else {
|
|
free(info->data);
|
|
info->length = 0;
|
|
info->data = NULL;
|
|
}
|
|
}
|
|
|
|
LOG_FUNC_RETURN (bytes);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_send() **
|
|
** **
|
|
** Description: Builds NAS message according to the given EMMAS Service **
|
|
** Access Point primitive and sends it to the Access Stratum **
|
|
** sublayer **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to be sent **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: None **
|
|
** Return: RETURNok, RETURNerror **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_send(const nas_user_t *user, const emm_as_t *msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
as_message_t as_msg;
|
|
memset(&as_msg, 0 , sizeof(as_message_t));
|
|
|
|
switch (msg->primitive) {
|
|
case _EMMAS_DATA_REQ:
|
|
as_msg.msgID = _emm_as_data_req(
|
|
&msg->u.data,
|
|
&as_msg.msg.ul_info_transfer_req);
|
|
break;
|
|
|
|
case _EMMAS_STATUS_IND:
|
|
as_msg.msgID = _emm_as_status_ind(
|
|
&msg->u.status,
|
|
&as_msg.msg.ul_info_transfer_req);
|
|
break;
|
|
|
|
case _EMMAS_RELEASE_REQ:
|
|
as_msg.msgID = _emm_as_release_req(
|
|
&msg->u.release,
|
|
&as_msg.msg.nas_release_req);
|
|
break;
|
|
|
|
|
|
case _EMMAS_SECURITY_RES:
|
|
as_msg.msgID = _emm_as_security_res(
|
|
&msg->u.security,
|
|
&as_msg.msg.ul_info_transfer_req);
|
|
break;
|
|
|
|
case _EMMAS_ESTABLISH_REQ:
|
|
as_msg.msgID = _emm_as_establish_req(
|
|
&msg->u.establish,
|
|
&as_msg.msg.nas_establish_req);
|
|
break;
|
|
|
|
|
|
case _EMMAS_CELL_INFO_REQ:
|
|
as_msg.msgID = _emm_as_cell_info_req(&msg->u.cell_info,
|
|
&as_msg.msg.cell_info_req);
|
|
/*
|
|
* TODO: NAS may provide a list of equivalent PLMNs, if available,
|
|
* that AS shall use for cell selection and cell reselection.
|
|
*/
|
|
break;
|
|
|
|
default:
|
|
as_msg.msgID = 0;
|
|
break;
|
|
}
|
|
|
|
/* Send the message to the Access Stratum or S1AP in case of MME */
|
|
if (as_msg.msgID > 0) {
|
|
|
|
# if defined(NAS_BUILT_IN_UE)
|
|
LOG_TRACE(DEBUG, "EMMAS-SAP - "
|
|
"Sending msg with id 0x%x, primitive %s (%d) to RRC layer for transmission",
|
|
as_msg.msgID,
|
|
_emm_as_primitive_str[msg->primitive - _EMMAS_START - 1],
|
|
msg->primitive);
|
|
|
|
switch (as_msg.msgID) {
|
|
case AS_CELL_INFO_REQ: {
|
|
nas_itti_cell_info_req(
|
|
as_msg.msg.cell_info_req.plmnID,
|
|
as_msg.msg.cell_info_req.rat);
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
break;
|
|
|
|
case AS_NAS_ESTABLISH_REQ: {
|
|
nas_itti_nas_establish_req(
|
|
as_msg.msg.nas_establish_req.cause,
|
|
as_msg.msg.nas_establish_req.type,
|
|
as_msg.msg.nas_establish_req.s_tmsi,
|
|
as_msg.msg.nas_establish_req.plmnID,
|
|
as_msg.msg.nas_establish_req.initialNasMsg.data,
|
|
as_msg.msg.nas_establish_req.initialNasMsg.length);
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
break;
|
|
|
|
case AS_UL_INFO_TRANSFER_REQ: {
|
|
nas_itti_ul_data_req(
|
|
as_msg.msg.ul_info_transfer_req.UEid,
|
|
as_msg.msg.ul_info_transfer_req.nasMsg.data,
|
|
as_msg.msg.ul_info_transfer_req.nasMsg.length);
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
break;
|
|
|
|
case AS_RAB_ESTABLISH_RSP: {
|
|
nas_itti_rab_establish_rsp(
|
|
as_msg.msg.rab_establish_rsp.s_tmsi,
|
|
as_msg.msg.rab_establish_rsp.rabID,
|
|
as_msg.msg.rab_establish_rsp.errCode);
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
# else
|
|
int bytes = as_message_send(&as_msg);
|
|
|
|
if (bytes > 0) {
|
|
LOG_FUNC_RETURN (RETURNok);
|
|
}
|
|
|
|
# endif
|
|
}
|
|
|
|
LOG_FUNC_RETURN (RETURNerror);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_data_req() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP data transfer request **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - EMM->AS: DATA_REQ - Data transfer procedure **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: as_msg: The message to send to the AS **
|
|
** Return: The identifier of the AS message **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_data_req(const emm_as_data_t *msg,
|
|
ul_info_transfer_req_t *as_msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int size = 0;
|
|
int is_encoded = FALSE;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Send AS data transfer request");
|
|
|
|
nas_message_t nas_msg;
|
|
memset(&nas_msg, 0 , sizeof(nas_message_t));
|
|
|
|
/* Setup the AS message */
|
|
if (msg->guti) {
|
|
as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode;
|
|
as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi;
|
|
} else {
|
|
as_msg->UEid = msg->ueid;
|
|
}
|
|
|
|
/* Setup the NAS security header */
|
|
EMM_msg *emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx);
|
|
|
|
/* Setup the NAS information message */
|
|
if (emm_msg != NULL) switch (msg->NASinfo) {
|
|
|
|
case EMM_AS_NAS_DATA_ATTACH:
|
|
size = emm_send_attach_complete(msg, &emm_msg->attach_complete);
|
|
break;
|
|
|
|
case EMM_AS_NAS_DATA_DETACH:
|
|
size = emm_send_detach_request(msg, &emm_msg->detach_request);
|
|
break;
|
|
|
|
|
|
default:
|
|
/* Send other NAS messages as already encoded ESM messages */
|
|
size = msg->NASmsg.length;
|
|
is_encoded = TRUE;
|
|
break;
|
|
}
|
|
|
|
if (size > 0) {
|
|
int bytes;
|
|
emm_security_context_t *emm_security_context = NULL;
|
|
|
|
emm_security_context = _emm_data.security;
|
|
|
|
if (emm_security_context) {
|
|
|
|
nas_msg.header.sequence_number = emm_security_context->ul_count.seq_num;
|
|
LOG_TRACE(DEBUG,
|
|
"Set nas_msg.header.sequence_number -> %u",
|
|
nas_msg.header.sequence_number);
|
|
}
|
|
|
|
if (!is_encoded) {
|
|
/* Encode the NAS information message */
|
|
bytes = _emm_as_encode(&as_msg->nasMsg,
|
|
&nas_msg,
|
|
size,
|
|
emm_security_context);
|
|
} else {
|
|
/* Encrypt the NAS information message */
|
|
bytes = _emm_as_encrypt(&as_msg->nasMsg,
|
|
&nas_msg.header,
|
|
(char *)(msg->NASmsg.value),
|
|
size,
|
|
emm_security_context);
|
|
}
|
|
|
|
if (bytes > 0) {
|
|
LOG_FUNC_RETURN (AS_UL_INFO_TRANSFER_REQ);
|
|
}
|
|
}
|
|
|
|
LOG_FUNC_RETURN (0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_status_ind() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP status indication primitive **
|
|
** **
|
|
** EMMAS-SAP - EMM->AS: STATUS_IND - EMM status report procedure **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: as_msg: The message to send to the AS **
|
|
** Return: The identifier of the AS message **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_status_ind(const emm_as_status_t *msg,
|
|
ul_info_transfer_req_t *as_msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int size = 0;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Send AS status indication (cause=%d)",
|
|
msg->emm_cause);
|
|
|
|
nas_message_t nas_msg;
|
|
memset(&nas_msg, 0 , sizeof(nas_message_t));
|
|
|
|
/* Setup the AS message */
|
|
if (msg->guti) {
|
|
as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode;
|
|
as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi;
|
|
} else {
|
|
as_msg->UEid = msg->ueid;
|
|
}
|
|
|
|
/* Setup the NAS security header */
|
|
EMM_msg *emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx);
|
|
|
|
/* Setup the NAS information message */
|
|
if (emm_msg != NULL) {
|
|
size = emm_send_status(msg, &emm_msg->emm_status);
|
|
}
|
|
|
|
if (size > 0) {
|
|
emm_security_context_t *emm_security_context = NULL;
|
|
|
|
emm_security_context = _emm_data.security;
|
|
|
|
if (emm_security_context) {
|
|
|
|
nas_msg.header.sequence_number = emm_security_context->ul_count.seq_num;
|
|
LOG_TRACE(DEBUG,
|
|
"Set nas_msg.header.sequence_number -> %u",
|
|
nas_msg.header.sequence_number);
|
|
}
|
|
|
|
/* Encode the NAS information message */
|
|
int bytes = _emm_as_encode(
|
|
&as_msg->nasMsg,
|
|
&nas_msg,
|
|
size,
|
|
emm_security_context);
|
|
|
|
if (bytes > 0) {
|
|
LOG_FUNC_RETURN (AS_UL_INFO_TRANSFER_REQ);
|
|
}
|
|
}
|
|
|
|
LOG_FUNC_RETURN (0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_release_req() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP connection release request **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - EMM->AS: RELEASE_REQ - NAS signalling release procedure **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: as_msg: The message to send to the AS **
|
|
** Return: The identifier of the AS message **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_release_req(const emm_as_release_t *msg,
|
|
nas_release_req_t *as_msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Send AS release request");
|
|
|
|
/* Setup the AS message */
|
|
if (msg->guti) {
|
|
as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode;
|
|
as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi;
|
|
} else {
|
|
as_msg->UEid = msg->ueid;
|
|
}
|
|
|
|
if (msg->cause == EMM_AS_CAUSE_AUTHENTICATION) {
|
|
as_msg->cause = AS_AUTHENTICATION_FAILURE;
|
|
} else if (msg->cause == EMM_AS_CAUSE_DETACH) {
|
|
as_msg->cause = AS_DETACH;
|
|
}
|
|
|
|
LOG_FUNC_RETURN (AS_NAS_RELEASE_REQ);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_security_res() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP security response primitive **
|
|
** **
|
|
** EMMAS-SAP - EMM->AS: SECURITY_RES - Security mode control procedure **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: as_msg: The message to send to the AS **
|
|
** Return: The identifier of the AS message **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_security_res(const emm_as_security_t *msg,
|
|
ul_info_transfer_req_t *as_msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int size = 0;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Send AS security response");
|
|
|
|
nas_message_t nas_msg;
|
|
memset(&nas_msg, 0 , sizeof(nas_message_t));
|
|
|
|
/* Setup the AS message */
|
|
if (msg->guti) {
|
|
as_msg->s_tmsi.MMEcode = msg->guti->gummei.MMEcode;
|
|
as_msg->s_tmsi.m_tmsi = msg->guti->m_tmsi;
|
|
}
|
|
|
|
/* Setup the NAS security header */
|
|
EMM_msg *emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx);
|
|
|
|
/* Setup the NAS security message */
|
|
if (emm_msg != NULL) switch (msg->msgType) {
|
|
case EMM_AS_MSG_TYPE_IDENT:
|
|
size = emm_send_identity_response(
|
|
msg,
|
|
&emm_msg->identity_response);
|
|
break;
|
|
|
|
case EMM_AS_MSG_TYPE_AUTH:
|
|
if (msg->emm_cause != EMM_CAUSE_SUCCESS) {
|
|
size = emm_send_authentication_failure(
|
|
msg,
|
|
&emm_msg->authentication_failure);
|
|
} else {
|
|
size = emm_send_authentication_response(
|
|
msg,
|
|
&emm_msg->authentication_response);
|
|
}
|
|
|
|
break;
|
|
|
|
case EMM_AS_MSG_TYPE_SMC:
|
|
if (msg->emm_cause != EMM_CAUSE_SUCCESS) {
|
|
size = emm_send_security_mode_reject(
|
|
msg,
|
|
&emm_msg->security_mode_reject);
|
|
} else {
|
|
size = emm_send_security_mode_complete(
|
|
msg,
|
|
&emm_msg->security_mode_complete);
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
LOG_TRACE(WARNING, "EMMAS-SAP - Type of NAS security "
|
|
"message 0x%.2x is not valid", msg->msgType);
|
|
}
|
|
|
|
if (size > 0) {
|
|
/* Encode the NAS security message */
|
|
int bytes = _emm_as_encode(&as_msg->nasMsg,
|
|
&nas_msg,
|
|
size,
|
|
_emm_data.security);
|
|
|
|
if (bytes > 0) {
|
|
LOG_FUNC_RETURN (AS_UL_INFO_TRANSFER_REQ);
|
|
}
|
|
}
|
|
|
|
LOG_FUNC_RETURN (0);
|
|
}
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_establish_req() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP connection establish request **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - EMM->AS: ESTABLISH_REQ - NAS signalling connection **
|
|
** The NAS requests the AS to establish signalling connection **
|
|
** to tranfer initial NAS message to the network. **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: as_msg: The message to send to the AS **
|
|
** Return: The identifier of the AS message **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_establish_req(const emm_as_establish_t *msg,
|
|
nas_establish_req_t *as_msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
int size = 0;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Send AS connection establish request");
|
|
|
|
nas_message_t nas_msg;
|
|
memset(&nas_msg, 0 , sizeof(nas_message_t));
|
|
|
|
/* Setup the AS message */
|
|
as_msg->cause = msg->RRCcause;
|
|
as_msg->type = msg->RRCtype;
|
|
as_msg->plmnID = *msg->plmnID;
|
|
|
|
/* Derive the S-TMSI from the GUTI, if valid */
|
|
if (msg->UEid.guti) {
|
|
as_msg->s_tmsi.MMEcode = msg->UEid.guti->gummei.MMEcode;
|
|
as_msg->s_tmsi.m_tmsi = msg->UEid.guti->m_tmsi;
|
|
}
|
|
|
|
/* Setup the NAS security header */
|
|
EMM_msg *emm_msg = _emm_as_set_header(&nas_msg, &msg->sctx);
|
|
|
|
/* Setup the initial NAS information message */
|
|
if (emm_msg != NULL) switch (msg->NASinfo) {
|
|
case EMM_AS_NAS_INFO_ATTACH:
|
|
size = emm_send_attach_request(msg, &emm_msg->attach_request);
|
|
break;
|
|
|
|
case EMM_AS_NAS_INFO_DETACH:
|
|
size = emm_send_initial_detach_request(msg,
|
|
&emm_msg->detach_request);
|
|
break;
|
|
|
|
case EMM_AS_NAS_INFO_TAU:
|
|
size = emm_send_initial_tau_request(msg,
|
|
&emm_msg->tracking_area_update_request);
|
|
break;
|
|
|
|
case EMM_AS_NAS_INFO_SR:
|
|
size = emm_send_initial_sr_request(msg,
|
|
&emm_msg->service_request);
|
|
break;
|
|
|
|
case EMM_AS_NAS_INFO_EXTSR:
|
|
size = emm_send_initial_extsr_request(msg,
|
|
&emm_msg->extended_service_request);
|
|
break;
|
|
|
|
default:
|
|
LOG_TRACE(WARNING, "EMMAS-SAP - Type of initial NAS "
|
|
"message 0x%.2x is not valid", msg->NASinfo);
|
|
break;
|
|
}
|
|
|
|
if (size > 0) {
|
|
/* Encode the initial NAS information message */
|
|
int bytes = _emm_as_encode(
|
|
&as_msg->initialNasMsg,
|
|
&nas_msg,
|
|
size,
|
|
_emm_data.security);
|
|
|
|
if (bytes > 0) {
|
|
LOG_FUNC_RETURN (AS_NAS_ESTABLISH_REQ);
|
|
}
|
|
}
|
|
|
|
LOG_FUNC_RETURN (0);
|
|
}
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
** **
|
|
** Name: _emm_as_cell_info_req() **
|
|
** **
|
|
** Description: Processes the EMMAS-SAP cell information request **
|
|
** primitive **
|
|
** **
|
|
** EMMAS-SAP - EMM->AS: CELL_INFO_REQ - PLMN and cell selection procedure **
|
|
** The NAS requests the AS to select a cell belonging to the **
|
|
** selected PLMN with associated Radio Access Technologies. **
|
|
** **
|
|
** Inputs: msg: The EMMAS-SAP primitive to process **
|
|
** Others: None **
|
|
** **
|
|
** Outputs: as_msg: The message to send to the AS **
|
|
** Return: The identifier of the AS message **
|
|
** Others: None **
|
|
** **
|
|
***************************************************************************/
|
|
static int _emm_as_cell_info_req(const emm_as_cell_info_t *msg,
|
|
cell_info_req_t *as_msg)
|
|
{
|
|
LOG_FUNC_IN;
|
|
|
|
LOG_TRACE(INFO, "EMMAS-SAP - Send AS cell information request");
|
|
|
|
as_msg->plmnID = msg->plmnIDs.plmn[0];
|
|
as_msg->rat = msg->rat;
|
|
|
|
LOG_FUNC_RETURN (AS_CELL_INFO_REQ);
|
|
}
|
|
|