Files
Robert Schmidt 0b91791f67 Use (std) bool instead of custom bool types
OAI is riddled with boolean_t, FALSE, TRUE, etc. This makes no sense, as
there is a standard bool type, and could lead to nasty bugs if a
definition of a bool is non-standard (0 == false, true == !false). This
commit removes all non-standard bools in the whole project.
2022-06-27 10:07:48 +02:00

675 lines
21 KiB
C

/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.openairinterface.org/?page_id=698
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*****************************************************************************
Eurecom OpenAirInterface 3
Copyright(c) 2012 Eurecom
Source as_simulator.c
Version 0.1
Date 2013/04/11
Product Access-Stratum sublayer simulator
Subsystem Main process
Author Frederic Maurel
Description Implements the Access-Stratum simulator operating between
the Non-Access-Stratum running in the UE at the user side
and the Non-Access-Stratum running in the MME at the network
side for testing purpose.
*****************************************************************************/
#include "as_simulator_parser.h"
#include "as_data.h"
#include "as_process.h"
#include "commonDef.h"
#include "socket.h"
#include "nas_log.h"
#include <stdio.h> // printf, perror, snprintf
#include <errno.h> // errno
#include <netdb.h> // gai_strerror
#include <stdlib.h> // exit
#include <string.h> // memset
#include <poll.h> // poll
#include <signal.h> // sigaction
#include <pthread.h>
/****************************************************************************/
/**************** E X T E R N A L D E F I N I T I O N S ****************/
/****************************************************************************/
/****************************************************************************/
/******************* L O C A L D E F I N I T I O N S *******************/
/****************************************************************************/
#define SLEEP_TIMEOUT 1000 /* 1 second */
#define AS_SIMULATOR_NO_TRANSFER (0)
#define AS_SIMULATOR_TRANSFER_TO_UE (1 << 0)
#define AS_SIMULATOR_TRANSFER_TO_MME (1 << 1)
/*
* Direction of the message to be transfered to the UE NAS process
*/
static uint8_t _as_simulator_ue_transfer = AS_SIMULATOR_NO_TRANSFER;
/*
* Direction of the message to be transfered to the MME NAS process
*/
static uint8_t _as_simulator_mme_transfer = AS_SIMULATOR_NO_TRANSFER;
/*
* Size of the message to be transfered to the UE NAS process
*/
static int _as_simulator_ue_size = 0;
/*
* Size of the message to be transfered to the MME NAS process
*/
static int _as_simulator_mme_size = 0;
/*
* String buffer used to send/receive messages to/from the UE NAS process
*/
#define AS_SIMULATOR_UE_BUFFER_SIZE 1024
static char _as_simulator_ue_buffer [AS_SIMULATOR_UE_BUFFER_SIZE];
/*
* String buffer used to send/receive messages to/from the MME NAS process
*/
#define AS_SIMULATOR_MME_BUFFER_SIZE 1024
static char _as_simulator_mme_buffer [AS_SIMULATOR_MME_BUFFER_SIZE];
/*
* The connection endpoint used for communication with the UE NAS process
*/
static socket_id_t * _as_simulator_ue_sid = NULL;
/*
* The connection endpoint used for communication with the MME NAS process
*/
static socket_id_t * _as_simulator_mme_sid = NULL;
/*
* UE NAS process connection manager's running indicator
*/
static bool _as_simulator_ue_is_running = false;
/*
* MME NAS process connection manager's running indicator
*/
static bool _as_simulator_mme_is_running = false;
static int _set_signal_handler(int signal, void (handler)(int));
static void _signal_handler(int signal_number);
static void* _as_simulator_ue_mngr(void*);
static void* _as_simulator_mme_mngr(void*);
static int _as_simulator_ue_process(int msg_id, as_message_t* msg);
static int _as_simulator_mme_process(int msg_id, as_message_t* msg);
/****************************************************************************/
/****************** E X P O R T E D F U N C T I O N S ******************/
/****************************************************************************/
/*
* -----------------------------------------------------------------------------
* RRC simulator main process
* -----------------------------------------------------------------------------
*/
int main (int argc, const char* argv[])
{
/*
* Get the command line options
*/
if ( as_simulator_parser_get_options(argc, argv) != RETURNok ) {
as_simulator_parser_print_usage();
exit(EXIT_FAILURE);
}
const char* uhost = as_simulator_parser_get_uhost();
const char* uport = as_simulator_parser_get_uport();
const char* mhost = as_simulator_parser_get_mhost();
const char* mport = as_simulator_parser_get_mport();
nas_log_init(0x2f);
/*
* Initialize the communication channel to the UE NAS process
*/
_as_simulator_ue_sid = socket_udp_open(SOCKET_SERVER, uhost, uport);
if (_as_simulator_ue_sid == NULL) {
const char* error = ( (errno < 0) ?
gai_strerror(errno) : strerror(errno) );
printf("ERROR\t: socket_udp_open() failed: %s\n", error);
exit(EXIT_FAILURE);
}
printf("INFO\t: %s - The RRC Simulator is now connected to %s/%s (%d)\n",
__FUNCTION__, uhost, uport, socket_get_fd(_as_simulator_ue_sid));
/*
* Initialize the communication channel to the MME NAS process
*/
_as_simulator_mme_sid = socket_udp_open(SOCKET_CLIENT, mhost, mport);
if (_as_simulator_mme_sid == NULL) {
const char* error = ( (errno < 0) ?
gai_strerror(errno) : strerror(errno) );
printf("ERROR\t: socket_udp_open() failed: %s\n", error);
socket_close(_as_simulator_ue_sid);
exit(EXIT_FAILURE);
}
printf("INFO\t: %s - The RRC Simulator is now connected to %s/%s (%d)\n",
__FUNCTION__, mhost, mport, socket_get_fd(_as_simulator_mme_sid));
printf("[%s][AS=%s]\n", getTime(), _as_id);
/*
* Set up signal handler
*/
(void) _set_signal_handler(SIGINT, _signal_handler);
(void) _set_signal_handler(SIGTERM, _signal_handler);
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
/*
* Start thread use to manage the connection endpoint with the
* UE NAS process
*/
pthread_t ue_mngr;
if ( pthread_create (&ue_mngr, &attr, _as_simulator_ue_mngr, NULL) != 0 ) {
perror("ERROR\t: Failed to create the UE management thread\n");
socket_close(_as_simulator_ue_sid);
socket_close(_as_simulator_mme_sid);
exit(EXIT_FAILURE);
}
/*
* Start thread use to manage the connection endpoint with the
* MME NAS process
*/
pthread_t mme_mngr;
if ( pthread_create (&mme_mngr, &attr, _as_simulator_mme_mngr, NULL) != 0 ) {
perror("ERROR\t: Failed to create the MME management thread\n");
socket_close(_as_simulator_ue_sid);
socket_close(_as_simulator_mme_sid);
exit(EXIT_FAILURE);
}
pthread_attr_destroy(&attr);
/*
* Suspend execution of the main process until connection
* managers are running
*/
poll(NULL, 0, SLEEP_TIMEOUT);
while (_as_simulator_ue_is_running && _as_simulator_mme_is_running) {
poll(NULL, 0, SLEEP_TIMEOUT);
}
/*
* Termination cleanup
*/
printf("INFO\t: %s - Closing UE's connection endpoint %d\n",
__FUNCTION__, socket_get_fd(_as_simulator_ue_sid));
socket_close(_as_simulator_ue_sid);
printf("INFO\t: %s - Closing MME's connection endpoint %d\n",
__FUNCTION__, socket_get_fd(_as_simulator_mme_sid));
socket_close(_as_simulator_mme_sid);
printf("INFO\t: %s - RRC simulator exited\n", __FUNCTION__);
exit(EXIT_SUCCESS);
}
/****************************************************************************/
/********************* L O C A L F U N C T I O N S *********************/
/****************************************************************************/
/*
* -----------------------------------------------------------------------------
* Signal handler setup function
* -----------------------------------------------------------------------------
*/
static int _set_signal_handler(int signal, void (handler)(int))
{
struct sigaction act;
/* Initialize signal set */
(void) memset (&act, 0, sizeof (act));
(void) sigfillset (&act.sa_mask);
(void) sigdelset (&act.sa_mask, SIGHUP);
(void) sigdelset (&act.sa_mask, SIGINT);
(void) sigdelset (&act.sa_mask, SIGTERM);
(void) sigdelset (&act.sa_mask, SIGILL);
(void) sigdelset (&act.sa_mask, SIGTRAP);
(void) sigdelset (&act.sa_mask, SIGIOT);
#ifndef LINUX
(void) sigdelset (&act.sa_mask, SIGEMT);
#endif
(void) sigdelset (&act.sa_mask, SIGFPE);
(void) sigdelset (&act.sa_mask, SIGBUS);
(void) sigdelset (&act.sa_mask, SIGSEGV);
(void) sigdelset (&act.sa_mask, SIGSYS);
/* Initialize signal handler */
act.sa_handler = handler;
if ( sigaction (signal, &act, 0) < 0 ) {
return RETURNerror;
}
return RETURNok;
}
/*
* -----------------------------------------------------------------------------
* Signal handler
* -----------------------------------------------------------------------------
*/
static void _signal_handler(int signal_number)
{
printf("\nWARNING\t: %s - Signal %d received\n", __FUNCTION__,
signal_number);
_as_simulator_ue_is_running = false;
_as_simulator_mme_is_running = false;
}
/*
* -----------------------------------------------------------------------------
* UE connection manager
* -----------------------------------------------------------------------------
*/
static void* _as_simulator_ue_mngr(void* args)
{
int msg_id;
as_message_t msg;
_as_simulator_ue_is_running = true;
printf("INFO\t: %s - UE connection manager started\n", __FUNCTION__);
printf("[%s][NAS-UE=%s]\n", getTime(), _ue_id);
/* Receiving loop */
while (_as_simulator_ue_is_running) {
int rc, rbytes, sbytes;
/* Receive message from the UE NAS process */
rbytes = socket_recv(_as_simulator_ue_sid, _as_simulator_ue_buffer,
AS_SIMULATOR_UE_BUFFER_SIZE);
if (rbytes == RETURNerror) {
perror("ERROR\t: socket_recv() failed");
break;
}
/* Decode the received message */
msg_id = as_message_decode(_as_simulator_ue_buffer, &msg, rbytes);
if (msg_id == RETURNerror) {
printf("WARNING\t: %s - Failed to decode AS message\n",
__FUNCTION__);
continue;
}
/* Reset the size of the message to be transfered */
_as_simulator_ue_size = 0;
_as_simulator_mme_size = 0;
/* Process the received message */
rc = _as_simulator_ue_process(msg_id, &msg);
if (rc != RETURNok) {
printf("WARNING\t: %s - Failed to process AS message (0x%x)\n",
__FUNCTION__, msg_id);
continue;
}
if (_as_simulator_ue_size > 0) {
/* Return the response message to the UE NAS process */
sbytes = socket_send(_as_simulator_ue_sid,
_as_simulator_ue_buffer,
_as_simulator_ue_size);
if (sbytes == RETURNerror) {
perror("ERROR\t: socket_send() failed");
break;
}
}
if (_as_simulator_mme_size > 0) {
/* Forward the received message to the MME NAS process */
sbytes = socket_send(_as_simulator_mme_sid,
_as_simulator_mme_buffer,
_as_simulator_mme_size);
if (sbytes == RETURNerror) {
perror("ERROR\t: socket_send() failed");
break;
}
}
}
/* Close the connection to the network sublayer */
_as_simulator_ue_is_running = false;
printf("ERROR\t: The UE connection manager exited\n");
return (NULL);
}
/*
* -----------------------------------------------------------------------------
* MME connection manager
* -----------------------------------------------------------------------------
*/
static void* _as_simulator_mme_mngr(void* args)
{
int msg_id;
as_message_t msg;
_as_simulator_mme_is_running = true;
printf("INFO\t: %s - MME connection manager started\n", __FUNCTION__);
printf("[%s][NAS-MME=%s]\n", getTime(), _mme_id);
/* Receiving loop */
while (_as_simulator_mme_is_running) {
int rc, rbytes, sbytes;
/* Receive message from the MME NAS process */
rbytes = socket_recv(_as_simulator_mme_sid, _as_simulator_mme_buffer,
AS_SIMULATOR_MME_BUFFER_SIZE);
if (rbytes == RETURNerror) {
perror("ERROR\t: socket_recv() failed");
break;
}
/* Decode the received message */
msg_id = as_message_decode(_as_simulator_mme_buffer, &msg, rbytes);
if (msg_id == RETURNerror) {
printf("ERROR\t: %s - as_message_decode() failed\n", __FUNCTION__);
continue;
}
/* Reset the size of the message to be transfered */
_as_simulator_ue_size = 0;
_as_simulator_mme_size = 0;
/* Process the received message */
rc = _as_simulator_mme_process(msg_id, &msg);
if (rc != RETURNok) {
printf("WARNING\t: %s - Failed to process AS message (0x%x)\n",
__FUNCTION__, msg_id);
continue;
}
if (_as_simulator_mme_size > 0) {
/* Return the response message to the MME NAS process */
sbytes = socket_send(_as_simulator_mme_sid,
_as_simulator_mme_buffer,
_as_simulator_mme_size);
if (sbytes == RETURNerror) {
perror("ERROR\t: socket_send() failed");
break;
}
}
if (_as_simulator_ue_size > 0) {
/* Forward the received message to the UE NAS process */
sbytes = socket_send(_as_simulator_ue_sid,
_as_simulator_ue_buffer,
_as_simulator_ue_size);
if (sbytes == RETURNerror) {
perror("ERROR\t: socket_send() failed");
break;
}
}
}
/* Close the connection to the network sublayer */
_as_simulator_mme_is_running = false;
printf("ERROR\t: %s - The MME connection manager exited\n", __FUNCTION__);
return (NULL);
}
/*
* -----------------------------------------------------------------------------
* Functions used to process messages received from the UE NAS process
* -----------------------------------------------------------------------------
*/
static int _as_simulator_ue_process(int msg_id, as_message_t* msg)
{
int rc = RETURNok;
as_message_t cnf;
as_message_t ind;
printf("\nINFO\t: %s - Received AS message 0x%x from UE NAS process\n",
__FUNCTION__, msg_id);
_as_simulator_ue_transfer = AS_SIMULATOR_NO_TRANSFER;
memset(&cnf, 0, sizeof(as_message_t));
memset(&ind, 0, sizeof(as_message_t));
switch (msg_id) {
case AS_CELL_INFO_REQ:
cnf.msgID = process_cell_info_req(msg_id,
&msg->msg.cell_info_req,
&cnf.msg.cell_info_cnf);
/* Return confirm message to the UE */
_as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_UE;
break;
case AS_NAS_ESTABLISH_REQ:
ind.msgID = process_nas_establish_req(msg_id,
&msg->msg.nas_establish_req,
&ind.msg.nas_establish_ind,
&cnf.msg.nas_establish_cnf);
if (ind.msgID) {
/* Forward indication message to the MME */
_as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_MME;
}
/* Return confirm message to the UE */
cnf.msgID = AS_NAS_ESTABLISH_CNF;
_as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_UE;
break;
case AS_UL_INFO_TRANSFER_REQ:
ind.msgID = process_ul_info_transfer_req(msg_id,
&msg->msg.ul_info_transfer_req,
&ind.msg.ul_info_transfer_ind,
&cnf.msg.ul_info_transfer_cnf);
if (ind.msgID) {
/* Forward indication message to the MME */
_as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_MME;
}
/* Return confirm message to the UE */
cnf.msgID = AS_UL_INFO_TRANSFER_CNF;
_as_simulator_ue_transfer |= AS_SIMULATOR_TRANSFER_TO_UE;
break;
case AS_NAS_RELEASE_REQ:
ind.msgID = process_nas_release_req(msg_id,
&msg->msg.nas_release_req);
break;
default:
printf("WARNING\t: %s - AS message is not valid (0x%x)\n",
__FUNCTION__, msg_id);
rc = RETURNerror;
break;
}
if (_as_simulator_ue_transfer & AS_SIMULATOR_TRANSFER_TO_UE) {
/* Encode the message confirmation returned to the NAS running
* at the UE side */
_as_simulator_ue_size = as_message_encode(_as_simulator_ue_buffer, &cnf,
AS_SIMULATOR_UE_BUFFER_SIZE);
if (_as_simulator_ue_size == RETURNerror) {
_as_simulator_ue_size = 0;
rc = RETURNerror;
}
}
if (_as_simulator_ue_transfer & AS_SIMULATOR_TRANSFER_TO_MME) {
/* Encode the message indication forwarded to the NAS running
* at the MME side */
_as_simulator_mme_size = as_message_encode(_as_simulator_mme_buffer, &ind,
AS_SIMULATOR_MME_BUFFER_SIZE);
if (_as_simulator_mme_size == RETURNerror) {
_as_simulator_mme_size = 0;
rc = RETURNerror;
}
}
return (rc);
}
/*
* -----------------------------------------------------------------------------
* Functions used to process messages received from the MME NAS process
* -----------------------------------------------------------------------------
*/
static int _as_simulator_mme_process(int msg_id, as_message_t* msg)
{
int rc = RETURNok;
as_message_t cnf;
as_message_t ind;
printf("\nINFO\t: %s - Received AS message 0x%x from MME NAS process\n",
__FUNCTION__, msg_id);
_as_simulator_mme_transfer = AS_SIMULATOR_NO_TRANSFER;
memset(&cnf, 0, sizeof(as_message_t));
memset(&ind, 0, sizeof(as_message_t));
switch (msg_id) {
case AS_NAS_ESTABLISH_RSP:
cnf.msgID = process_nas_establish_rsp(msg_id,
&msg->msg.nas_establish_rsp,
&cnf.msg.nas_establish_cnf);
if (cnf.msgID) {
/* Forward confirm message to the UE */
_as_simulator_mme_transfer |= AS_SIMULATOR_TRANSFER_TO_UE;
}
break;
case AS_DL_INFO_TRANSFER_REQ:
ind.msgID = process_dl_info_transfer_req(msg_id,
&msg->msg.dl_info_transfer_req,
&ind.msg.dl_info_transfer_ind,
&cnf.msg.dl_info_transfer_cnf);
if (ind.msgID) {
/* Forward indication message to the UE */
_as_simulator_mme_transfer |= AS_SIMULATOR_TRANSFER_TO_UE;
}
/* Return confirm message to the MME */
cnf.msgID = AS_DL_INFO_TRANSFER_CNF;
_as_simulator_mme_transfer |= AS_SIMULATOR_TRANSFER_TO_MME;
break;
case AS_NAS_RELEASE_REQ:
ind.msgID = process_nas_release_ind(msg_id,
&msg->msg.nas_release_req,
&ind.msg.nas_release_ind);
/* Forward indication message to the UE */
_as_simulator_mme_transfer |= AS_SIMULATOR_TRANSFER_TO_UE;
break;
default:
printf("WARNING\t: %s - AS message is not valid (0x%x)\n",
__FUNCTION__, msg_id);
rc = RETURNerror;
break;
}
if (_as_simulator_mme_transfer & AS_SIMULATOR_TRANSFER_TO_UE) {
if (ind.msgID > 0) {
/* Encode the message indication forwarded to the NAS running
* at the UE side */
_as_simulator_ue_size = as_message_encode(_as_simulator_ue_buffer,
&ind, AS_SIMULATOR_UE_BUFFER_SIZE);
} else if (cnf.msgID > 0) {
/* Encode the message confirmation forwarded to the NAS running
* at the UE side */
_as_simulator_ue_size = as_message_encode(_as_simulator_ue_buffer,
&cnf, AS_SIMULATOR_UE_BUFFER_SIZE);
}
if (_as_simulator_ue_size == RETURNerror) {
_as_simulator_ue_size = 0;
rc = RETURNerror;
}
}
if (_as_simulator_mme_transfer & AS_SIMULATOR_TRANSFER_TO_MME) {
/* Encode the message confirmation returned to the NAS running
* at the MME side */
_as_simulator_mme_size = as_message_encode(_as_simulator_mme_buffer,
&cnf, AS_SIMULATOR_MME_BUFFER_SIZE);
if (_as_simulator_mme_size == RETURNerror) {
_as_simulator_mme_size = 0;
rc = RETURNerror;
}
}
return (rc);
}