Commit 481d6462 authored by Robert Schmidt's avatar Robert Schmidt

Remove dead code

parent 1d232952
......@@ -50,10 +50,6 @@ memleak:openair1/PHY/CODING/TESTBENCH/ltetest.c
invalidPrintfArgType_sint:openair1/PHY/CODING/TESTBENCH/pdcch_test.c
//
//-----------------------------------------------------------------------------
// oaisim deprecated, remove?
doubleFree:openair3/TEST/oaisim_mme_list_benchmark.c
//
//-----------------------------------------------------------------------------
// is itti analyzer deprecated
nullPointer:common/utils/itti_analyzer/itti_analyzer.c
nullPointerRedundantCheck:common/utils/itti_analyzer/libbuffers/buffers.c
......
......@@ -3118,38 +3118,6 @@ foreach(myExe dlsim dlsim_tm7 ulsim pbchsim scansim mbmssim pdcchsim pucchsim pr
endforeach(myExe)
add_executable(test_epc_generate_scenario
${OPENAIR3_DIR}/TEST/EPC_TEST/generate_scenario.c
${OPENAIR3_DIR}/TEST/EPC_TEST/generate_scenario.h
${OPENAIR2_DIR}/ENB_APP/enb_config.h
${OPENAIR2_DIR}/COMMON/commonDef.h
${OPENAIR2_DIR}/COMMON/messages_def.h
${OPENAIR3_DIR}/S1AP/s1ap_eNB_defs.h
)
target_link_libraries (test_epc_generate_scenario
-Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB X2AP_ENB M2AP_LIB M2AP_ENB M3AP_LIB M3AP_ENB F1AP_LIB F1AP GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT MME_APP SCHED_LIB PHY LFDS ITTI L2 -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} CONFIG_LIB
)
add_executable(test_epc_play_scenario
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_decode.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_display.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_fsm.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_parse.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_s1ap.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_s1ap_compare_ie.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_sctp.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario.h
${OPENAIR2_DIR}/COMMON/commonDef.h
${OPENAIR2_DIR}/COMMON/messages_def.h
)
target_include_directories(test_epc_play_scenario PUBLIC /usr/local/share/asn1c)
target_link_libraries (test_epc_play_scenario
-Wl,--start-group RRC_LIB S1AP_LIB X2AP_LIB X2AP_ENB M3AP_LIB M3AP_ENB F1AP_LIB F1AP GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT MME_APP SCHED_LIB PHY_NR_COMMON PHY_COMMON PHY PHY_UE LFDS ITTI -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} CONFIG_LIB
)
#unitary tests for Core NEtwork pieces
#################################
foreach(myExe s1ap
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Active_eNBs = ( "eNB_Eurecom_LTEBox");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
eNBs =
(
{
////////// Identification parameters:
eNB_ID = 0xe00;
cell_type = "CELL_MACRO_ENB";
eNB_name = "eNB_Eurecom_LTEBox";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ( { mcc = 208; mnc = 95; mnc_length = 2; } );
////////// Physical parameters:
component_carriers = (
{
frame_type = "FDD";
tdd_config = 3;
tdd_config_s = 0;
prefix_type = "NORMAL";
eutra_band = 7;
downlink_frequency = 2660000000L;
uplink_frequency_offset = -120000000;
Nid_cell = 0;
N_RB_DL = 25;
Nid_cell_mbsfn = 0;
nb_antennas_tx = 1;
nb_antennas_rx = 1;
tx_gain = 90;
rx_gain = 120;
prach_root = 0;
prach_config_index = 0;
prach_high_speed = "DISABLE";
prach_zero_correlation = 1;
prach_freq_offset = 2;
pucch_delta_shift = 1;
pucch_nRB_CQI = 1;
pucch_nCS_AN = 0;
pucch_n1_AN = 0;
pdsch_referenceSignalPower = -26;
pdsch_p_b = 0;
pusch_n_SB = 1;
pusch_enable64QAM = "DISABLE";
pusch_hoppingMode = "interSubFrame";
pusch_hoppingOffset = 0;
pusch_groupHoppingEnabled = "ENABLE";
pusch_groupAssignment = 0;
pusch_sequenceHoppingEnabled = "DISABLE";
pusch_nDMRS1 = 1;
phich_duration = "NORMAL";
phich_resource = "ONESIXTH";
srs_enable = "DISABLE";
/* srs_BandwidthConfig =;
srs_SubframeConfig =;
srs_ackNackST =;
srs_MaxUpPts =;*/
pusch_p0_Nominal = -90;
pusch_alpha = "AL1";
pucch_p0_Nominal = -108;
msg3_delta_Preamble = 6;
pucch_deltaF_Format1 = "deltaF2";
pucch_deltaF_Format1b = "deltaF3";
pucch_deltaF_Format2 = "deltaF0";
pucch_deltaF_Format2a = "deltaF0";
pucch_deltaF_Format2b = "deltaF0";
rach_numberOfRA_Preambles = 64;
rach_preamblesGroupAConfig = "DISABLE";
/*
rach_sizeOfRA_PreamblesGroupA = ;
rach_messageSizeGroupA = ;
rach_messagePowerOffsetGroupB = ;
*/
rach_powerRampingStep = 4;
rach_preambleInitialReceivedTargetPower = -108;
rach_preambleTransMax = 10;
rach_raResponseWindowSize = 10;
rach_macContentionResolutionTimer = 48;
rach_maxHARQ_Msg3Tx = 4;
pcch_default_PagingCycle = 128;
pcch_nB = "oneT";
bcch_modificationPeriodCoeff = 2;
ue_TimersAndConstants_t300 = 1000;
ue_TimersAndConstants_t301 = 1000;
ue_TimersAndConstants_t310 = 1000;
ue_TimersAndConstants_t311 = 10000;
ue_TimersAndConstants_n310 = 20;
ue_TimersAndConstants_n311 = 1;
}
);
srb1_parameters :
{
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
timer_poll_retransmit = 80;
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
timer_reordering = 35;
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
timer_status_prohibit = 0;
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
poll_pdu = 4;
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
poll_byte = 99999;
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
max_retx_threshold = 4;
}
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// MME parameters:
mme_ip_address = ( { ipv4 = "192.188.2.2";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
ENB_INTERFACE_NAME_FOR_S1_MME = "tun2";
ENB_IPV4_ADDRESS_FOR_S1_MME = "192.188.2.2/24";
ENB_INTERFACE_NAME_FOR_S1U = "lo";
ENB_IPV4_ADDRESS_FOR_S1U = "127.0.0.1/24";
ENB_PORT_FOR_S1U = 2153; # Spec 2152
};
log_config :
{
global_log_level ="info";
hw_log_level ="info";
phy_log_level ="info";
mac_log_level ="info";
rlc_log_level ="info";
pdcp_log_level ="info";
rrc_log_level ="info";
gtpu_log_level ="info";
udp_log_level ="info";
};
}
);
Active_eNBs = ( "eNB_Eurecom_LTEBox");
# Asn1_verbosity, choice in: none, info, annoying
Asn1_verbosity = "none";
eNBs =
(
{
////////// Identification parameters:
eNB_ID = 0xe00;
cell_type = "CELL_MACRO_ENB";
eNB_name = "eNB_Eurecom_LTEBox";
// Tracking area code, 0x0000 and 0xfffe are reserved values
tracking_area_code = 1;
plmn_list = ( { mcc = 208; mnc = 95; mnc_length = 2; } );
////////// Physical parameters:
component_carriers = (
{
frame_type = "FDD";
tdd_config = 3;
tdd_config_s = 0;
prefix_type = "NORMAL";
eutra_band = 7;
downlink_frequency = 2660000000L;
uplink_frequency_offset = -120000000;
Nid_cell = 0;
N_RB_DL = 25;
Nid_cell_mbsfn = 0;
nb_antennas_tx = 1;
nb_antennas_rx = 1;
tx_gain = 90;
rx_gain = 120;
prach_root = 0;
prach_config_index = 0;
prach_high_speed = "DISABLE";
prach_zero_correlation = 1;
prach_freq_offset = 2;
pucch_delta_shift = 1;
pucch_nRB_CQI = 1;
pucch_nCS_AN = 0;
pucch_n1_AN = 0;
pdsch_referenceSignalPower = -26;
pdsch_p_b = 0;
pusch_n_SB = 1;
pusch_enable64QAM = "DISABLE";
pusch_hoppingMode = "interSubFrame";
pusch_hoppingOffset = 0;
pusch_groupHoppingEnabled = "ENABLE";
pusch_groupAssignment = 0;
pusch_sequenceHoppingEnabled = "DISABLE";
pusch_nDMRS1 = 1;
phich_duration = "NORMAL";
phich_resource = "ONESIXTH";
srs_enable = "DISABLE";
/* srs_BandwidthConfig =;
srs_SubframeConfig =;
srs_ackNackST =;
srs_MaxUpPts =;*/
pusch_p0_Nominal = -90;
pusch_alpha = "AL1";
pucch_p0_Nominal = -108;
msg3_delta_Preamble = 6;
pucch_deltaF_Format1 = "deltaF2";
pucch_deltaF_Format1b = "deltaF3";
pucch_deltaF_Format2 = "deltaF0";
pucch_deltaF_Format2a = "deltaF0";
pucch_deltaF_Format2b = "deltaF0";
rach_numberOfRA_Preambles = 64;
rach_preamblesGroupAConfig = "DISABLE";
/*
rach_sizeOfRA_PreamblesGroupA = ;
rach_messageSizeGroupA = ;
rach_messagePowerOffsetGroupB = ;
*/
rach_powerRampingStep = 4;
rach_preambleInitialReceivedTargetPower = -108;
rach_preambleTransMax = 10;
rach_raResponseWindowSize = 10;
rach_macContentionResolutionTimer = 48;
rach_maxHARQ_Msg3Tx = 4;
pcch_default_PagingCycle = 128;
pcch_nB = "oneT";
bcch_modificationPeriodCoeff = 2;
ue_TimersAndConstants_t300 = 1000;
ue_TimersAndConstants_t301 = 1000;
ue_TimersAndConstants_t310 = 1000;
ue_TimersAndConstants_t311 = 10000;
ue_TimersAndConstants_n310 = 20;
ue_TimersAndConstants_n311 = 1;
}
);
srb1_parameters :
{
# timer_poll_retransmit = (ms) [5, 10, 15, 20,... 250, 300, 350, ... 500]
timer_poll_retransmit = 80;
# timer_reordering = (ms) [0,5, ... 100, 110, 120, ... ,200]
timer_reordering = 35;
# timer_reordering = (ms) [0,5, ... 250, 300, 350, ... ,500]
timer_status_prohibit = 0;
# poll_pdu = [4, 8, 16, 32 , 64, 128, 256, infinity(>10000)]
poll_pdu = 4;
# poll_byte = (kB) [25,50,75,100,125,250,375,500,750,1000,1250,1500,2000,3000,infinity(>10000)]
poll_byte = 99999;
# max_retx_threshold = [1, 2, 3, 4 , 6, 8, 16, 32]
max_retx_threshold = 4;
}
# ------- SCTP definitions
SCTP :
{
# Number of streams to use in input/output
SCTP_INSTREAMS = 2;
SCTP_OUTSTREAMS = 2;
};
////////// MME parameters:
mme_ip_address = ( { ipv4 = "192.168.12.17";
ipv6 = "192:168:30::17";
active = "yes";
preference = "ipv4";
}
);
NETWORK_INTERFACES :
{
ENB_INTERFACE_NAME_FOR_S1_MME = "eth0";
ENB_IPV4_ADDRESS_FOR_S1_MME = "192.168.12.213/24";
ENB_INTERFACE_NAME_FOR_S1U = "eth0";
ENB_IPV4_ADDRESS_FOR_S1U = "192.168.12.213/24";
ENB_PORT_FOR_S1U = 2152; # Spec 2152
};
log_config :
{
global_log_level ="debug";
hw_log_level ="info";
phy_log_level ="info";
rlc_log_level ="info";
pdcp_log_level ="info";
rrc_log_level ="info";
};
}
);
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* 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
*/
/*
generate_scenario.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <string.h>
#include <limits.h>
#include <libconfig.h>
#include <inttypes.h>
#include <getopt.h>
#include <libgen.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <libxml/xmlmemory.h>
#include <libxml/debugXML.h>
#include <libxml/HTMLtree.h>
#include <libxml/xmlIO.h>
#include <libxml/DOCBparser.h>
#include <libxml/xinclude.h>
#include <libxml/catalog.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include "assertions.h"
#include "generate_scenario.h"
#include "s1ap_eNB.h"
#include "intertask_interface.h"
#define ENB_CONFIG_STRING_ACTIVE_ENBS "Active_eNBs"
#define ENB_CONFIG_STRING_ENB_LIST "eNBs"
#define ENB_CONFIG_STRING_ENB_ID "eNB_ID"
#define ENB_CONFIG_STRING_CELL_TYPE "cell_type"
#define ENB_CONFIG_STRING_ENB_NAME "eNB_name"
#define ENB_CONFIG_STRING_TRACKING_AREA_CODE "tracking_area_code"
#define ENB_CONFIG_STRING_MOBILE_COUNTRY_CODE "mobile_country_code"
#define ENB_CONFIG_STRING_MOBILE_NETWORK_CODE "mobile_network_code"
#define ENB_CONFIG_STRING_MME_IP_ADDRESS "mme_ip_address"
#define ENB_CONFIG_STRING_MME_IPV4_ADDRESS "ipv4"
#define ENB_CONFIG_STRING_MME_IPV6_ADDRESS "ipv6"
#define ENB_CONFIG_STRING_MME_IP_ADDRESS_ACTIVE "active"
#define ENB_CONFIG_STRING_MME_IP_ADDRESS_PREFERENCE "preference"
#define ENB_CONFIG_STRING_SCTP_CONFIG "SCTP"
#define ENB_CONFIG_STRING_SCTP_INSTREAMS "SCTP_INSTREAMS"
#define ENB_CONFIG_STRING_SCTP_OUTSTREAMS "SCTP_OUTSTREAMS"
#define ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG "NETWORK_INTERFACES"
#define ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1_MME "ENB_INTERFACE_NAME_FOR_S1_MME"
#define ENB_CONFIG_STRING_ENB_IPV4_ADDRESS_FOR_S1_MME "ENB_IPV4_ADDRESS_FOR_S1_MME"
#define ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1U "ENB_INTERFACE_NAME_FOR_S1U"
#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U "ENB_IPV4_ADDRESS_FOR_S1U"
#define ENB_CONFIG_STRING_ENB_PORT_FOR_S1U "ENB_PORT_FOR_S1U"
#define ENB_CONFIG_MAX_XSLT_PARAMS 32
Enb_properties_array_t g_enb_properties;
char *g_test_dir = NULL;
char *g_pdml_in_origin = NULL;
extern int xmlLoadExtDtdDefaultValue;
#define GENERATE_PDML_FILE 1
#define GENERATE_SCENARIO 2
#define GS_IS_FILE 1
#define GS_IS_DIR 2
//------------------------------------------------------------------------------
// test if file exist in current directory
int is_file_exists( const char const * file_nameP, const char const *file_roleP)
{
struct stat s;
int err = stat(file_nameP, &s);
if(-1 == err) {
if(ENOENT == errno) {
fprintf(stderr, "Please provide a valid %s, %s does not exist\n", file_roleP, file_nameP);
} else {
perror("stat");
exit(1);
}
} else {
if(S_ISREG(s.st_mode)) {
return GS_IS_FILE;
} else if(S_ISDIR(s.st_mode)) {
return GS_IS_DIR;
} else {
fprintf(stderr, "Please provide a valid test %s, %s exists but is not found valid\n", file_roleP, file_nameP);
}
}
return 0;
}
//------------------------------------------------------------------------------
int strip_extension(char *in_filename)
{
static const uint8_t name_min_len = 1;
static const uint8_t max_ext_len = 5; // .pdml !
fprintf(stdout, "strip_extension %s\n", in_filename);
if (NULL != in_filename) {
/* Check chars starting at end of string to find last '.' */
for (ssize_t i = strlen(in_filename); i >= name_min_len; i--) {
if (in_filename[i] == '.') {
in_filename[i] = '\0';
return i;
}
}
}
return -1;
}
//------------------------------------------------------------------------------
// return number of splitted items
int split_path( char * pathP, char *** resP)
{
char * saveptr1;
char * p = strtok_r (pathP, "/", &saveptr1);
int n_spaces = 0;
/// split string and append tokens to 'res'
while (p) {
*resP = realloc (*resP, sizeof (char*) * ++n_spaces);
AssertFatal (*resP, "realloc failed");
(*resP)[n_spaces-1] = p;
p = strtok_r (NULL, "/", &saveptr1);
}
return n_spaces;
}
//------------------------------------------------------------------------------
int generate_test_scenario(const char const * test_nameP, const char const * pdml_in_basenameP)
//------------------------------------------------------------------------------
{
//int fd_pdml_in;
xsltStylesheetPtr cur = NULL;
xmlDocPtr doc, res;
FILE *test_scenario_file = NULL;
const char test_scenario_filename[NAME_MAX];
const char *params[2*ENB_CONFIG_MAX_XSLT_PARAMS];
int nb_params = 0;
int i,j;
char astring[1024];
char *astring2 = NULL;
struct in_addr addr;
memset(test_scenario_filename, 0, sizeof(test_scenario_filename));
memset(astring, 0, sizeof(astring));
if (getcwd(astring, sizeof(astring)) != NULL) {
fprintf(stdout, "working in %s directory\n", astring);
} else {
perror("getcwd() error");
exit(1);
}
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
cur = xsltParseStylesheetFile("/usr/share/oai/xsl/generic_scenario.xsl");
if (NULL == cur) {
AssertFatal (0, "Could not parse stylesheet file /usr/share/oai/xsl/generic_scenario.xsl!\n");
} else {
fprintf(stdout, "XSLT style sheet: /usr/share/oai/xsl/generic_scenario.xsl\n");
}
doc = xmlParseFile(pdml_in_basenameP);
if (NULL == doc) {
AssertFatal (0, "Could not parse pdml file %s!\n", pdml_in_basenameP);
} else {
fprintf(stdout, "pdml file: %s\n", pdml_in_basenameP);
}
params[nb_params++] = "test_name";
sprintf(astring, "%s", pdml_in_basenameP);
if (strip_extension(astring) > 0) {
astring2 = strdup(astring);
sprintf(astring, "\"%s\"", astring2);
free(astring2);
astring2 = NULL;
} else {
fprintf(stderr, "Assigning test name failed: %s\n", astring);
}
params[nb_params++] = strdup(astring);
for (i = 0; i < g_enb_properties.number; i++) {
// eNB S1-C IPv4 address
sprintf(astring, "enb%d_s1c", i);
params[nb_params++] = strdup(astring);
addr.s_addr = g_enb_properties.properties[i]->enb_ipv4_address_for_S1_MME;
sprintf(astring, "\"%s\"", inet_ntoa(addr));
params[nb_params++] = strdup(astring);
// MME S1-C IPv4 address
for (j = 0; j < g_enb_properties.properties[i]->nb_mme; j++) {
sprintf(astring, "mme%d_s1c_%d", i, j);
params[nb_params++] = strdup(astring);
AssertFatal (g_enb_properties.properties[i]->mme_ip_address[j].ipv4_address,
"Only support MME IPv4 address\n");
sprintf(astring, "\"%s\"", g_enb_properties.properties[i]->mme_ip_address[j].ipv4_address);
params[nb_params++] = strdup(astring);
}
}
params[nb_params] = NULL;
res = xsltApplyStylesheet(cur, doc, params);
if (NULL != res) {
// since pdml filename is not relative (no path), just filename in current directory we can safely remove
sprintf(test_scenario_filename,"%s",pdml_in_basenameP);
if (strip_extension(test_scenario_filename) > 0) {
strcat(test_scenario_filename, ".xml");
test_scenario_file = fopen( test_scenario_filename, "w+");
if (NULL != test_scenario_file) {
xsltSaveResultToFile(test_scenario_file, res, cur);
fclose(test_scenario_file);
fprintf(stdout, "Wrote test scenario to %s\n", test_scenario_filename);
} else {
fprintf(stderr, "Error in fopen(%s)\n", test_scenario_filename);
}
} else {
fprintf(stderr, "Error in strip_extension()\n");
}
} else {
fprintf(stderr, "Error in xsltApplyStylesheet()\n");
}
xsltFreeStylesheet(cur);
xmlFreeDoc(res);
xmlFreeDoc(doc);
xsltCleanupGlobals();
xmlCleanupParser();
}
//------------------------------------------------------------------------------
static void enb_config_display(void)
//------------------------------------------------------------------------------
{
int i;
printf( "\n----------------------------------------------------------------------\n");
printf( " ENB CONFIG FILE CONTENT LOADED:\n");
printf( "----------------------------------------------------------------------\n");
for (i = 0; i < g_enb_properties.number; i++) {
printf( "ENB CONFIG for instance %d:\n\n", i);
printf( "\teNB name: \t%s\n",g_enb_properties.properties[i]->eNB_name);
printf( "\teNB ID: \t%"PRIu32"\n",g_enb_properties.properties[i]->eNB_id);
printf( "\tCell type: \t%s\n",g_enb_properties.properties[i]->cell_type == CELL_MACRO_ENB ? "CELL_MACRO_ENB":"CELL_HOME_ENB");
printf( "\tTAC: \t%"PRIu16"\n",g_enb_properties.properties[i]->tac);
printf( "\tMCC: \t%"PRIu16"\n",g_enb_properties.properties[i]->mcc);
if (g_enb_properties.properties[i]->mnc_digit_length == 3) {
printf( "\tMNC: \t%03"PRIu16"\n",g_enb_properties.properties[i]->mnc);
} else {
printf( "\tMNC: \t%02"PRIu16"\n",g_enb_properties.properties[i]->mnc);
}
printf( "\n--------------------------------------------------------\n");
}
}
#ifdef LIBCONFIG_LONG
#define libconfig_int long
#else
#define libconfig_int int
#endif
//------------------------------------------------------------------------------
void enb_config_init(const char const * lib_config_file_name_pP)
//------------------------------------------------------------------------------
{
config_t cfg;
config_setting_t *setting = NULL;
config_setting_t *subsetting = NULL;
config_setting_t *setting_mme_addresses = NULL;
config_setting_t *setting_mme_address = NULL;
config_setting_t *setting_enb = NULL;
int num_enb_properties = 0;
int enb_properties_index = 0;
int num_enbs = 0;
int num_mme_address = 0;
int i = 0;
int j = 0;
int parse_errors = 0;
libconfig_int enb_id = 0;
const char* cell_type = NULL;
const char* tac = 0;
const char* enb_name = NULL;
const char* mcc = 0;
const char* mnc = 0;
char* ipv4 = NULL;
char* ipv6 = NULL;
char* active = NULL;
char* preference = NULL;
const char* active_enb[EPC_TEST_SCENARIO_MAX_ENB];
char* enb_interface_name_for_S1U = NULL;
char* enb_ipv4_address_for_S1U = NULL;
libconfig_int enb_port_for_S1U = 0;
char* enb_interface_name_for_S1_MME = NULL;
char* enb_ipv4_address_for_S1_MME = NULL;
char *address = NULL;
char *cidr = NULL;
AssertFatal (lib_config_file_name_pP != NULL,
"Bad parameter lib_config_file_name_pP %s , must reference a valid eNB config file\n",
lib_config_file_name_pP);
memset((char*)active_enb, 0 , EPC_TEST_SCENARIO_MAX_ENB * sizeof(char*));
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
if (! config_read_file(&cfg, lib_config_file_name_pP)) {
config_destroy(&cfg);
AssertFatal (0, "Failed to parse eNB configuration file %s!\n", lib_config_file_name_pP);
}
// Get list of active eNBs, (only these will be configured)
setting = config_lookup(&cfg, ENB_CONFIG_STRING_ACTIVE_ENBS);
if (setting != NULL) {
num_enbs = config_setting_length(setting);
for (i = 0; i < num_enbs; i++) {
setting_enb = config_setting_get_elem(setting, i);
active_enb[i] = config_setting_get_string (setting_enb);
AssertFatal (active_enb[i] != NULL,
"Failed to parse config file %s, %dth attribute %s \n",
lib_config_file_name_pP, i, ENB_CONFIG_STRING_ACTIVE_ENBS);
active_enb[i] = strdup(active_enb[i]);
num_enb_properties += 1;
}
}
/* Output a list of all eNBs. */
setting = config_lookup(&cfg, ENB_CONFIG_STRING_ENB_LIST);
if (setting != NULL) {
enb_properties_index = g_enb_properties.number;
parse_errors = 0;
num_enbs = config_setting_length(setting);
for (i = 0; i < num_enbs; i++) {
setting_enb = config_setting_get_elem(setting, i);
if (! config_setting_lookup_int(setting_enb, ENB_CONFIG_STRING_ENB_ID, &enb_id)) {
/* Calculate a default eNB ID */
# if defined(ENABLE_USE_MME)
uint32_t hash;
hash = s1ap_generate_eNB_id ();
enb_id = i + (hash & 0xFFFF8);
# else
enb_id = i;
# endif
}
if ( !( config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_CELL_TYPE, &cell_type)
&& config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_ENB_NAME, &enb_name)
&& config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_TRACKING_AREA_CODE, &tac)
&& config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_MOBILE_COUNTRY_CODE, &mcc)
&& config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_MOBILE_NETWORK_CODE, &mnc)
)
) {
AssertError (0, parse_errors ++,
"Failed to parse eNB configuration file %s, %d th enb\n",
lib_config_file_name_pP, i);
continue; // FIXME this prevents segfaults below, not sure what happens after function exit
}
// search if in active list
for (j=0; j < num_enb_properties; j++) {
if (strcmp(active_enb[j], enb_name) == 0) {
g_enb_properties.properties[enb_properties_index] = calloc(1, sizeof(Enb_properties_t));
g_enb_properties.properties[enb_properties_index]->eNB_id = enb_id;
if (strcmp(cell_type, "CELL_MACRO_ENB") == 0) {
g_enb_properties.properties[enb_properties_index]->cell_type = CELL_MACRO_ENB;
} else if (strcmp(cell_type, "CELL_HOME_ENB") == 0) {
g_enb_properties.properties[enb_properties_index]->cell_type = CELL_HOME_ENB;
} else {
AssertError (0, parse_errors ++,
"Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n",
lib_config_file_name_pP, i, cell_type);
}
g_enb_properties.properties[enb_properties_index]->eNB_name = strdup(enb_name);
g_enb_properties.properties[enb_properties_index]->tac = (uint16_t)atoi(tac);
g_enb_properties.properties[enb_properties_index]->mcc = (uint16_t)atoi(mcc);
g_enb_properties.properties[enb_properties_index]->mnc = (uint16_t)atoi(mnc);
g_enb_properties.properties[enb_properties_index]->mnc_digit_length = strlen(mnc);
AssertFatal((g_enb_properties.properties[enb_properties_index]->mnc_digit_length == 2) ||
(g_enb_properties.properties[enb_properties_index]->mnc_digit_length == 3),
"BAD MNC DIGIT LENGTH %d",
g_enb_properties.properties[i]->mnc_digit_length);
setting_mme_addresses = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_MME_IP_ADDRESS);
num_mme_address = config_setting_length(setting_mme_addresses);
g_enb_properties.properties[enb_properties_index]->nb_mme = 0;
for (j = 0; j < num_mme_address; j++) {
setting_mme_address = config_setting_get_elem(setting_mme_addresses, j);
if ( !(
config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IPV4_ADDRESS, (const char **)&ipv4)
&& config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IPV6_ADDRESS, (const char **)&ipv6)
&& config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IP_ADDRESS_ACTIVE, (const char **)&active)
&& config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IP_ADDRESS_PREFERENCE, (const char **)&preference)
)
) {
AssertError (0, parse_errors ++,
"Failed to parse eNB configuration file %s, %d th enb %d th mme address !\n",
lib_config_file_name_pP, i, j);
continue; // FIXME will prevent segfaults below, not sure what happens at function exit...
}
g_enb_properties.properties[enb_properties_index]->nb_mme += 1;
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4_address = strdup(ipv4);
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6_address = strdup(ipv6);
if (strcmp(active, "yes") == 0) {
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].active = 1;
} // else { (calloc)
if (strcmp(preference, "ipv4") == 0) {
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4 = 1;
} else if (strcmp(preference, "ipv6") == 0) {
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1;
} else if (strcmp(preference, "no") == 0) {
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4 = 1;
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1;
}
}
// NETWORK_INTERFACES
subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
if (subsetting != NULL) {
if ( (
config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1_MME,
(const char **)&enb_interface_name_for_S1_MME)
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_IPV4_ADDRESS_FOR_S1_MME,
(const char **)&enb_ipv4_address_for_S1_MME)
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1U,
(const char **)&enb_interface_name_for_S1U)
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U,
(const char **)&enb_ipv4_address_for_S1U)
&& config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_PORT_FOR_S1U,
&enb_port_for_S1U)
)
) {
g_enb_properties.properties[enb_properties_index]->enb_interface_name_for_S1U = strdup(enb_interface_name_for_S1U);
cidr = enb_ipv4_address_for_S1U;
address = strtok(cidr, "/");
if (address) {
IPV4_STR_ADDR_TO_INT_NWBO ( address, g_enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_S1U, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" );
}
g_enb_properties.properties[enb_properties_index]->enb_port_for_S1U = enb_port_for_S1U;
g_enb_properties.properties[enb_properties_index]->enb_interface_name_for_S1_MME = strdup(enb_interface_name_for_S1_MME);
cidr = enb_ipv4_address_for_S1_MME;
address = strtok(cidr, "/");
if (address) {
IPV4_STR_ADDR_TO_INT_NWBO ( address, g_enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_S1_MME, "BAD IP ADDRESS FORMAT FOR eNB S1_MME !\n" );
}
}
} // if (subsetting != NULL) {
enb_properties_index += 1;
} // if (strcmp(active_enb[j], enb_name) == 0)
} // for (j=0; j < num_enb_properties; j++)
} // for (i = 0; i < num_enbs; i++)
} // if (setting != NULL) {
g_enb_properties.number += num_enb_properties;
AssertFatal (parse_errors == 0,
"Failed to parse eNB configuration file %s, found %d error%s !\n",
lib_config_file_name_pP, parse_errors, parse_errors > 1 ? "s" : "");
}
//------------------------------------------------------------------------------
static void usage (
int argc,
char *argv[])
//------------------------------------------------------------------------------
{
fprintf (stdout, "Please report any bug to: %s\n",PACKAGE_BUGREPORT);
fprintf (stdout, "Usage: %s [options]\n\n", argv[0]);
fprintf (stdout, "\n");
fprintf (stdout, "Mandatory options:\n");
fprintf (stdout, "\t-c | --enb-conf-file <file> Provide the old eNB config file for generating a copy of the original test\n");
fprintf (stdout, "\t-d | --test-dir <dir> Directory where a set of files related to a particular test are located\n");
fprintf (stdout, "\t-p | --pdml <file> File name (with no path) in 'test-dir' directory of an original scenario that has to be reworked (IP addresses) with new testbed\n");
fprintf (stdout, "\n");
fprintf (stdout, "Other options:\n");
fprintf (stdout, "\t-h | --help Print this help and return\n");
fprintf (stdout, "\t-v | --version Print informations about the version of this executable\n");
fprintf (stdout, "\n");
fprintf (stdout, "Example of generate_scenario use case: \n");
fprintf (stdout, "\n");
fprintf (stdout, " Generate a generix xml scenario from a captured pcap file: \n");
fprintf (stdout, " +---------------------+ \n");
fprintf (stdout, " |captured pcap-ng file| \n");
fprintf (stdout, " +----------+----------+ \n");
fprintf (stdout, " |\n");
fprintf (stdout, " mme_test_s1_pcap2pdml --pcap_file <`captured pcap-ng file`>\n");
fprintf (stdout, " |\n");
fprintf (stdout, " +--------V----------+ +--------------------+\n");
fprintf (stdout, " |'pdml-in-orig' file| |'enb-conf-file' file|\n");
fprintf (stdout, " +--------+----------+ +--------------------+\n");
fprintf (stdout, " | |\n");
fprintf (stdout, " +----------------------------+\n");
fprintf (stdout, " |\n");
fprintf (stdout, " generate_scenario -d <dir> -p <'pdml-in-orig' file> -c <'enb-conf-file' file> \n");
fprintf (stdout, " |\n");
fprintf (stdout, " +------------V--------------+\n");
fprintf (stdout, " +'xml-test-scenario' file |\n");
fprintf (stdout, " +---------------------------+\n");
fprintf (stdout, "\n");
}
//------------------------------------------------------------------------------
int
config_parse_opt_line (
int argc,
char *argv[])
//------------------------------------------------------------------------------
{
int option;
int rv = 0;
char *enb_config_file_name = NULL;
char *pdml_in_file_name = NULL;
char *test_dir_name = NULL;
enum long_option_e {
LONG_OPTION_START = 0x100, /* Start after regular single char options */
LONG_OPTION_ENB_CONF_FILE,
LONG_OPTION_PDML,
LONG_OPTION_TEST_DIR,
LONG_OPTION_HELP,
LONG_OPTION_VERSION,
};
static struct option long_options[] = {
{"enb-conf-file", required_argument, 0, LONG_OPTION_ENB_CONF_FILE},
{"pdml ", required_argument, 0, LONG_OPTION_PDML},
{"test-dir", required_argument, 0, LONG_OPTION_TEST_DIR},
{"help", no_argument, 0, LONG_OPTION_HELP},
{"version", no_argument, 0, LONG_OPTION_VERSION},
{NULL, 0, NULL, 0}
};
/*
* Parsing command line
*/
while ((option = getopt_long (argc, argv, "vhp:n:c:s:d:", long_options, NULL)) != -1) {
switch (option) {
case LONG_OPTION_ENB_CONF_FILE:
case 'c':
if (optarg) {
enb_config_file_name = optarg;
printf("eNB config file name is %s\n", enb_config_file_name);
rv |= GENERATE_SCENARIO;
}
break;
case LONG_OPTION_PDML:
case 'p':
if (optarg) {
pdml_in_file_name = strdup(optarg);
printf("PDML input file name is %s\n", pdml_in_file_name);
rv |= GENERATE_SCENARIO;
}
break;
case LONG_OPTION_TEST_DIR:
case 'd':
if (optarg) {
test_dir_name = strdup(optarg);
if (is_file_exists(test_dir_name, "test dirname") != GS_IS_DIR) {
fprintf(stderr, "Please provide a valid test dirname, %s is not a valid directory name\n", test_dir_name);
exit(1);
}
printf("Test dir name is %s\n", test_dir_name);
}
break;
case LONG_OPTION_VERSION:
case 'v':
printf("Version %s\n", PACKAGE_VERSION);
exit (0);
break;
case LONG_OPTION_HELP:
case 'h':
default:
usage (argc, argv);
exit (0);
}
}
if (NULL == test_dir_name) {
fprintf(stderr, "Please provide a valid test dirname\n");
exit(1);
}
g_test_dir = test_dir_name; test_dir_name = NULL;
if (chdir(g_test_dir) != 0) {
fprintf(stderr, "Error: chdir %s returned %s\n", g_test_dir, strerror(errno));
exit(1);
}
if (rv & GENERATE_SCENARIO) {
if (NULL == enb_config_file_name) {
fprintf(stderr, "Error: please provide the original eNB config file name that should be in %s\n", g_test_dir);
}
if (is_file_exists(enb_config_file_name, "ENB config file") != GS_IS_FILE) {
fprintf(stderr, "Error: eNB config file name %s is not found in dir %s\n", enb_config_file_name, g_test_dir);
}
enb_config_init(enb_config_file_name);
//enb_config_display();
if (NULL == pdml_in_file_name) {
fprintf(stderr, "Error: please provide the PDML file name that should be in %s\n", g_test_dir);
}
if (is_file_exists(pdml_in_file_name, "PDML file") != GS_IS_FILE) {
fprintf(stderr, "Error: PDML file name %s is not found in dir %s\n", pdml_in_file_name, g_test_dir);
}
g_pdml_in_origin = pdml_in_file_name; pdml_in_file_name = NULL;
}
return rv;
}
//------------------------------------------------------------------------------
int main( int argc, char **argv )
//------------------------------------------------------------------------------
{
int actions = 0;
memset((char*) &g_enb_properties, 0 , sizeof(g_enb_properties));
actions = config_parse_opt_line (argc, argv); //Command-line options
if (actions & GENERATE_SCENARIO) {
generate_test_scenario(g_test_dir, g_pdml_in_origin);
}
return 0;
}
/*
* 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
*/
/*
generate_scenario.h
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#ifndef GENERATE_SCENARIO_H_
#define GENERATE_SCENARIO_H_
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "commonDef.h"
#include "platform_types.h"
#include "platform_constants.h"
#include "s1ap_messages_types.h"
#include "SystemInformationBlockType2.h"
#define IPV4_STR_ADDR_TO_INT_NWBO(AdDr_StR,NwBo,MeSsAgE ) do {\
struct in_addr inp;\
if ( inet_aton(AdDr_StR, &inp ) < 0 ) {\
AssertFatal (0, MeSsAgE);\
} else {\
NwBo = inp.s_addr;\
}\
} while (0);
/** @defgroup _enb_app ENB APP
* @ingroup _oai2
* @{
*/
// Hard to find a defined value for max enb...
#define EPC_TEST_SCENARIO_MAX_ENB 4
typedef struct mme_ip_address_s {
unsigned ipv4:1;
unsigned ipv6:1;
unsigned active:1;
char *ipv4_address;
char *ipv6_address;
} mme_ip_address_t;
typedef struct Enb_properties_s {
/* Unique eNB_id to identify the eNB within EPC.
* For macro eNB ids this field should be 20 bits long.
* For home eNB ids this field should be 28 bits long.
*/
uint32_t eNB_id;
/* The type of the cell */
enum cell_type_e cell_type;
/* Optional name for the cell
* NOTE: the name can be NULL (i.e no name) and will be cropped to 150
* characters.
*/
char *eNB_name;
/* Tracking area code */
uint16_t tac;
/* Mobile Country Code
* Mobile Network Code
*/
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_digit_length;
/* Nb of MME to connect to */
uint8_t nb_mme;
/* List of MME to connect to */
mme_ip_address_t mme_ip_address[S1AP_MAX_NB_MME_IP_ADDRESS];
int sctp_in_streams;
int sctp_out_streams;
char *enb_interface_name_for_S1U;
in_addr_t enb_ipv4_address_for_S1U;
tcp_udp_port_t enb_port_for_S1U;
char *enb_interface_name_for_S1_MME;
in_addr_t enb_ipv4_address_for_S1_MME;
} Enb_properties_t;
typedef struct Enb_properties_array_s {
int number;
Enb_properties_t *properties[EPC_TEST_SCENARIO_MAX_ENB];
} Enb_properties_array_t;
void enb_config_init(const char const * lib_config_file_name_pP);
#endif /* ENB_CONFIG_H_ */
/** @} */
/*
* 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
*/
/*
play_scenario.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <string.h>
#include <limits.h>
#include <libconfig.h>
#include <inttypes.h>
#include <getopt.h>
#include <libgen.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include "assertions.h"
#include "s1ap_common.h"
#include "intertask_interface.h"
#include "play_scenario.h"
#include "sctp_eNB_task.h"
#include "sctp_default_values.h"
#include "log.h"
//------------------------------------------------------------------------------
#define PLAY_SCENARIO 1
#define GS_IS_FILE 1
#define GS_IS_DIR 2
//------------------------------------------------------------------------------
Enb_properties_array_t g_enb_properties;
int g_max_speed = 0;
//------------------------------------------------------------------------------
extern et_scenario_t *g_scenario;
extern int xmlLoadExtDtdDefaultValue;
extern int asn_debug;
extern int asn1_xer_print;
extern pthread_mutex_t g_fsm_lock;
//------------------------------------------------------------------------------
// MEMO:
// Scenario with several eNBs: We may have to create ethx.y interfaces
//
//------------------------------------------------------------------------------
// test if file exist in current directory
int is_file_exists( const char const * file_nameP, const char const *file_roleP)
{
struct stat s;
int err = stat(file_nameP, &s);
if(-1 == err) {
if(ENOENT == errno) {
fprintf(stderr, "Please provide a valid %s, %s does not exist\n", file_roleP, file_nameP);
} else {
perror("stat");
exit(1);
}
} else {
if(S_ISREG(s.st_mode)) {
return GS_IS_FILE;
} else if(S_ISDIR(s.st_mode)) {
return GS_IS_DIR;
} else {
fprintf(stderr, "Please provide a valid test %s, %s exists but is not found valid\n", file_roleP, file_nameP);
}
}
return 0;
}
//------------------------------------------------------------------------------
int et_strip_extension(char *in_filename)
{
static const uint8_t name_min_len = 1;
static const uint8_t max_ext_len = 5; // .pdml !
fprintf(stdout, "strip_extension %s\n", in_filename);
if (NULL != in_filename) {
/* Check chars starting at end of string to find last '.' */
for (ssize_t i = strlen(in_filename); i > name_min_len; i--) {
if (in_filename[i] == '.') {
in_filename[i] = '\0';
return i;
}
}
}
return -1;
}
//------------------------------------------------------------------------------
// return number of splitted items
void et_get_shift_arg( char * line_argument, shift_packet_t * const shift)
{
int len = strlen(line_argument);
int i = 0;
int j = 0;
int num_milli = 0;
char my_num[64];
int negative = 0;
while ((line_argument[i] != ':') && (i < len)) {
if (isdigit(line_argument[i])) { // may occur '\"'
my_num[j++] = line_argument[i];
}
i += 1;
}
AssertFatal(':' == line_argument[i], "Bad format");
i += 1; // ':'
my_num[j++] = '\0';
shift->frame_number = atoi(my_num);
AssertFatal(i<len, "Shift argument %s bad format", line_argument);
if (line_argument[i] == '-') {
negative = 1;
i += 1;
} else if (line_argument[i] == '+') {
i += 1;
}
AssertFatal(i<len, "Shift argument %s bad format", line_argument);
j = 0;
while ((line_argument[i] != '.') && (i < len)) {
my_num[j++] = line_argument[i++];
}
my_num[j] = '\0';
j = 0;
i += 1;
shift->shift_seconds = atoi(my_num);
// may omit .mmm, accept .m or .mm or .mmm or ...
while ((i < len) && (num_milli++ < 3)){
my_num[j++] = line_argument[i++];
}
while (num_milli++ < 6){
my_num[j++] = '0';
}
my_num[j] = '\0';
shift->shift_microseconds = atoi(my_num);
if (negative == 1) {
shift->shift_seconds = - shift->shift_seconds;
shift->shift_microseconds = - shift->shift_microseconds;
}
}
//------------------------------------------------------------------------------
// return number of splitted items
int split_path( char * pathP, char *** resP)
{
char * saveptr1;
char * p = strtok_r (pathP, "/", &saveptr1);
int n_spaces = 0;
/// split string and append tokens to 'res'
while (p) {
*resP = realloc (*resP, sizeof (char*) * ++n_spaces);
AssertFatal (*resP, "realloc failed");
(*resP)[n_spaces-1] = p;
p = strtok_r (NULL, "/", &saveptr1);
}
return n_spaces;
}
//------------------------------------------------------------------------------
void et_free_packet(et_packet_t* packet)
{
if (packet) {
switch (packet->sctp_hdr.chunk_type) {
case SCTP_CID_DATA:
et_free_pointer(packet->sctp_hdr.u.data_hdr.payload.binary_stream);
break;
default:
;
}
et_free_pointer(packet);
}
}
//------------------------------------------------------------------------------
void et_free_scenario(et_scenario_t* scenario)
{
et_packet_t *packet = NULL;
et_packet_t *next_packet = NULL;
if (scenario) {
packet = scenario->list_packet;
while (packet) {
next_packet = packet->next;
et_free_packet(packet);
packet = next_packet->next;
}
et_free_pointer(scenario);
pthread_mutex_destroy(&g_fsm_lock);
}
}
//------------------------------------------------------------------------------
char * et_ip2ip_str(const et_ip_t * const ip)
{
static char str[INET6_ADDRSTRLEN];
sprintf(str, "ERROR");
switch (ip->address_family) {
case AF_INET6:
inet_ntop(AF_INET6, &(ip->address.ipv6), str, INET6_ADDRSTRLEN);
break;
case AF_INET:
inet_ntop(AF_INET, &(ip->address.ipv4), str, INET_ADDRSTRLEN);
break;
default:
;
}
return str;
}
//------------------------------------------------------------------------------
//convert hexstring to len bytes of data
//returns 0 on success, negative on error
//data is a buffer of at least len bytes
//hexstring is upper or lower case hexadecimal, NOT prepended with "0x"
int et_hex2data(unsigned char * const data, const unsigned char * const hexstring, const unsigned int len)
{
unsigned const char *pos = hexstring;
char *endptr = NULL;
size_t count = 0;
fprintf(stdout, "%s(%s,%u)\n", __FUNCTION__, hexstring, len);
if ((len > 1) && (strlen((const char*)hexstring) % 2)) {
//or hexstring has an odd length
return -3;
}
if (len == 1) {
char buf[5] = {'0', 'x', 0, pos[0], '\0'};
data[0] = strtol(buf, &endptr, 16);
/* Check for various possible errors */
AssertFatal ((errno == 0) || (data[0] != 0), "ERROR %s() strtol: %s\n", __FUNCTION__, strerror(errno));
AssertFatal (endptr != buf, "ERROR %s() No digits were found\n", __FUNCTION__);
return 0;
}
for(count = 0; count < len/2; count++) {
char buf[5] = {'0', 'x', pos[0], pos[1], 0};
data[count] = strtol(buf, &endptr, 16);
pos += 2 * sizeof(char);
AssertFatal (endptr[0] == '\0', "ERROR %s() non-hexadecimal character encountered buf %p endptr %p buf %s count %zu pos %p\n", __FUNCTION__, buf, endptr, buf, count, pos);
AssertFatal (endptr != buf, "ERROR %s() No digits were found\n", __FUNCTION__);
}
return 0;
}
//------------------------------------------------------------------------------
sctp_cid_t et_chunk_type_str2cid(const xmlChar * const chunk_type_str)
{
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"DATA"))) { return SCTP_CID_DATA;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"INIT"))) { return SCTP_CID_INIT;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"INIT_ACK"))) { return SCTP_CID_INIT_ACK;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"SACK"))) { return SCTP_CID_SACK;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"HEARTBEAT"))) { return SCTP_CID_HEARTBEAT;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"HEARTBEAT_ACK"))) { return SCTP_CID_HEARTBEAT_ACK;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"ABORT"))) { return SCTP_CID_ABORT;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"SHUTDOWN"))) { return SCTP_CID_SHUTDOWN;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"SHUTDOWN_ACK"))) { return SCTP_CID_SHUTDOWN_ACK;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"ERROR"))) { return SCTP_CID_ERROR;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"COOKIE_ECHO"))) { return SCTP_CID_COOKIE_ECHO;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"COOKIE_ACK"))) { return SCTP_CID_COOKIE_ACK;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"ECN_ECNE"))) { return SCTP_CID_ECN_ECNE;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"ECN_CWR"))) { return SCTP_CID_ECN_CWR;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"SHUTDOWN_COMPLETE"))) { return SCTP_CID_SHUTDOWN_COMPLETE;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"AUTH"))) { return SCTP_CID_AUTH;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"FWD_TSN"))) { return SCTP_CID_FWD_TSN;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"ASCONF"))) { return SCTP_CID_ASCONF;}
if ((!xmlStrcmp(chunk_type_str, (const xmlChar *)"ASCONF_ACK"))) { return SCTP_CID_ASCONF_ACK;}
AssertFatal (0, "ERROR: %s() cannot convert: %s\n", __FUNCTION__, chunk_type_str);
}
//------------------------------------------------------------------------------
const char * const et_chunk_type_cid2str(const sctp_cid_t chunk_type)
{
switch (chunk_type) {
case SCTP_CID_DATA: return "DATA"; break;
case SCTP_CID_INIT: return "INIT"; break;
case SCTP_CID_INIT_ACK: return "INIT_ACK"; break;
case SCTP_CID_SACK: return "SACK"; break;
case SCTP_CID_HEARTBEAT: return "HEARTBEAT"; break;
case SCTP_CID_HEARTBEAT_ACK: return "HEARTBEAT_ACK"; break;
case SCTP_CID_ABORT: return "ABORT"; break;
case SCTP_CID_SHUTDOWN: return "SHUTDOWN"; break;
case SCTP_CID_SHUTDOWN_ACK: return "SHUTDOWN_ACK"; break;
case SCTP_CID_ERROR: return "ERROR"; break;
case SCTP_CID_COOKIE_ECHO: return "COOKIE_ECHO"; break;
case SCTP_CID_COOKIE_ACK: return "COOKIE_ACK"; break;
case SCTP_CID_ECN_ECNE: return "ECN_ECNE"; break;
case SCTP_CID_ECN_CWR: return "ECN_CWR"; break;
case SCTP_CID_SHUTDOWN_COMPLETE: return "SHUTDOWN_COMPLETE"; break;
case SCTP_CID_AUTH: return "AUTH"; break;
case SCTP_CID_FWD_TSN: return "FWD_TSN"; break;
case SCTP_CID_ASCONF: return "ASCONF"; break;
case SCTP_CID_ASCONF_ACK: return "ASCONF_ACK"; break;
default:
AssertFatal (0, "ERROR: Unknown chunk_type %d!\n", chunk_type);
}
}
//------------------------------------------------------------------------------
const char * const et_error_match2str(const int err)
{
switch (err) {
// from asn_compare.h
case COMPARE_ERR_CODE_NO_MATCH: return "CODE_NO_MATCH"; break;
case COMPARE_ERR_CODE_TYPE_MISMATCH: return "TYPE_MISMATCH"; break;
case COMPARE_ERR_CODE_TYPE_ARG_NULL: return "TYPE_ARG_NULL"; break;
case COMPARE_ERR_CODE_VALUE_NULL: return "VALUE_NULL"; break;
case COMPARE_ERR_CODE_VALUE_ARG_NULL: return "VALUE_ARG_NULL"; break;
case COMPARE_ERR_CODE_CHOICE_NUM: return "CHOICE_NUM"; break;
case COMPARE_ERR_CODE_CHOICE_PRESENT: return "CHOICE_PRESENT"; break;
case COMPARE_ERR_CODE_CHOICE_MALFORMED: return "CHOICE_MALFORMED"; break;
case COMPARE_ERR_CODE_SET_MALFORMED: return "SET_MALFORMED"; break;
case COMPARE_ERR_CODE_COLLECTION_NUM_ELEMENTS: return "COLLECTION_NUM_ELEMENTS"; break;
// from play_scenario.h
case ET_ERROR_MATCH_PACKET_SCTP_CHUNK_TYPE: return "SCTP_CHUNK_TYPE"; break;
case ET_ERROR_MATCH_PACKET_SCTP_PPID: return "SCTP_PPID"; break;
case ET_ERROR_MATCH_PACKET_SCTP_ASSOC_ID: return "SCTP_ASSOC_ID"; break;
case ET_ERROR_MATCH_PACKET_SCTP_STREAM_ID: return "SCTP_STREAM_ID"; break;
case ET_ERROR_MATCH_PACKET_SCTP_SSN: return "SCTP_SSN"; break;
case ET_ERROR_MATCH_PACKET_S1AP_PRESENT: return "S1AP_PRESENT"; break;
case ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE: return "S1AP_PROCEDURE_CODE"; break;
case ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY: return "S1AP_CRITICALITY"; break;
default:
AssertFatal (0, "ERROR: Unknown match error %d!(TODO handle an1c error codes)\n", err);
}
}
//------------------------------------------------------------------------------
et_packet_action_t et_action_str2et_action_t(const xmlChar * const action)
{
if ((!xmlStrcmp(action, (const xmlChar *)"SEND"))) { return ET_PACKET_ACTION_S1C_SEND;}
if ((!xmlStrcmp(action, (const xmlChar *)"RECEIVE"))) { return ET_PACKET_ACTION_S1C_RECEIVE;}
AssertFatal (0, "ERROR: cannot convert: %s\n", action);
//if (NULL == action) {return ACTION_S1C_NULL;}
}
//------------------------------------------------------------------------------
void et_ip_str2et_ip(const xmlChar * const ip_str, et_ip_t * const ip)
{
AssertFatal (NULL != ip_str, "ERROR Cannot convert null string to ip address!\n");
AssertFatal (NULL != ip, "ERROR out parameter pointer is NULL!\n");
// store this IP address in sa:
if (inet_pton(AF_INET, (const char*)ip_str, (void*)&(ip->address.ipv4)) > 0) {
ip->address_family = AF_INET;
strncpy((char *)ip->str, (const char *)ip_str, INET_ADDRSTRLEN+1);
} else if (inet_pton(AF_INET6, (const char*)ip_str, (void*)&(ip->address.ipv6)) > 0) {
ip->address_family = AF_INET6;
strncpy((char *)ip->str, (const char *)ip_str, INET6_ADDRSTRLEN+1);
} else {
ip->address_family = AF_UNSPEC;
AssertFatal (0, "ERROR %s() Could not parse ip address %s!\n", __FUNCTION__, ip_str);
}
}
//------------------------------------------------------------------------------
int et_compare_et_ip_to_net_ip_address(const et_ip_t * const ip, const net_ip_address_t * const net_ip)
{
AssertFatal (NULL != ip, "ERROR ip parameter\n");
AssertFatal (NULL != net_ip, "ERROR net_ip parameter\n");
switch (ip->address_family) {
case AF_INET:
if (net_ip->ipv4) {
//S1AP_DEBUG("%s(%s,%s)=%d\n",__FUNCTION__,ip->str, net_ip->ipv4_address, strcmp(ip->str, net_ip->ipv4_address));
return strcmp(ip->str, net_ip->ipv4_address);
}
//S1AP_DEBUG("%s(%s,%s)=-1 (IP version (4) not matching)\n",__FUNCTION__,ip->str, net_ip->ipv4_address);
return -1;
break;
case AF_INET6:
if (net_ip->ipv6) {
//S1AP_DEBUG("%s(%s,%s)=%d\n",__FUNCTION__,ip->str, net_ip->ipv4_address, strcmp(ip->str, net_ip->ipv6_address));
return strcmp(ip->str, net_ip->ipv6_address);
}
//S1AP_DEBUG("%s(%s,%s)=-1 (IP version (6) not matching)\n",__FUNCTION__,ip->str, net_ip->ipv6_address);
return -1;
break;
default:
S1AP_DEBUG("%s(%s,...)=-1 (unknown IP version)\n",__FUNCTION__,ip->str);
return -1;
}
}
#ifdef LIBCONFIG_LONG
#define libconfig_int long
#else
#define libconfig_int int
#endif
//------------------------------------------------------------------------------
void et_enb_config_init(const char const * lib_config_file_name_pP)
//------------------------------------------------------------------------------
{
config_t cfg;
config_setting_t *setting = NULL;
config_setting_t *subsetting = NULL;
config_setting_t *setting_mme_addresses = NULL;
config_setting_t *setting_mme_address = NULL;
config_setting_t *setting_enb = NULL;
libconfig_int my_int;
int num_enb_properties = 0;
int enb_properties_index = 0;
int num_enbs = 0;
int num_mme_address = 0;
int i = 0;
int j = 0;
int parse_errors = 0;
libconfig_int enb_id = 0;
const char* cell_type = NULL;
const char* tac = 0;
const char* enb_name = NULL;
const char* mcc = 0;
const char* mnc = 0;
char* ipv4 = NULL;
char* ipv6 = NULL;
char* active = NULL;
char* preference = NULL;
const char* active_enb[MAX_ENB];
char* enb_interface_name_for_S1U = NULL;
char* enb_ipv4_address_for_S1U = NULL;
libconfig_int enb_port_for_S1U = 0;
char* enb_interface_name_for_S1_MME = NULL;
char* enb_ipv4_address_for_S1_MME = NULL;
char *address = NULL;
char *cidr = NULL;
AssertFatal (lib_config_file_name_pP != NULL,
"Bad parameter lib_config_file_name_pP %s , must reference a valid eNB config file\n",
lib_config_file_name_pP);
memset((char*)active_enb, 0 , MAX_ENB * sizeof(char*));
config_init(&cfg);
/* Read the file. If there is an error, report it and exit. */
if (! config_read_file(&cfg, lib_config_file_name_pP)) {
config_destroy(&cfg);
AssertFatal (0, "Failed to parse eNB configuration file %s!\n", lib_config_file_name_pP);
}
// Get list of active eNBs, (only these will be configured)
setting = config_lookup(&cfg, ENB_CONFIG_STRING_ACTIVE_ENBS);
if (setting != NULL) {
num_enbs = config_setting_length(setting);
for (i = 0; i < num_enbs; i++) {
setting_enb = config_setting_get_elem(setting, i);
active_enb[i] = config_setting_get_string (setting_enb);
AssertFatal (active_enb[i] != NULL,
"Failed to parse config file %s, %dth attribute %s \n",
lib_config_file_name_pP, i, ENB_CONFIG_STRING_ACTIVE_ENBS);
active_enb[i] = strdup(active_enb[i]);
num_enb_properties += 1;
}
}
/* Output a list of all eNBs. */
setting = config_lookup(&cfg, ENB_CONFIG_STRING_ENB_LIST);
if (setting != NULL) {
enb_properties_index = g_enb_properties.number;
parse_errors = 0;
num_enbs = config_setting_length(setting);
for (i = 0; i < num_enbs; i++) {
setting_enb = config_setting_get_elem(setting, i);
if (! config_setting_lookup_int(setting_enb, ENB_CONFIG_STRING_ENB_ID, &enb_id)) {
/* Calculate a default eNB ID */
# if defined(ENABLE_USE_MME)
uint32_t hash;
hash = et_s1ap_generate_eNB_id ();
enb_id = i + (hash & 0xFFFF8);
# else
enb_id = i;
# endif
}
if ( !( config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_CELL_TYPE, &cell_type)
&& config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_ENB_NAME, &enb_name)
&& config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_TRACKING_AREA_CODE, &tac)
&& config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_MOBILE_COUNTRY_CODE, &mcc)
&& config_setting_lookup_string(setting_enb, ENB_CONFIG_STRING_MOBILE_NETWORK_CODE, &mnc)
)
) {
AssertError (0, parse_errors ++,
"Failed to parse eNB configuration file %s, %d th enb\n",
lib_config_file_name_pP, i);
continue; // FIXME this prevents segfaults below, not sure what happens after function exit
}
// search if in active list
for (j=0; j < num_enb_properties; j++) {
if (strcmp(active_enb[j], enb_name) == 0) {
g_enb_properties.properties[enb_properties_index] = calloc(1, sizeof(Enb_properties_t));
g_enb_properties.properties[enb_properties_index]->eNB_id = enb_id;
if (strcmp(cell_type, "CELL_MACRO_ENB") == 0) {
g_enb_properties.properties[enb_properties_index]->cell_type = CELL_MACRO_ENB;
} else if (strcmp(cell_type, "CELL_HOME_ENB") == 0) {
g_enb_properties.properties[enb_properties_index]->cell_type = CELL_HOME_ENB;
} else {
AssertError (0, parse_errors ++,
"Failed to parse eNB configuration file %s, enb %d unknown value \"%s\" for cell_type choice: CELL_MACRO_ENB or CELL_HOME_ENB !\n",
lib_config_file_name_pP, i, cell_type);
}
g_enb_properties.properties[enb_properties_index]->eNB_name = strdup(enb_name);
g_enb_properties.properties[enb_properties_index]->tac = (uint16_t)atoi(tac);
g_enb_properties.properties[enb_properties_index]->mcc = (uint16_t)atoi(mcc);
g_enb_properties.properties[enb_properties_index]->mnc = (uint16_t)atoi(mnc);
g_enb_properties.properties[enb_properties_index]->mnc_digit_length = strlen(mnc);
AssertFatal((g_enb_properties.properties[enb_properties_index]->mnc_digit_length == 2) ||
(g_enb_properties.properties[enb_properties_index]->mnc_digit_length == 3),
"BAD MNC DIGIT LENGTH %d",
g_enb_properties.properties[i]->mnc_digit_length);
setting_mme_addresses = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_MME_IP_ADDRESS);
num_mme_address = config_setting_length(setting_mme_addresses);
g_enb_properties.properties[enb_properties_index]->nb_mme = 0;
for (j = 0; j < num_mme_address; j++) {
setting_mme_address = config_setting_get_elem(setting_mme_addresses, j);
if ( !(
config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IPV4_ADDRESS, (const char **)&ipv4)
&& config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IPV6_ADDRESS, (const char **)&ipv6)
&& config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IP_ADDRESS_ACTIVE, (const char **)&active)
&& config_setting_lookup_string(setting_mme_address, ENB_CONFIG_STRING_MME_IP_ADDRESS_PREFERENCE, (const char **)&preference)
)
) {
AssertError (0, parse_errors ++,
"Failed to parse eNB configuration file %s, %d th enb %d th mme address !\n",
lib_config_file_name_pP, i, j);
continue; // FIXME will prevent segfaults below, not sure what happens at function exit...
}
g_enb_properties.properties[enb_properties_index]->nb_mme += 1;
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4_address = strdup(ipv4);
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6_address = strdup(ipv6);
if (strcmp(active, "yes") == 0) {
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].active = 1;
} // else { (calloc)
if (strcmp(preference, "ipv4") == 0) {
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4 = 1;
} else if (strcmp(preference, "ipv6") == 0) {
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1;
} else if (strcmp(preference, "no") == 0) {
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv4 = 1;
g_enb_properties.properties[enb_properties_index]->mme_ip_address[j].ipv6 = 1;
}
}
// SCTP SETTING
g_enb_properties.properties[enb_properties_index]->sctp_out_streams = SCTP_OUT_STREAMS;
g_enb_properties.properties[enb_properties_index]->sctp_in_streams = SCTP_IN_STREAMS;
subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_SCTP_CONFIG);
if (subsetting != NULL) {
if ( (config_setting_lookup_int( subsetting, ENB_CONFIG_STRING_SCTP_INSTREAMS, &my_int) )) {
g_enb_properties.properties[enb_properties_index]->sctp_in_streams = (uint16_t)my_int;
}
if ( (config_setting_lookup_int( subsetting, ENB_CONFIG_STRING_SCTP_OUTSTREAMS, &my_int) )) {
g_enb_properties.properties[enb_properties_index]->sctp_out_streams = (uint16_t)my_int;
}
}
// NETWORK_INTERFACES
subsetting = config_setting_get_member (setting_enb, ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG);
if (subsetting != NULL) {
if ( (
config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1_MME,
(const char **)&enb_interface_name_for_S1_MME)
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_IPV4_ADDRESS_FOR_S1_MME,
(const char **)&enb_ipv4_address_for_S1_MME)
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1U,
(const char **)&enb_interface_name_for_S1U)
&& config_setting_lookup_string( subsetting, ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U,
(const char **)&enb_ipv4_address_for_S1U)
&& config_setting_lookup_int(subsetting, ENB_CONFIG_STRING_ENB_PORT_FOR_S1U,
&enb_port_for_S1U)
)
) {
g_enb_properties.properties[enb_properties_index]->enb_interface_name_for_S1U = strdup(enb_interface_name_for_S1U);
cidr = enb_ipv4_address_for_S1U;
address = strtok(cidr, "/");
if (address) {
IPV4_STR_ADDR_TO_INT_NWBO ( address, g_enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_S1U, "BAD IP ADDRESS FORMAT FOR eNB S1_U !\n" );
}
g_enb_properties.properties[enb_properties_index]->enb_port_for_S1U = enb_port_for_S1U;
g_enb_properties.properties[enb_properties_index]->enb_interface_name_for_S1_MME = strdup(enb_interface_name_for_S1_MME);
cidr = enb_ipv4_address_for_S1_MME;
address = strtok(cidr, "/");
if (address) {
IPV4_STR_ADDR_TO_INT_NWBO ( address, g_enb_properties.properties[enb_properties_index]->enb_ipv4_address_for_S1_MME, "BAD IP ADDRESS FORMAT FOR eNB S1_MME !\n" );
}
}
} // if (subsetting != NULL) {
enb_properties_index += 1;
} // if (strcmp(active_enb[j], enb_name) == 0)
} // for (j=0; j < num_enb_properties; j++)
} // for (i = 0; i < num_enbs; i++)
} // if (setting != NULL) {
g_enb_properties.number += num_enb_properties;
AssertFatal (parse_errors == 0,
"Failed to parse eNB configuration file %s, found %d error%s !\n",
lib_config_file_name_pP, parse_errors, parse_errors > 1 ? "s" : "");
}
/*------------------------------------------------------------------------------*/
const Enb_properties_array_t *et_enb_config_get(void)
{
return &g_enb_properties;
}
/*------------------------------------------------------------------------------*/
void et_eNB_app_register(const Enb_properties_array_t *enb_properties)
{
uint32_t enb_id = 0;
uint32_t mme_id = 0;
MessageDef *msg_p = NULL;
char *str = NULL;
struct in_addr addr = {.s_addr = 0};
g_scenario->register_enb_pending = 0;
for (enb_id = 0; (enb_id < enb_properties->number) ; enb_id++) {
{
s1ap_register_enb_req_t *s1ap_register_eNB = NULL;
/* note: there is an implicit relationship between the data structure and the message name */
msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ);
s1ap_register_eNB = &S1AP_REGISTER_ENB_REQ(msg_p);
/* Some default/random parameters */
s1ap_register_eNB->eNB_id = enb_properties->properties[enb_id]->eNB_id;
s1ap_register_eNB->cell_type = enb_properties->properties[enb_id]->cell_type;
s1ap_register_eNB->eNB_name = enb_properties->properties[enb_id]->eNB_name;
s1ap_register_eNB->tac = enb_properties->properties[enb_id]->tac;
s1ap_register_eNB->mcc = enb_properties->properties[enb_id]->mcc;
s1ap_register_eNB->mnc = enb_properties->properties[enb_id]->mnc;
s1ap_register_eNB->mnc_digit_length = enb_properties->properties[enb_id]->mnc_digit_length;
s1ap_register_eNB->nb_mme = enb_properties->properties[enb_id]->nb_mme;
AssertFatal (s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS, "Too many MME for eNB %d (%d/%d)!", enb_id, s1ap_register_eNB->nb_mme,
S1AP_MAX_NB_MME_IP_ADDRESS);
for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++) {
s1ap_register_eNB->mme_ip_address[mme_id].ipv4 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4;
s1ap_register_eNB->mme_ip_address[mme_id].ipv6 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6;
strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
}
s1ap_register_eNB->sctp_in_streams = enb_properties->properties[enb_id]->sctp_in_streams;
s1ap_register_eNB->sctp_out_streams = enb_properties->properties[enb_id]->sctp_out_streams;
s1ap_register_eNB->enb_ip_address.ipv6 = 0;
s1ap_register_eNB->enb_ip_address.ipv4 = 1;
addr.s_addr = enb_properties->properties[enb_id]->enb_ipv4_address_for_S1_MME;
str = inet_ntoa(addr);
strcpy(s1ap_register_eNB->enb_ip_address.ipv4_address, str);
g_scenario->register_enb_pending++;
itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
}
}
}
/*------------------------------------------------------------------------------*/
void *et_eNB_app_task(void *args_p)
{
et_scenario_t *scenario = (et_scenario_t*)args_p;
MessageDef *msg_p = NULL;
const char *msg_name = NULL;
instance_t instance = 0;
int result = 0;
itti_mark_task_ready (TASK_ENB_APP);
do {
// Wait for a message
itti_receive_msg (TASK_ENB_APP, &msg_p);
msg_name = ITTI_MSG_NAME (msg_p);
instance = ITTI_MSG_DESTINATION_INSTANCE (msg_p);
switch (ITTI_MSG_ID(msg_p)) {
case TERMINATE_MESSAGE:
itti_exit_task ();
break;
case S1AP_REGISTER_ENB_CNF:
LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
DevAssert(scenario->register_enb_pending > 0);
scenario->register_enb_pending--;
/* Check if at least eNB is registered with one MME */
if (S1AP_REGISTER_ENB_CNF(msg_p).nb_mme > 0) {
scenario->registered_enb++;
}
/* Check if all register eNB requests have been processed */
if (scenario->register_enb_pending == 0) {
timer_remove(scenario->enb_register_retry_timer_id);
if (scenario->registered_enb == scenario->enb_properties->number) {
/* If all eNB are registered, start scenario */
LOG_D(ENB_APP, " All eNB are now associated with a MME\n");
et_event_t event;
event.code = ET_EVENT_S1C_CONNECTED;
et_scenario_fsm_notify_event(event);
} else {
uint32_t not_associated = scenario->enb_properties->number - scenario->registered_enb;
LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
not_associated, not_associated > 1 ? "are" : "is", ET_ENB_REGISTER_RETRY_DELAY);
/* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */
if (timer_setup (ET_ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
NULL, &scenario->enb_register_retry_timer_id) < 0) {
LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
sleep(ET_ENB_REGISTER_RETRY_DELAY);
/* Restart the registration process */
scenario->registered_enb = 0;
et_eNB_app_register (scenario->enb_properties);
}
}
}
break;
case S1AP_DEREGISTERED_ENB_IND:
LOG_W(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
S1AP_DEREGISTERED_ENB_IND(msg_p).nb_mme);
/* TODO handle recovering of registration */
break;
case TIMER_HAS_EXPIRED:
LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
if (TIMER_HAS_EXPIRED (msg_p).timer_id == scenario->enb_register_retry_timer_id) {
/* Restart the registration process */
scenario->registered_enb = 0;
et_eNB_app_register (scenario->enb_properties);
}
break;
default:
LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
break;
}
result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
} while (1);
return NULL;
}
//------------------------------------------------------------------------------
int et_play_scenario(et_scenario_t* const scenario, const struct shift_packet_s *shifts)
{
et_event_t event;
struct shift_packet_s *shift = shifts;
et_packet_t *packet = NULL;
et_packet_t *next_packet = NULL;
struct timeval shift_all_packets = { .tv_sec = 0, .tv_usec = 0 };
struct timeval relative_last_sent_packet = { .tv_sec = 0, .tv_usec = 0 };
struct timeval relative_last_received_packet = { .tv_sec = 0, .tv_usec = 0 };
struct timeval initial_time = { .tv_sec = 0, .tv_usec = 0 };
char first_packet = 1;
char first_sent_packet = 1;
char first_received_packet = 1;
// first apply timing shifts if requested
while (shift) {
packet = scenario->list_packet;
while (packet) {
//fprintf(stdout, "*shift: %p\n", shift);
//fprintf(stdout, "\tframe_number: %d\n", shift->frame_number);
//fprintf(stdout, "\tshift_seconds: %ld\n", shift->shift_seconds);
//fprintf(stdout, "\tshift_microseconds: %ld\n", shift->shift_microseconds);
//fprintf(stdout, "\tsingle: %d\n\n", shift->single);
//fprintf(stdout, "\tshift_all_packets_seconds: %ld\n", shift_all_packets.tv_sec);
//fprintf(stdout, "\tshift_all_packets_microseconds: %ld\n", shift_all_packets.tv_usec);
AssertFatal((packet->time_relative_to_first_packet.tv_sec >= 0) && (packet->time_relative_to_first_packet.tv_usec >= 0),
"Bad timing result time_relative_to_first_packet=%d.%d packet num %u, original frame number %u",
packet->time_relative_to_first_packet.tv_sec,
packet->time_relative_to_first_packet.tv_usec,
packet->packet_number,
packet->original_frame_number);
AssertFatal((packet->time_relative_to_last_received_packet.tv_sec >= 0) && (packet->time_relative_to_last_received_packet.tv_usec >= 0),
"Bad timing result time_relative_to_last_received_packet=%d.%d packet num %u, original frame number %u",
packet->time_relative_to_last_received_packet.tv_sec,
packet->time_relative_to_last_received_packet.tv_usec,
packet->packet_number,
packet->original_frame_number);
AssertFatal((packet->time_relative_to_last_sent_packet.tv_sec >= 0) && (packet->time_relative_to_last_sent_packet.tv_usec >= 0),
"Bad timing result time_relative_to_last_sent_packet=%d.%d packet num %u, original frame number %u",
packet->time_relative_to_last_sent_packet.tv_sec,
packet->time_relative_to_last_sent_packet.tv_usec,
packet->packet_number,
packet->original_frame_number);
// fprintf(stdout, "\tpacket num %u, original frame number %u time_relative_to_first_packet=%d.%d\n",
// packet->packet_number,
// packet->original_frame_number,
// packet->time_relative_to_first_packet.tv_sec,
// packet->time_relative_to_first_packet.tv_usec);
// fprintf(stdout, "\tpacket num %u, original frame number %u time_relative_to_last_received_packet=%d.%d\n",
// packet->packet_number,
// packet->original_frame_number,
// packet->time_relative_to_last_received_packet.tv_sec,
// packet->time_relative_to_last_received_packet.tv_usec);
// fprintf(stdout, "\tpacket num %u, original frame number %u time_relative_to_last_sent_packet=%d.%d\n",
// packet->packet_number,
// packet->original_frame_number,
// packet->time_relative_to_last_sent_packet.tv_sec,
// packet->time_relative_to_last_sent_packet.tv_usec);
if ((shift->single) && (shift->frame_number == packet->original_frame_number)) {
struct timeval t_offset = { .tv_sec = shift->shift_seconds, .tv_usec = shift->shift_microseconds };
et_packet_shift_timing(packet, &t_offset);
next_packet = packet->next;
if (next_packet) {
t_offset.tv_sec = -t_offset.tv_sec;
t_offset.tv_usec = -t_offset.tv_usec;
if (packet->action == ET_PACKET_ACTION_S1C_SEND) {
timeval_add(&next_packet->time_relative_to_last_sent_packet, &next_packet->time_relative_to_last_sent_packet, &t_offset);
} else if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
timeval_add(&next_packet->time_relative_to_last_received_packet, &next_packet->time_relative_to_last_received_packet, &t_offset);
}
}
}
if ((0 == shift->single) && (shift->frame_number == packet->original_frame_number)) {
shift_all_packets.tv_sec = shift->shift_seconds;
shift_all_packets.tv_usec = shift->shift_microseconds;
timeval_add(&packet->time_relative_to_first_packet, &packet->time_relative_to_first_packet, &shift_all_packets);
fprintf(stdout, "\tpacket num %u, now original frame number %u time_relative_to_first_packet=%d.%d\n",
packet->packet_number,
packet->original_frame_number,
packet->time_relative_to_first_packet.tv_sec,
packet->time_relative_to_first_packet.tv_usec);
AssertFatal((packet->time_relative_to_first_packet.tv_sec >= 0) && (packet->time_relative_to_first_packet.tv_usec >= 0),
"Bad timing result time_relative_to_first_packet=%d.%d packet num %u, original frame number %u",
packet->time_relative_to_first_packet.tv_sec,
packet->time_relative_to_first_packet.tv_usec,
packet->packet_number,
packet->original_frame_number);
} else if ((0 == shift->single) && (shift->frame_number < packet->original_frame_number)) {
timeval_add(&packet->time_relative_to_first_packet, &packet->time_relative_to_first_packet, &shift_all_packets);
fprintf(stdout, "\tpacket num %u, now original frame number %u time_relative_to_first_packet=%d.%d\n",
packet->packet_number,
packet->original_frame_number,
packet->time_relative_to_first_packet.tv_sec,
packet->time_relative_to_first_packet.tv_usec);
AssertFatal((packet->time_relative_to_first_packet.tv_sec >= 0) && (packet->time_relative_to_first_packet.tv_usec >= 0),
"Bad timing result time_relative_to_first_packet=%d.%d packet num %u, original frame number %u",
packet->time_relative_to_first_packet.tv_sec,
packet->time_relative_to_first_packet.tv_usec,
packet->packet_number,
packet->original_frame_number);
}
packet = packet->next;
}
shift = shift->next;
}
// now recompute time_relative_to_last_received_packet, time_relative_to_last_sent_packet
packet = scenario->list_packet;
while (packet) {
if (first_packet > 0) {
initial_time = packet->time_relative_to_first_packet;
packet->time_relative_to_first_packet.tv_sec = 0;
packet->time_relative_to_first_packet.tv_usec = 0;
first_packet = 0;
} else {
timersub(&packet->time_relative_to_first_packet, &initial_time,
&packet->time_relative_to_first_packet);
}
if (packet->action == ET_PACKET_ACTION_S1C_SEND) {
if (first_sent_packet > 0) {
relative_last_sent_packet = packet->time_relative_to_first_packet;
packet->time_relative_to_last_sent_packet.tv_sec = 0;
packet->time_relative_to_last_sent_packet.tv_usec = 0;
first_sent_packet = 0;
} else {
timersub(&packet->time_relative_to_first_packet, &relative_last_sent_packet,
&packet->time_relative_to_last_sent_packet);
relative_last_sent_packet = packet->time_relative_to_first_packet;
}
if (first_received_packet > 0) {
packet->time_relative_to_last_received_packet.tv_sec = 0;
packet->time_relative_to_last_received_packet.tv_usec = 0;
} else {
timersub(&packet->time_relative_to_first_packet, &relative_last_received_packet,
&packet->time_relative_to_last_received_packet);
}
} else if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
if (first_received_packet > 0) {
relative_last_received_packet.tv_sec = packet->time_relative_to_first_packet.tv_sec;
relative_last_received_packet.tv_usec = packet->time_relative_to_first_packet.tv_usec;
packet->time_relative_to_last_received_packet.tv_sec = 0;
packet->time_relative_to_last_received_packet.tv_usec = 0;
first_received_packet = 0;
} else {
timersub(&packet->time_relative_to_first_packet, &relative_last_received_packet,
&packet->time_relative_to_last_received_packet);
relative_last_received_packet = packet->time_relative_to_first_packet;
}
if (first_sent_packet > 0) {
packet->time_relative_to_last_sent_packet.tv_sec = 0;
packet->time_relative_to_last_sent_packet.tv_usec = 0;
} else {
timersub(&packet->time_relative_to_first_packet, &relative_last_sent_packet,
&packet->time_relative_to_last_sent_packet);
}
}
packet = packet->next;
}
//et_display_scenario(scenario);
// create SCTP ITTI task: same as eNB code
if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) {
LOG_E(SCTP, "Create task for SCTP failed\n");
return -1;
}
// create S1AP ITTI task: not as same as eNB code
if (itti_create_task (TASK_S1AP, et_s1ap_eNB_task, NULL) < 0) {
LOG_E(S1AP, "Create task for S1AP failed\n");
return -1;
}
// create ENB_APP ITTI task: not as same as eNB code
if (itti_create_task (TASK_ENB_APP, et_eNB_app_task, scenario) < 0) {
LOG_E(ENB_APP, "Create task for ENB_APP failed\n");
return -1;
}
event.code = ET_EVENT_INIT;
event.u.init.scenario = scenario;
et_scenario_fsm_notify_event(event);
return 0;
}
//------------------------------------------------------------------------------
static void et_usage (
int argc,
char *argv[])
//------------------------------------------------------------------------------
{
fprintf (stdout, "Please report any bug to: %s\n",PACKAGE_BUGREPORT);
fprintf (stdout, "Usage: %s [options]\n\n", argv[0]);
fprintf (stdout, "\n");
fprintf (stdout, "\t-d | --test-dir <dir> Directory where a set of files related to a particular test are located\n");
fprintf (stdout, "\t-c | --enb-conf-file <file> Provide an eNB config file, valid for the testbed\n");
fprintf (stdout, "\t-D | --delay-on-exit <delay-in-sec> Wait delay-in-sec before exiting\n");
fprintf (stdout, "\t-f | --shift-packet <frame:[+|-]seconds[.usec]> Shift the timing of a packet'\n");
fprintf (stdout, "\t-F | --shift-packets <frame:[+|-]seconds[.usec]> Shift the timing of packets starting at frame 'frame' included\n");
fprintf (stdout, "\t-m | --max-speed Play scenario as fast as possible without respecting frame timings\n");
fprintf (stdout, "\t-s | --scenario <file> File name (with no path) of a test scenario that has to be replayed ()\n");
fprintf (stdout, "\n");
fprintf (stdout, "Other options:\n");
fprintf (stdout, "\t-h | --help Print this help and return\n");
fprintf (stdout, "\t-v | --version Print informations about the version of this executable\n");
fprintf (stdout, "\n");
}
//------------------------------------------------------------------------------
int
et_config_parse_opt_line (
int argc,
char *argv[],
char **et_dir_name,
char **scenario_file_name,
char **enb_config_file_name,
shift_packet_t **shifts,
int *delay_on_exit)
//------------------------------------------------------------------------------
{
int option = 0;
int rv = 0;
shift_packet_t *shift = NULL;
enum long_option_e {
LONG_OPTION_START = 0x100, /* Start after regular single char options */
LONG_OPTION_ENB_CONF_FILE,
LONG_OPTION_SCENARIO_FILE,
LONG_OPTION_MAX_SPEED,
LONG_OPTION_TEST_DIR,
LONG_OPTION_DELAY_EXIT,
LONG_OPTION_SHIFT_PACKET,
LONG_OPTION_SHIFT_PACKETS,
LONG_OPTION_HELP,
LONG_OPTION_VERSION
};
static struct option long_options[] = {
{"enb-conf-file", required_argument, 0, LONG_OPTION_ENB_CONF_FILE},
{"scenario ", required_argument, 0, LONG_OPTION_SCENARIO_FILE},
{"max-speed ", no_argument, 0, LONG_OPTION_MAX_SPEED},
{"test-dir", required_argument, 0, LONG_OPTION_TEST_DIR},
{"delay-on-exit", required_argument, 0, LONG_OPTION_DELAY_EXIT},
{"shift-packet", required_argument, 0, LONG_OPTION_SHIFT_PACKET},
{"shift-packets", required_argument, 0, LONG_OPTION_SHIFT_PACKETS},
{"help", no_argument, 0, LONG_OPTION_HELP},
{"version", no_argument, 0, LONG_OPTION_VERSION},
{NULL, 0, NULL, 0}
};
/*
* Parsing command line
*/
while ((option = getopt_long (argc, argv, "vhmc:s:d:f:F", long_options, NULL)) != -1) {
switch (option) {
case LONG_OPTION_ENB_CONF_FILE:
case 'c':
if (optarg) {
*enb_config_file_name = strdup(optarg);
printf("eNB config file name is %s\n", *enb_config_file_name);
rv |= PLAY_SCENARIO;
}
break;
case LONG_OPTION_SCENARIO_FILE:
case 's':
if (optarg) {
*scenario_file_name = strdup(optarg);
printf("Scenario file name is %s\n", *scenario_file_name);
rv |= PLAY_SCENARIO;
}
break;
case LONG_OPTION_TEST_DIR:
case 'd':
if (optarg) {
*et_dir_name = strdup(optarg);
if (is_file_exists(*et_dir_name, "test dirname") != GS_IS_DIR) {
fprintf(stderr, "Please provide a valid test dirname, %s is not a valid directory name\n", *et_dir_name);
exit(1);
}
printf("Test dir name is %s\n", *et_dir_name);
}
break;
case LONG_OPTION_DELAY_EXIT:
case 'D':
if (optarg) {
delay_on_exit = atoi(optarg);
if (0 > delay_on_exit) {
fprintf(stderr, "Please provide a valid -D/--delay-on-exit argument, %s is not a valid value\n", delay_on_exit);
exit(1);
}
printf("Delay on exit is %d\n", (int) delay_on_exit);
}
break;
case LONG_OPTION_SHIFT_PACKET:
case 'f':
if (optarg) {
if (NULL == *shifts) {
shift = calloc(1, sizeof (*shift));
*shifts = shift;
} else {
shift->next = calloc(1, sizeof (*shift));
shift = shift->next;
}
shift->single = 1;
printf("Arg Shift packet %s\n", optarg);
et_get_shift_arg(optarg, shift);
}
break;
case LONG_OPTION_SHIFT_PACKETS:
case 'F':
if (optarg) {
if (NULL == *shifts) {
shift = calloc(1, sizeof (*shift));
*shifts = shift;
} else {
shift->next = calloc(1, sizeof (*shift));
shift = shift->next;
}
et_get_shift_arg(optarg, shift);
printf("Arg Shift packets %s\n", optarg);
}
break;
case LONG_OPTION_MAX_SPEED:
case 'm':
g_max_speed = 1;
break;
case LONG_OPTION_VERSION:
case 'v':
printf("Version %s\n", PACKAGE_VERSION);
exit (0);
break;
case LONG_OPTION_HELP:
case 'h':
default:
et_usage (argc, argv);
exit (0);
}
}
if (NULL == *et_dir_name) {
fprintf(stderr, "Please provide a valid test dirname\n");
exit(1);
}
if (chdir(*et_dir_name) != 0) {
fprintf(stderr, "ERROR: chdir %s returned %s\n", *et_dir_name, strerror(errno));
exit(1);
}
if (rv & PLAY_SCENARIO) {
if (NULL == *enb_config_file_name) {
fprintf(stderr, "ERROR: please provide the original eNB config file name that should be in %s\n", *et_dir_name);
}
if (is_file_exists(*enb_config_file_name, "eNB config file") != GS_IS_FILE) {
fprintf(stderr, "ERROR: original eNB config file name %s is not found in dir %s\n", *enb_config_file_name, *et_dir_name);
}
et_enb_config_init(*enb_config_file_name);
if (NULL == *scenario_file_name) {
fprintf(stderr, "ERROR: please provide the scenario file name that should be in %s\n", *et_dir_name);
}
if (is_file_exists(*scenario_file_name, "Scenario file") != GS_IS_FILE) {
fprintf(stderr, "ERROR: Scenario file name %s is not found in dir %s\n", *scenario_file_name, *et_dir_name);
}
}
return rv;
}
//------------------------------------------------------------------------------
int main( int argc, char **argv )
//------------------------------------------------------------------------------
{
int actions = 0;
char *et_dir_name = NULL;
char *scenario_file_name = NULL;
char *enb_config_file_name = NULL;
struct shift_packet_s *shifts = NULL;
int ret = 0;
int delay_on_exit = 0;
et_scenario_t *scenario = NULL;
char play_scenario_filename[NAME_MAX];
memset(play_scenario_filename, 0, sizeof(play_scenario_filename));
// logging
logInit();
set_glog(LOG_TRACE, LOG_MED);
itti_init(TASK_MAX, tasks_info);
set_comp_log(ENB_APP, LOG_TRACE, LOG_MED, 1);
set_comp_log(S1AP, LOG_TRACE, LOG_MED, 1);
set_comp_log(SCTP, LOG_TRACE, LOG_FULL, 1);
asn_debug = 0;
asn1_xer_print = 1;
//parameters
actions = et_config_parse_opt_line (argc, argv, &et_dir_name, &scenario_file_name, &enb_config_file_name, &shifts, &delay_on_exit); //Command-line options
if (actions & PLAY_SCENARIO) {
if (et_generate_xml_scenario(et_dir_name, scenario_file_name,enb_config_file_name, play_scenario_filename) == 0) {
if (NULL != (scenario = et_generate_scenario(play_scenario_filename))) {
ret = et_play_scenario(scenario, shifts);
} else {
fprintf(stderr, "ERROR: Could not generate scenario from tsml file\n");
ret = -1;
}
} else {
fprintf(stderr, "ERROR: Could not generate tsml scenario from xml file\n");
ret = -1;
}
et_free_pointer(et_dir_name);
et_free_pointer(scenario_file_name);
et_free_pointer(enb_config_file_name);
}
itti_wait_tasks_end();
if (0 < delay_on_exit) {
sleep(delay_on_exit);
}
return ret;
}
/*
* 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
*/
/*
play_scenario.h
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#ifndef PLAY_SCENARIO_H_
#define PLAY_SCENARIO_H_
# include <time.h>
# include <stdint.h>
# include <libxml/tree.h>
# include <libxml/xpath.h>
# include <netinet/in.h>
#include "S1AP-PDU.h"
#include "s1ap_ies_defs.h"
#include "play_scenario_s1ap_eNB_defs.h"
#include "hashtable.h"
#include "asn_compare.h"
#define ET_XPATH_EXPRESSION_MAX_LENGTH 400
// powers of 2
#define ET_BIT_MASK_MATCH_SCTP_STREAM 1
#define ET_BIT_MASK_MATCH_SCTP_SSN 2
//#define ET_BIT_MASK_MATCH_S1AP_ 2
#define MAX_ENB 16
#define ENB_CONFIG_STRING_ACTIVE_ENBS "Active_eNBs"
#define ENB_CONFIG_STRING_ENB_LIST "eNBs"
#define ENB_CONFIG_STRING_ENB_ID "eNB_ID"
#define ENB_CONFIG_STRING_CELL_TYPE "cell_type"
#define ENB_CONFIG_STRING_ENB_NAME "eNB_name"
#define ENB_CONFIG_STRING_TRACKING_AREA_CODE "tracking_area_code"
#define ENB_CONFIG_STRING_MOBILE_COUNTRY_CODE "mobile_country_code"
#define ENB_CONFIG_STRING_MOBILE_NETWORK_CODE "mobile_network_code"
#define ENB_CONFIG_STRING_MME_IP_ADDRESS "mme_ip_address"
#define ENB_CONFIG_STRING_MME_IPV4_ADDRESS "ipv4"
#define ENB_CONFIG_STRING_MME_IPV6_ADDRESS "ipv6"
#define ENB_CONFIG_STRING_MME_IP_ADDRESS_ACTIVE "active"
#define ENB_CONFIG_STRING_MME_IP_ADDRESS_PREFERENCE "preference"
#define ENB_CONFIG_STRING_SCTP_CONFIG "SCTP"
#define ENB_CONFIG_STRING_SCTP_INSTREAMS "SCTP_INSTREAMS"
#define ENB_CONFIG_STRING_SCTP_OUTSTREAMS "SCTP_OUTSTREAMS"
#define ENB_CONFIG_STRING_NETWORK_INTERFACES_CONFIG "NETWORK_INTERFACES"
#define ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1_MME "ENB_INTERFACE_NAME_FOR_S1_MME"
#define ENB_CONFIG_STRING_ENB_IPV4_ADDRESS_FOR_S1_MME "ENB_IPV4_ADDRESS_FOR_S1_MME"
#define ENB_CONFIG_STRING_ENB_INTERFACE_NAME_FOR_S1U "ENB_INTERFACE_NAME_FOR_S1U"
#define ENB_CONFIG_STRING_ENB_IPV4_ADDR_FOR_S1U "ENB_IPV4_ADDRESS_FOR_S1U"
#define ENB_CONFIG_STRING_ENB_PORT_FOR_S1U "ENB_PORT_FOR_S1U"
typedef struct shift_packet_s {
unsigned int frame_number; // original frame number
int shift_seconds;
int shift_microseconds;
int single; // shift timing only for this packet (not also following packets)
struct shift_packet_s *next;
} shift_packet_t;
typedef struct mme_ip_address_s {
unsigned ipv4:1;
unsigned ipv6:1;
unsigned active:1;
char *ipv4_address;
char *ipv6_address;
} mme_ip_address_t;
#define IPV4_STR_ADDR_TO_INT_NWBO(AdDr_StR,NwBo,MeSsAgE ) do {\
struct in_addr inp;\
if ( inet_aton(AdDr_StR, &inp ) < 0 ) {\
AssertFatal (0, MeSsAgE);\
} else {\
NwBo = inp.s_addr;\
}\
} while (0);
typedef struct Enb_properties_s {
/* Unique eNB_id to identify the eNB within EPC.
* For macro eNB ids this field should be 20 bits long.
* For home eNB ids this field should be 28 bits long.
*/
uint32_t eNB_id;
/* The type of the cell */
enum cell_type_e cell_type;
/* Optional name for the cell
* NOTE: the name can be NULL (i.e no name) and will be cropped to 150
* characters.
*/
char *eNB_name;
/* Tracking area code */
uint16_t tac;
/* Mobile Country Code
* Mobile Network Code
*/
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_digit_length;
/* Physical parameters */
int16_t Nid_cell[1+MAX_NUM_CCs];// for testing, change later
/* Nb of MME to connect to */
uint8_t nb_mme;
/* List of MME to connect to */
mme_ip_address_t mme_ip_address[S1AP_MAX_NB_MME_IP_ADDRESS];
int sctp_in_streams;
int sctp_out_streams;
char *enb_interface_name_for_S1U;
in_addr_t enb_ipv4_address_for_S1U;
tcp_udp_port_t enb_port_for_S1U;
char *enb_interface_name_for_S1_MME;
in_addr_t enb_ipv4_address_for_S1_MME;
} Enb_properties_t;
typedef struct Enb_properties_array_s {
int number;
Enb_properties_t *properties[MAX_ENB];
} Enb_properties_array_t;
# define ET_ENB_REGISTER_RETRY_DELAY 3
# define ET_FSM_STATE_WAITING_RX_EVENT_DELAY_SEC 15
typedef enum {
ET_PACKET_STATUS_START = 0,
ET_PACKET_STATUS_NONE = ET_PACKET_STATUS_START,
ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT,
ET_PACKET_STATUS_SCHEDULED_FOR_SENDING,
ET_PACKET_STATUS_SENT,
ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING,
ET_PACKET_STATUS_RECEIVED,
ET_PACKET_STATUS_END
} et_packet_status_t;
typedef enum {
ET_FSM_STATE_START = 0,
ET_FSM_STATE_NULL = ET_FSM_STATE_START,
ET_FSM_STATE_CONNECTING_S1C,
ET_FSM_STATE_WAITING_RX_EVENT,
ET_FSM_STATE_WAITING_TX_EVENT,
ET_FSM_STATE_RUNNING,
ET_FSM_STATE_END
} et_fsm_state_t;
enum COMPARE_ERR_CODE_e;
typedef enum {
ET_ERROR_MATCH_START = COMPARE_ERR_CODE_END,
ET_ERROR_MATCH_PACKET_SCTP_CHUNK_TYPE = ET_ERROR_MATCH_START,
ET_ERROR_MATCH_PACKET_SCTP_PPID,
ET_ERROR_MATCH_PACKET_SCTP_ASSOC_ID,
ET_ERROR_MATCH_PACKET_SCTP_STREAM_ID,
ET_ERROR_MATCH_PACKET_SCTP_SSN,
ET_ERROR_MATCH_PACKET_S1AP_PRESENT,
ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE,
ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY,
ET_ERROR_MATCH_END
} et_error_match_code_t;
typedef enum {
ET_PACKET_ACTION_S1C_START = 0,
ET_PACKET_ACTION_S1C_NULL = ET_PACKET_ACTION_S1C_START,
ET_PACKET_ACTION_S1C_SEND,
ET_PACKET_ACTION_S1C_RECEIVE,
ET_PACKET_ACTION_S1C_END
} et_packet_action_t;
// from kernel source file 3.19/include/linux/sctp.h
typedef enum {
SCTP_CID_DATA = 0,
SCTP_CID_INIT = 1,
SCTP_CID_INIT_ACK = 2,
SCTP_CID_SACK = 3,
SCTP_CID_HEARTBEAT = 4,
SCTP_CID_HEARTBEAT_ACK = 5,
SCTP_CID_ABORT = 6,
SCTP_CID_SHUTDOWN = 7,
SCTP_CID_SHUTDOWN_ACK = 8,
SCTP_CID_ERROR = 9,
SCTP_CID_COOKIE_ECHO = 10,
SCTP_CID_COOKIE_ACK = 11,
SCTP_CID_ECN_ECNE = 12,
SCTP_CID_ECN_CWR = 13,
SCTP_CID_SHUTDOWN_COMPLETE = 14,
/* AUTH Extension Section 4.1 */
SCTP_CID_AUTH = 0x0F,
/* PR-SCTP Sec 3.2 */
SCTP_CID_FWD_TSN = 0xC0,
/* Use hex, as defined in ADDIP sec. 3.1 */
SCTP_CID_ASCONF = 0xC1,
SCTP_CID_ASCONF_ACK = 0x80,
} sctp_cid_t; /* enum */
typedef enum {
TEST_S1AP_PDU_TYPE_START = 0,
TEST_S1AP_PDU_TYPE_UNKNOWN = TEST_S1AP_PDU_TYPE_START,
TEST_S1AP_PDU_TYPE_INITIATING,
TEST_S1AP_PDU_TYPE_SUCCESSFUL_OUTCOME,
TEST_S1AP_PDU_TYPE_UNSUCCESSFUL_OUTCOME,
TEST_S1AP_PDU_TYPE_END
} et_s1ap_pdu_type_t;
typedef struct et_s1ap_s {
//et_s1ap_pdu_type_t pdu_type;
S1AP_S1AP_PDU_t pdu; // decoded ASN1 C type: choice of initiatingMessage, successfulOutcome, unsuccessfulOutcome
uint16_t xml_stream_pos_offset;
uint16_t binary_stream_pos;
uint16_t binary_stream_allocated_size;
uint8_t *binary_stream;
xmlDocPtr doc; // XML representation of the S1AP PDU
} et_s1ap_t;
// from kernel source file 3.19/include/linux/sctp.h, Big Endians
typedef struct sctp_datahdr_s {
uint32_t tsn;
uint16_t stream;
uint16_t ssn;
uint32_t ppid;
uint32_t assoc_id; // filled when running scenario
et_s1ap_t payload;
} sctp_datahdr_t;
// from kernel source file 3.19/include/linux/sctp.h, Big Endians
typedef struct sctp_inithdr {
uint32_t init_tag;
uint32_t a_rwnd;
uint16_t num_outbound_streams;
uint16_t num_inbound_streams;
uint32_t initial_tsn;
uint8_t params[0];
} sctp_inithdr_t;
typedef sctp_inithdr_t sctp_initackhdr_t;
typedef struct et_sctp_hdr_s {
unsigned int src_port;
unsigned int dst_port;
sctp_cid_t chunk_type;
union {
sctp_datahdr_t data_hdr;
sctp_inithdr_t init_hdr;
sctp_initackhdr_t init_ack_hdr;
} u;
} et_sctp_hdr_t;
typedef struct et_ip_s {
unsigned int address_family; // AF_INET, AF_INET6
union {
struct in6_addr ipv6;
in_addr_t ipv4;
} address;
char str[INET6_ADDRSTRLEN+1];
} et_ip_t;
typedef struct et_ip_hdr_s {
et_ip_t src;
et_ip_t dst;
} et_ip_hdr_t;
typedef struct et_packet_s {
et_packet_action_t action;
struct timeval time_relative_to_first_packet;
struct timeval time_relative_to_last_sent_packet;
struct timeval time_relative_to_last_received_packet;
unsigned int original_frame_number;
unsigned int packet_number;
instance_t enb_instance;
et_ip_hdr_t ip_hdr;
et_sctp_hdr_t sctp_hdr;
struct et_packet_s *next;
//scenario running vars
et_packet_status_t status;
long timer_id; // ITTI timer id for waiting rx packets
struct timeval timestamp_packet; // timestamp when rx or tx packet
} et_packet_t;
typedef struct sctp_epoll_s {
/* Array of events monitored by the task.
* By default only one fd is monitored (the one used to received messages
* from other tasks).
* More events can be suscribed later by the task itself.
*/
struct epoll_event *events;
int epoll_nb_events;
} thread_desc_t;
typedef struct et_scenario_s {
xmlChar *name;
et_packet_t *list_packet;
//--------------------------
// playing scenario
//--------------------------
Enb_properties_array_t *enb_properties;
uint32_t register_enb_pending;
uint32_t registered_enb;
long enb_register_retry_timer_id;
hash_table_t *hash_mme2association_id;
hash_table_t *hash_old_ue_mme_id2ue_mme_id;
struct timeval time_last_tx_packet; // Time last sent packet
struct timeval time_last_rx_packet; // Time last packet received with all previous scenario RX packet received.
et_packet_t *last_rx_packet; // Last packet received with all previous scenario RX packet received.
et_packet_t *last_tx_packet; // Last sent packet
et_packet_t *next_packet; // Next packet to be handled in the scenario (RX or TX packet)
int timer_count;
} et_scenario_t;
typedef enum {
ET_EVENT_START = 0,
ET_EVENT_INIT = ET_EVENT_START,
ET_EVENT_S1C_CONNECTED,
ET_EVENT_RX_SCTP_EVENT,
ET_EVENT_RX_S1AP,
ET_EVENT_RX_PACKET_TIME_OUT,
ET_EVENT_TX_TIMED_PACKET,
ET_EVENT_TICK,
ET_EVENT_END
} et_event_code_t;
typedef struct et_event_init_s {
et_scenario_t *scenario;
} et_event_init_t;
typedef struct et_event_s1ap_data_ind_s {
sctp_datahdr_t sctp_datahdr;
} et_event_s1ap_data_ind_t;
typedef struct et_event_s1ap_data_req_s {
} et_event_s1ap_data_req_t;
typedef struct et_event_s {
et_event_code_t code;
union {
et_event_init_t init;
et_event_s1ap_data_ind_t s1ap_data_ind;
et_packet_t *tx_timed_packet;
et_packet_t *rx_packet_time_out;
} u;
} et_event_t;
inline void et_free_pointer(void *p) {if (NULL != p) {free(p);}};
//-------------------------
void et_free_packet(et_packet_t *packet);
void et_free_scenario(et_scenario_t *scenario);
//-------------------------
void et_display_packet_s1ap_data(const et_s1ap_t *const s1ap);
void et_display_packet_sctp_init(const sctp_inithdr_t *const sctp);
void et_display_packet_sctp_initack(const sctp_initackhdr_t *const sctp);
void et_display_packet_sctp_data(const sctp_datahdr_t *const sctp);
void et_display_packet_sctp(const et_sctp_hdr_t *const sctp);
void et_display_packet_ip(const et_ip_hdr_t *const ip);
void et_display_packet(const et_packet_t *const packet);
void et_display_scenario(const et_scenario_t *const scenario);
//-------------------------
int et_s1ap_decode_initiating_message(s1ap_message *message, S1AP_InitiatingMessage_t *initiating_p);
int et_s1ap_decode_successful_outcome(s1ap_message *message, S1AP_SuccessfulOutcome_t *successfullOutcome_p);
int et_s1ap_decode_unsuccessful_outcome(s1ap_message *message, S1AP_UnsuccessfulOutcome_t *unSuccessfullOutcome_p);
int et_s1ap_decode_pdu(S1AP_PDU_t *const pdu, s1ap_message *const message, const uint8_t *const buffer, const uint32_t length);
void et_decode_s1ap(et_s1ap_t *const s1ap);
//-------------------------
int et_s1ap_eNB_compare_assoc_id( struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2);
uint32_t et_s1ap_generate_eNB_id(void);
uint16_t et_s1ap_eNB_fetch_add_global_cnx_id(void);
void et_s1ap_eNB_prepare_internal_data(void);
void et_s1ap_eNB_insert_new_instance(s1ap_eNB_instance_t *new_instance_p);
struct s1ap_eNB_mme_data_s *et_s1ap_eNB_get_MME(s1ap_eNB_instance_t *instance_p,int32_t assoc_id, uint16_t cnx_id);
s1ap_eNB_instance_t *et_s1ap_eNB_get_instance(instance_t instance);
void et_s1ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,uint32_t buffer_length, uint16_t stream);
int et_handle_s1ap_mismatch_mme_ue_s1ap_id(et_packet_t *const spacket, et_packet_t *const rx_packet);
asn_comp_rval_t *et_s1ap_is_matching(et_s1ap_t *const s1ap1, et_s1ap_t *const s1ap2, const uint32_t constraints);
et_packet_t *et_build_packet_from_s1ap_data_ind(et_event_s1ap_data_ind_t *const s1ap_data_ind);
int et_scenario_set_packet_received(et_packet_t *const packet);
int et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t *const sctp_data_ind);
void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *const sctp_data_ind);
void et_s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
net_ip_address_t *mme_ip_address,
net_ip_address_t *local_ip_addr,
uint16_t in_streams,
uint16_t out_streams);
void et_s1ap_handle_s1_setup_message(s1ap_eNB_mme_data_t *mme_desc_p, int sctp_shutdown);
void et_s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB);
void et_s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
void *et_s1ap_eNB_task(void *arg);
//-------------------------
int et_generate_xml_scenario(
const char const *xml_in_dir_name,
const char const *xml_in_scenario_filename,
const char const *enb_config_filename,
char const *tsml_out_scenario_filename);
//-------------------------
void timeval_add (struct timeval *const result, const struct timeval *const a, const struct timeval *const b);
int timeval_subtract (struct timeval *const result, struct timeval *const a, struct timeval *const b);
void et_scenario_wait_rx_packet(et_packet_t *const packet);
void et_scenario_schedule_tx_packet(et_packet_t *packet);
et_fsm_state_t et_scenario_fsm_notify_event_state_running(et_event_t event);
et_fsm_state_t et_scenario_fsm_notify_event_state_waiting_tx(et_event_t event);
et_fsm_state_t et_scenario_fsm_notify_event_state_waiting_rx(et_event_t event);
et_fsm_state_t et_scenario_fsm_notify_event_state_connecting_s1c(et_event_t event);
et_fsm_state_t et_scenario_fsm_notify_event_state_null(et_event_t event);
et_fsm_state_t et_scenario_fsm_notify_event(et_event_t event);
//-------------------------
void et_parse_s1ap(xmlDocPtr doc, const xmlNode const *s1ap_node, et_s1ap_t *const s1ap);
void et_parse_sctp_data_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_datahdr_t *const sctp_hdr);
void et_parse_sctp_init_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_inithdr_t *const sctp_hdr);
void et_parse_sctp_init_ack_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_initackhdr_t *const sctp_hdr);
void et_parse_sctp(xmlDocPtr doc, const xmlNode const *sctp_node, et_sctp_hdr_t *const sctp_hdr);
et_packet_t *et_parse_xml_packet(xmlDocPtr doc, xmlNodePtr node);
et_scenario_t *et_generate_scenario(const char *const et_scenario_filename);
//-------------------------
asn_comp_rval_t *et_s1ap_ies_is_matching(const S1AP_PDU_PR present, s1ap_message *const m1, s1ap_message *const m2, const uint32_t constraints);
void update_xpath_node_mme_ue_s1ap_id(et_s1ap_t *const s1ap, xmlNode *node, const S1AP_MME_UE_S1AP_ID_t new_id);
void update_xpath_nodes_mme_ue_s1ap_id(et_s1ap_t *const s1ap_payload, xmlNodeSetPtr nodes, const S1AP_MME_UE_S1AP_ID_t new_id);
int et_s1ap_update_mme_ue_s1ap_id(et_packet_t *const packet, const S1AP_MME_UE_S1AP_ID_t old_id, const S1AP_MME_UE_S1AP_ID_t new_id);
//-------------------------
asn_comp_rval_t *et_sctp_data_is_matching(sctp_datahdr_t *const sctp1, sctp_datahdr_t *const sctp2, const uint32_t constraints);
asn_comp_rval_t *et_sctp_is_matching(et_sctp_hdr_t *const sctp1, et_sctp_hdr_t *const sctp2, const uint32_t constraints);
//------------------------------------------------------------------------------
void et_print_hex_octets(const unsigned char *const byte_stream, const unsigned long int num);
int et_is_file_exists ( const char const *file_nameP, const char const *file_roleP);
int et_strip_extension( char *in_filename);
void et_get_shift_arg( char *line_argument, shift_packet_t *const shift);
int et_split_path ( char *pathP, char *** resP);
void et_display_node ( xmlNodePtr node, unsigned int indent);
void et_display_tree ( xmlNodePtr node, unsigned int indent);
char *et_ip2ip_str(const et_ip_t *const ip);
int et_compare_et_ip_to_net_ip_address(const et_ip_t *const ip, const net_ip_address_t *const net_ip);
int et_hex2data(unsigned char *const data, const unsigned char *const hexstring, const unsigned int len);
sctp_cid_t et_chunk_type_str2cid(const xmlChar *const chunk_type_str);
const char *const et_chunk_type_cid2str(const sctp_cid_t chunk_type);
const char *const et_error_match2str(const int err);
et_packet_action_t et_action_str2et_action_t(const xmlChar *const action);
void et_ip_str2et_ip(const xmlChar *const ip_str, et_ip_t *const ip);
void et_enb_config_init(const char const *lib_config_file_name_pP);
const Enb_properties_array_t *et_enb_config_get(void);
void et_eNB_app_register(const Enb_properties_array_t *enb_properties);
void *et_eNB_app_task(void *args_p);
int et_play_scenario(et_scenario_t *const scenario, const struct shift_packet_s *shifts);
#endif /* PLAY_SCENARIO_H_ */
/*
* 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
*/
/*
play_scenario_decode.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include "intertask_interface.h"
#include "platform_types.h"
#include "s1ap_eNB_decoder.h"
#include "assertions.h"
#include "play_scenario.h"
//------------------------------------------------------------------------------
int et_s1ap_decode_pdu(S1AP_PDU_t *const pdu, const uint8_t *const buffer, const uint32_t length)
{
asn_dec_rval_t dec_ret;
DevAssert(buffer != NULL);
memset((void *)pdu, 0, sizeof(S1AP_S1AP_PDU_t));
dec_ret = aper_decode(NULL,
&asn_DEF_S1AP_S1AP_PDU,
(void **)&pdu,
buffer,
length,
0,
0);
if (dec_ret.code != RC_OK) {
S1AP_ERROR("Failed to decode pdu\n");
return -1;
}
return dec_ret.code;
}
//------------------------------------------------------------------------------
void et_decode_s1ap(et_s1ap_t *const s1ap)
{
if (NULL != s1ap) {
if (et_s1ap_decode_pdu(&s1ap->pdu, s1ap->binary_stream, s1ap->binary_stream_allocated_size) < 0) {
AssertFatal (0, "ERROR %s() Cannot decode S1AP message!\n", __FUNCTION__);
}
}
}
/*
* 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
*/
/*
play_scenario_display.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <string.h>
#include <stdio.h>
#include "intertask_interface.h"
#include "platform_types.h"
#include "assertions.h"
#include "s1ap_eNB_decoder.h"
#include "play_scenario.h"
//-----------------------------------------------------------------------------
void et_print_hex_octets(const unsigned char *const byte_stream, const unsigned long int num)
{
unsigned long octet_index = 0;
if (byte_stream == NULL) {
return;
}
fprintf(stdout, "+-----+-------------------------------------------------+\n");
fprintf(stdout, "| | 0 1 2 3 4 5 6 7 8 9 a b c d e f |\n");
fprintf(stdout, "+-----+-------------------------------------------------+\n");
for (octet_index = 0; octet_index < num; octet_index++) {
if ((octet_index % 16) == 0) {
if (octet_index != 0) {
fprintf(stdout, " |\n");
}
fprintf(stdout, " %04lu |", octet_index);
}
/*
* Print every single octet in hexadecimal form
*/
fprintf(stdout, " %02x", byte_stream[octet_index]);
/*
* Align newline and pipes according to the octets in groups of 2
*/
}
/*
* Append enough spaces and put final pipe
*/
unsigned char index;
for (index = octet_index; index < 16; ++index) {
fprintf(stdout, " ");
}
fprintf(stdout, " |\n");
}
//------------------------------------------------------------------------------
void et_display_node(xmlNodePtr node, unsigned int indent)
{
int i = 0;
if (node->type == XML_ELEMENT_NODE) {
xmlChar *path = xmlGetNodePath(node);
for (i=0; i<indent; i++) {
printf(" ");
}
if (node->children != NULL && node->children->type == XML_TEXT_NODE) {
xmlChar *content = xmlNodeGetContent(node);
printf("%s -> %s\n", path, content);
xmlFree(content);
} else {
printf("%s\n", path);
}
xmlFree(path);
}
}
//------------------------------------------------------------------------------
void et_display_tree(xmlNodePtr node, unsigned int indent)
{
xmlNode *cur_node = NULL;
for (cur_node = node; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
et_display_node(cur_node, indent);
}
et_display_tree(cur_node->children, indent++);
}
}
//------------------------------------------------------------------------------
void et_display_packet_S1AP_data(const et_S1AP_t *const s1ap)
{
char *message_string = NULL;
if (s1ap) {
message_string = calloc(20000, sizeof(char));
AssertFatal (NULL != message_string, "ERROR malloc()failed!\n");
switch(s1ap->pdu.present) {
case S1AP_S1AP_PDU_PR_initiatingMessage:
switch(s1ap->pdu.choice.initiatingMessage.procedureCode) {
case S1AP_ProcedureCode_id_downlinkNASTransport: s1ap_xer_print_s1ap_downlinknastransport(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_InitialContextSetup: s1ap_xer_print_s1ap_initialcontextsetuprequest(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_UEContextRelease: s1ap_xer_print_s1ap_uecontextreleasecommand(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_Paging: s1ap_xer_print_s1ap_paging(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_uplinkNASTransport: s1ap_xer_print_s1ap_uplinknastransport(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_S1Setup: s1ap_xer_print_s1ap_s1setuprequest(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_initialUEMessage: s1ap_xer_print_s1ap_initialuemessage(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_UEContextReleaseRequest: s1ap_xer_print_s1ap_uecontextreleaserequest(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_UECapabilityInfoIndication:s1ap_xer_print_s1ap_uecapabilityinfoindication(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_NASNonDeliveryIndication: s1ap_xer_print_s1ap_nasnondeliveryindication_(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
default:
AssertFatal( 0, "Unknown procedure ID (%d) for initiating message\n",
(int)s1ap->pdu.choice.initiatingMessage.procedureCode);
}
break;
case S1AP_S1AP_PDU_PR_successfulOutcome:
switch(s1ap->pdu.choice.successfulOutcome.procedureCode) {
case S1AP_ProcedureCode_id_S1Setup: s1ap_xer_print_s1ap_s1setupresponse(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_InitialContextSetup: s1ap_xer_print_s1ap_initialcontextsetupresponse(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_UEContextRelease: s1ap_xer_print_s1ap_uecontextreleasecomplete(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
default:
AssertFatal(0, "Unknown procedure ID (%d) for successfull outcome message\n",
(int)s1ap->pdu.choice.successfulOutcome.procedureCode);
}
break;
case S1AP_S1AP_PDU_PR_unsuccessfulOutcome:
switch(s1ap->pdu.choice.unsuccessfulOutcome.procedureCode) {
case S1AP_ProcedureCode_id_S1Setup: s1ap_xer_print_s1ap_s1setupfailure(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
case S1AP_ProcedureCode_id_InitialContextSetup: s1ap_xer_print_s1ap_initialcontextsetupfailure(s1ap_xer__print2sp, message_string, (S1AP_message *)&s1ap->message); break;
default:
et_free_pointer(message_string);
AssertFatal(0,"Unknown procedure ID (%d) for unsuccessfull outcome message\n",
(int)s1ap->pdu.choice.unsuccessfulOutcome.procedureCode);
break;
}
break;
default:
AssertFatal(0, "Unknown presence (%d) or not implemented\n", (int)s1ap->pdu.present);
break;
}
fprintf(stdout, "\t\tSCTP.data XML dump:\n%s\n", message_string);
et_free_pointer(message_string);
}
}
//------------------------------------------------------------------------------
void et_display_packet_sctp_init(const sctp_inithdr_t *const sctp)
{
if (sctp) {
fprintf(stdout, "\t\tSCTP.init.init_tag : %u\n", sctp->init_tag);
fprintf(stdout, "\t\tSCTP.init.a_rwnd : %u\n", sctp->a_rwnd);
fprintf(stdout, "\t\tSCTP.init.num_inbound_streams : %u\n", sctp->num_inbound_streams);
fprintf(stdout, "\t\tSCTP.init.num_outbound_streams : %u\n", sctp->num_outbound_streams);
fprintf(stdout, "\t\tSCTP.init.initial_tsn : %u\n", sctp->initial_tsn);
}
}
//------------------------------------------------------------------------------
void et_display_packet_sctp_initack(const sctp_initackhdr_t *const sctp)
{
if (sctp) {
fprintf(stdout, "\t\tSCTP.initack.init_tag : %u\n", sctp->init_tag);
fprintf(stdout, "\t\tSCTP.initack.a_rwnd : %u\n", sctp->a_rwnd);
fprintf(stdout, "\t\tSCTP.initack.num_inbound_streams : %u\n", sctp->num_inbound_streams);
fprintf(stdout, "\t\tSCTP.initack.num_outbound_streams : %u\n", sctp->num_outbound_streams);
fprintf(stdout, "\t\tSCTP.initack.initial_tsn : %u\n", sctp->initial_tsn);
}
}
//------------------------------------------------------------------------------
void et_display_packet_sctp_data(const sctp_datahdr_t *const sctp)
{
if (sctp) {
fprintf(stdout, "\t\tSCTP.data.tsn : %u\n", sctp->tsn);
fprintf(stdout, "\t\tSCTP.data.stream : %u\n", sctp->stream);
fprintf(stdout, "\t\tSCTP.data.ssn : %u\n", sctp->ssn);
fprintf(stdout, "\t\tSCTP.data.ppid : %u\n", sctp->ppid);
if (sctp->ppid == 18) {
et_display_packet_s1ap_data(&sctp->payload);
}
fprintf(stdout, "\t\tSCTP.data.binary_stream_allocated_size : %u\n", sctp->payload.binary_stream_allocated_size);
if (NULL != sctp->payload.binary_stream) {
fprintf(stdout, "\t\tSCTP.data.binary_stream :\n");
et_print_hex_octets(sctp->payload.binary_stream, sctp->payload.binary_stream_allocated_size);
} else {
fprintf(stdout, "\t\tSCTP.data.binary_stream : NULL\n");
}
}
}
//------------------------------------------------------------------------------
void et_display_packet_sctp(const et_sctp_hdr_t *const sctp)
{
if (sctp) {
fprintf(stdout, "\t\tSCTP.src_port : %u\n", sctp->src_port);
fprintf(stdout, "\t\tSCTP.dst_port : %u\n", sctp->dst_port);
fprintf(stdout, "\t\tSCTP.chunk_type : %s\n", et_chunk_type_cid2str(sctp->chunk_type));
switch (sctp->chunk_type) {
case SCTP_CID_DATA:
et_display_packet_sctp_data(&sctp->u.data_hdr);
break;
case SCTP_CID_INIT:
et_display_packet_sctp_initack(&sctp->u.init_hdr);
break;
case SCTP_CID_INIT_ACK:
et_display_packet_sctp_initack(&sctp->u.init_ack_hdr);
break;
default:
;
}
}
}
//------------------------------------------------------------------------------
void et_display_packet_ip(const et_ip_hdr_t *const ip)
{
if (ip) {
fprintf(stdout, "\t\tSource address : %s\n", et_ip2ip_str(&ip->src));
fprintf(stdout, "\t\tDestination address : %s\n", et_ip2ip_str(&ip->dst));
}
}
//------------------------------------------------------------------------------
void et_display_packet(const et_packet_t *const packet)
{
if (packet) {
fprintf(stdout, "-------------------------------------------------------------------------------\n");
fprintf(stdout, "\tPacket:\tnum %u | original frame number %u \n", packet->packet_number, packet->original_frame_number);
fprintf(stdout, "\tPacket:\ttime relative to 1st packet %ld.%06lu\n",
packet->time_relative_to_first_packet.tv_sec, packet->time_relative_to_first_packet.tv_usec);
fprintf(stdout, "\tPacket:\ttime relative to last tx packet %ld.%06lu\n",
packet->time_relative_to_last_sent_packet.tv_sec, packet->time_relative_to_last_sent_packet.tv_usec);
fprintf(stdout, "\tPacket:\ttime relative to last_received packet %ld.%06lu\n",
packet->time_relative_to_last_received_packet.tv_sec, packet->time_relative_to_last_received_packet.tv_usec);
switch(packet->action) {
case ET_PACKET_ACTION_S1C_SEND:
fprintf(stdout, "\tPacket:\tAction SEND\n");
break;
case ET_PACKET_ACTION_S1C_RECEIVE:
fprintf(stdout, "\tPacket:\tAction RECEIVE\n");
break;
default:
fprintf(stdout, "\tPacket:\tAction UNKNOWN\n");
}
switch(packet->status) {
case ET_PACKET_STATUS_NONE:
fprintf(stdout, "\tPacket:\tStatus NONE\n");
break;
case ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT:
fprintf(stdout, "\tPacket:\tStatus NOT_TAKEN_IN_ACCOUNT\n");
break;
case ET_PACKET_STATUS_SCHEDULED_FOR_SENDING:
fprintf(stdout, "\tPacket:\tStatus SCHEDULED_FOR_SENDING\n");
break;
case ET_PACKET_STATUS_SENT:
fprintf(stdout, "\tPacket:\tStatus SENT\n");
break;
case ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING:
fprintf(stdout, "\tPacket:\tStatus SCHEDULED_FOR_RECEIVING\n");
break;
case ET_PACKET_STATUS_RECEIVED:
fprintf(stdout, "\tPacket:\tStatus RECEIVED\n");
break;
default:
fprintf(stdout, "\tPacket:\tStatus UNKNOWN\n");
}
et_display_packet_ip(&packet->ip_hdr);
et_display_packet_sctp(&packet->sctp_hdr);
}
}
//------------------------------------------------------------------------------
void et_display_scenario(const et_scenario_t *const scenario)
{
et_packet_t *packet = NULL;
if (scenario) {
fprintf(stdout, "Scenario: %s\n", (scenario->name != NULL) ? (char *)scenario->name:"UNKNOWN NAME");
packet = scenario->list_packet;
while (packet) {
et_display_packet(packet);
packet = packet->next;
}
}
}
/*
* 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
*/
/*
play_scenario_fsm.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <stdio.h>
#include <sys/time.h>
#include <pthread.h>
#include "intertask_interface.h"
#include "platform_types.h"
#include "assertions.h"
#include "play_scenario.h"
#include "play_scenario_s1ap_eNB_defs.h"
//------------------------------------------------------------------------------
extern int g_max_speed;
//------------------------------------------------------------------------------
et_scenario_t *g_scenario = NULL;
pthread_mutex_t g_fsm_lock = PTHREAD_MUTEX_INITIALIZER;
et_fsm_state_t g_fsm_state = ET_FSM_STATE_NULL;
uint32_t g_constraints = ET_BIT_MASK_MATCH_SCTP_STREAM | ET_BIT_MASK_MATCH_SCTP_SSN;
//------------------------------------------------------------------------------
// it is assumed that if a time is negative tv_sec and tv_usec are both negative
void timeval_add (struct timeval *const result, const struct timeval *const a, const struct timeval *const b)
{
AssertFatal(((a->tv_sec <= 0) && (a->tv_usec <= 0)) || ((a->tv_sec >= 0) && (a->tv_usec >= 0)), " Bad time format arg a\n");
AssertFatal(((b->tv_sec <= 0) && (b->tv_usec <= 0)) || ((b->tv_sec >= 0) && (b->tv_usec >= 0)), " Bad time format arg b\n");
// may happen overflows but were are not dealing with very large timings
long long int r = a->tv_usec + b->tv_usec + (a->tv_sec + b->tv_sec) * 1000000;
result->tv_sec = r / (long long int)1000000;
result->tv_usec = r % (long long int)1000000;
if ((result != a) && (result != b)) {
LOG_D(ENB_APP, "timeval_add(%ld.%06d, %ld.%06d)=%ld.%06d\n", a->tv_sec, a->tv_usec, b->tv_sec, b->tv_usec, result->tv_sec, result->tv_usec);
}
}
//------------------------------------------------------------------------------
// it is assumed that if a time is negative tv_sec and tv_usec are both negative
// return true if result is positive
int timeval_subtract (struct timeval *const result, struct timeval *const a, struct timeval *const b)
{
AssertFatal(((a->tv_sec <= 0) && (a->tv_usec <= 0)) || ((a->tv_sec >= 0) && (a->tv_usec >= 0)), " Bad time format arg a\n");
AssertFatal(((b->tv_sec <= 0) && (b->tv_usec <= 0)) || ((b->tv_sec >= 0) && (b->tv_usec >= 0)), " Bad time format arg b\n");
// may happen overflows but were are not dealing with very large timings
long long int r = a->tv_usec - b->tv_usec + (a->tv_sec - b->tv_sec) * 1000000;
result->tv_sec = r / (long long int)1000000;
result->tv_usec = r % (long long int)1000000;
if ((result != a) && (result != b)) {
LOG_D(ENB_APP, "timeval_subtract(%ld.%06d, %ld.%06d)=%ld.%06d\n", a->tv_sec, a->tv_usec, b->tv_sec, b->tv_usec, result->tv_sec, result->tv_usec);
}
return (result->tv_sec >= 0) && (result->tv_usec >= 0);
}
//------------------------------------------------------------------------------
void et_scenario_wait_rx_packet(et_packet_t *const packet)
{
packet->status = ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING;
g_fsm_state = ET_FSM_STATE_WAITING_RX_EVENT;
if (timer_setup (ET_FSM_STATE_WAITING_RX_EVENT_DELAY_SEC, 0, TASK_S1AP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
packet, &packet->timer_id) < 0) {
AssertFatal(0, " Can not start waiting RX event timer\n");
}
g_scenario->timer_count++;
LOG_D(ENB_APP, "Waiting RX packet num %d original frame number %u\n", packet->packet_number, packet->original_frame_number);
}
//------------------------------------------------------------------------------
void et_scenario_schedule_tx_packet(et_packet_t *packet)
{
s1ap_eNB_instance_t *s1ap_eNB_instance = NULL;
struct timeval now = { .tv_sec = 0, .tv_usec = 0 };
struct timeval offset_last_tx_packet = { .tv_sec = 0, .tv_usec = 0 };
struct timeval offset_last_rx_packet = { .tv_sec = 0, .tv_usec = 0 };
struct timeval offset_tx_rx = { .tv_sec = 0, .tv_usec = 0 };
struct timeval offset = { .tv_sec = 0, .tv_usec = 0 };
int last_packet_was_rx = 0;
int we_are_too_late = 0;
int original_frame_number = -1;
AssertFatal(NULL != packet, "packet argument is NULL");
s1ap_eNB_instance = et_s1ap_eNB_get_instance(packet->enb_instance);
AssertFatal(NULL != s1ap_eNB_instance, "Cannot get s1ap_eNB_instance_t for eNB instance %d", packet->enb_instance);
LOG_D(ENB_APP, "%s\n", __FUNCTION__);
g_fsm_state = ET_FSM_STATE_WAITING_TX_EVENT;
switch (packet->sctp_hdr.chunk_type) {
case SCTP_CID_DATA:
// check if we can send it now
// TODO: BUG we have to discard in scenario all packets that cannot be processed (SACK, COOKIEs, etc)
AssertFatal(gettimeofday(&now, NULL) == 0, "gettimeofday failed");
timeval_subtract(&offset_last_tx_packet,&now,&g_scenario->time_last_tx_packet);
timeval_subtract(&offset_last_rx_packet,&now,&g_scenario->time_last_rx_packet);
LOG_D(ENB_APP, "offset_last_tx_packet=%ld.%06d\n", offset_last_tx_packet.tv_sec, offset_last_tx_packet.tv_usec);
LOG_D(ENB_APP, "offset_last_rx_packet=%ld.%06d\n", offset_last_rx_packet.tv_sec, offset_last_rx_packet.tv_usec);
last_packet_was_rx = timeval_subtract(&offset_tx_rx,&offset_last_tx_packet,&offset_last_rx_packet);
if (last_packet_was_rx) {
LOG_D(ENB_APP, "last_packet_was_rx\n");
we_are_too_late = timeval_subtract(&offset,&offset_last_rx_packet,&packet->time_relative_to_last_received_packet);
LOG_D(ENB_APP, "we_are_too_late=%d, offset=%ld.%06d\n", we_are_too_late, offset.tv_sec, offset.tv_usec);
} else {
LOG_D(ENB_APP, "last_packet_was_tx\n");
we_are_too_late = timeval_subtract(&offset,&offset_last_tx_packet,&packet->time_relative_to_last_sent_packet);
LOG_D(ENB_APP, "we_are_too_late=%d, offset=%ld.%06d\n", we_are_too_late, offset.tv_sec, offset.tv_usec);
}
if ((0 == we_are_too_late) && (0 == g_max_speed)) {
// set timer
if ((offset.tv_sec <= 0) || (offset.tv_usec <= 0)) {
offset.tv_sec = -offset.tv_sec;
offset.tv_usec = -offset.tv_usec;
}
LOG_D(ENB_APP, "Send packet num %u original frame number %u in %ld.%06d sec\n",
packet->packet_number, packet->original_frame_number, offset.tv_sec, offset.tv_usec);
packet->status = ET_PACKET_STATUS_SCHEDULED_FOR_SENDING;
if (timer_setup (offset.tv_sec, offset.tv_usec, TASK_S1AP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,packet, &packet->timer_id) < 0) {
AssertFatal(0, " Can not start TX event timer\n");
}
g_scenario->timer_count++;
// Done g_fsm_state = ET_FSM_STATE_WAITING_TX_EVENT;
} else {
// send immediately
AssertFatal(0 == gettimeofday(&packet->timestamp_packet, NULL), "gettimeofday() Failed");
original_frame_number = packet->original_frame_number;
do {
g_scenario->time_last_tx_packet.tv_sec = packet->timestamp_packet.tv_sec;
g_scenario->time_last_tx_packet.tv_usec = packet->timestamp_packet.tv_usec;
LOG_D(ENB_APP, "Sending packet num %d original frame number %u immediately\n",packet->packet_number, packet->original_frame_number);
et_s1ap_eNB_itti_send_sctp_data_req(
packet->enb_instance,
packet->sctp_hdr.u.data_hdr.assoc_id,
packet->sctp_hdr.u.data_hdr.payload.binary_stream,
packet->sctp_hdr.u.data_hdr.payload.binary_stream_allocated_size,
packet->sctp_hdr.u.data_hdr.stream);
packet->status = ET_PACKET_STATUS_SENT;
g_scenario->next_packet = g_scenario->next_packet->next;
packet = packet->next;
} while ((NULL != packet) && (packet->original_frame_number == original_frame_number));
g_fsm_state = ET_FSM_STATE_RUNNING;
}
break;
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
AssertFatal(0, "Invalid case TX packet SCTP_CID_INIT or SCTP_CID_INIT_ACK");
break;
default:
AssertFatal(0, "Invalid case TX packet SCTP_CID %d", packet->sctp_hdr.chunk_type);
}
}
//------------------------------------------------------------------------------
et_fsm_state_t et_scenario_fsm_notify_event_state_running(et_event_t event)
{
switch (event.code) {
case ET_EVENT_TICK:
while (NULL != g_scenario->next_packet) {
LOG_D(ENB_APP, "EVENT_TICK: Considering packet num %d original frame number %u\n", g_scenario->next_packet->packet_number, g_scenario->next_packet->original_frame_number);
switch (g_scenario->next_packet->sctp_hdr.chunk_type) {
case SCTP_CID_DATA :
// no init in this scenario, may be sub-scenario
if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_SEND) {
if (g_scenario->next_packet->status == ET_PACKET_STATUS_NONE) {
et_scenario_schedule_tx_packet(g_scenario->next_packet);
pthread_mutex_unlock(&g_fsm_lock);
et_event_t continue_event;
continue_event.code = ET_EVENT_TICK;
et_scenario_fsm_notify_event(continue_event);
return g_fsm_state;
} else if (g_scenario->next_packet->status != ET_PACKET_STATUS_SCHEDULED_FOR_SENDING) {
AssertFatal(0, "Invalid packet status %d", g_scenario->next_packet->status);
}
} else if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
if (g_scenario->next_packet->status == ET_PACKET_STATUS_RECEIVED) {
g_scenario->next_packet = g_scenario->next_packet->next;
} else if (g_scenario->next_packet->status == ET_PACKET_STATUS_NONE) {
et_scenario_wait_rx_packet(g_scenario->next_packet);
pthread_mutex_unlock(&g_fsm_lock);
return g_fsm_state;
} else {
AssertFatal(0, "Invalid packet status %d", g_scenario->next_packet->status);
}
} else {
AssertFatal(0, "Invalid packet action %d", g_scenario->next_packet->action);
}
break;
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
case SCTP_CID_HEARTBEAT:
case SCTP_CID_HEARTBEAT_ACK:
case SCTP_CID_COOKIE_ECHO:
case SCTP_CID_COOKIE_ACK:
case SCTP_CID_ECN_ECNE:
case SCTP_CID_ECN_CWR:
LOG_D(ENB_APP, "EVENT_TICK: Ignoring packet num %d SCTP CID %s\n",
g_scenario->next_packet->packet_number,
et_chunk_type_cid2str(g_scenario->next_packet->sctp_hdr.chunk_type));
g_scenario->next_packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
g_scenario->next_packet = g_scenario->next_packet->next;
break;
case SCTP_CID_ABORT:
case SCTP_CID_SHUTDOWN:
case SCTP_CID_SHUTDOWN_ACK:
case SCTP_CID_ERROR:
case SCTP_CID_SHUTDOWN_COMPLETE:
AssertFatal(0, "The scenario should be cleaned (packet %s cannot be processed at this time)",
et_chunk_type_cid2str(g_scenario->next_packet->sctp_hdr.chunk_type));
break;
default:
LOG_D(ENB_APP, "EVENT_TICK: Ignoring packet num %d SCTP CID %s\n",
g_scenario->next_packet->packet_number,
et_chunk_type_cid2str(g_scenario->next_packet->sctp_hdr.chunk_type));
g_scenario->next_packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
g_scenario->next_packet = g_scenario->next_packet->next;
}
}
fprintf(stderr, "No Packet found in this scenario: %s\n", g_scenario->name);
g_fsm_state = ET_FSM_STATE_NULL;
pthread_mutex_unlock(&g_fsm_lock);
if (0 == g_scenario->timer_count) {
fprintf(stderr, "End of scenario: %s\n", g_scenario->name);
fflush(stderr);
fflush(stdout);
return 0;
//exit(0);
}
fprintf(stderr, "Remaining timers running: %d\n", g_scenario->timer_count);
return g_fsm_state;
break;
case ET_EVENT_RX_PACKET_TIME_OUT:
AssertFatal(0, "Event ET_EVENT_RX_PACKET_TIME_OUT not handled in FSM state ET_FSM_STATE_RUNNING");
break;
case ET_EVENT_TX_TIMED_PACKET:
AssertFatal(0, "Event ET_EVENT_TX_TIMED_PACKET not handled in FSM state ET_FSM_STATE_RUNNING");
break;
case ET_EVENT_RX_S1AP:
et_s1ap_process_rx_packet(&event.u.s1ap_data_ind);
break;
default:
AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_RUNNING", event.code);
}
pthread_mutex_unlock(&g_fsm_lock);
return 0;
}
//------------------------------------------------------------------------------
et_fsm_state_t et_scenario_fsm_notify_event_state_waiting_tx(et_event_t event)
{
int rv = 0;
int original_frame_number = -1;
et_packet_t *packet = NULL;
switch (event.code) {
case ET_EVENT_TICK:
fprintf(stdout, "EVENT_TICK: waiting for tx event\n");
break;
case ET_EVENT_RX_S1AP:
rv = et_s1ap_process_rx_packet(&event.u.s1ap_data_ind);
break;
case ET_EVENT_TX_TIMED_PACKET:
// send immediately
packet = event.u.tx_timed_packet;
AssertFatal(0 == gettimeofday(&packet->timestamp_packet, NULL), "gettimeofday() Failed");
original_frame_number = packet->original_frame_number;
do {
g_scenario->time_last_tx_packet.tv_sec = packet->timestamp_packet.tv_sec;
g_scenario->time_last_tx_packet.tv_usec = packet->timestamp_packet.tv_usec;
LOG_D(ENB_APP, "Sending packet num %d original frame number %u immediately\n",packet->packet_number, packet->original_frame_number);
et_s1ap_eNB_itti_send_sctp_data_req(
packet->enb_instance,
packet->sctp_hdr.u.data_hdr.assoc_id,
packet->sctp_hdr.u.data_hdr.payload.binary_stream,
packet->sctp_hdr.u.data_hdr.payload.binary_stream_allocated_size,
packet->sctp_hdr.u.data_hdr.stream);
packet->status = ET_PACKET_STATUS_SENT;
packet = packet->next;
g_scenario->next_packet = packet;
} while ( (NULL != packet) && (packet->original_frame_number == original_frame_number));
g_fsm_state = ET_FSM_STATE_RUNNING;
break;
case ET_EVENT_RX_PACKET_TIME_OUT:
default:
AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_WAITING_TX", event.code);
}
pthread_mutex_unlock(&g_fsm_lock);
return 0;
}
//------------------------------------------------------------------------------
et_fsm_state_t et_scenario_fsm_notify_event_state_waiting_rx(et_event_t event)
{
int rv = 0;
switch (event.code) {
case ET_EVENT_TICK:
fprintf(stdout, "EVENT_TICK: waiting for rx event\n");
break;
case ET_EVENT_RX_PACKET_TIME_OUT:
fprintf(stderr, "Error The following packet is not received:\n");
//et_display_packet(event.u.rx_packet_time_out);
AssertFatal(0, "Waited packet not received");
break;
case ET_EVENT_RX_S1AP:
rv = et_s1ap_process_rx_packet(&event.u.s1ap_data_ind);
// waited packet
if (rv == 0) {
g_fsm_state = ET_FSM_STATE_RUNNING;
}
break;
case ET_EVENT_TX_TIMED_PACKET:
default:
AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_WAITING_RX", event.code);
}
pthread_mutex_unlock(&g_fsm_lock);
return 0;
}
//------------------------------------------------------------------------------
et_fsm_state_t et_scenario_fsm_notify_event_state_connecting_s1c(et_event_t event)
{
switch (event.code) {
case ET_EVENT_TICK:
break;
case ET_EVENT_S1C_CONNECTED:
// hack simulate we have been able to get the right timing values for STCP connect
AssertFatal(gettimeofday(&g_scenario->time_last_rx_packet, NULL) == 0, "gettimeofday failed");
while (NULL != g_scenario->next_packet) {
switch (g_scenario->next_packet->sctp_hdr.chunk_type) {
case SCTP_CID_DATA :
// no init in this scenario, may be sub-scenario
if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_SEND) {
et_scenario_schedule_tx_packet(g_scenario->next_packet);
pthread_mutex_unlock(&g_fsm_lock);
et_event_t continue_event;
continue_event.code = ET_EVENT_TICK;
et_scenario_fsm_notify_event(continue_event);
return g_fsm_state;
} else if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
if (g_scenario->next_packet->status == ET_PACKET_STATUS_RECEIVED) {
g_scenario->last_rx_packet = g_scenario->next_packet;
g_scenario->time_last_rx_packet = g_scenario->last_rx_packet->timestamp_packet;
g_scenario->next_packet = g_scenario->next_packet->next;
} else if (g_scenario->next_packet->status == ET_PACKET_STATUS_NONE) {
et_scenario_wait_rx_packet(g_scenario->next_packet);
pthread_mutex_unlock(&g_fsm_lock);
return g_fsm_state;
} else {
AssertFatal(0, "Invalid packet status %d", g_scenario->next_packet->status);
}
} else {
AssertFatal(0, "Invalid packet action %d", g_scenario->next_packet->action);
}
break;
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
case SCTP_CID_HEARTBEAT:
case SCTP_CID_HEARTBEAT_ACK:
case SCTP_CID_COOKIE_ECHO:
case SCTP_CID_COOKIE_ACK:
case SCTP_CID_ECN_ECNE:
case SCTP_CID_ECN_CWR:
g_scenario->next_packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
g_scenario->next_packet = g_scenario->next_packet->next;
break;
case SCTP_CID_ABORT:
case SCTP_CID_SHUTDOWN:
case SCTP_CID_SHUTDOWN_ACK:
case SCTP_CID_ERROR:
case SCTP_CID_SHUTDOWN_COMPLETE:
AssertFatal(0, "The scenario should be cleaned (packet %s cannot be processed at this time)",
et_chunk_type_cid2str(g_scenario->next_packet->sctp_hdr.chunk_type));
break;
default:
g_scenario->next_packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
g_scenario->next_packet = g_scenario->next_packet->next;
}
}
fprintf(stderr, "No Packet found in this scenario: %s\n", g_scenario->name);
g_fsm_state = ET_FSM_STATE_NULL;
pthread_mutex_unlock(&g_fsm_lock);
if (0 == g_scenario->timer_count) {
fprintf(stderr, "End of scenario: %s\n", g_scenario->name);
fflush(stderr);
fflush(stdout);
exit(0);
}
fprintf(stderr, "Remaining timers running: %d\n", g_scenario->timer_count);
return g_fsm_state;
break;
default:
AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_CONNECTING_S1C", event.code);
}
pthread_mutex_unlock(&g_fsm_lock);
return 0;
}
//------------------------------------------------------------------------------
et_fsm_state_t et_scenario_fsm_notify_event_state_null(et_event_t event)
{
switch (event.code) {
case ET_EVENT_TICK:
break;
case ET_EVENT_INIT:
AssertFatal(NULL == g_scenario, "Current scenario not ended");
g_scenario = event.u.init.scenario;
g_scenario->next_packet = g_scenario->list_packet;
g_scenario->last_rx_packet = NULL;
g_scenario->last_tx_packet = NULL;
while (NULL != g_scenario->next_packet) {
switch (g_scenario->next_packet->sctp_hdr.chunk_type) {
case SCTP_CID_DATA :
// no init in this scenario, may be sub-scenario, ...
if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_SEND) {
et_scenario_schedule_tx_packet(g_scenario->next_packet);
pthread_mutex_unlock(&g_fsm_lock);
et_event_t continue_event;
continue_event.code = ET_EVENT_TICK;
et_scenario_fsm_notify_event(continue_event);
return g_fsm_state;
} else if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
if (g_scenario->next_packet->status == ET_PACKET_STATUS_RECEIVED) {
g_scenario->last_rx_packet = g_scenario->next_packet;
g_scenario->time_last_rx_packet = g_scenario->last_rx_packet->timestamp_packet;
g_scenario->next_packet = g_scenario->next_packet->next;
} else if (g_scenario->next_packet->status == ET_PACKET_STATUS_NONE) {
et_scenario_wait_rx_packet(g_scenario->next_packet);
pthread_mutex_unlock(&g_fsm_lock);
return g_fsm_state;
} else {
AssertFatal(0, "Invalid packet status %d", g_scenario->next_packet->status);
}
} else {
AssertFatal(0, "Invalid packet action %d", g_scenario->next_packet->action);
}
break;
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
g_scenario->enb_properties = (Enb_properties_array_t *)et_enb_config_get();
g_scenario->hash_old_ue_mme_id2ue_mme_id = hashtable_create (256,NULL,NULL);
g_scenario->hash_mme2association_id = hashtable_create (256,NULL,NULL);
// Try to register each eNB
g_scenario->registered_enb = 0;
g_fsm_state = ET_FSM_STATE_CONNECTING_S1C;
AssertFatal(gettimeofday(&g_scenario->time_last_tx_packet, NULL) == 0, "gettimeofday failed");
et_eNB_app_register (g_scenario->enb_properties);
pthread_mutex_unlock(&g_fsm_lock);
return g_fsm_state;
break;
case SCTP_CID_HEARTBEAT:
case SCTP_CID_HEARTBEAT_ACK:
case SCTP_CID_COOKIE_ECHO:
case SCTP_CID_COOKIE_ACK:
case SCTP_CID_ECN_ECNE:
case SCTP_CID_ECN_CWR:
g_scenario->next_packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
g_scenario->next_packet = g_scenario->next_packet->next;
break;
case SCTP_CID_ABORT:
case SCTP_CID_SHUTDOWN:
case SCTP_CID_SHUTDOWN_ACK:
case SCTP_CID_ERROR:
case SCTP_CID_SHUTDOWN_COMPLETE:
AssertFatal(0, "The scenario should be cleaned (packet %s cannot be processed at this time)",
et_chunk_type_cid2str(g_scenario->next_packet->sctp_hdr.chunk_type));
break;
default:
g_scenario->next_packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
g_scenario->next_packet = g_scenario->next_packet->next;
}
}
fprintf(stderr, "No Useful packet found in this scenario: %s\n", g_scenario->name);
g_fsm_state = ET_FSM_STATE_NULL;
pthread_mutex_unlock(&g_fsm_lock);
return g_fsm_state;
break;
default:
AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_NULL", event.code);
}
return 0;
}
//------------------------------------------------------------------------------
et_fsm_state_t et_scenario_fsm_notify_event(et_event_t event)
{
AssertFatal((event.code >= ET_EVENT_START) && (event.code < ET_EVENT_END), "Unknown et_event_t.code %d", event.code);
pthread_mutex_lock(&g_fsm_lock);
switch (g_fsm_state) {
case ET_FSM_STATE_NULL: return et_scenario_fsm_notify_event_state_null(event); break;
case ET_FSM_STATE_CONNECTING_S1C: return et_scenario_fsm_notify_event_state_connecting_s1c(event); break;
case ET_FSM_STATE_WAITING_TX_EVENT: return et_scenario_fsm_notify_event_state_waiting_tx(event); break;
case ET_FSM_STATE_WAITING_RX_EVENT: return et_scenario_fsm_notify_event_state_waiting_rx(event); break;
case ET_FSM_STATE_RUNNING: return et_scenario_fsm_notify_event_state_running(event); break;
default:
AssertFatal(0, "Case fsm_state %d not handled", g_fsm_state);
}
pthread_mutex_unlock(&g_fsm_lock);
return g_fsm_state;
}
/*
* 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
*/
/*
play_scenario_parse.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <libxml/xmlmemory.h>
#include <libxml/debugXML.h>
#include <libxml/xmlIO.h>
#include <libxml/DOCBparser.h>
#include <libxml/xinclude.h>
#include <libxml/catalog.h>
#include <libxml/xmlreader.h>
#include <libxslt/xslt.h>
#include <libxslt/xsltInternals.h>
#include <libxslt/transform.h>
#include <libxslt/xsltutils.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "intertask_interface.h"
#include "platform_types.h"
#include "assertions.h"
#include "play_scenario.h"
//------------------------------------------------------------------------------
#define ENB_CONFIG_MAX_XSLT_PARAMS 32
//------------------------------------------------------------------------------
extern Enb_properties_array_t g_enb_properties;
//------------------------------------------------------------------------------
void et_parse_s1ap(xmlDocPtr doc, const xmlNode const *s1ap_node, et_s1ap_t * const s1ap)
{
xmlNodePtr cur_node = NULL;
xmlChar *xml_char = NULL;
xmlChar *xml_char2 = NULL;
unsigned int size = 0;
int rc = 0;
unsigned int go_deeper_in_tree = 1;
if ((NULL != s1ap_node) && (NULL != s1ap)) {
// see http://www.xmlsoft.org/html/libxml-tree.html#xmlCopyNode
if (NULL == s1ap->doc) {
xmlUnlinkNode(s1ap_node);
//cur_node = xmlCopyNodeList(s1ap_node);
// arg2: if 1 do a recursive copy (properties, namespaces and children when applicable) if 2 copy properties and namespaces (when applicable)
//cur_node = xmlCopyNode(s1ap_node, 1);
//AssertFatal(NULL != cur_node, "xmlCopyNode Failed");
s1ap->doc = xmlNewDoc(BAD_CAST "1.0");
xmlDocSetRootElement(s1ap->doc, s1ap_node);
}
for (cur_node = (xmlNode *)s1ap_node; cur_node; cur_node = cur_node->next) {
go_deeper_in_tree = 1;
if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"field"))) {
// do not get hidden fields
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"hide");
if (NULL != xml_char) {
if ((!xmlStrcmp(xml_char, (const xmlChar *)"yes"))) {
go_deeper_in_tree = 0;
}
xmlFree(xml_char);
}
if (0 < go_deeper_in_tree) {
// first get size
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"size");
if (NULL != xml_char) {
size = strtoul((const char *)xml_char, NULL, 0);
xmlFree(xml_char);
// second: try to get value (always hex)
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"value");
if (NULL != xml_char) {
xml_char2 = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"name");
fprintf(stdout, "s1ap %p field name %s size %u value %s\n",s1ap, xml_char2, size, xml_char);
xmlFree(xml_char2);
// if success to get value, do not parse children
//AssertFatal ((xmlStrlen(xml_char) == size), "ERROR %s() mismatch in size %d and strlen %d\n", __FUNCTION__, size, xmlStrlen(xml_char));
//if (xmlStrlen(xml_char) == size) {
AssertFatal ((s1ap->binary_stream_pos+xmlStrlen(xml_char)/2) <= s1ap->binary_stream_allocated_size,
"ERROR in buffer size: binary_stream_pos %d xmlStrlen(xml_char)/2=%d\n", s1ap->binary_stream_pos, xmlStrlen(xml_char)/2);
rc = et_hex2data( &s1ap->binary_stream[s1ap->binary_stream_pos], xml_char, xmlStrlen(xml_char));
s1ap->binary_stream_pos += xmlStrlen(xml_char)/2;
//et_display_node(cur_node, 0);
AssertFatal (rc >= 0, "ERROR in converting hex string %s len %d size %u rc %d\n", xml_char, xmlStrlen(xml_char), size, rc);
go_deeper_in_tree = 0;
//}
xmlFree(xml_char);
}
}
}
}
if (0 < go_deeper_in_tree) {
et_parse_s1ap(doc, cur_node->children, s1ap);
}
}
}
}
//------------------------------------------------------------------------------
void et_parse_sctp_data_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_datahdr_t * const sctp_hdr)
{
xmlNode *cur_node = NULL;
xmlChar *xml_char = NULL;
xmlChar *xml_char2 = NULL;
if ((NULL != sctp_node) && (NULL != sctp_hdr)) {
xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name");
if (NULL != xml_char) {
if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.data_payload_proto_id"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show");
if (NULL != xml_char2) {
sctp_hdr->ppid = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.data_sid"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show");
if (NULL != xml_char2) {
sctp_hdr->stream = strtoul((const char *)xml_char2, NULL, 16);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.data_tsn"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show");
if (NULL != xml_char2) {
sctp_hdr->tsn = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.data_ssn"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show");
if (NULL != xml_char2) {
sctp_hdr->ssn = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
}
xmlFree(xml_char);
}
for (cur_node = sctp_node->children; cur_node; cur_node = cur_node->next) {
et_parse_sctp_data_chunk(doc, cur_node, sctp_hdr);
}
}
}
//------------------------------------------------------------------------------
void et_parse_sctp_init_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_inithdr_t * const sctp_hdr)
{
xmlNode *cur_node = NULL;
xmlChar *xml_char = NULL;
xmlChar *xml_char2 = NULL;
if ((NULL != sctp_node) && (NULL != sctp_hdr)) {
xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name");
if (NULL != xml_char) {
if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_nr_out_streams"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->num_outbound_streams = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_nr_in_streams"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->num_inbound_streams = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_credit"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->a_rwnd = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_initial_tsn"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show");
if (NULL != xml_char2) {
sctp_hdr->initial_tsn = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.init_initiate_tag"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show");
if (NULL != xml_char2) {
sctp_hdr->init_tag = strtoul((const char *)xml_char2, NULL, 16);
xmlFree(xml_char2);
}
}
xmlFree(xml_char);
}
for (cur_node = sctp_node->children; cur_node; cur_node = cur_node->next) {
et_parse_sctp_init_chunk(doc, cur_node, sctp_hdr);
}
}
}
//------------------------------------------------------------------------------
void et_parse_sctp_init_ack_chunk(xmlDocPtr doc, const xmlNode const *sctp_node, sctp_initackhdr_t * const sctp_hdr)
{
xmlNode *cur_node = NULL;
xmlChar *xml_char = NULL;
xmlChar *xml_char2 = NULL;
if ((NULL != sctp_node) && (NULL != sctp_hdr)) {
xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name");
if (NULL != xml_char) {
if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_nr_out_streams"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->num_outbound_streams = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_nr_in_streams"))) {
xml_char2 = xmlGetProp((xmlNode *)(xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->num_inbound_streams = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_credit"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->a_rwnd = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_initial_tsn"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show");
if (NULL != xml_char2) {
sctp_hdr->initial_tsn = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.initack_initiate_tag"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"show");
if (NULL != xml_char2) {
sctp_hdr->init_tag = strtoul((const char *)xml_char2, NULL, 16);
xmlFree(xml_char2);
}
}
xmlFree(xml_char);
}
for (cur_node = sctp_node->children; cur_node; cur_node = cur_node->next) {
et_parse_sctp_init_ack_chunk(doc, cur_node, sctp_hdr);
}
}
}
//------------------------------------------------------------------------------
void et_parse_sctp(xmlDocPtr doc, const xmlNode const *sctp_node, et_sctp_hdr_t * const sctp_hdr)
{
xmlNode *cur_node = NULL;
xmlChar *xml_char = NULL;
xmlChar *xml_char2 = NULL;
if ((NULL != sctp_node) && (NULL != sctp_hdr)) {
if ((!xmlStrcmp(sctp_node->name, (const xmlChar *)"proto"))) {
xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name");
if (NULL != xml_char) {
if ((!xmlStrcmp(xml_char, (const xmlChar *)"s1ap"))) {
xmlFree(xml_char);
xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"pos");
if (NULL != xml_char) {
sctp_hdr->u.data_hdr.payload.xml_stream_pos_offset = strtoul((const char *)xml_char, NULL, 0);
xmlFree(xml_char);
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"size");
if (NULL != xml_char2) {
sctp_hdr->u.data_hdr.payload.binary_stream_allocated_size = strtoul((const char *)xml_char2, NULL, 0);
sctp_hdr->u.data_hdr.payload.binary_stream = calloc(1, sctp_hdr->u.data_hdr.payload.binary_stream_allocated_size);
sctp_hdr->u.data_hdr.payload.binary_stream_pos = 0;
fprintf(stdout, "Allocating payload of sctp_hdr %p %u bytes\n", sctp_hdr, sctp_hdr->u.data_hdr.payload.binary_stream_allocated_size);
xmlFree(xml_char2);
}
et_parse_s1ap(doc, sctp_node, &sctp_hdr->u.data_hdr.payload);
et_decode_s1ap(&sctp_hdr->u.data_hdr.payload);
return;
}
}
xmlFree(xml_char);
}
}
//if ((cur_node->type == XML_ATTRIBUTE_NODE) || (cur_node->type == XML_ELEMENT_NODE)) {
xml_char = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"name");
if (NULL != xml_char) {
if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.srcport"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->src_port = strtoul((const char *)xml_char2, NULL, 16);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.dstport"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->dst_port = strtoul((const char *)xml_char2, NULL, 16);
xmlFree(xml_char2);
}
} else if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp.chunk_type"))) {
xml_char2 = xmlGetProp((xmlNode *)sctp_node, (const xmlChar *)"value");
if (NULL != xml_char2) {
sctp_hdr->chunk_type = strtoul((const char *)xml_char2, NULL, 0);
xmlFree(xml_char2);
switch (sctp_hdr->chunk_type) {
case SCTP_CID_DATA:
et_parse_sctp_data_chunk(doc, sctp_node->parent, &sctp_hdr->u.data_hdr);
break;
case SCTP_CID_INIT:
et_parse_sctp_init_chunk(doc, sctp_node->parent, &sctp_hdr->u.init_hdr);
break;
case SCTP_CID_INIT_ACK:
et_parse_sctp_init_ack_chunk(doc, sctp_node->parent, &sctp_hdr->u.init_ack_hdr);
break;
default:
;
}
}
}
}
for (cur_node = sctp_node->children; cur_node; cur_node = cur_node->next) {
et_parse_sctp(doc, cur_node, sctp_hdr);
}
}
}
//------------------------------------------------------------------------------
void et_packet_shift_timing(et_packet_t * const packet, const struct timeval * const shift)
{
timeval_add(&packet->time_relative_to_first_packet, &packet->time_relative_to_first_packet, shift);
AssertFatal((packet->time_relative_to_first_packet.tv_sec >= 0) && (packet->time_relative_to_first_packet.tv_usec >= 0),
"Bad timing result time_relative_to_first_packet=%d.%d packet num %u, original frame number %u",
packet->time_relative_to_first_packet.tv_sec,
packet->time_relative_to_first_packet.tv_usec,
packet->packet_number,
packet->original_frame_number);
timeval_add(&packet->time_relative_to_last_received_packet, &packet->time_relative_to_last_received_packet, shift);
AssertFatal((packet->time_relative_to_last_received_packet.tv_sec >= 0) && (packet->time_relative_to_last_received_packet.tv_usec >= 0),
"Bad timing result time_relative_to_last_received_packet=%d.%d packet num %u, original frame number %u",
packet->time_relative_to_last_received_packet.tv_sec,
packet->time_relative_to_last_received_packet.tv_usec,
packet->packet_number,
packet->original_frame_number);
timeval_add(&packet->time_relative_to_last_sent_packet, &packet->time_relative_to_last_sent_packet, shift);
AssertFatal((packet->time_relative_to_last_sent_packet.tv_sec >= 0) && (packet->time_relative_to_last_sent_packet.tv_usec >= 0),
"Bad timing result time_relative_to_last_sent_packet=%d.%d packet num %u, original frame number %u",
packet->time_relative_to_last_sent_packet.tv_sec,
packet->time_relative_to_last_sent_packet.tv_usec,
packet->packet_number,
packet->original_frame_number);
}
//------------------------------------------------------------------------------
et_packet_t* et_parse_xml_packet(xmlDocPtr doc, xmlNodePtr node)
{
et_packet_t *packet = NULL;
xmlNode *cur_node = NULL;
xmlChar *xml_char = NULL;
float afloat = (float)0.0;
static struct timeval initial_time = { .tv_sec = 0, .tv_usec = 0 };
static struct timeval relative_last_sent_packet = { .tv_sec = 0, .tv_usec = 0 };
static struct timeval relative_last_received_packet = { .tv_sec = 0, .tv_usec = 0 };
static char first_packet = 1;
static char first_sent_packet = 1;
static char first_received_packet = 1;
static unsigned int packet_number = 1;
if (NULL != node) {
packet = calloc(1, sizeof(*packet));
xml_char = xmlGetProp(node, (const xmlChar *)"action");
packet->action = et_action_str2et_action_t(xml_char);
packet->status = ET_PACKET_STATUS_NONE;
xmlFree(xml_char);
packet->packet_number = packet_number++;
for (cur_node = node->children; cur_node; cur_node = cur_node->next) {
//if (cur_node->type == XML_ELEMENT_NODE) {
if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"frame.time_relative"))) {
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"value");
afloat = atof((const char*)xml_char);
xmlFree(xml_char);
fprintf(stdout, "Parsing packet frame.time_relative: %f\n", afloat);
packet->time_relative_to_first_packet.tv_sec = (int)afloat;
packet->time_relative_to_first_packet.tv_usec = (int)((afloat - packet->time_relative_to_first_packet.tv_sec)*1000000.0);
if (first_packet > 0) {
initial_time = packet->time_relative_to_first_packet;
packet->time_relative_to_first_packet.tv_sec = 0;
packet->time_relative_to_first_packet.tv_usec = 0;
first_packet = 0;
} else {
timersub(&packet->time_relative_to_first_packet, &initial_time,
&packet->time_relative_to_first_packet);
}
} else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"frame.number"))) {
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"value");
packet->original_frame_number = strtoul((const char *)xml_char, NULL, 0);
fprintf(stdout, "Parsing packet frame.number: %u\n", packet->original_frame_number);
xmlFree(xml_char);
} else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"ip.src"))) {
xml_char = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
et_ip_str2et_ip(xml_char, &packet->ip_hdr.src);
xmlFree(xml_char);
} else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"ip.dst"))) {
xml_char = xmlNodeListGetString(doc, cur_node->xmlChildrenNode, 1);
et_ip_str2et_ip(xml_char, &packet->ip_hdr.dst);
xmlFree(xml_char);
} else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"proto"))) {
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"name");
if (NULL != xml_char) {
if ((!xmlStrcmp(xml_char, (const xmlChar *)"sctp"))) {
et_parse_sctp(doc, cur_node, &packet->sctp_hdr);
}
xmlFree(xml_char);
}
} else if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"eNB.instance"))) {
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"value");
packet->enb_instance = strtoul((const char *)xml_char, NULL, 0);
xmlFree(xml_char);
}
//}
}
}
return packet;
}
//------------------------------------------------------------------------------
et_scenario_t* et_generate_scenario(
const char * const tsml_out_scenario_filename)
{
xmlDocPtr doc = NULL;
xmlNodePtr root = NULL;
xmlNodePtr node = NULL;
xmlChar *xml_char = NULL;
et_scenario_t *scenario = NULL;
et_packet_t *last_packet = NULL;
et_packet_t *packet = NULL;
et_packet_t **next_packet = NULL;
doc = xmlParseFile(tsml_out_scenario_filename);
if (NULL == doc) {
AssertFatal (0, "Could not parse scenario xml file %s!\n", tsml_out_scenario_filename);
} else {
fprintf(stdout, "Test scenario file to play: %s\n", tsml_out_scenario_filename);
//xmlDebugDumpDocument(NULL, doc);
}
// Get root
root = xmlDocGetRootElement(doc);
if (NULL != root) {
if ((!xmlStrcmp(root->name, (const xmlChar *)"scenario"))) {
xml_char = xmlGetProp(root, (const xmlChar *)"name");
printf("scenario name: %s\n", xml_char);
scenario = calloc(1, sizeof(*scenario));
scenario->name = xml_char; // nodup nofree
next_packet = &scenario->list_packet;
for (node = root->children; node != NULL; node = node->next) {
if ((!xmlStrcmp(node->name, (const xmlChar *)"packet"))) {
packet = et_parse_xml_packet(doc, node);
if (NULL != packet) {
// special case: S1AP same frame for 2 packets
if (NULL != last_packet) {
if (last_packet->original_frame_number == packet->original_frame_number) {
// updating because these informations are not in 2nd sctp header (same IP packet)
packet->sctp_hdr.dst_port = last_packet->sctp_hdr.dst_port;
packet->sctp_hdr.src_port = last_packet->sctp_hdr.src_port;
}
}
*next_packet = packet;
next_packet = &packet->next;
} else {
fprintf(stdout, "WARNING omitted packet\n");
}
}
last_packet = packet;
}
}
} else {
fprintf(stderr, "Empty xml document\n");
}
xmlFreeDoc(doc);
xmlCleanupParser();
return scenario;
}
//------------------------------------------------------------------------------
int et_generate_xml_scenario(
const char const * xml_in_dir_name,
const char const * xml_in_scenario_filename,
const char const * enb_config_filename,
char const * tsml_out_scenario_filename)
//------------------------------------------------------------------------------
{
//int fd_pdml_in;
xsltStylesheetPtr cur = NULL;
xmlDocPtr doc, res;
FILE *play_scenario_file = NULL;
const char *params[2*ENB_CONFIG_MAX_XSLT_PARAMS];
int nb_params = 0;
int i,j;
char astring[1024];
struct in_addr addr;
int ret = 0;
memset(astring, 0, sizeof(astring));
if (getcwd(astring, sizeof(astring)) != NULL) {
fprintf(stdout, "working in %s directory\n", astring);
} else {
perror("getcwd() ERROR");
exit(1);
}
xmlSubstituteEntitiesDefault(1);
xmlLoadExtDtdDefaultValue = 1;
cur = xsltParseStylesheetFile((const xmlChar *)"/usr/share/oai/xsl/play_scenario.xsl");
if (NULL == cur) {
AssertFatal (0, "Could not parse stylesheet file /usr/share/oai/xsl/play_scenario.xsl!\n");
} else {
fprintf(stdout, "XSLT style sheet: /usr/share/oai/xsl/play_scenario.xsl\n");
}
doc = xmlParseFile(xml_in_scenario_filename);
if (NULL == doc) {
AssertFatal (0, "Could not parse scenario xml file %s!\n", xml_in_scenario_filename);
} else {
fprintf(stdout, "Test scenario file: %s\n", xml_in_scenario_filename);
}
for (i = 0; i < g_enb_properties.number; i++) {
// eNB S1-C IPv4 address
sprintf(astring, "enb%d_s1c", i);
params[nb_params++] = strdup(astring);
addr.s_addr = g_enb_properties.properties[i]->enb_ipv4_address_for_S1_MME;
sprintf(astring, "\"%s\"", inet_ntoa(addr));
params[nb_params++] = strdup(astring);
// MME S1-C IPv4 address
for (j = 0; j < g_enb_properties.properties[i]->nb_mme; j++) {
sprintf(astring, "mme%d_s1c_%d", i, j);
params[nb_params++] = strdup(astring);
AssertFatal (g_enb_properties.properties[i]->mme_ip_address[j].ipv4_address,
"Only support MME IPv4 address\n");
sprintf(astring, "\"%s\"", g_enb_properties.properties[i]->mme_ip_address[j].ipv4_address);
params[nb_params++] = strdup(astring);
}
}
params[nb_params] = NULL;
res = xsltApplyStylesheet(cur, doc, params);
if (NULL != res) {
sprintf((char *)tsml_out_scenario_filename,"%s",xml_in_scenario_filename);
if (et_strip_extension((char *)tsml_out_scenario_filename) > 0) {
strcat((char *)tsml_out_scenario_filename, ".tsml");
play_scenario_file = fopen( tsml_out_scenario_filename, "w+");
if (NULL != play_scenario_file) {
xsltSaveResultToFile(play_scenario_file, res, cur);
fclose(play_scenario_file);
fprintf(stdout, "Wrote test scenario to %s\n", tsml_out_scenario_filename);
} else {
fprintf(stderr, "ERROR in fopen(%s)\n", tsml_out_scenario_filename);
ret = -1;
}
} else {
fprintf(stderr, "ERROR in strip_extension()\n");
ret = -1;
}
} else {
fprintf(stderr, "ERROR in xsltApplyStylesheet()\n");
ret = -1;
}
xsltFreeStylesheet(cur);
xmlFreeDoc(doc);
xmlFreeDoc(res);
xsltCleanupGlobals();
xmlCleanupParser();
return ret;
}
/*
* 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
*/
/*
play_scenario_s1ap.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <crypt.h>
#include <sys/time.h>
#include "tree.h"
#include "queue.h"
#include "intertask_interface.h"
#include "platform_types.h"
#include "assertions.h"
#include "conversions.h"
#include "s1ap_common.h"
#include "play_scenario_s1ap_eNB_defs.h"
#include "play_scenario.h"
//------------------------------------------------------------------------------
s1ap_eNB_internal_data_t s1ap_eNB_internal_data;
RB_GENERATE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry, et_s1ap_eNB_compare_assoc_id);
//------------------------------------------------------------------------------
extern et_scenario_t *g_scenario;
extern uint32_t g_constraints;
//------------------------------------------------------------------------------
int et_s1ap_eNB_compare_assoc_id(
struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2)
{
if (p1->assoc_id == -1) {
if (p1->cnx_id < p2->cnx_id) {
return -1;
}
if (p1->cnx_id > p2->cnx_id) {
return 1;
}
} else {
if (p1->assoc_id < p2->assoc_id) {
return -1;
}
if (p1->assoc_id > p2->assoc_id) {
return 1;
}
}
/* Matching reference */
return 0;
}
//------------------------------------------------------------------------------
uint32_t et_s1ap_generate_eNB_id(void)
{
char *out;
char hostname[50];
int ret;
uint32_t eNB_id;
/* Retrieve the host name */
ret = gethostname(hostname, sizeof(hostname));
DevAssert(ret == 0);
out = crypt(hostname, "eurecom");
DevAssert(out != NULL);
eNB_id = ((out[0] << 24) | (out[1] << 16) | (out[2] << 8) | out[3]);
return eNB_id;
}
//------------------------------------------------------------------------------
uint16_t et_s1ap_eNB_fetch_add_global_cnx_id(void)
{
return ++s1ap_eNB_internal_data.global_cnx_id;
}
//------------------------------------------------------------------------------
void et_s1ap_eNB_prepare_internal_data(void)
{
memset(&s1ap_eNB_internal_data, 0, sizeof(s1ap_eNB_internal_data));
STAILQ_INIT(&s1ap_eNB_internal_data.s1ap_eNB_instances_head);
}
//------------------------------------------------------------------------------
void et_s1ap_eNB_insert_new_instance(s1ap_eNB_instance_t *new_instance_p)
{
DevAssert(new_instance_p != NULL);
STAILQ_INSERT_TAIL(&s1ap_eNB_internal_data.s1ap_eNB_instances_head,
new_instance_p, s1ap_eNB_entries);
}
//------------------------------------------------------------------------------
struct s1ap_eNB_mme_data_s *et_s1ap_eNB_get_MME(
s1ap_eNB_instance_t *instance_p,
int32_t assoc_id, uint16_t cnx_id)
{
struct s1ap_eNB_mme_data_s temp;
struct s1ap_eNB_mme_data_s *found;
memset(&temp, 0, sizeof(struct s1ap_eNB_mme_data_s));
temp.assoc_id = assoc_id;
temp.cnx_id = cnx_id;
if (instance_p == NULL) {
STAILQ_FOREACH(instance_p, &s1ap_eNB_internal_data.s1ap_eNB_instances_head,
s1ap_eNB_entries) {
found = RB_FIND(s1ap_mme_map, &instance_p->s1ap_mme_head, &temp);
if (found != NULL) {
return found;
}
}
} else {
return RB_FIND(s1ap_mme_map, &instance_p->s1ap_mme_head, &temp);
}
return NULL;
}
//------------------------------------------------------------------------------
s1ap_eNB_instance_t *et_s1ap_eNB_get_instance(instance_t instance)
{
s1ap_eNB_instance_t *temp = NULL;
STAILQ_FOREACH(temp, &s1ap_eNB_internal_data.s1ap_eNB_instances_head,
s1ap_eNB_entries) {
if (temp->instance == instance) {
/* Matching occurence */
return temp;
}
}
return NULL;
}
//------------------------------------------------------------------------------
void et_s1ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream)
{
MessageDef *message_p;
sctp_data_req_t *sctp_data_req;
message_p = itti_alloc_new_message(TASK_S1AP, SCTP_DATA_REQ);
sctp_data_req = &message_p->ittiMsg.sctp_data_req;
sctp_data_req->assoc_id = assoc_id;
sctp_data_req->buffer = buffer;
sctp_data_req->buffer_length = buffer_length;
sctp_data_req->stream = stream;
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
}
//------------------------------------------------------------------------------
int et_handle_s1ap_mismatch_mme_ue_s1ap_id(et_packet_t * const spacket, et_packet_t * const rx_packet)
{
S1AP_MME_UE_S1AP_ID_t scenario_mme_ue_s1ap_id = 0;
S1AP_MME_UE_S1AP_ID_t rx_mme_ue_s1ap_id = 0;
S1AP_PDU_PR present;
present = rx_packet->sctp_hdr.u.data_hdr.payload.pdu.present;
switch (rx_packet->sctp_hdr.u.data_hdr.payload.message.procedureCode) {
case S1AP_ProcedureCode_id_HandoverPreparation:
if (present == S1AP_S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequiredIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequiredIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverCommandIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverCommandIEs.mme_ue_s1ap_id;
}
break;
case S1AP_ProcedureCode_id_HandoverResourceAllocation:
if (present == S1AP_S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequestIEs.mme_ue_s1ap_id;
} else if (present == S1AP_S1AP_PDU_PR_successfulOutcome) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequestAcknowledgeIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverRequestAcknowledgeIEs.mme_ue_s1ap_id;
} else if (present == S1AP_S1AP_PDU_PR_unsuccessfulOutcome) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverFailureIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverFailureIEs.mme_ue_s1ap_id;
}
break;
case S1AP_ProcedureCode_id_HandoverNotification:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverNotifyIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverNotifyIEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_PathSwitchRequest:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_PathSwitchRequestIEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_PathSwitchRequestIEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_HandoverCancel:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverCancelIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_HandoverCancelIEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_E_RABSetup:
if (present == S1AP_S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABSetupRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABSetupRequestIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABSetupResponseIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABSetupResponseIEs.mme_ue_s1ap_id;
}
break;
case S1ap_ProcedureCode_id_E_RABModify:
if (present == S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABModifyRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABModifyRequestIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABModifyResponseIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABModifyResponseIEs.mme_ue_s1ap_id;
}
break;
case S1ap_ProcedureCode_id_E_RABRelease:
if (present == S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseCommandIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseCommandIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseResponseIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseResponseIEs.mme_ue_s1ap_id;
}
break;
case S1ap_ProcedureCode_id_E_RABReleaseIndication:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseIndicationIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_E_RABReleaseIndicationIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_InitialContextSetup:
if (present == S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialContextSetupRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialContextSetupRequestIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialContextSetupResponseIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialContextSetupResponseIEs.mme_ue_s1ap_id;
}
break;
case S1ap_ProcedureCode_id_Paging:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_PagingIEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_PagingIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_downlinkNASTransport:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkNASTransportIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkNASTransportIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_initialUEMessage:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialUEMessageIEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_InitialUEMessageIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_uplinkNASTransport:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkNASTransportIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkNASTransportIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_Reset:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ResetIEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ResetIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_ErrorIndication:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ErrorIndicationIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ErrorIndicationIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_NASNonDeliveryIndication:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_NASNonDeliveryIndication_IEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_NASNonDeliveryIndication_IEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_S1Setup:
/*if (present == S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupRequestIEs.mme_ue_s1ap_id;
} else if (present == S1AP_PDU_PR_successfulOutcome) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupResponseIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupResponseIEs.mme_ue_s1ap_id;
} else if (present == S1AP_PDU_PR_unsuccessfulOutcome) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupFailureIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_S1SetupFailureIEs.mme_ue_s1ap_id;
}*/
break;
case S1ap_ProcedureCode_id_UEContextReleaseRequest:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseRequestIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_DownlinkS1cdma2000tunneling:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkS1cdma2000tunnelingIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkS1cdma2000tunnelingIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_UplinkS1cdma2000tunneling:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkS1cdma2000tunnelingIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkS1cdma2000tunnelingIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_UEContextModification:
if (present == S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationRequestIEs.mme_ue_s1ap_id;
} else if (present == S1AP_PDU_PR_successfulOutcome) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationResponseIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationResponseIEs.mme_ue_s1ap_id;
} else if (present == S1AP_PDU_PR_unsuccessfulOutcome) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationFailureIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextModificationFailureIEs.mme_ue_s1ap_id;
}
break;
case S1ap_ProcedureCode_id_UECapabilityInfoIndication:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UECapabilityInfoIndicationIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UECapabilityInfoIndicationIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_UEContextRelease:
if (present == S1AP_PDU_PR_initiatingMessage) {
switch (rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCommandIEs.uE_S1AP_IDs.present) {
case S1ap_UE_S1AP_IDs_PR_uE_S1AP_ID_pair:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCommandIEs.uE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCommandIEs.uE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID;
break;
case S1ap_UE_S1AP_IDs_PR_mME_UE_S1AP_ID:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCommandIEs.uE_S1AP_IDs.choice.mME_UE_S1AP_ID;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCommandIEs.uE_S1AP_IDs.choice.mME_UE_S1AP_ID;
break;
}
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCompleteIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UEContextReleaseCompleteIEs.mme_ue_s1ap_id;
}
break;
case S1ap_ProcedureCode_id_eNBStatusTransfer:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBStatusTransferIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBStatusTransferIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_MMEStatusTransfer:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEStatusTransferIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEStatusTransferIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_DeactivateTrace:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DeactivateTraceIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DeactivateTraceIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_TraceStart:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_TraceStartIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_TraceStartIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_TraceFailureIndication:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_TraceFailureIndicationIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_TraceFailureIndicationIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_ENBConfigurationUpdate:
/*if (present == S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateIEs.mme_ue_s1ap_id;
} else if (present == S1AP_PDU_PR_successfulOutcome) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateAcknowledgeIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateAcknowledgeIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateFailureIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBConfigurationUpdateFailureIEs.mme_ue_s1ap_id;
}*/
break;
case S1ap_ProcedureCode_id_MMEConfigurationUpdate:
/*if (present == S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateIEs.mme_ue_s1ap_id;
} else if (present == S1AP_PDU_PR_successfulOutcome) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateAcknowledgeIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateAcknowledgeIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateFailureIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEConfigurationUpdateFailureIEs.mme_ue_s1ap_id;
}*/
break;
case S1ap_ProcedureCode_id_LocationReportingControl:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportingControlIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportingControlIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_LocationReportingFailureIndication:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportingFailureIndicationIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportingFailureIndicationIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_LocationReport:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_LocationReportIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_OverloadStart:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_OverloadStartIEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_OverloadStartIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_OverloadStop:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_OverloadStopIEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_OverloadStopIEs.mme_ue_s1ap_id;
break;
case S1ap_ProcedureCode_id_WriteReplaceWarning:
/*if (present == S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_WriteReplaceWarningRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_WriteReplaceWarningRequestIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_WriteReplaceWarningResponseIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_WriteReplaceWarningResponseIEs.mme_ue_s1ap_id;
}*/
break;
case S1AP_ProcedureCode_id_eNBDirectInformationTransfer:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBDirectInformationTransferIEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_ENBDirectInformationTransferIEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_MMEDirectInformationTransfer:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEDirectInformationTransferIEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_MMEDirectInformationTransferIEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_PrivateMessage:
case S1AP_ProcedureCode_id_eNBConfigurationTransfer:
case S1AP_ProcedureCode_id_MMEConfigurationTransfer:
AssertFatal(0, "TODO");
break;
case S1AP_ProcedureCode_id_CellTrafficTrace:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_CellTrafficTraceIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_CellTrafficTraceIEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_Kill:
/*if (present == S1AP_S1AP_PDU_PR_initiatingMessage) {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_KillRequestIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_KillRequestIEs.mme_ue_s1ap_id;
} else {
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_KillResponseIEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_KillResponseIEs.mme_ue_s1ap_id;
}*/
break;
case S1AP_ProcedureCode_id_downlinkUEAssociatedLPPaTransport:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_uplinkUEAssociatedLPPaTransport:
rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_downlinkNonUEAssociatedLPPaTransport:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkNonUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_DownlinkNonUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
break;
case S1AP_ProcedureCode_id_uplinkNonUEAssociatedLPPaTransport:
//rx_mme_ue_s1ap_id = rx_packet->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkNonUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
//scenario_mme_ue_s1ap_id = spacket->sctp_hdr.u.data_hdr.payload.message.msg.s1ap_UplinkNonUEAssociatedLPPaTransport_IEs.mme_ue_s1ap_id;
break;
default:
AssertFatal(0, "Unknown procedure code %ld", rx_packet->sctp_hdr.u.data_hdr.payload.message.procedureCode);
}
if (scenario_mme_ue_s1ap_id != rx_mme_ue_s1ap_id) {
S1AP_DEBUG("%s() Updating mme_ue_s1ap_id %u -> %u \n", __FUNCTION__, scenario_mme_ue_s1ap_id, rx_mme_ue_s1ap_id);
et_packet_t *p = spacket;
while (p) {
et_s1ap_update_mme_ue_s1ap_id(p, scenario_mme_ue_s1ap_id, rx_mme_ue_s1ap_id);
p = p->next;
}
return 0;
}
return 1;
}
//------------------------------------------------------------------------------
asn_comp_rval_t * et_s1ap_is_matching(et_s1ap_t * const s1ap1, et_s1ap_t * const s1ap2, const uint32_t constraints)
{
asn_comp_rval_t *rv = NULL;
if (s1ap1->pdu.present != s1ap2->pdu.present) {rv = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_PRESENT; return rv;}
switch (s1ap1->pdu.present) {
case S1AP_PDU_PR_NOTHING:
break;
case S1AP_PDU_PR_initiatingMessage:
if (s1ap1->pdu.choice.initiatingMessage.procedureCode != s1ap2->pdu.choice.initiatingMessage.procedureCode)
{rv = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE; return rv;}
if (s1ap1->pdu.choice.initiatingMessage.criticality != s1ap2->pdu.choice.initiatingMessage.criticality)
{rv = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY; return rv;}
break;
case S1AP_PDU_PR_successfulOutcome:
if (s1ap1->pdu.choice.successfulOutcome.procedureCode != s1ap2->pdu.choice.successfulOutcome.procedureCode)
{rv = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE; return rv;}
if (s1ap1->pdu.choice.successfulOutcome.criticality != s1ap2->pdu.choice.successfulOutcome.criticality)
{rv = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY; return rv;}
break;
case S1AP_PDU_PR_unsuccessfulOutcome:
if (s1ap1->pdu.choice.unsuccessfulOutcome.procedureCode != s1ap2->pdu.choice.unsuccessfulOutcome.procedureCode)
{rv = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_PROCEDURE_CODE; return rv;}
if (s1ap1->pdu.choice.unsuccessfulOutcome.criticality != s1ap2->pdu.choice.unsuccessfulOutcome.criticality)
{rv = calloc(1, sizeof(asn_comp_rval_t)); rv->err_code = ET_ERROR_MATCH_PACKET_S1AP_CRITICALITY; return rv;}
break;
default:
AssertFatal(0, "Unknown pdu.present %d", s1ap1->pdu.present);
}
if (s1ap1->binary_stream_allocated_size == s1ap2->binary_stream_allocated_size) {
if (memcmp((void*)s1ap1->binary_stream, (void*)s1ap2->binary_stream, s1ap1->binary_stream_allocated_size) == 0) return NULL;
}
// if no matching, may be the scenario need minor corrections (same enb_ue_s1ap_id but need to update mme_ue_s1ap_id)
return et_s1ap_ies_is_matching(s1ap1->pdu.present, &s1ap1->message, &s1ap2->message, constraints);
}
//------------------------------------------------------------------------------
et_packet_t* et_build_packet_from_s1ap_data_ind(et_event_s1ap_data_ind_t * const s1ap_data_ind)
{
et_packet_t * packet = NULL;
AssertFatal (NULL != s1ap_data_ind, "Bad parameter sctp_data_ind\n");
packet = calloc(1, sizeof(*packet));
packet->action = ET_PACKET_ACTION_S1C_NULL;
//packet->time_relative_to_first_packet.tv_sec = 0;
//packet->time_relative_to_first_packet.tv_usec = 0;
//packet->time_relative_to_last_sent_packet.tv_sec = 0;
//packet->time_relative_to_last_sent_packet.tv_usec = 0;
//packet->time_relative_to_last_received_packet.tv_sec = 0;
//packet->time_relative_to_last_received_packet.tv_usec = 0;
//packet->original_frame_number = 0;
//packet->packet_number = 0;
packet->enb_instance = 0; //TODO
//packet->ip_hdr;
// keep in mind: allocated buffer: sctp_datahdr.payload.binary_stream
packet->sctp_hdr.chunk_type = SCTP_CID_DATA;
memcpy((void*)&packet->sctp_hdr.u.data_hdr, (void*)&s1ap_data_ind->sctp_datahdr, sizeof(packet->sctp_hdr));
//packet->next = NULL;
packet->status = ET_PACKET_STATUS_RECEIVED;
//packet->timer_id = 0;
AssertFatal(0 == gettimeofday(&packet->timestamp_packet, NULL), "gettimeofday() Failed");
return packet;
}
//------------------------------------------------------------------------------
// return 0 if packet was waited
int et_scenario_set_packet_received(et_packet_t * const packet)
{
et_packet_t * p = NULL;
int rc = 0;
packet->status = ET_PACKET_STATUS_RECEIVED;
S1AP_DEBUG("Packet received: num %u | original frame number %u \n", packet->packet_number, packet->original_frame_number);
S1AP_DEBUG("Last Packet received: num %u | original frame number %u \n", g_scenario->last_rx_packet->packet_number, g_scenario->last_rx_packet->original_frame_number);
p = g_scenario->last_rx_packet;
while (NULL != p) {
if (ET_PACKET_ACTION_S1C_RECEIVE == p->action) {
if ((ET_PACKET_STATUS_RECEIVED == p->status) || (ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT == p->status)) {
g_scenario->last_rx_packet = p;
g_scenario->time_last_rx_packet.tv_sec = p->timestamp_packet.tv_sec;
g_scenario->time_last_rx_packet.tv_usec = p->timestamp_packet.tv_usec;
S1AP_DEBUG("Set Last Packet received: num %u | original frame number %u \n", g_scenario->last_rx_packet->packet_number, g_scenario->last_rx_packet->original_frame_number);
S1AP_DEBUG("Set time_last_rx_packet %ld.%06d\n", g_scenario->time_last_rx_packet.tv_sec, g_scenario->time_last_rx_packet.tv_usec);
} else {
break;
}
}
p = p->next;
}
if (0 != packet->timer_id) {
rc = timer_remove(packet->timer_id);
AssertFatal(rc == 0, "TODO: Debug Timer on Rx packet num %u unknown", packet->packet_number);
g_scenario->timer_count--;
return rc;
}
return 1;
}
//------------------------------------------------------------------------------
int et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const s1ap_data_ind)
{
et_packet_t *packet = NULL;
et_packet_t *rx_packet = NULL;
unsigned long int not_found = 1;
asn_comp_rval_t *comp_results = NULL;
asn_comp_rval_t *comp_results2 = NULL;
unsigned char error_code = 0;
AssertFatal (NULL != s1ap_data_ind, "Bad parameter sctp_data_ind\n");
rx_packet = et_build_packet_from_s1ap_data_ind(s1ap_data_ind);
if (NULL == g_scenario->last_rx_packet) {
packet = g_scenario->list_packet;
while (NULL != packet) {
if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
if ((ET_PACKET_STATUS_RECEIVED == packet->status) || (ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT == packet->status)) {
g_scenario->last_rx_packet = packet;
if (ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT != packet->status) {
g_scenario->time_last_rx_packet.tv_sec = packet->timestamp_packet.tv_sec;
g_scenario->time_last_rx_packet.tv_usec = packet->timestamp_packet.tv_usec;
}
S1AP_DEBUG("Set Last Packet received: num %u | original frame number %u \n", g_scenario->last_rx_packet->packet_number, g_scenario->last_rx_packet->original_frame_number);
S1AP_DEBUG("Set time_last_rx_packet %ld.%06d\n", g_scenario->time_last_rx_packet.tv_sec, g_scenario->time_last_rx_packet.tv_usec);
} else {
break;
}
}
packet = packet->next;
}
packet = g_scenario->list_packet;
} else {
packet = g_scenario->last_rx_packet->next;
}
// not_found threshold may sure depend on number of mme, may be not sure on number of UE
while ((NULL != packet) && (not_found < 9)) {
S1AP_DEBUG("%s() Considering packet num %d original frame number %u\n", __FUNCTION__, packet->packet_number, packet->original_frame_number);
if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
comp_results = et_sctp_is_matching(&packet->sctp_hdr, &rx_packet->sctp_hdr, g_constraints);
if (NULL == comp_results) {
S1AP_DEBUG("Compare RX packet with packet: num %u | original frame number %u \n", packet->packet_number, packet->original_frame_number);
packet->timestamp_packet.tv_sec = rx_packet->timestamp_packet.tv_sec;
packet->timestamp_packet.tv_usec = rx_packet->timestamp_packet.tv_usec;
return et_scenario_set_packet_received(packet);
} else {
S1AP_DEBUG("Compare RX packet with packet: num %u | original frame number %u failed\n",
packet->packet_number, packet->original_frame_number);
while (comp_results) {
S1AP_DEBUG("Result err code %s(%u) ASN1 struct name %s\n",
et_error_match2str(comp_results->err_code), comp_results->err_code, comp_results->name);
// (each asn1 rc <= 166 (enum e_S1AP_ProtocolIE_ID, in generated file S1AP_ProtocolIE_ID.h))
if (comp_results->err_code == COMPARE_ERR_CODE_NO_MATCH) {
//TODO MME_UE_S1AP_ID, etc.
// get latest error code
if (strcmp(comp_results->name, "S1ap-MME-UE-S1AP-ID") == 0) {
if (0 == et_handle_s1ap_mismatch_mme_ue_s1ap_id((et_packet_t *const)packet, (et_packet_t *const)rx_packet)) {
packet->timestamp_packet.tv_sec = rx_packet->timestamp_packet.tv_sec;
packet->timestamp_packet.tv_usec = rx_packet->timestamp_packet.tv_usec;
return et_scenario_set_packet_received(packet);
}
} else if (strcmp(comp_results->name, "S1ap-TransportLayerAddress") == 0) {
S1AP_WARN("Some work needed there for %s, TODO in generic_scenario.xsl, add sgw conf file in the process, anyway continuing...\n",comp_results->name);
packet->timestamp_packet.tv_sec = rx_packet->timestamp_packet.tv_sec;
packet->timestamp_packet.tv_usec = rx_packet->timestamp_packet.tv_usec;
return et_scenario_set_packet_received(packet);
} else {
S1AP_WARN("\n\nRX PACKET:\n");
et_display_packet_sctp(&rx_packet->sctp_hdr);
S1AP_WARN("\n\nWAITED PACKET:\n");
et_display_packet_sctp(&packet->sctp_hdr);
AssertFatal(0,"Some work needed there");
}
}
comp_results2 = comp_results;
comp_results = comp_results2->next;
et_free_pointer(comp_results2);
}
}
}
not_found += 1;
packet = packet->next;
}
et_display_packet_sctp(&rx_packet->sctp_hdr);
AssertFatal(0, "Rx packet not found in scenario (see dump above)");
return -1;
}
//------------------------------------------------------------------------------
void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t * const sctp_data_ind)
{
int result = 0;
et_event_t event;
DevAssert(sctp_data_ind != NULL);
memset((void*)&event, 0, sizeof(event));
event.code = ET_EVENT_RX_S1AP;
event.u.s1ap_data_ind.sctp_datahdr.tsn = 0;
event.u.s1ap_data_ind.sctp_datahdr.stream = sctp_data_ind->stream;
event.u.s1ap_data_ind.sctp_datahdr.ssn = 0;
event.u.s1ap_data_ind.sctp_datahdr.ppid = S1AP_SCTP_PPID;
event.u.s1ap_data_ind.sctp_datahdr.assoc_id = sctp_data_ind->assoc_id;
event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream_pos = 0;
event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream_allocated_size = sctp_data_ind->buffer_length;
event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream = NULL;
if ((sctp_data_ind->buffer_length > 0) && (NULL != sctp_data_ind->buffer)) {
event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream = calloc(1, sctp_data_ind->buffer_length);
memcpy(event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream,
sctp_data_ind->buffer,
sctp_data_ind->buffer_length);
if (et_s1ap_decode_pdu(
&event.u.s1ap_data_ind.sctp_datahdr.payload.pdu,
&event.u.s1ap_data_ind.sctp_datahdr.payload.message,
event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream,
event.u.s1ap_data_ind.sctp_datahdr.payload.binary_stream_allocated_size) < 0) {
AssertFatal (0, "ERROR Cannot decode RX S1AP message!\n");
}
}
result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
et_scenario_fsm_notify_event(event);
memset((void*)&event, 0, sizeof(event));
event.code = ET_EVENT_TICK;
et_scenario_fsm_notify_event(event);
}
//------------------------------------------------------------------------------
void et_s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
net_ip_address_t *mme_ip_address,
net_ip_address_t *local_ip_addr,
uint16_t in_streams,
uint16_t out_streams)
{
MessageDef *message_p = NULL;
sctp_new_association_req_t *sctp_new_association_req_p = NULL;
s1ap_eNB_mme_data_t *s1ap_mme_data_p = NULL;
DevAssert(instance_p != NULL);
DevAssert(mme_ip_address != NULL);
message_p = itti_alloc_new_message(TASK_S1AP, SCTP_NEW_ASSOCIATION_REQ);
sctp_new_association_req_p = &message_p->ittiMsg.sctp_new_association_req;
sctp_new_association_req_p->port = S1AP_PORT_NUMBER;
sctp_new_association_req_p->ppid = S1AP_SCTP_PPID;
sctp_new_association_req_p->in_streams = in_streams;
sctp_new_association_req_p->out_streams = out_streams;
memcpy(&sctp_new_association_req_p->remote_address,
mme_ip_address,
sizeof(*mme_ip_address));
memcpy(&sctp_new_association_req_p->local_address,
local_ip_addr,
sizeof(*local_ip_addr));
/* Create new MME descriptor */
s1ap_mme_data_p = calloc(1, sizeof(*s1ap_mme_data_p));
DevAssert(s1ap_mme_data_p != NULL);
s1ap_mme_data_p->cnx_id = et_s1ap_eNB_fetch_add_global_cnx_id();
sctp_new_association_req_p->ulp_cnx_id = s1ap_mme_data_p->cnx_id;
s1ap_mme_data_p->assoc_id = -1;
s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
memcpy((void*)&s1ap_mme_data_p->mme_net_ip_address, mme_ip_address, sizeof(*mme_ip_address));
STAILQ_INIT(&s1ap_mme_data_p->served_gummei);
/* Insert the new descriptor in list of known MME
* but not yet associated.
*/
RB_INSERT(s1ap_mme_map, &instance_p->s1ap_mme_head, s1ap_mme_data_p);
s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
instance_p->s1ap_mme_nb ++;
instance_p->s1ap_mme_pending_nb ++;
itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
}
//------------------------------------------------------------------------------
void et_s1ap_update_assoc_id_of_packets(const int32_t assoc_id,
struct s1ap_eNB_instance_s * const s1ap_eNB_instance,
s1ap_eNB_mme_data_t * const mme_desc_p)
{
et_packet_t *packet = NULL;
int ret;
unsigned int old_enb_port = 0;
unsigned int old_mme_port = 0;
S1AP_DEBUG("%s for SCTP association (%u)\n",__FUNCTION__,assoc_id);
packet = g_scenario->list_packet;
while (NULL != packet) {
switch (packet->sctp_hdr.chunk_type) {
case SCTP_CID_DATA :
S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_DATA\n",__FUNCTION__,assoc_id);
if ((ET_PACKET_STATUS_NONE == packet->status) || (ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING == packet->status)) {
if (0 < old_mme_port) {
if (packet->action == ET_PACKET_ACTION_S1C_SEND) {
ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.dst, &mme_desc_p->mme_net_ip_address);
if (0 == ret) {
ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.src, &s1ap_eNB_instance->s1c_net_ip_address);
if (0 == ret) {
// same IP src, same IP dst
if ((packet->sctp_hdr.dst_port == old_mme_port) && (packet->sctp_hdr.src_port == old_enb_port)) {
packet->sctp_hdr.u.data_hdr.assoc_id = assoc_id;
S1AP_DEBUG("tPacket:\tnum %u | original frame number %u \n", packet->packet_number, packet->original_frame_number);
S1AP_DEBUG("\tUpdated assoc id: %u\n", assoc_id);
}
}
}
} else if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.src, &mme_desc_p->mme_net_ip_address);
if (0 == ret) {
ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.dst, &s1ap_eNB_instance->s1c_net_ip_address);
if (0 == ret) {
// same IP src, same IP dst
if ((packet->sctp_hdr.src_port == old_mme_port) && (packet->sctp_hdr.dst_port == old_enb_port)) {
packet->sctp_hdr.u.data_hdr.assoc_id = assoc_id;
S1AP_DEBUG("tPacket:\tnum %u | original frame number %u \n", packet->packet_number, packet->original_frame_number);
S1AP_DEBUG("\tUpdated assoc id: %u\n", assoc_id);
}
}
}
}
}
}
break;
// Strong assumption
// in replayed scenario, the order of SCTP INIT packets is supposed to be the same as in the catched scenario
case SCTP_CID_INIT:
S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_INIT\n",__FUNCTION__,assoc_id);
ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.dst, &mme_desc_p->mme_net_ip_address);
if (0 == ret) {
ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.src, &s1ap_eNB_instance->s1c_net_ip_address);
if (0 == ret) {
if (0 == old_enb_port) {
if (ET_PACKET_STATUS_NONE == packet->status) {
packet->status = ET_PACKET_STATUS_SENT;
old_enb_port = packet->sctp_hdr.src_port;
S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_INIT SUCCESS\n",__FUNCTION__,assoc_id);
}
}
}
}
break;
case SCTP_CID_INIT_ACK:
S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_INIT_ACK\n",__FUNCTION__,assoc_id);
ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.src, &mme_desc_p->mme_net_ip_address);
if (0 == ret) {
ret = et_compare_et_ip_to_net_ip_address(&packet->ip_hdr.dst, &s1ap_eNB_instance->s1c_net_ip_address);
if (0 == ret) {
if (old_enb_port == packet->sctp_hdr.dst_port) {
if (ET_PACKET_STATUS_NONE == packet->status) {
packet->status = ET_PACKET_STATUS_RECEIVED;
old_mme_port = packet->sctp_hdr.dst_port;
S1AP_DEBUG("%s for SCTP association (%u) SCTP_CID_INIT_ACK SUCCESS\n",__FUNCTION__,assoc_id);
}
}
}
}
break;
case SCTP_CID_HEARTBEAT:
case SCTP_CID_HEARTBEAT_ACK:
case SCTP_CID_COOKIE_ECHO:
case SCTP_CID_COOKIE_ACK:
case SCTP_CID_ECN_ECNE:
case SCTP_CID_ECN_CWR:
break;
case SCTP_CID_ABORT:
case SCTP_CID_SHUTDOWN:
case SCTP_CID_SHUTDOWN_ACK:
case SCTP_CID_ERROR:
case SCTP_CID_SHUTDOWN_COMPLETE:
//TODO
break;
default:
AssertFatal(0, "Unknown chunk_type %d packet num %u", packet->sctp_hdr.chunk_type, packet->packet_number);
;
}
packet = packet->next;
}
}
//------------------------------------------------------------------------------
void et_s1ap_handle_s1_setup_message(s1ap_eNB_mme_data_t *mme_desc_p, int sctp_shutdown)
{
if (sctp_shutdown) {
/* A previously connected MME has been shutdown */
/* TODO check if it was used by some eNB and send a message to inform these eNB if there is no more associated MME */
if (mme_desc_p->state == S1AP_ENB_STATE_CONNECTED) {
mme_desc_p->state = S1AP_ENB_STATE_DISCONNECTED;
if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb > 0) {
/* Decrease associated MME number */
mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb --;
}
/* If there are no more associated MME, inform eNB app */
if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb == 0) {
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_S1AP, S1AP_DEREGISTERED_ENB_IND);
S1AP_DEREGISTERED_ENB_IND(message_p).nb_mme = 0;
itti_send_msg_to_task(TASK_ENB_APP, mme_desc_p->s1ap_eNB_instance->instance, message_p);
}
}
} else {
/* Check that at least one setup message is pending */
DevCheck(mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb > 0, mme_desc_p->s1ap_eNB_instance->instance,
mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb, 0);
if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb > 0) {
/* Decrease pending messages number */
mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb --;
mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb++;
}
et_s1ap_update_assoc_id_of_packets(mme_desc_p->assoc_id,
mme_desc_p->s1ap_eNB_instance,
mme_desc_p);
/* If there are no more pending messages, inform eNB app */
if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb == 0) {
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_S1AP, S1AP_REGISTER_ENB_CNF);
S1AP_REGISTER_ENB_CNF(message_p).nb_mme = mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb;
itti_send_msg_to_task(TASK_ENB_APP, mme_desc_p->s1ap_eNB_instance->instance, message_p);
}
}
}
//------------------------------------------------------------------------------
void et_s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB)
{
s1ap_eNB_instance_t *new_instance;
uint8_t index;
DevAssert(s1ap_register_eNB != NULL);
/* Look if the provided instance already exists */
new_instance = et_s1ap_eNB_get_instance(instance);
if (new_instance != NULL) {
/* Checks if it is a retry on the same eNB */
DevCheck(new_instance->eNB_id == s1ap_register_eNB->eNB_id, new_instance->eNB_id, s1ap_register_eNB->eNB_id, 0);
DevCheck(new_instance->cell_type == s1ap_register_eNB->cell_type, new_instance->cell_type, s1ap_register_eNB->cell_type, 0);
DevCheck(new_instance->tac == s1ap_register_eNB->tac, new_instance->tac, s1ap_register_eNB->tac, 0);
DevCheck(new_instance->mcc == s1ap_register_eNB->mcc, new_instance->mcc, s1ap_register_eNB->mcc, 0);
DevCheck(new_instance->mnc == s1ap_register_eNB->mnc, new_instance->mnc, s1ap_register_eNB->mnc, 0);
DevCheck(new_instance->mnc_digit_length == s1ap_register_eNB->mnc_digit_length, new_instance->mnc_digit_length, s1ap_register_eNB->mnc_digit_length, 0);
DevCheck(memcmp((void*)&new_instance->s1c_net_ip_address, (void*)&s1ap_register_eNB->enb_ip_address, sizeof(new_instance->s1c_net_ip_address)) == 0, 0,0,0);
} else {
new_instance = calloc(1, sizeof(s1ap_eNB_instance_t));
DevAssert(new_instance != NULL);
RB_INIT(&new_instance->s1ap_ue_head);
RB_INIT(&new_instance->s1ap_mme_head);
/* Copy usefull parameters */
new_instance->instance = instance;
new_instance->eNB_name = s1ap_register_eNB->eNB_name;
new_instance->eNB_id = s1ap_register_eNB->eNB_id;
new_instance->cell_type = s1ap_register_eNB->cell_type;
new_instance->tac = s1ap_register_eNB->tac;
new_instance->mcc = s1ap_register_eNB->mcc;
new_instance->mnc = s1ap_register_eNB->mnc;
new_instance->mnc_digit_length = s1ap_register_eNB->mnc_digit_length;
memcpy((void*)&new_instance->s1c_net_ip_address, (void*)&s1ap_register_eNB->enb_ip_address, sizeof(new_instance->s1c_net_ip_address));
/* Add the new instance to the list of eNB (meaningfull in virtual mode) */
et_s1ap_eNB_insert_new_instance(new_instance);
S1AP_DEBUG("Registered new eNB[%d] and %s eNB id %u\n",
instance,
s1ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
s1ap_register_eNB->eNB_id);
}
DevCheck(s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS,
S1AP_MAX_NB_MME_IP_ADDRESS, s1ap_register_eNB->nb_mme, 0);
/* Trying to connect to provided list of MME ip address */
for (index = 0; index < s1ap_register_eNB->nb_mme; index++) {
et_s1ap_eNB_register_mme(new_instance,
&s1ap_register_eNB->mme_ip_address[index],
&s1ap_register_eNB->enb_ip_address,
s1ap_register_eNB->sctp_in_streams,
s1ap_register_eNB->sctp_out_streams);
}
}
//------------------------------------------------------------------------------
void et_s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
{
s1ap_eNB_instance_t *instance_p = NULL;
s1ap_eNB_mme_data_t *s1ap_mme_data_p = NULL;
DevAssert(sctp_new_association_resp != NULL);
instance_p = et_s1ap_eNB_get_instance(instance);
DevAssert(instance_p != NULL);
s1ap_mme_data_p = et_s1ap_eNB_get_MME(instance_p, -1,
sctp_new_association_resp->ulp_cnx_id);
DevAssert(s1ap_mme_data_p != NULL);
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
S1AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
sctp_new_association_resp->sctp_state,
instance,
sctp_new_association_resp->ulp_cnx_id);
et_s1ap_handle_s1_setup_message(s1ap_mme_data_p, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
return;
}
S1AP_DEBUG("Received successful result for SCTP association (%u), instance %d, cnx_id %u\n",
sctp_new_association_resp->sctp_state,
instance,
sctp_new_association_resp->ulp_cnx_id);
/* Update parameters */
s1ap_mme_data_p->assoc_id = sctp_new_association_resp->assoc_id;
s1ap_mme_data_p->in_streams = sctp_new_association_resp->in_streams;
s1ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams;
et_s1ap_handle_s1_setup_message(s1ap_mme_data_p, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
}
//------------------------------------------------------------------------------
void *et_s1ap_eNB_task(void *arg)
{
MessageDef *received_msg = NULL;
int result;
S1AP_DEBUG("Starting S1AP layer\n");
et_s1ap_eNB_prepare_internal_data();
itti_mark_task_ready(TASK_S1AP);
while (1) {
itti_receive_msg(TASK_S1AP, &received_msg);
switch (ITTI_MSG_ID(received_msg)) {
case TERMINATE_MESSAGE:
S1AP_WARN("*** Exiting S1AP thread\n");
itti_exit_task();
break;
case S1AP_REGISTER_ENB_REQ: {
/* Register a new eNB.
* in Virtual mode eNBs will be distinguished using the mod_id/
* Each eNB has to send an S1AP_REGISTER_ENB message with its
* own parameters.
*/
et_s1ap_eNB_handle_register_eNB(ITTI_MSG_DESTINATION_INSTANCE(received_msg),
&S1AP_REGISTER_ENB_REQ(received_msg));
}
break;
case SCTP_NEW_ASSOCIATION_RESP: {
et_s1ap_eNB_handle_sctp_association_resp(ITTI_MSG_DESTINATION_INSTANCE(received_msg),
&received_msg->ittiMsg.sctp_new_association_resp);
}
break;
case SCTP_DATA_IND: {
et_s1ap_eNB_handle_sctp_data_ind(&received_msg->ittiMsg.sctp_data_ind);
}
break;
case TIMER_HAS_EXPIRED:
LOG_I(S1AP, " Received TIMER_HAS_EXPIRED: timer_id %d\n", TIMER_HAS_EXPIRED(received_msg).timer_id);
{
et_packet_t * packet = (et_packet_t*)TIMER_HAS_EXPIRED (received_msg).arg;
et_event_t event;
g_scenario->timer_count--;
if (NULL != packet) {
if (packet->status == ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING) {
memset((void*)&event, 0, sizeof(event));
event.code = ET_EVENT_RX_PACKET_TIME_OUT;
event.u.rx_packet_time_out = packet;
et_scenario_fsm_notify_event(event);
} else if (packet->status == ET_PACKET_STATUS_SCHEDULED_FOR_SENDING) {
memset((void*)&event, 0, sizeof(event));
event.code = ET_EVENT_TX_TIMED_PACKET;
event.u.tx_timed_packet = packet;
et_scenario_fsm_notify_event(event);
et_event_t continue_event;
continue_event.code = ET_EVENT_TICK;
et_scenario_fsm_notify_event(continue_event);
} else if ((packet->status != ET_PACKET_STATUS_SENT) && ((packet->status != ET_PACKET_STATUS_RECEIVED))) {
AssertFatal (0, "Bad status %d of packet timed out!\n", packet->status);
}
} else {
LOG_W(S1AP, " Received TIMER_HAS_EXPIRED: timer_id %d, no packet attached to timer\n", TIMER_HAS_EXPIRED(received_msg).timer_id);
}
}
if (TIMER_HAS_EXPIRED (received_msg).timer_id == g_scenario->enb_register_retry_timer_id) {
/* Restart the registration process */
g_scenario->registered_enb = 0;
et_eNB_app_register (g_scenario->enb_properties);
}
break;
default:
S1AP_ERROR("Received unhandled message: %d:%s\n",
ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
break;
}
result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
received_msg = NULL;
}
return NULL;
}
/*
* 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
*/
/*
play_scenario_s1ap_compare_ie.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdarg.h>
#include <unistd.h>
#include <crypt.h>
#include <errno.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#include "tree.h"
#include "queue.h"
#include "intertask_interface.h"
#include "platform_types.h"
#include "assertions.h"
#include "conversions.h"
#include "s1ap_common.h"
#include "play_scenario_s1ap_eNB_defs.h"
#include "play_scenario.h"
//------------------------------------------------------------------------------
extern et_scenario_t *g_scenario;
extern uint32_t g_constraints;
//------------------------------------------------------------------------------
//asn_comp_rval_t * et_s1ap_ies_is_matching(const S1AP_PDU_PR present, s1ap_message * const m1, s1ap_message * const m2, const uint32_t constraints)
//{
//}
void update_xpath_node_mme_ue_s1ap_id(et_s1ap_t * const s1ap, xmlNode *node, const S1ap_MME_UE_S1AP_ID_t new_id)
{
xmlNode *cur_node = NULL;
xmlAttrPtr attr = NULL;
xmlChar *xml_char = NULL;
int size = 0;
int pos = 0;
int go_deeper_in_tree = 1;
//S1AP_INFO("%s() mme_ue_s1ap_id %u\n", __FUNCTION__, new_id);
// modify
for (cur_node = (xmlNode *)node; cur_node; cur_node = cur_node->next) {
go_deeper_in_tree = 1;
if ((!xmlStrcmp(cur_node->name, (const xmlChar *)"field"))) {
// do not get hidden fields
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"hide");
if (NULL != xml_char) {
if ((!xmlStrcmp(xml_char, (const xmlChar *)"yes"))) {
go_deeper_in_tree = 0;
}
xmlFree(xml_char);
}
if (0 < go_deeper_in_tree) {
// first get size
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"pos");
if (NULL != xml_char) {
pos = strtoul((const char *)xml_char, NULL, 0);
pos -= s1ap->xml_stream_pos_offset;
AssertFatal(pos >= 0, "Bad pos %d xml_stream_pos_offset %d", pos, s1ap->xml_stream_pos_offset);
xmlFree(xml_char);
xml_char = xmlGetProp((xmlNode *)cur_node, (const xmlChar *)"size");
if (NULL != xml_char) {
const xmlChar value_d[32];
const xmlChar value_h[20];
const xmlChar showname[64];
int ret = 0;
int pos2 = 0;
unsigned long int uli = 0;
char hex[3] = {0,0,0};
char *end_ptr = NULL;
size = strtoul((const char *)xml_char, NULL, 0);
xmlFree(xml_char);
// second: try to set value (always hex)
ret = snprintf((char *)value_d, 32, "%ld", new_id);
AssertFatal((ret > 0) && (ret < 32), "Could not convert int to dec str");
ret = snprintf((char *)value_h, 20, "C0%08X", new_id);
AssertFatal((ret > 0) && (ret < 20), "Could not convert int to hex str");
ret = snprintf((char *)showname, 64, "MME-UE-S1AP-ID: %d", new_id);
AssertFatal((ret > 0) && (ret < 64), "Could not convert int to dec str");
attr = xmlSetProp((xmlNode *)cur_node, (const xmlChar *)"value", value_h);
attr = xmlSetProp((xmlNode *)cur_node, (const xmlChar *)"show", value_d);
attr = xmlSetProp((xmlNode *)cur_node, (const xmlChar *)"showname", showname);
//TODO update s1ap->binary_stream @pos with new_id_hex, size
AssertFatal((pos+size) < s1ap->binary_stream_allocated_size, "Rewrite of mme_ue_s1ap_id out of bounds of binary_stream");
//avoid endianess issues
do {
hex[0] = value_h[pos2++];
hex[1] = value_h[pos2++];
hex[2] = '\0';
end_ptr = hex;
uli = strtoul(hex, &end_ptr, 16);
AssertFatal((uli != ULONG_MAX) && (end_ptr != NULL) && (*end_ptr == '\0'), "Conversion of hexstring %s failed returned %lu errno %d", hex, uli, errno);
s1ap->binary_stream[pos++] = (unsigned char)uli;
} while (pos2 < (2*5));
// update ASN1
et_decode_s1ap(s1ap);
//S1AP_INFO("Updated ASN1 for %s\n", showname);
}
}
}
}
if (0 < go_deeper_in_tree) {
update_xpath_node_mme_ue_s1ap_id(s1ap, cur_node->children, new_id);
}
}
}
/**
* update_xpath_nodes:
* @nodes: the nodes set.
* @value: the new value for the node(s)
*
* Prints the @nodes content to @output.
* From http://www.xmlsoft.org/examples/#xpath2.c
*/
void update_xpath_nodes_mme_ue_s1ap_id(et_s1ap_t * const s1ap_payload, xmlNodeSetPtr nodes, const S1ap_MME_UE_S1AP_ID_t new_id)
{
int size = 0;
int i = 0;
xmlNode *s1ap_node = NULL;
size = (nodes) ? nodes->nodeNr : 0;
//S1AP_DEBUG("%s() num nodes %u\n", __FUNCTION__, size);
/*
* NOTE: the nodes are processed in reverse order, i.e. reverse document
* order because xmlNodeSetContent can actually free up descendant
* of the node and such nodes may have been selected too ! Handling
* in reverse order ensure that descendant are accessed first, before
* they get removed. Mixing XPath and modifications on a tree must be
* done carefully !
*/
for(i = size - 1; i >= 0; i--) {
s1ap_node = nodes->nodeTab[i];
AssertFatal(NULL != s1ap_node, "One element of resultset of XPATH expression is NULL\n");
update_xpath_node_mme_ue_s1ap_id(s1ap_payload, s1ap_node, new_id);
/*
* All the elements returned by an XPath query are pointers to
* elements from the tree *except* namespace nodes where the XPath
* semantic is different from the implementation in libxml2 tree.
* As a result when a returned node set is freed when
* xmlXPathFreeObject() is called, that routine must check the
* element type. But node from the returned set may have been removed
* by xmlNodeSetContent() resulting in access to freed data.
* This can be exercised by running valgrind
* There is 2 ways around it:
* - make a copy of the pointers to the nodes from the result set
* then call xmlXPathFreeObject() and then modify the nodes
* or
* - remove the reference to the modified nodes from the node set
* as they are processed, if they are not namespace nodes.
*/
if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL) {
nodes->nodeTab[i] = NULL;
}
}
}
//------------------------------------------------------------------------------
int et_s1ap_update_mme_ue_s1ap_id(et_packet_t * const packet, const S1ap_MME_UE_S1AP_ID_t old_id, const S1ap_MME_UE_S1AP_ID_t new_id)
{
xmlChar xpath_expression[ET_XPATH_EXPRESSION_MAX_LENGTH];
int ret = 0;
xmlDocPtr doc = NULL;
xmlXPathContextPtr xpath_ctx = NULL;
xmlXPathObjectPtr xpath_obj = NULL;
//S1AP_DEBUG("%s() packet num %u original frame number %u, mme_ue_s1ap_id %u -> %u\n", __FUNCTION__, packet->packet_number, packet->original_frame_number, old_id, new_id);
ret = snprintf(xpath_expression, ET_XPATH_EXPRESSION_MAX_LENGTH, "//field[@name=\"s1ap.MME_UE_S1AP_ID\"][@show=\"%u\"]", old_id);
AssertFatal((ret > 0) && (ret < ET_XPATH_EXPRESSION_MAX_LENGTH), "Could not build XPATH expression err=%d", ret);
doc = packet->sctp_hdr.u.data_hdr.payload.doc;
// Create xpath evaluation context
xpath_ctx = xmlXPathNewContext(doc);
if(xpath_ctx == NULL) {
fprintf(stderr,"Error: unable to create new XPath context\n");
xmlFreeDoc(doc);
return(-1);
}
// Evaluate xpath expression
xpath_obj = xmlXPathEvalExpression(xpath_expression, xpath_ctx);
xmlXPathFreeContext(xpath_ctx);
AssertFatal(xpath_obj != NULL, "Unable to evaluate XPATH expression \"%s\"\n", xpath_expression);
if(xmlXPathNodeSetIsEmpty(xpath_obj->nodesetval)){
xmlXPathFreeObject(xpath_obj);
S1AP_DEBUG("%s() No match \"%s\"packet num %u original frame number %u, mme_ue_s1ap_id %u -> %u\n",
__FUNCTION__, xpath_expression, packet->packet_number, packet->original_frame_number, old_id, new_id);
return -1;
}
// update selected nodes
update_xpath_nodes_mme_ue_s1ap_id(&packet->sctp_hdr.u.data_hdr.payload, xpath_obj->nodesetval, new_id);
// Cleanup of XPath data
xmlXPathFreeObject(xpath_obj);
return 0;
}
/*
* 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
*/
#include <stdint.h>
#include "queue.h"
#include "tree.h"
#include "sctp_eNB_defs.h"
#ifndef PLAY_SCENARIO_S1AP_ENB_DEFS_H_
#define PLAY_SCENARIO_S1AP_ENB_DEFS_H_
#define ENB_TAC (1)
#define ENB_MCC (208)
#define ENB_MNC (92)
#define ENB_NAME "Eurecom ENB"
#define ENB_NAME_FORMAT (ENB_NAME" %u")
#define S1AP_PORT_NUMBER (36412)
#define S1AP_SCTP_PPID (18)
#define X2AP_PORT_NUMBER (36422)
#define X2AP_SCTP_PPID (27)
#define S1AP_ENB_NAME_LENGTH_MAX (150)
typedef enum {
/* Disconnected state: initial state for any association. */
S1AP_ENB_STATE_DISCONNECTED = 0x0,
/* State waiting for S1 Setup response message if eNB is MME accepted or
* S1 Setup failure if MME rejects the eNB.
*/
S1AP_ENB_STATE_WAITING = 0x1,
/* The eNB is successfully connected to MME, UE contexts can be created. */
S1AP_ENB_STATE_CONNECTED = 0x2,
/* The MME has sent an overload start message. Once the MME disables the
* OVERLOAD marker, the state of the association will be
* S1AP_ENB_STATE_CONNECTED.
*/
S1AP_ENB_OVERLOAD = 0x3,
/* Max number of states available */
S1AP_ENB_STATE_MAX,
} s1ap_eNB_state_t;
/* If the Overload Action IE in the OVERLOAD START message is set to
* - “reject all RRC connection establishments for non-emergency mobile
* originated data transfer “ (i.e. reject traffic corresponding to RRC cause
* “mo-data “ (TS 36.331 [16])), or
* - “reject all RRC connection establishments for signalling “ (i.e. reject
* traffic corresponding to RRC cause “modata” and “mo-signalling”
* (TS 36.331 [16])),or
* - “only permit RRC connection establishments for emergency sessions and
* mobile terminated services” (i.e. only permit traffic corresponding to RRC
* cause “emergency” and “mt-Access” (TS 36.331 [16])).
*
* NOTE: When the Overload Action IE is set to “only permit RRC connection
* establishments for emergency sessions and mobile terminated services”,
* emergency calls with RRC cause “highPriorityAcess” from high priority users
* are rejected (TS 24.301 [24]).
*/
typedef enum {
S1AP_OVERLOAD_REJECT_MO_DATA = 0x0,
S1AP_OVERLOAD_REJECT_ALL_SIGNALLING = 0x1,
S1AP_OVERLOAD_ONLY_EMERGENCY_AND_MT = 0x2,
S1AP_NO_OVERLOAD = 0x3,
S1AP_OVERLOAD_MAX,
} s1ap_overload_state_t;
/* Served PLMN identity element */
struct plmn_identity_s {
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_digit_length;
STAILQ_ENTRY(plmn_identity_s) next;
};
/* Served group id element */
struct served_group_id_s {
uint16_t mme_group_id;
STAILQ_ENTRY(served_group_id_s) next;
};
/* Served mme code for a particular MME */
struct mme_code_s {
uint8_t mme_code;
STAILQ_ENTRY(mme_code_s) next;
};
/* Served gummei element */
struct served_gummei_s {
/* Number of MME served PLMNs */
uint8_t nb_served_plmns;
/* List of served PLMNs by MME */
STAILQ_HEAD(served_plmns_s, plmn_identity_s) served_plmns;
/* Number of group id in list */
uint8_t nb_group_id;
/* Served group id list */
STAILQ_HEAD(served_group_ids_s, served_group_id_s) served_group_ids;
/* Number of MME code */
uint8_t nb_mme_code;
/* MME Code to uniquely identify an MME within an MME pool area */
STAILQ_HEAD(mme_codes_s, mme_code_s) mme_codes;
/* Next GUMMEI element */
STAILQ_ENTRY(served_gummei_s) next;
};
struct s1ap_eNB_instance_s;
/* This structure describes association of a eNB to a MME */
typedef struct s1ap_eNB_mme_data_s {
/* MME descriptors tree, ordered by sctp assoc id */
RB_ENTRY(s1ap_eNB_mme_data_s) entry;
/* This is the optional name provided by the MME */
char *mme_name;
net_ip_address_t mme_net_ip_address; // useful for joining assoc_id and ip address of packets
/* List of served GUMMEI per MME. There is one GUMMEI per RAT with a max
* number of 8 RATs but in our case only one is used. The LTE related pool
* configuration is included on the first place in the list.
*/
STAILQ_HEAD(served_gummeis_s, served_gummei_s) served_gummei;
/* Relative processing capacity of an MME with respect to the other MMEs
* in the pool in order to load-balance MMEs within a pool as defined
* in TS 23.401.
*/
uint8_t relative_mme_capacity;
/* Current MME overload information (if any). */
s1ap_overload_state_t overload_state;
/* Current eNB->MME S1AP association state */
s1ap_eNB_state_t state;
/* Next usable stream for UE signalling */
int32_t nextstream;
/* Number of input/ouput streams */
uint16_t in_streams;
uint16_t out_streams;
/* Connexion id used between SCTP/S1AP */
uint16_t cnx_id;
/* SCTP association id */
int32_t assoc_id;
/* Only meaningfull in virtual mode */
struct s1ap_eNB_instance_s *s1ap_eNB_instance;
} s1ap_eNB_mme_data_t;
typedef struct s1ap_eNB_instance_s {
/* Next s1ap eNB association.
* Only used for virtual mode.
*/
STAILQ_ENTRY(s1ap_eNB_instance_s) s1ap_eNB_entries;
/* Number of MME requested by eNB (tree size) */
uint32_t s1ap_mme_nb;
/* Number of MME for which association is pending */
uint32_t s1ap_mme_pending_nb;
/* Number of MME successfully associated to eNB */
uint32_t s1ap_mme_associated_nb;
/* Tree of S1AP MME associations ordered by association ID */
RB_HEAD(s1ap_mme_map, s1ap_eNB_mme_data_s) s1ap_mme_head;
/* TODO: add a map ordered by relative MME capacity */
/* Tree of UE ordered by eNB_ue_s1ap_id's */
RB_HEAD(s1ap_ue_map, s1ap_eNB_ue_context_s) s1ap_ue_head;
/* For virtual mode, mod_id as defined in the rest of the L1/L2 stack */
instance_t instance;
/* Displayable name of eNB */
char *eNB_name;
net_ip_address_t s1c_net_ip_address;
/* Unique eNB_id to identify the eNB within EPC.
* In our case the eNB is a macro eNB so the id will be 20 bits long.
* For Home eNB id, this field should be 28 bits long.
*/
uint32_t eNB_id;
/* The type of the cell */
enum cell_type_e cell_type;
/* Tracking area code */
uint16_t tac;
/* Mobile Country Code
* Mobile Network Code
*/
uint16_t mcc;
uint16_t mnc;
uint8_t mnc_digit_length;
} s1ap_eNB_instance_t;
typedef struct {
/* List of served eNBs
* Only used for virtual mode
*/
STAILQ_HEAD(s1ap_eNB_instances_head_s, s1ap_eNB_instance_s) s1ap_eNB_instances_head;
/* Nb of registered eNBs */
uint8_t nb_registered_eNBs;
/* Generate a unique connexion id used between S1AP and SCTP */
uint16_t global_cnx_id;
} s1ap_eNB_internal_data_t;
int s1ap_eNB_compare_assoc_id(
struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2);
/* Generate the tree management functions */
RB_PROTOTYPE(s1ap_mme_map, s1ap_eNB_mme_data_s, entry,
s1ap_eNB_compare_assoc_id);
#endif /* PLAY_SCENARIO_S1AP_ENB_DEFS_H_ */
/*
* 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
*/
/*
play_scenario_sctp.c
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <errno.h>
#include "intertask_interface.h"
#include "platform_types.h"
#include "assertions.h"
#include "play_scenario.h"
//------------------------------------------------------------------------------
asn_comp_rval_t *et_sctp_data_is_matching(sctp_datahdr_t *const sctp1, sctp_datahdr_t *const sctp2, const uint32_t constraints)
{
asn_comp_rval_t *rv = NULL;
// no comparison for ports
if (sctp1->ppid != sctp2->ppid) {
S1AP_WARN("No Matching SCTP PPID %u %u\n", sctp1->ppid, sctp2->ppid);
rv = calloc(1, sizeof(asn_comp_rval_t));
rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_PPID;
return rv;
}
if (sctp1->assoc_id != sctp2->assoc_id) {
S1AP_WARN("No Matching SCTP assoc id %u %u\n", sctp1->assoc_id, sctp2->assoc_id);
rv = calloc(1, sizeof(asn_comp_rval_t));
rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_ASSOC_ID;
return rv;
}
if (sctp1->stream != sctp2->stream) {
if (constraints & ET_BIT_MASK_MATCH_SCTP_STREAM) {
rv = calloc(1, sizeof(asn_comp_rval_t));
rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_STREAM_ID;
return rv;
} else {
S1AP_WARN("No Matching SCTP stream %u %u\n", sctp1->stream, sctp2->stream);
}
}
// We do not have SSN from lower layers
// if (sctp1->ssn != sctp2->ssn) {
// if (constraints & ET_BIT_MASK_MATCH_SCTP_SSN) {
// rv = calloc(1, sizeof(asn_comp_rval_t));
// rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_SSN;
// return rv;
// } else {
// S1AP_WARN("No Matching SCTP STREAM SN %u %u\n", sctp1->ssn, sctp2->ssn);
// }
// }
return et_s1ap_is_matching(&sctp1->payload, &sctp2->payload, constraints);
}
//------------------------------------------------------------------------------
asn_comp_rval_t *et_sctp_is_matching(et_sctp_hdr_t *const sctp1, et_sctp_hdr_t *const sctp2, const uint32_t constraints)
{
// no comparison for ports
asn_comp_rval_t *rv = NULL;
if (sctp1->chunk_type != sctp2->chunk_type) {
S1AP_WARN("No Matching chunk_type %u %u\n", sctp1->chunk_type, sctp2->chunk_type);
rv = calloc(1, sizeof(asn_comp_rval_t));
rv->err_code = ET_ERROR_MATCH_PACKET_SCTP_CHUNK_TYPE;
return rv;
}
switch (sctp1->chunk_type) {
case SCTP_CID_DATA:
return et_sctp_data_is_matching(&sctp1->u.data_hdr, &sctp2->u.data_hdr, constraints);
break;
case SCTP_CID_INIT:
AssertFatal(0, "Not needed now");
break;
case SCTP_CID_INIT_ACK:
AssertFatal(0, "Not needed now");
break;
default:
AssertFatal(0, "Not needed now cid %d", sctp1->chunk_type);
}
return NULL;
}
/*
* 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
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include "sctp_primitives_client.h"
#include "s1ap_common.h"
#include "s1ap_eNB.h"
#include "s1ap_mme.h"
char ip_addr[] = "127.0.0.1";
int assoc[2];
uint8_t id[] = { 0x03, 0x56, 0xf0, 0xd8 };
char identity[] = { 0x02, 0x08, 0x34 };
char tac[] = { 0x00, 0x01 };
char infoNAS[] = { 0x07, 0x42, 0x01, 0xE0, 0x06, 0x00, 0x00, 0xF1, 0x10, 0x00, 0x01, 0x00, 0x2C,
0x52, 0x01, 0xC1, 0x01, 0x09, 0x10, 0x03, 0x77, 0x77, 0x77, 0x07, 0x61, 0x6E, 0x72, 0x69, 0x74,
0x73, 0x75, 0x03, 0x63, 0x6F, 0x6D, 0x05, 0x01, 0x0A, 0x01, 0x20, 0x37, 0x27, 0x0E, 0x80, 0x80,
0x21, 0x0A, 0x03, 0x00, 0x00, 0x0A, 0x81, 0x06, 0x0A, 0x00, 0x00, 0x01, 0x50, 0x0B, 0xF6,
0x00, 0xF1, 0x10, 0x80, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01
};
uint32_t eNB_UE_S1AP_ID = 0;
int s1ap_eNB_generate_initial_ue_message(uint8_t **buffer,
uint32_t *length);
int s1ap_eNB_generate_initial_ue_message(uint8_t **buffer,
uint32_t *length)
{
InitialUEMessageIEs initialUEmessageIEs;
InitialUEMessageIEs *initialUEmessageIEs_p = &initialUEmessageIEs;
memset(initialUEmessageIEs_p, 0, sizeof(InitialUEMessageIEs));
initialUEmessageIEs.eNB_UE_S1AP_ID = eNB_UE_S1AP_ID;
initialUEmessageIEs.nas_pdu.buf = infoNAS;
initialUEmessageIEs.nas_pdu.size = sizeof(infoNAS);
initialUEmessageIEs.tai.tAC.buf = tac;
initialUEmessageIEs.tai.tAC.size = 2;
initialUEmessageIEs.tai.pLMNidentity.buf = identity;
initialUEmessageIEs.tai.pLMNidentity.size = 3;
initialUEmessageIEs.eutran_cgi.pLMNidentity.buf = identity;
initialUEmessageIEs.eutran_cgi.pLMNidentity.size = 3;
initialUEmessageIEs.eutran_cgi.cell_ID.buf = id;
initialUEmessageIEs.eutran_cgi.cell_ID.size = 4;
initialUEmessageIEs.eutran_cgi.cell_ID.bits_unused = 4;
initialUEmessageIEs.rrC_Establishment_Cause = RRC_Establishment_Cause_mo_Data;
return s1ap_eNB_encode_initial_ue_message(initialUEmessageIEs_p, buffer, length);
}
void recv_callback(uint8_t *buffer, uint32_t length)
{
uint8_t *bufferS;
uint32_t len;
s1ap_eNB_generate_initial_ue_message(&bufferS, &len);
sctp_send_msg(assoc[0], 1, bufferS, len);
}
int main(int argc, char *argv[])
{
asn_enc_rval_t retVal;
uint8_t *buffer;
uint32_t len;
SupportedTAs_Item_t ta;
PLMNidentity_t plmnIdentity;
asn_debug = 0;
asn1_xer_print = 0;
S1SetupRequestIEs s1SetupRequest;
memset(&s1SetupRequest, 0, sizeof(S1SetupRequestIEs));
s1SetupRequest.global_ENB_ID.eNB_ID.present = ENB_ID_PR_macroENB_ID;
s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.buf = id;
s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.size = 3;
s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.bits_unused = 4;
OCTET_STRING_fromBuf(&s1SetupRequest.global_ENB_ID.pLMNidentity, identity, 3);
s1SetupRequest.presenceMask |= S1SETUPREQUESTIES_ENBNAME_PRESENT;
OCTET_STRING_fromBuf(&s1SetupRequest.eNBname, "ENB 1 eurecom",
strlen("ENB 1 eurecom"));
memset(&ta, 0, sizeof(SupportedTAs_Item_t));
memset(&plmnIdentity, 0, sizeof(PLMNidentity_t));
OCTET_STRING_fromBuf(&ta.tAC, tac, 2);
OCTET_STRING_fromBuf(&plmnIdentity, identity, 3);
ASN_SEQUENCE_ADD(&ta.broadcastPLMNs, &plmnIdentity);
ASN_SEQUENCE_ADD(&s1SetupRequest.supportedTAs, &ta);
s1SetupRequest.defaultPagingDRX = PagingDRX_v64;
s1ap_eNB_encode_s1setuprequest(&s1SetupRequest, &buffer, &len);
assoc[0] = sctp_connect_to_remote_host(ip_addr, 36412, &recv_callback);
sctp_send_msg(0, 0, buffer, len);
free(buffer);
// generateUplinkNASTransport(&buffer, &len);
// sctp_send_msg(assoc[0], 0, buffer, len);
// s1ap_mme_decode_pdu(buffer, len);
pthread_join(sctp_get_receiver_thread(assoc[0]), NULL);
return(0);
}
/*
* 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
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sched.h>
#include "mme_config.h"
#include "gtpv1u_sgw_defs.h"
#include "intertask_interface.h"
#include "sctp_primitives_server.h"
#include "udp_primitives_server.h"
#include "s1ap_mme.h"
#include "log.h"
#include "sgw_lite_defs.h"
#include "ipv4_defs.h"
int main(int argc, char *argv[])
{
int i = 0;
int prio = 0;
mme_config_t mme_config;
MessageDef *message_p;
struct sched_param param = {
.sched_priority = 10,
};
config_parse_opt_line(argc, argv, &mme_config);
fprintf(stdout, "Starting %s ITTI test\n", PACKAGE_STRING);
if (setpriority(PRIO_PROCESS, 0, prio) < 0) {
fprintf(stderr, "Cannot assign requested prio: %d\n"
"%d:%s\n", prio, errno, strerror(errno));
return -1;
}
if (sched_setscheduler(0, SCHED_RR, &param) < 0) {
fprintf(stderr, "Cannot assign requested scheduler policy\n"
"%d:%s\n", errno, strerror(errno));
return -1;
}
/* Calling each layer init function */
log_init(&mme_config);
itti_init(TASK_MAX, tasks_info);
sctp_init(&mme_config);
udp_init(&mme_config);
s1ap_mme_init(&mme_config);
gtpv1u_init(&mme_config);
ipv4_init(&mme_config);
sgw_lite_init(&mme_config);
message_p = itti_alloc_new_message(TASK_S1AP, MESSAGE_TEST);
while(i < (1 << 15)) {
if (send_broadcast_message(message_p) < 0) {
fprintf(stderr, "Failed to send broadcast message %d\n", i);
}
i++;
}
fprintf(stderr, "Successfully sent %lu messages", get_current_message_number());
return 0;
}
/*
* 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
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include "sctp_primitives_client.h"
#include "s1ap_common.h"
#include "s1ap_eNB.h"
#include "s1ap_mme.h"
#include "s1ap_eNB_encoder.h"
#include "s1ap_eNB_decoder.h"
#define NB_OF_ENB 10
#define NB_OF_UES 100
static int connected_eNB = 0;
static char ip_addr[] = "127.0.0.1";
uint32_t ipv4_local = 0x7F000001;
static uint8_t id[] = { 0x03, 0x56, 0xf0, 0xd8 };
static char identity[] = { 0x02, 0x08, 0x34 };
static char tac[] = { 0x00, 0x01 };
static char infoNAS[] = { 0x07, 0x42, 0x01, 0xE0, 0x06, 0x00, 0x00, 0xF1, 0x10, 0x00, 0x01, 0x00, 0x2C,
0x52, 0x01, 0xC1, 0x01, 0x09, 0x10, 0x03, 0x77, 0x77, 0x77, 0x07, 0x61, 0x6E, 0x72, 0x69, 0x74,
0x73, 0x75, 0x03, 0x63, 0x6F, 0x6D, 0x05, 0x01, 0x0A, 0x01, 0x20, 0x37, 0x27, 0x0E, 0x80, 0x80,
0x21, 0x0A, 0x03, 0x00, 0x00, 0x0A, 0x81, 0x06, 0x0A, 0x00, 0x00, 0x01, 0x50, 0x0B, 0xF6,
0x00, 0xF1, 0x10, 0x80, 0x01, 0x01, 0x00, 0x00, 0x00, 0x01
};
uint32_t nb_eNB = NB_OF_ENB;
uint32_t nb_ue = NB_OF_UES;
void s1ap_test_generate_s1_setup_request(uint32_t eNB_id, uint8_t **buffer,
uint32_t *length);
int s1ap_test_generate_initial_ue_message(uint32_t eNB_UE_S1AP_ID,
uint8_t **buffer,
uint32_t *length);
int recv_callback(uint32_t assocId,
uint32_t stream,
uint8_t *buffer,
uint32_t length);
int sctp_connected(void *args,
uint32_t assocId,
uint32_t instreams,
uint32_t outstreams);
void s1ap_test_generate_s1_setup_request(uint32_t eNB_id, uint8_t **buffer,
uint32_t *length)
{
S1SetupRequestIEs_t s1SetupRequest;
SupportedTAs_Item_t ta;
PLMNidentity_t plmnIdentity;
uint8_t *id_p = (uint8_t *)(&eNB_id + 1);
memset(&s1SetupRequest, 0, sizeof(S1SetupRequestIEs_t));
s1SetupRequest.global_ENB_ID.eNB_ID.present = ENB_ID_PR_macroENB_ID;
s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.buf = id_p;
s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.size = 3;
s1SetupRequest.global_ENB_ID.eNB_ID.choice.macroENB_ID.bits_unused = 4;
OCTET_STRING_fromBuf(&s1SetupRequest.global_ENB_ID.pLMNidentity, identity, 3);
s1SetupRequest.presenceMask |= S1SETUPREQUESTIES_ENBNAME_PRESENT;
OCTET_STRING_fromBuf(&s1SetupRequest.eNBname, "ENB 1 eurecom",
strlen("ENB 1 eurecom"));
memset(&ta, 0, sizeof(SupportedTAs_Item_t));
memset(&plmnIdentity, 0, sizeof(PLMNidentity_t));
OCTET_STRING_fromBuf(&ta.tAC, tac, 2);
OCTET_STRING_fromBuf(&plmnIdentity, identity, 3);
ASN_SEQUENCE_ADD(&ta.broadcastPLMNs, &plmnIdentity);
ASN_SEQUENCE_ADD(&s1SetupRequest.supportedTAs, &ta);
s1SetupRequest.defaultPagingDRX = PagingDRX_v64;
s1ap_eNB_encode_s1_setup_request(&s1SetupRequest, buffer, length);
}
int s1ap_test_generate_initial_ue_message(uint32_t eNB_UE_S1AP_ID,
uint8_t **buffer,
uint32_t *length)
{
InitialUEMessageIEs_t initialUEmessageIEs;
InitialUEMessageIEs_t *initialUEmessageIEs_p = &initialUEmessageIEs;
memset(initialUEmessageIEs_p, 0, sizeof(InitialUEMessageIEs_t));
initialUEmessageIEs.eNB_UE_S1AP_ID = eNB_UE_S1AP_ID & 0x00ffffff;
initialUEmessageIEs.nas_pdu.buf = (uint8_t *)infoNAS;
initialUEmessageIEs.nas_pdu.size = sizeof(infoNAS);
initialUEmessageIEs.tai.tAC.buf = (uint8_t *)tac;
initialUEmessageIEs.tai.tAC.size = 2;
initialUEmessageIEs.tai.pLMNidentity.buf = (uint8_t *)identity;
initialUEmessageIEs.tai.pLMNidentity.size = 3;
initialUEmessageIEs.eutran_cgi.pLMNidentity.buf = (uint8_t *)identity;
initialUEmessageIEs.eutran_cgi.pLMNidentity.size = 3;
initialUEmessageIEs.eutran_cgi.cell_ID.buf = (uint8_t *)id;
initialUEmessageIEs.eutran_cgi.cell_ID.size = 4;
initialUEmessageIEs.eutran_cgi.cell_ID.bits_unused = 4;
initialUEmessageIEs.rrC_Establishment_Cause = RRC_Establishment_Cause_mo_Data;
return s1ap_eNB_encode_initial_ue_message(initialUEmessageIEs_p, buffer, length);
}
int s1ap_test_generate_initial_setup_resp(uint32_t eNB_UE_S1AP_ID,
uint32_t mme_UE_S1AP_ID,
uint8_t eRAB_id,
uint32_t teid,
uint8_t **buffer,
uint32_t *length)
{
InitialContextSetupResponseIEs_t initialResponseIEs;
InitialContextSetupResponseIEs_t *initialResponseIEs_p = &initialResponseIEs;
E_RABSetupItemCtxtSURes_t e_RABSetupItemCtxtSURes;
memset(initialResponseIEs_p, 0, sizeof(InitialContextSetupResponseIEs_t));
memset(&e_RABSetupItemCtxtSURes, 0, sizeof(E_RABSetupItemCtxtSURes_t));
initialResponseIEs_p->mme_ue_s1ap_id = mme_UE_S1AP_ID;
initialResponseIEs_p->eNB_UE_S1AP_ID = eNB_UE_S1AP_ID;
e_RABSetupItemCtxtSURes.e_RAB_ID = eRAB_id;
e_RABSetupItemCtxtSURes.transportLayerAddress.buf = (uint8_t *)&ipv4_local;
e_RABSetupItemCtxtSURes.transportLayerAddress.size = 4;
e_RABSetupItemCtxtSURes.gTP_TEID.buf = (uint8_t *)&teid;
e_RABSetupItemCtxtSURes.gTP_TEID.size = 4;
ASN_SEQUENCE_ADD(
&initialResponseIEs_p->e_RABSetupListCtxtSURes.e_RABSetupItemCtxtSURes,
&e_RABSetupItemCtxtSURes);
return s1ap_eNB_encode_initial_context_setup_response(initialResponseIEs_p,
buffer, length);
}
int recv_callback(uint32_t assocId,
uint32_t stream,
uint8_t *buffer,
uint32_t length)
{
S1AP_S1AP_PDU_t pdu;
uint8_t *buffer2;
uint32_t len;
int j;
if (s1ap_eNB_decode_pdu(&pdu, buffer, length) < 0) {
fprintf(stderr, "s1ap_eNB_decode_pdu returned status < 0\n");
free(buffer);
return -1;
}
if (pdu.initiatingMessage.procedureCode == S1AP_ProcedureCode_id_S1Setup
&& pdu.present == S1AP_S1AP_PDU_PR_successfulOutcome) {
for (j = 0; j < nb_ue; j++) {
s1ap_test_generate_initial_ue_message(j, &buffer2, &len);
if (sctp_send_msg(assocId, j % 64 + 1, buffer2, len) < 0) {
fprintf(stderr,
"sctp_send_msg returned status < 0\nSomething bad happened on SCTP layer\n");
free(buffer2);
break;
}
free(buffer2);
}
} else if (pdu.initiatingMessage.procedureCode == S1AP_ProcedureCode_id_InitialContextSetup
&& pdu.present == S1AP_PDU_PR_initiatingMessage) {
fprintf(stdout, "Received InitialContextSetup request\n");
s1ap_test_generate_initial_setup_resp(
message.msg.initialContextSetupRequestIEs.eNB_UE_S1AP_ID,
message.msg.initialContextSetupRequestIEs.mme_ue_s1ap_id,
0x5,
0x1,
&buffer2,
&len);
if (sctp_send_msg(assocId, stream, buffer2, len) < 0) {
fprintf(stderr,
"sctp_send_msg returned status < 0\nSomething bad happened on SCTP layer\n");
free(buffer2);
}
free(buffer2);
} else {
fprintf(stderr, "Received unexpected message %d %d\n", message.procedureCode,
message.direction);
free(buffer);
return -1;
}
free(buffer);
return 0;
}
int sctp_connected(void *args,
uint32_t assocId,
uint32_t instreams,
uint32_t outstreams)
{
uint8_t *buffer;
uint32_t len;
fprintf(stdout, "New association %d\n", assocId);
s1ap_test_generate_s1_setup_request(assocId * nb_eNB, &buffer, &len);
if (sctp_send_msg(assocId, 0, buffer, len) < 0) {
free(buffer);
fprintf(stderr,
"sctp_send_msg returned status < 0. Something bad happened on SCTP layer\n");
exit(0);
}
free(buffer);
connected_eNB++;
return 0;
}
int main(int argc, char *argv[])
{
asn_enc_rval_t retVal;
int i;
SupportedTAs_Item_t ta;
PLMNidentity_t plmnIdentity;
asn_debug = 0;
asn1_xer_print = 0;
if (argc > 1) {
nb_eNB = atoi(argv[1]);
if (argc > 2) {
nb_ue = atoi(argv[2]);
}
}
for (i = 0; i < nb_eNB; i++) {
sctp_connect_to_remote_host(ip_addr, 36412, 18, NULL, sctp_connected,
recv_callback);
}
while (1) {
sleep(1);
}
// generateUplinkNASTransport(&buffer, &len);
// sctp_send_msg(assoc[0], 0, buffer, len);
// s1ap_mme_decode_pdu(buffer, len);
sctp_terminate();
return(0);
}
/*
* 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
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "s1ap_common.h"
#include "s1ap_eNB_decoder.h"
#include "s1ap_mme_decoder.h"
#include "s1ap_eNB_encoder.h"
#define MAX_BUF_LENGTH (1024)
typedef struct {
char *procedure_name;
uint8_t buffer[MAX_BUF_LENGTH];
uint32_t buf_len;
} s1ap_test_t;
s1ap_test_t s1ap_test[] = {
// {
// .procedure_name = "Downlink NAS transport",
// .buffer = {
// 0x00, 0x0B, 0x40, 0x21, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
// 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03,
// 0x40, 0x01, 0xB3, 0x00, 0x1A, 0x00, 0x0A, 0x09, 0x27, 0xAB,
// 0x1F, 0x7C, 0xEC, 0x01, 0x02, 0x01, 0xD9
// },
// .buf_len = 37,
// },
{
.procedure_name = "Uplink NAS transport",
.buffer = {
0x00, 0x0D, 0x40, 0x41, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03,
0x40, 0x01, 0xB3, 0x00, 0x1A, 0x00, 0x14, 0x13, 0x27, 0xD3,
0x77, 0xED, 0x4C, 0x01, 0x02, 0x01, 0xDA, 0x28, 0x08, 0x03,
0x69, 0x6D, 0x73, 0x03, 0x70, 0x66, 0x74, 0x00, 0x64, 0x40,
0x08, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x00, 0x20, 0x40, 0x00,
0x43, 0x40, 0x06, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x04,
},
.buf_len = 69,
},
{
.procedure_name = "UE capability info indication",
.buffer = {
0x00, 0x16, 0x40, 0x37, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00, 0x03,
0x40, 0x01, 0xB3, 0x00, 0x4A, 0x40, 0x20, 0x1F, 0x00, 0xE8,
0x01, 0x01, 0xA8, 0x13, 0x80, 0x00, 0x20, 0x83, 0x13, 0x05,
0x0B, 0x8B, 0xFC, 0x2E, 0x2F, 0xF0, 0xB8, 0xBF, 0xAF, 0x87,
0xFE, 0x40, 0x44, 0x04, 0x07, 0x0C, 0xA7, 0x4A, 0x80,
},
.buf_len = 59,
},
{
.procedure_name = "Initial Context Setup Request",
.buffer = {
0x00, 0x09, 0x00, 0x80, 0xD4, 0x00, 0x00, 0x06, 0x00, 0x00,
0x00, 0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x00,
0x03, 0x40, 0x01, 0xB3, 0x00, 0x42, 0x00, 0x0A, 0x18, 0x08,
0xF0, 0xD1, 0x80, 0x60, 0x02, 0xFA, 0xF0, 0x80, 0x00, 0x18,
0x00, 0x80, 0x81, 0x00, 0x00, 0x34, 0x00, 0x7C, 0x45, 0x00,
0x09, 0x3D, 0x0F, 0x80, 0x0A, 0x05, 0x00, 0x02, 0x03, 0x78,
0x48, 0x86, 0x6D, 0x27, 0xC7, 0x97, 0x8E, 0xA1, 0x02, 0x07,
0x42, 0x01, 0x49, 0x06, 0x00, 0x02, 0xF8, 0x29, 0x00, 0x04,
0x00, 0x48, 0x52, 0x01, 0xC1, 0x01, 0x09, 0x1B, 0x03, 0x69,
0x6D, 0x73, 0x03, 0x70, 0x66, 0x74, 0x06, 0x6D, 0x6E, 0x63,
0x30, 0x39, 0x32, 0x06, 0x6D, 0x63, 0x63, 0x32, 0x30, 0x38,
0x04, 0x67, 0x70, 0x72, 0x73, 0x05, 0x01, 0x0A, 0x80, 0x00,
0x24, 0x5D, 0x01, 0x00, 0x30, 0x10, 0x23, 0x93, 0x1F, 0x93,
0x96, 0xFE, 0xFE, 0x74, 0x4B, 0xFF, 0xFF, 0x00, 0xC5, 0x00,
0x6C, 0x00, 0x32, 0x0B, 0x84, 0x34, 0x01, 0x08, 0x5E, 0x04,
0xFE, 0xFE, 0xC5, 0x6C, 0x50, 0x0B, 0xF6, 0x02, 0xF8, 0x29,
0x80, 0x00, 0x01, 0xF0, 0x00, 0x70, 0x8A, 0x53, 0x12, 0x64,
0x01, 0x01, 0x00, 0x6B, 0x00, 0x05, 0x18, 0x00, 0x0C, 0x00,
0x00, 0x00, 0x49, 0x00, 0x20, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
},
.buf_len = 217,
},
{
.procedure_name = "Initial context setup response",
.buffer = {
0x20, 0x09, 0x00, 0x26, 0x00, 0x00, 0x03, 0x00, 0x00, 0x40,
0x05, 0xC0, 0x01, 0x10, 0xCE, 0xCC, 0x00, 0x08, 0x40, 0x03,
0x40, 0x01, 0xB3, 0x00, 0x33, 0x40, 0x0F, 0x00, 0x00, 0x32,
0x40, 0x0A, 0x0A, 0x1F, 0x0A, 0x05, 0x02, 0x05, 0x00, 0x0F,
0x7A, 0x03,
},
.buf_len = 42,
}
};
static int compare_buffer(uint8_t *buffer, uint32_t length_buffer,
uint8_t *pattern,
uint32_t length_pattern)
{
int i;
if (length_buffer != length_pattern) {
printf("Length mismatch, expecting %d bytes, got %d bytes\n", length_pattern,
length_buffer);
return -1;
}
for (i = 0; i < length_buffer; i++) {
if (pattern[i] != buffer[i]) {
printf("Mismatch fount in bytes %d\nExpecting 0x%02x, got 0x%02x\n",
i, pattern[i], buffer[i]);
}
}
return 0;
}
int main(int argc, char *argv[])
{
int i;
asn1_xer_print = 2;
if (argc > 1) {
asn_debug = 1;
}
for (i = 0; i < sizeof(s1ap_test) / sizeof(s1ap_test_t); i++) {
S1AP_S1AP_PDU_t pdu;
uint8_t *buffer;
uint32_t length;
memset(&pdu, 0, sizeof(pdu));
printf("Trying to decode %s procedure with asn1c decoder\n",
s1ap_test[i].procedure_name);
if (s1ap_mme_decode_pdu(&pdu, s1ap_test[i].buffer,
s1ap_test[i].buf_len) < 0) {
if (s1ap_eNB_decode_pdu(&pdu, s1ap_test[i].buffer,
s1ap_test[i].buf_len) < 0) {
printf("Failed to decode this message\n");
} else {
printf("Succesfully decoded %s with eNB decoder\n", s1ap_test[i].procedure_name);
}
} else {
printf("Succesfully decoded %s with MME decoder\n", s1ap_test[i].procedure_name);
}
printf("Trying to encode %s procedure with asn1c encoder\n",
s1ap_test[i].procedure_name);
if (s1ap_eNB_encode_pdu(&pdu, &buffer, &length) < 0) {
printf("Failed to encode this message on MME side, trying eNB side\n");
} else {
compare_buffer(buffer, length, s1ap_test[i].buffer, s1ap_test[i].buf_len);
free(buffer);
}
}
return 0;
}
/*
* 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
*/
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/sctp.h>
#include <arpa/inet.h>
#include "sctp_primitives_client.h"
#include "s1ap_common.h"
#include "s1ap_eNB.h"
#include "s1ap_mme.h"
#include "s1ap_eNB_encoder.h"
#include "s1ap_eNB_decoder.h"
int recv_callback(uint32_t assocId,
uint32_t stream,
uint8_t *buffer,
uint32_t length)
{
free(buffer);
return 0;
}
int sctp_connected(void *args,
uint32_t assocId,
uint32_t instreams,
uint32_t outstreams)
{
return 0;
}
int main(int argc, char *argv[])
{
asn_enc_rval_t retVal;
int i;
for (i = 0; i < nb_eNB; i++) {
sctp_connect_to_remote_host(ip_addr, 36412, NULL, sctp_connected, recv_callback);
}
while (1) {
sleep(1);
}
sctp_terminate();
return(0);
}
/*
* 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
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <syscall.h>
#include "UTIL/LOG/log_extern.h"
#include "assertions.h"
#include "intertask_interface.h"
#include "sctp_eNB_task.h"
#include "s1ap_eNB.h"
#include "enb_config.h"
#include "oaisim_mme_test_s1c.h"
# define ENB_REGISTER_RETRY_DELAY 5
//------------------------------------------------------------------------------
static void get_options (int argc, char **argv);
static uint32_t eNB_app_register(const uint32_t enb_id_start, const uint32_t enb_id_end, const Enb_properties_array_t *enb_properties);
static void *eNB_app_task (void *args_p);
void mme_test_s1_start_test(instance_t instance);
//------------------------------------------------------------------------------
static char *conf_config_file_name = NULL;
const Enb_properties_array_t *enb_properties = NULL;
int16_t glog_level = LOG_INFO;
int16_t glog_verbosity = LOG_MED;
s1c_test_t s1c_test = {
0, // scenario_index
0, // tx_next_message_index
0, // rx_next_message_index
0 // assoc_id
};
//------------------------------------------------------------------------------
static void get_options (int argc, char **argv)
//------------------------------------------------------------------------------
{
int c;
while ((c = getopt_long (argc, argv, "K:g:G:O:",NULL,NULL)) != -1) {
switch (c) {
case 'O':
conf_config_file_name = optarg;
break;
case 'g':
glog_level=atoi(optarg); // value between 1 - 9
break;
case 'G':
glog_verbosity=atoi(optarg);// value from 0, 0x5, 0x15, 0x35, 0x75
break;
default:
break;
}
}
AssertFatal(conf_config_file_name != NULL,"Please provide a configuration file\n");
}
//------------------------------------------------------------------------------
static uint32_t eNB_app_register(const uint32_t enb_id_start, const uint32_t enb_id_end, const Enb_properties_array_t *enb_properties)
//------------------------------------------------------------------------------
{
uint32_t enb_id;
uint32_t mme_id;
MessageDef *msg_p;
uint32_t register_enb_pending = 0;
char *str = NULL;
struct in_addr addr;
// 1 eNB should be max.
// 1 eNB should be max.
for (enb_id = enb_id_start; (enb_id < enb_id_end) ; enb_id++) {
{
s1ap_register_enb_req_t *s1ap_register_eNB;
/* note: there is an implicit relationship between the data structure and the message name */
msg_p = itti_alloc_new_message (TASK_ENB_APP, S1AP_REGISTER_ENB_REQ);
s1ap_register_eNB = &S1AP_REGISTER_ENB_REQ(msg_p);
/* Some default/random parameters */
s1ap_register_eNB->eNB_id = enb_properties->properties[enb_id]->eNB_id;
s1ap_register_eNB->cell_type = enb_properties->properties[enb_id]->cell_type;
s1ap_register_eNB->eNB_name = enb_properties->properties[enb_id]->eNB_name;
s1ap_register_eNB->tac = enb_properties->properties[enb_id]->tac;
s1ap_register_eNB->mcc = enb_properties->properties[enb_id]->mcc;
s1ap_register_eNB->mnc = enb_properties->properties[enb_id]->mnc;
s1ap_register_eNB->mnc_digit_length = enb_properties->properties[enb_id]->mnc_digit_length;
s1ap_register_eNB->default_drx = enb_properties->properties[enb_id]->pcch_defaultPagingCycle[0];
s1ap_register_eNB->nb_mme = enb_properties->properties[enb_id]->nb_mme;
AssertFatal (s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS, "Too many MME for eNB %d (%d/%d)!", enb_id, s1ap_register_eNB->nb_mme,
S1AP_MAX_NB_MME_IP_ADDRESS);
for (mme_id = 0; mme_id < s1ap_register_eNB->nb_mme; mme_id++) {
s1ap_register_eNB->mme_ip_address[mme_id].ipv4 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4;
s1ap_register_eNB->mme_ip_address[mme_id].ipv6 = enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6;
strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv4_address,
enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv4_address,
sizeof(s1ap_register_eNB->mme_ip_address[0].ipv4_address));
strncpy (s1ap_register_eNB->mme_ip_address[mme_id].ipv6_address,
enb_properties->properties[enb_id]->mme_ip_address[mme_id].ipv6_address,
sizeof(s1ap_register_eNB->mme_ip_address[0].ipv6_address));
}
s1ap_register_eNB->enb_ip_address.ipv6 = 0;
s1ap_register_eNB->enb_ip_address.ipv4 = 1;
addr.s_addr = enb_properties->properties[enb_id]->enb_ipv4_address_for_S1_MME;
str = inet_ntoa(addr);
strcpy(s1ap_register_eNB->enb_ip_address.ipv4_address, str);
itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
register_enb_pending++;
}
}
return register_enb_pending;
}
//------------------------------------------------------------------------------
static void *eNB_app_task(void *args_p)
//------------------------------------------------------------------------------
{
const Enb_properties_array_t *enb_properties_p = NULL;
uint32_t enb_nb = 1; /* Default number of eNB is 1 */
uint32_t enb_id_start = 0;
uint32_t enb_id_end = enb_id_start + enb_nb;
uint32_t register_enb_pending;
uint32_t registered_enb;
long enb_register_retry_timer_id;
MessageDef *msg_p = NULL;
const char *msg_name = NULL;
instance_t instance;
int result;
itti_mark_task_ready (TASK_ENB_APP);
enb_properties_p = enb_config_get();
AssertFatal (enb_nb <= enb_properties_p->number,
"Number of eNB is greater than eNB defined in configuration file (%d/%d)!",
enb_nb, enb_properties_p->number);
/* Try to register each eNB */
registered_enb = 0;
register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
do {
// Wait for a message
itti_receive_msg (TASK_ENB_APP, &msg_p);
msg_name = ITTI_MSG_NAME (msg_p);
instance = ITTI_MSG_DESTINATION_INSTANCE (msg_p);
switch (ITTI_MSG_ID(msg_p)) {
case TERMINATE_MESSAGE:
itti_exit_task ();
break;
case MESSAGE_TEST:
LOG_I(ENB_APP, "Received %s\n", ITTI_MSG_NAME(msg_p));
break;
case S1AP_REGISTER_ENB_CNF:
LOG_I(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
S1AP_REGISTER_ENB_CNF(msg_p).nb_mme);
DevAssert(register_enb_pending > 0);
register_enb_pending--;
/* Check if at least eNB is registered with one MME */
if (S1AP_REGISTER_ENB_CNF(msg_p).nb_mme > 0) {
registered_enb++;
}
/* Check if all register eNB requests have been processed */
if (register_enb_pending == 0) {
if (registered_enb == enb_nb) {
mme_test_s1_start_test(instance);
} else {
uint32_t not_associated = enb_nb - registered_enb;
LOG_W(ENB_APP, " %d eNB %s not associated with a MME, retrying registration in %d seconds ...\n",
not_associated, not_associated > 1 ? "are" : "is", ENB_REGISTER_RETRY_DELAY);
/* Restart the eNB registration process in ENB_REGISTER_RETRY_DELAY seconds */
if (timer_setup (ENB_REGISTER_RETRY_DELAY, 0, TASK_ENB_APP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
NULL, &enb_register_retry_timer_id) < 0) {
LOG_E(ENB_APP, " Can not start eNB register retry timer, use \"sleep\" instead!\n");
sleep(ENB_REGISTER_RETRY_DELAY);
/* Restart the registration process */
registered_enb = 0;
register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
}
}
}
break;
case S1AP_DEREGISTERED_ENB_IND:
LOG_W(ENB_APP, "[eNB %d] Received %s: associated MME %d\n", instance, msg_name,
S1AP_DEREGISTERED_ENB_IND(msg_p).nb_mme);
/* TODO handle recovering of registration */
break;
case TIMER_HAS_EXPIRED:
LOG_I(ENB_APP, " Received %s: timer_id %d\n", msg_name, TIMER_HAS_EXPIRED(msg_p).timer_id);
if (TIMER_HAS_EXPIRED (msg_p).timer_id == enb_register_retry_timer_id) {
/* Restart the registration process */
registered_enb = 0;
register_enb_pending = eNB_app_register (enb_id_start, enb_id_end, enb_properties_p);
}
break;
default:
LOG_E(ENB_APP, "Received unexpected message %s\n", msg_name);
break;
}
result = itti_free (ITTI_MSG_ORIGIN_ID(msg_p), msg_p);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
} while (1);
return NULL;
}
//------------------------------------------------------------------------------
void mme_test_s1_start_test(instance_t instance)
//------------------------------------------------------------------------------
{
s1ap_eNB_itti_send_sctp_data_req(instance,
s1c_test.assoc_id,
s1ap_scenarios[s1c_test.scenario_index][s1c_test.tx_next_message_index].buffer,
s1ap_scenarios[s1c_test.scenario_index][s1c_test.tx_next_message_index].buf_len,
s1ap_scenarios[s1c_test.scenario_index][s1c_test.tx_next_message_index].sctp_stream_id);
}
//------------------------------------------------------------------------------
void mme_test_s1_notify_sctp_data_ind(uint32_t assoc_id, int32_t stream, const uint8_t * const data, const uint32_t data_length)
//------------------------------------------------------------------------------
{
}
//------------------------------------------------------------------------------
int main( int argc, char **argv )
//------------------------------------------------------------------------------
{
// initialize the log (see log.h for details)
logInit();
get_options (argc, argv); //Command-line options
set_glog(glog_level, glog_verbosity);
log_set_instance_type (LOG_INSTANCE_ENB);
/* Read eNB configuration file */
enb_properties = enb_config_init(conf_config_file_name);
itti_init(TASK_MAX, tasks_info);
itti_wait_ready(1);
if (itti_create_task (TASK_SCTP, sctp_eNB_task, NULL) < 0) {
LOG_E(SCTP, "Create task for SCTP failed\n");
return -1;
}
if (itti_create_task (TASK_S1AP, s1ap_eNB_task, NULL) < 0) {
LOG_E(S1AP, "Create task for S1AP failed\n");
return -1;
}
if (itti_create_task (TASK_ENB_APP, eNB_app_task, NULL) < 0) {
LOG_E(S1AP, "Create task for S1AP failed\n");
return -1;
}
itti_wait_ready(0);
sleep(30);
logClean();
return 0;
}
/*
* 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
*/
typedef struct s1c_test_s {
int scenario_index;
int tx_next_message_index;
int rx_next_message_index;
int32_t assoc_id;
}s1c_test_t;
void mme_test_s1_start_test(instance_t instance);
void mme_test_s1_notify_sctp_data_ind(uint32_t assoc_id, int32_t stream, const uint8_t * const data, const uint32_t data_length);
/*
* 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
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <syscall.h>
#include "tree.h"
#include "queue.h"
#include "intertask_interface.h"
#include "s1ap_eNB_default_values.h"
#include "s1ap_common.h"
#include "s1ap_eNB_defs.h"
#include "s1ap_eNB_management_procedures.h"
#include "assertions.h"
#include "platform_types.h"
#include "oaisim_mme_test_s1c.h"
void s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind)
{
int result;
DevAssert(sctp_data_ind != NULL);
mme_test_s1_notify_sctp_data_ind(sctp_data_ind->assoc_id, sctp_data_ind->stream,
sctp_data_ind->buffer, sctp_data_ind->buffer_length);
result = itti_free(TASK_UNKNOWN, sctp_data_ind->buffer);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
}
void s1ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream)
{
MessageDef *message_p;
sctp_data_req_t *sctp_data_req;
message_p = itti_alloc_new_message(TASK_S1AP, SCTP_DATA_REQ);
sctp_data_req = &message_p->ittiMsg.sctp_data_req;
sctp_data_req->assoc_id = assoc_id;
sctp_data_req->buffer = buffer;
sctp_data_req->buffer_length = buffer_length;
sctp_data_req->stream = stream;
itti_send_msg_to_task(TASK_SCTP, instance, message_p);
}
void s1ap_handle_s1_setup_message(s1ap_eNB_mme_data_t *mme_desc_p, int sctp_shutdown)
{
if (sctp_shutdown) {
/* A previously connected MME has been shutdown */
/* TODO check if it was used by some eNB and send a message to inform these eNB if there is no more associated MME */
if (mme_desc_p->state == S1AP_ENB_STATE_CONNECTED) {
mme_desc_p->state = S1AP_ENB_STATE_DISCONNECTED;
if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb > 0) {
/* Decrease associated MME number */
mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb --;
}
/* If there are no more associated MME, inform eNB app */
if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb == 0) {
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_S1AP, S1AP_DEREGISTERED_ENB_IND);
S1AP_DEREGISTERED_ENB_IND(message_p).nb_mme = 0;
itti_send_msg_to_task(TASK_ENB_APP, mme_desc_p->s1ap_eNB_instance->instance, message_p);
}
}
} else {
/* Check that at least one setup message is pending */
DevCheck(mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb > 0, mme_desc_p->s1ap_eNB_instance->instance,
mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb, 0);
if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb > 0) {
/* Decrease pending messages number */
mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb --;
}
/* If there are no more pending messages, inform eNB app */
if (mme_desc_p->s1ap_eNB_instance->s1ap_mme_pending_nb == 0) {
MessageDef *message_p;
message_p = itti_alloc_new_message(TASK_S1AP, S1AP_REGISTER_ENB_CNF);
S1AP_REGISTER_ENB_CNF(message_p).nb_mme = mme_desc_p->s1ap_eNB_instance->s1ap_mme_associated_nb;
itti_send_msg_to_task(TASK_ENB_APP, mme_desc_p->s1ap_eNB_instance->instance, message_p);
}
}
}
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp)
{
s1ap_eNB_instance_t *instance_p;
s1ap_eNB_mme_data_t *s1ap_mme_data_p;
DevAssert(sctp_new_association_resp != NULL);
instance_p = s1ap_eNB_get_instance(instance);
DevAssert(instance_p != NULL);
s1ap_mme_data_p = s1ap_eNB_get_MME(instance_p, -1,
sctp_new_association_resp->ulp_cnx_id);
DevAssert(s1ap_mme_data_p != NULL);
if (sctp_new_association_resp->sctp_state != SCTP_STATE_ESTABLISHED) {
S1AP_WARN("Received unsuccessful result for SCTP association (%u), instance %d, cnx_id %u\n",
sctp_new_association_resp->sctp_state,
instance,
sctp_new_association_resp->ulp_cnx_id);
s1ap_handle_s1_setup_message(s1ap_mme_data_p, sctp_new_association_resp->sctp_state == SCTP_STATE_SHUTDOWN);
return;
}
/* Update parameters */
s1ap_mme_data_p->assoc_id = sctp_new_association_resp->assoc_id;
s1ap_mme_data_p->in_streams = sctp_new_association_resp->in_streams;
s1ap_mme_data_p->out_streams = sctp_new_association_resp->out_streams;
/* Prepare new S1 Setup Request */
mme_test_s1_start_test(instance_p, s1ap_mme_data_p);
}
void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
net_ip_address_t *mme_ip_address,
net_ip_address_t *local_ip_addr)
{
MessageDef *message_p = NULL;
sctp_new_association_req_t *sctp_new_association_req_p = NULL;
s1ap_eNB_mme_data_t *s1ap_mme_data_p = NULL;
DevAssert(instance_p != NULL);
DevAssert(mme_ip_address != NULL);
message_p = itti_alloc_new_message(TASK_S1AP, SCTP_NEW_ASSOCIATION_REQ);
sctp_new_association_req_p = &message_p->ittiMsg.sctp_new_association_req;
sctp_new_association_req_p->port = S1AP_PORT_NUMBER;
sctp_new_association_req_p->ppid = S1AP_SCTP_PPID;
memcpy(&sctp_new_association_req_p->remote_address,
mme_ip_address,
sizeof(*mme_ip_address));
memcpy(&sctp_new_association_req_p->local_address,
local_ip_addr,
sizeof(*local_ip_addr));
/* Create new MME descriptor */
s1ap_mme_data_p = calloc(1, sizeof(*s1ap_mme_data_p));
DevAssert(s1ap_mme_data_p != NULL);
s1ap_mme_data_p->cnx_id = s1ap_eNB_fetch_add_global_cnx_id();
sctp_new_association_req_p->ulp_cnx_id = s1ap_mme_data_p->cnx_id;
s1ap_mme_data_p->assoc_id = -1;
s1ap_mme_data_p->s1ap_eNB_instance = instance_p;
STAILQ_INIT(&s1ap_mme_data_p->served_gummei);
/* Insert the new descriptor in list of known MME
* but not yet associated.
*/
RB_INSERT(s1ap_mme_map, &instance_p->s1ap_mme_head, s1ap_mme_data_p);
s1ap_mme_data_p->state = S1AP_ENB_STATE_WAITING;
instance_p->s1ap_mme_nb ++;
instance_p->s1ap_mme_pending_nb ++;
itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
}
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB)
{
s1ap_eNB_instance_t *new_instance;
uint8_t index;
DevAssert(s1ap_register_eNB != NULL);
/* Look if the provided instance already exists */
new_instance = s1ap_eNB_get_instance(instance);
if (new_instance != NULL) {
/* Checks if it is a retry on the same eNB */
DevCheck(new_instance->eNB_id == s1ap_register_eNB->eNB_id, new_instance->eNB_id, s1ap_register_eNB->eNB_id, 0);
DevCheck(new_instance->cell_type == s1ap_register_eNB->cell_type, new_instance->cell_type, s1ap_register_eNB->cell_type, 0);
DevCheck(new_instance->tac == s1ap_register_eNB->tac, new_instance->tac, s1ap_register_eNB->tac, 0);
DevCheck(new_instance->mcc == s1ap_register_eNB->mcc, new_instance->mcc, s1ap_register_eNB->mcc, 0);
DevCheck(new_instance->mnc == s1ap_register_eNB->mnc, new_instance->mnc, s1ap_register_eNB->mnc, 0);
DevCheck(new_instance->mnc_digit_length == s1ap_register_eNB->mnc_digit_length, new_instance->mnc_digit_length, s1ap_register_eNB->mnc_digit_length, 0);
DevCheck(new_instance->default_drx == s1ap_register_eNB->default_drx, new_instance->default_drx, s1ap_register_eNB->default_drx, 0);
} else {
new_instance = calloc(1, sizeof(s1ap_eNB_instance_t));
DevAssert(new_instance != NULL);
RB_INIT(&new_instance->s1ap_ue_head);
RB_INIT(&new_instance->s1ap_mme_head);
/* Copy usefull parameters */
new_instance->instance = instance;
new_instance->eNB_name = s1ap_register_eNB->eNB_name;
new_instance->eNB_id = s1ap_register_eNB->eNB_id;
new_instance->cell_type = s1ap_register_eNB->cell_type;
new_instance->tac = s1ap_register_eNB->tac;
new_instance->mcc = s1ap_register_eNB->mcc;
new_instance->mnc = s1ap_register_eNB->mnc;
new_instance->mnc_digit_length = s1ap_register_eNB->mnc_digit_length;
new_instance->default_drx = s1ap_register_eNB->default_drx;
/* Add the new instance to the list of eNB (meaningfull in virtual mode) */
s1ap_eNB_insert_new_instance(new_instance);
S1AP_DEBUG("Registered new eNB[%d] and %s eNB id %u\n",
instance,
s1ap_register_eNB->cell_type == CELL_MACRO_ENB ? "macro" : "home",
s1ap_register_eNB->eNB_id);
}
DevCheck(s1ap_register_eNB->nb_mme <= S1AP_MAX_NB_MME_IP_ADDRESS,
S1AP_MAX_NB_MME_IP_ADDRESS, s1ap_register_eNB->nb_mme, 0);
/* Trying to connect to provided list of MME ip address */
for (index = 0; index < s1ap_register_eNB->nb_mme; index++) {
s1ap_eNB_register_mme(new_instance, &s1ap_register_eNB->mme_ip_address[index],
&s1ap_register_eNB->enb_ip_address);
}
}
void *s1ap_eNB_task(void *arg)
{
MessageDef *received_msg = NULL;
int result;
S1AP_DEBUG("Starting S1AP layer\n");
s1ap_eNB_prepare_internal_data();
itti_mark_task_ready(TASK_S1AP);
while (1) {
itti_receive_msg(TASK_S1AP, &received_msg);
switch (ITTI_MSG_ID(received_msg)) {
case TERMINATE_MESSAGE:
itti_exit_task();
break;
case S1AP_REGISTER_ENB_REQ: {
/* Register a new eNB.
* in Virtual mode eNBs will be distinguished using the mod_id/
* Each eNB has to send an S1AP_REGISTER_ENB message with its
* own parameters.
*/
s1ap_eNB_handle_register_eNB(ITTI_MSG_DESTINATION_INSTANCE(received_msg),
&S1AP_REGISTER_ENB_REQ(received_msg));
}
break;
case SCTP_NEW_ASSOCIATION_RESP: {
s1ap_eNB_handle_sctp_association_resp(ITTI_MSG_DESTINATION_INSTANCE(received_msg),
&received_msg->ittiMsg.sctp_new_association_resp);
}
break;
case SCTP_DATA_IND: {
s1ap_eNB_handle_sctp_data_ind(&received_msg->ittiMsg.sctp_data_ind);
}
break;
default:
S1AP_ERROR("Received unhandled message: %d:%s\n",
ITTI_MSG_ID(received_msg), ITTI_MSG_NAME(received_msg));
break;
}
result = itti_free (ITTI_MSG_ORIGIN_ID(received_msg), received_msg);
AssertFatal (result == EXIT_SUCCESS, "Failed to free memory (%d)!\n", result);
received_msg = NULL;
}
return NULL;
}
/*
* 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
*/
#ifndef __TEST_OAISIM_MME_TEST_S1C_S1AP__H__
#define __TEST_OAISIM_MME_TEST_S1C_S1AP__H__
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sched.h>
#include <linux/sched.h>
#include <signal.h>
#include <execinfo.h>
#include <getopt.h>
#include <syscall.h>
void s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind);
void s1ap_eNB_itti_send_sctp_data_req(instance_t instance, int32_t assoc_id, uint8_t *buffer,
uint32_t buffer_length, uint16_t stream);
void s1ap_handle_s1_setup_message(s1ap_eNB_mme_data_t *mme_desc_p, int sctp_shutdown);
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
net_ip_address_t *mme_ip_address,
net_ip_address_t *local_ip_addr,
uint16_t in_streams,
uint16_t out_streams);
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB);
void *s1ap_eNB_task(void *arg);
#endif
/*
* 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
*/
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include "oaisim_mme_test_s1c_scenario.h"
int scenario_index = 0;
int scenario_message_index = 0;
int debug = 0;
int error_count = 0;
int break_on_error = 0;
extern s1ap_message_test_t s1ap_scenario1[];
s1ap_message_test_t s1ap_scenarios[][] = {s1ap_scenario1};
/* -1 means invalid */
static const signed char hex_digits[0x100] = {
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
};
//------------------------------------------------------------------------------
void
fail (const char *format, ...)
//------------------------------------------------------------------------------
{
char str[1024];
va_list arg_ptr;
va_start (arg_ptr, format);
vsnprintf ( str, sizeof(str), format, arg_ptr);
va_end (arg_ptr);
fputs(str, stderr);
error_count++;
if (break_on_error)
exit (1);
}
//------------------------------------------------------------------------------
void
success (const char *format, ...)
//------------------------------------------------------------------------------
{
char str[1024];
va_list arg_ptr;
va_start (arg_ptr, format);
vsnprintf ( str, sizeof(str), format, arg_ptr);
va_end (arg_ptr);
fputs(str, stderr);
}
//------------------------------------------------------------------------------
void
escapeprint (const char *str, size_t len)
//------------------------------------------------------------------------------
{
size_t i;
printf (" (length %d bytes):\n\t", (int) len);
for (i = 0; i < len; i++) {
if (((str[i] & 0xFF) >= 'A' && (str[i] & 0xFF) <= 'Z') ||
((str[i] & 0xFF) >= 'a' && (str[i] & 0xFF) <= 'z') ||
((str[i] & 0xFF) >= '0' && (str[i] & 0xFF) <= '9')
|| (str[i] & 0xFF) == ' ' || (str[i] & 0xFF) == '.')
printf ("%c", (str[i] & 0xFF));
else
printf ("\\x%02X", (str[i] & 0xFF));
if ((i + 1) % 16 == 0 && (i + 1) < len)
printf ("'\n\t'");
}
printf ("\n");
}
//------------------------------------------------------------------------------
void
hexprint (const void *_str, size_t len)
//------------------------------------------------------------------------------
{
size_t i;
const char* str = _str;
printf ("\t;; ");
for (i = 0; i < len; i++) {
printf ("%02x ", (str[i] & 0xFF));
if ((i + 1) % 8 == 0)
printf (" ");
if ((i + 1) % 16 == 0 && i + 1 < len)
printf ("\n\t;; ");
}
printf ("\n");
}
//------------------------------------------------------------------------------
void
binprint (const void *_str, size_t len)
//------------------------------------------------------------------------------
{
size_t i;
const char* str = _str;
printf ("\t;; ");
for (i = 0; i < len; i++) {
printf ("%d%d%d%d%d%d%d%d ",
(str[i] & 0xFF) & 0x80 ? 1 : 0,
(str[i] & 0xFF) & 0x40 ? 1 : 0,
(str[i] & 0xFF) & 0x20 ? 1 : 0,
(str[i] & 0xFF) & 0x10 ? 1 : 0,
(str[i] & 0xFF) & 0x08 ? 1 : 0,
(str[i] & 0xFF) & 0x04 ? 1 : 0,
(str[i] & 0xFF) & 0x02 ? 1 : 0, (str[i] & 0xFF) & 0x01 ? 1 : 0);
if ((i + 1) % 3 == 0)
printf (" ");
if ((i + 1) % 6 == 0 && i + 1 < len)
printf ("\n\t;; ");
}
printf ("\n");
}
//------------------------------------------------------------------------------
int
compare_buffer(const uint8_t *buffer, const uint32_t length_buffer,
const uint8_t *pattern, const uint32_t length_pattern)
//------------------------------------------------------------------------------
{
int i;
if (length_buffer != length_pattern) {
printf("Length mismatch, expecting %d bytes, got %d bytes\n", length_pattern,
length_buffer);
hexprint(buffer, length_buffer);
return -1;
}
for (i = 0; i < length_buffer; i++) {
if (pattern[i] != buffer[i]) {
printf("Expecting:\n");
hexprint(pattern, length_pattern);
printf("Received:\n");
hexprint(buffer, length_buffer);
printf("Mismatch fount in byte %d\nExpecting 0x%02x, got 0x%02x\n",
i, pattern[i], buffer[i]);
return -1;
}
}
return 0;
}
//------------------------------------------------------------------------------
unsigned
decode_hex_length(const char *h)
//------------------------------------------------------------------------------
{
const unsigned char *hex = (const unsigned char *) h;
unsigned count;
unsigned i;
for (count = i = 0; hex[i]; i++) {
if (isspace(hex[i]))
continue;
if (hex_digits[hex[i]] < 0)
abort();
count++;
}
if (count % 2)
abort();
return count / 2;
}
//------------------------------------------------------------------------------
int
decode_hex(uint8_t *dst, const char *h)
//------------------------------------------------------------------------------
{
const unsigned char *hex = (const unsigned char *) h;
unsigned i = 0;
for (;;) {
int high, low;
while (*hex && isspace(*hex))
hex++;
if (!*hex)
return 1;
high = hex_digits[*hex++];
if (high < 0)
return 0;
while (*hex && isspace(*hex))
hex++;
if (!*hex)
return 0;
low = hex_digits[*hex++];
if (low < 0)
return 0;
dst[i++] = (high << 4) | low;
}
}
//------------------------------------------------------------------------------
uint8_t *
decode_hex_dup(const char *hex)
//------------------------------------------------------------------------------
{
uint8_t *p;
unsigned length = decode_hex_length(hex);
p = malloc(length * sizeof(uint8_t));
if (decode_hex(p, hex))
return p;
else {
free(p);
return NULL;
}
}
/*
* 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
*/
#ifndef __TEST_OAISIM_MME_TEST_S1C_SCENARIO__H__
#define __TEST_OAISIM_MME_TEST_S1C_SCENARIO__H__
#include <stdlib.h>
#include <stdint.h>
#define MME_TEST_S1_MAX_BUF_LENGTH (1024)
#define MME_TEST_S1_MAX_BYTES_TEST (32)
typedef enum entity_s{
MME,
ENB
} entity_t;
typedef struct s1ap_message_test_s{
char *procedure_name;
uint8_t buffer[MME_TEST_S1_MAX_BUF_LENGTH];
uint16_t dont_check[MME_TEST_S1_MAX_BYTES_TEST]; // bytes index test that can be omitted
uint32_t buf_len;
entity_t originating;
uint16_t sctp_stream_id;
uint32_t assoc_id;
} s1ap_message_test_t;
void fail (const char *format, ...);
void success (const char *format, ...);
void escapeprint (const char *str, size_t len);
void hexprint (const void *_str, size_t len);
void binprint (const void *_str, size_t len);
int compare_buffer(const uint8_t *buffer, const uint32_t length_buffer, const uint8_t *pattern, const uint32_t length_pattern);
unsigned decode_hex_length(const char *h);
int decode_hex(uint8_t *dst, const char *h);
uint8_t *decode_hex_dup(const char *hex);
#endif
/*
* 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
*/
#include <stdlib.h>
#include "oaisim_mme_test_s1c_scenario.h"
// Description succesfull attach of UE, release UE.
s1ap_message_test_t s1ap_scenario1[] = {
{
.procedure_name = "id-initialUEMessage",
.buffer = {
0x00, 0x0C,
0x00, 0x5C, 0x00, 0x00, 0x05, 0x00, 0x08, 0x00, 0x04, 0x80, 0x06, 0x69, 0x2D, 0x00, 0x1A, 0x00,
0x32, 0x31, 0x07, 0x41, 0x71, 0x08, 0x29, 0x80, 0x39, 0x00, 0x00, 0x00, 0x00, 0x10, 0x02, 0xE0,
0xE0, 0x00, 0x20, 0x02, 0x01, 0xD0, 0x11, 0x27, 0x1A, 0x80, 0x80, 0x21, 0x10, 0x01, 0x00, 0x00,
0x10, 0x81, 0x06, 0x00, 0x00, 0x00, 0x00, 0x83, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x00,
0x00, 0x0A, 0x00, 0x00, 0x43, 0x00, 0x06, 0x00, 0x02, 0xF8, 0x39, 0x00, 0x01, 0x00, 0x64, 0x40,
0x08, 0x00, 0x02, 0xF8, 0x39, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x86, 0x40, 0x01, 0x30
},
.dont_check = {
-1
},
.buf_len = 96,
.sctp_stream_id = 1,
.originating = ENB,
},
{
.procedure_name = "id-downlinkNASTransport, Authentication request",
.buffer = {
0x00, 0x0B,
0x00, 0x3D, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xC0, 0x80, 0x00, 0x15, 0x20, 0x00, 0x08,
0x00, 0x04, 0x80, 0x06, 0x69, 0x2D, 0x00, 0x1A, 0x00, 0x25, 0x24, 0x07, 0x52, 0x00, 0xD3, 0xB5,
0xF0, 0x89, 0x68, 0x02, 0x66, 0x5A, 0x08, 0xE6, 0x51, 0xC7, 0x29, 0x6B, 0x4D, 0xA0, 0x10, 0xDD,
0x04, 0x53, 0xC8, 0x3F, 0x94, 0x80, 0x00, 0x03, 0xAF, 0x2F, 0x49, 0xF3, 0xC8, 0x38, 0x90, 0x00,
0x00, 0x00
},
.dont_check = {
-1
},
.buf_len = 65,
.sctp_stream_id = 1,
.originating = MME,
},
{
.procedure_name = "id-uplinkNASTransport, 0xAuthentication response",
.buffer = {
0x00, 0x0d,
0x40, 0x3a, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x80, 0x00, 0x15, 0x20, 0x00, 0x08,
0x00, 0x04, 0x80, 0x06, 0x69, 0x2d, 0x00, 0x1a, 0x00, 0x0C, 0x0b, 0x07, 0x53, 0x08, 0x11, 0x82,
0x98, 0x98, 0x3b, 0xca, 0xF2, 0x97, 0x00, 0x64, 0x40, 0x08, 0x00, 0x02, 0xF8, 0x39, 0x00, 0x00,
0xe0, 0x00, 0x00, 0x43, 0x40, 0x06, 0x00, 0x02, 0xF8, 0x39, 0x00, 0x01, 0x00, 0x00
},
.dont_check = {
-1
},
.buf_len = 62,
.sctp_stream_id = 1,
.originating = ENB,
},
{
.procedure_name = "id-downlinkNASTransport, Security mode command",
.buffer = {
0x00, 0x0b,
0x00, 0x26, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x80, 0x00, 0x15, 0x20, 0x00, 0x08,
0x00, 0x04, 0x80, 0x06, 0x69, 0x2d, 0x00, 0x1a, 0x00, 0x0e, 0x0d, 0x37, 0xFC, 0xc1, 0xda, 0xd9,
0x00, 0x07, 0x5d, 0x02, 0x00, 0x02, 0xe0, 0xe0, 0x00, 0x00
},
.dont_check = {
-1
},
.buf_len = 42,
.sctp_stream_id = 1,
.originating = MME,
},
{
.procedure_name = "id-uplinkNASTransport, Security mode complete",
.buffer = {
0x00, 0x0d,
0x40, 0x37, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x80, 0x00, 0x15, 0x20, 0x00, 0x08,
0x00, 0x04, 0x80, 0x06, 0x69, 0x2d, 0x00, 0x1a, 0x00, 0x09, 0x08, 0x47, 0x1d, 0xd0, 0xbb, 0xad,
0x00, 0x07, 0x5e, 0x00, 0x64, 0x40, 0x08, 0x00, 0x02, 0xF8, 0x39, 0x00, 0x00, 0xe0, 0x00, 0x00,
0x43, 0x40, 0x06, 0x00, 0x02, 0xF8, 0x39, 0x00, 0x01, 0x00
},
.dont_check = {
-1
},
.buf_len = 59,
.sctp_stream_id = 1,
.originating = ENB,
},
{
.procedure_name = "id-InitialContextSetup, InitialContextSetupRequest , Attach accept, Activate default EPS bearer context request",
.buffer = {
0x00, 0x09,
0x00, 0x80, 0xba, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x80, 0x00, 0x15, 0x20, 0x00,
0x08, 0x00, 0x04, 0x80, 0x06, 0x69, 0x2d, 0x00, 0x42, 0x00, 0x0a, 0x18, 0x05, 0xF5, 0xe1, 0x00,
0x60, 0x02, 0xFa, 0xF0, 0x80, 0x00, 0x18, 0x00, 0x67, 0x00, 0x00, 0x34, 0x00, 0x62, 0x45, 0x00,
0x09, 0x04, 0x0f, 0x80, 0x7f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x53, 0x27, 0x8b, 0xe6,
0x60, 0xb5, 0x01, 0x07, 0x42, 0x01, 0x4a, 0x06, 0x20, 0x02, 0xF8, 0x39, 0x00, 0x01, 0x00, 0x31,
0x52, 0x01, 0xc1, 0x01, 0x09, 0x09, 0x03, 0x6f, 0x61, 0x69, 0x04, 0x69, 0x70, 0x76, 0x34, 0x05,
0x01, 0xc0, 0xbb, 0x00, 0x02, 0x5e, 0x04, 0xFe, 0xFe, 0xde, 0x9e, 0x27, 0x14, 0x80, 0x80, 0x21,
0x10, 0x03, 0x00, 0x00, 0x10, 0x81, 0x06, 0xc0, 0xa8, 0x0C, 0x64, 0x83, 0x06, 0xc0, 0xa8, 0x6a,
0x0C, 0x50, 0x0b, 0xF6, 0x02, 0xF8, 0x39, 0x80, 0x00, 0x01, 0x78, 0x00, 0x0C, 0x20, 0x17, 0x2C,
0x00, 0x6b, 0x00, 0x05, 0x10, 0x00, 0x02, 0x00, 0x00, 0x00, 0x49, 0x00, 0x20, 0xFa, 0x59, 0x15,
0x4e, 0x32, 0x95, 0x04, 0x2d, 0x35, 0xa4, 0x47, 0xc3, 0x80, 0xab, 0x63, 0xd8, 0xe6, 0x91, 0x83,
0x6C, 0x9a, 0xF0, 0xed, 0x85, 0x38, 0xa8, 0x27, 0x41, 0x6b, 0x2b, 0x64, 0x86, 0x00
},
.dont_check = {
-1
},
.buf_len = 191,
.sctp_stream_id = 1,
.originating = MME,
},
{
.procedure_name = "id-UECapabilityInfoIndication",
.buffer = {
0x00, 0x16,
0x40, 0x2C, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x80, 0x00, 0x15, 0x20, 0x00, 0x08,
0x00, 0x04, 0x80, 0x06, 0x69, 0x2d, 0x00, 0x4a, 0x40, 0x14, 0x13, 0x81, 0x20, 0x00, 0x03, 0x00,
0x10, 0x60, 0xe0, 0xc1, 0xF8, 0x3f, 0x07, 0xe0 ,0xfd, 0x78, 0x37, 0x62, 0x00, 0x00
},
.dont_check = {
-1
},
.buf_len = 48,
.originating = ENB,
},
{
.procedure_name = "id-InitialContextSetup, InitialContextSetupResponse ",
.buffer = {
0x20, 0x09,
0x00, 0x27, 0x00, 0x00, 0x03, 0x00, 0x00, 0x40, 0x05, 0xc0, 0x80, 0x00, 0x15, 0x20, 0x00, 0x08,
0x40, 0x04, 0x80, 0x06, 0x69, 0x2d, 0x00, 0x33, 0x40, 0x0f, 0x00, 0x00, 0x32, 0x40, 0x0a, 0x0a,
0x1f, 0x7f, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01
},
.dont_check = {
-1
},
.buf_len = 64,
.sctp_stream_id = 1,
.originating = ENB,
},
{
.procedure_name = "id-uplinkNASTransport, Attach complete, Activate default EPS bearer context accept",
.buffer = {
0x00, 0x0d,
0x05, 0x00, 0x00, 0x00, 0x05, 0xc0, 0x80, 0x00, 0x15, 0x20, 0x00, 0x08, 0x00, 0x04, 0x80, 0x06,
0x69, 0x2d, 0x00, 0x1a, 0x00, 0x0e, 0x0d, 0x27, 0xc7, 0x8f, 0x5a, 0xd2, 0x01, 0x07, 0x43, 0x00,
0x03, 0x52, 0x00, 0xc2, 0x00, 0x64, 0x40, 0x08, 0x00, 0x02, 0xF8, 0x39, 0x00, 0x00, 0xe0, 0x00,
0x00, 0x43, 0x40, 0x06, 0x00, 0x02, 0xF8, 0x39, 0x00, 0x01
},
.dont_check = {
-1
},
.buf_len = 64,
.sctp_stream_id = 1,
.originating = ENB,
}
};
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment