From e58be6bbc14cc1b1bde0a126d9bd9bd9206bca8c Mon Sep 17 00:00:00 2001
From: gauthier <lionel.gauthier@eurecom.fr>
Date: Mon, 23 Nov 2015 16:54:44 +0100
Subject: [PATCH] Remaining TODO fill assoc_id and mme_ue_id of packets
---
cmake_targets/CMakeLists.txt | 5 +-
openair3/TEST/EPC_TEST/generate_scenario.c | 4 +-
openair3/TEST/EPC_TEST/generic_scenario.xsl | 144 ++++--
openair3/TEST/EPC_TEST/play_scenario.c | 309 ++++++++++--
openair3/TEST/EPC_TEST/play_scenario.h | 186 +++++++-
openair3/TEST/EPC_TEST/play_scenario_fsm.c | 319 +++++++++++--
openair3/TEST/EPC_TEST/play_scenario_parse.c | 27 +-
openair3/TEST/EPC_TEST/play_scenario_s1ap.c | 445 +++++++++++++++++-
.../EPC_TEST/play_scenario_s1ap_eNB_defs.h | 250 ++++++++++
9 files changed, 1518 insertions(+), 171 deletions(-)
create mode 100644 openair3/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h
diff --git a/cmake_targets/CMakeLists.txt b/cmake_targets/CMakeLists.txt
index 148aae2419..bcf90bdb83 100644
--- a/cmake_targets/CMakeLists.txt
+++ b/cmake_targets/CMakeLists.txt
@@ -1667,17 +1667,16 @@ add_executable(test_epc_play_scenario
${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_eNB_defs.h
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario_sctp.c
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario.h
- ${OPENAIR2_DIR}/ENB_APP/enb_config.h
${OPENAIR2_DIR}/COMMON/commonDef.h
${OPENAIR2_DIR}/COMMON/messages_def.h
${OPENAIR2_DIR}/COMMON/messages_types.h
- ${OPENAIR3_DIR}/S1AP/s1ap_eNB_defs.h
${OPENAIR_BIN_DIR}/messages_xml.h
)
target_link_libraries (test_epc_play_scenario
- -Wl,--start-group RRC_LIB S1AP_LIB S1AP_ENB X2AP_LIB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} L2 -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
+ -Wl,--start-group RRC_LIB S1AP_LIB X2AP_LIB GTPV1U LIB_NAS_UE SECU_CN UTIL HASHTABLE SCTP_CLIENT UDP SCHED_LIB PHY LFDS ${ITTI_LIB} ${MSC_LIB} -Wl,--end-group pthread m rt crypt sctp ${LIBXML2_LIBRARIES} ${LIBXSLT_LIBRARIES} ${CRYPTO_LIBRARIES} ${OPENSSL_LIBRARIES} ${NETTLE_LIBRARIES} ${CONFIG_LIBRARIES}
)
diff --git a/openair3/TEST/EPC_TEST/generate_scenario.c b/openair3/TEST/EPC_TEST/generate_scenario.c
index 8f39b9873e..9f4e16baef 100644
--- a/openair3/TEST/EPC_TEST/generate_scenario.c
+++ b/openair3/TEST/EPC_TEST/generate_scenario.c
@@ -228,7 +228,7 @@ int generate_test_scenario(const char const * test_nameP, const char const * pdm
for (i = 0; i < g_enb_properties.number; i++) {
// eNB S1-C IPv4 address
- sprintf(astring, "enb_s1c%d", i);
+ 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));
@@ -236,7 +236,7 @@ int generate_test_scenario(const char const * test_nameP, const char const * pdm
// MME S1-C IPv4 address
for (j = 0; j < g_enb_properties.properties[i]->nb_mme; j++) {
- sprintf(astring, "mme_s1c%d_%d", i, 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");
diff --git a/openair3/TEST/EPC_TEST/generic_scenario.xsl b/openair3/TEST/EPC_TEST/generic_scenario.xsl
index 1d49b4942e..592bef83d4 100644
--- a/openair3/TEST/EPC_TEST/generic_scenario.xsl
+++ b/openair3/TEST/EPC_TEST/generic_scenario.xsl
@@ -8,30 +8,30 @@
/>
<!-- Ugly but no time to find a better way in XSLT 1.0 (map/list)-->
- <xsl:param name="enb_s1c0" select="'0.0.0.0'"/>
- <xsl:param name="enb_s1c1" select="'0.0.0.0'"/>
- <xsl:param name="enb_s1c2" select="'0.0.0.0'"/>
- <xsl:param name="enb_s1c3" select="'0.0.0.0'"/>
- <xsl:param name="enb_s1c4" select="'0.0.0.0'"/>
- <xsl:param name="enb_s1c5" select="'0.0.0.0'"/>
- <xsl:param name="enb_s1c6" select="'0.0.0.0'"/>
- <xsl:param name="enb_s1c7" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c0_0" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c0_1" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c0_2" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c0_3" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c1_0" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c1_1" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c1_2" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c1_3" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c2_0" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c2_1" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c2_2" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c2_3" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c3_0" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c3_1" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c3_2" select="'0.0.0.0'"/>
- <xsl:param name="mme_s1c3_3" select="'0.0.0.0'"/>
+ <xsl:param name="enb0_s1c" select="'0.0.0.0'"/>
+ <xsl:param name="enb1_s1c" select="'0.0.0.0'"/>
+ <xsl:param name="enb2_s1c" select="'0.0.0.0'"/>
+ <xsl:param name="enb3_s1c" select="'0.0.0.0'"/>
+ <xsl:param name="enb4_s1c" select="'0.0.0.0'"/>
+ <xsl:param name="enb5_s1c" select="'0.0.0.0'"/>
+ <xsl:param name="enb6_s1c" select="'0.0.0.0'"/>
+ <xsl:param name="enb7_s1c" select="'0.0.0.0'"/>
+ <xsl:param name="mme0_s1c_0" select="'0.0.0.0'"/>
+ <xsl:param name="mme0_s1c_1" select="'0.0.0.0'"/>
+ <xsl:param name="mme0_s1c_2" select="'0.0.0.0'"/>
+ <xsl:param name="mme0_s1c_3" select="'0.0.0.0'"/>
+ <xsl:param name="mme1_s1c_0" select="'0.0.0.0'"/>
+ <xsl:param name="mme1_s1c_1" select="'0.0.0.0'"/>
+ <xsl:param name="mme1_s1c_2" select="'0.0.0.0'"/>
+ <xsl:param name="mme1_s1c_3" select="'0.0.0.0'"/>
+ <xsl:param name="mme2_s1c_0" select="'0.0.0.0'"/>
+ <xsl:param name="mme2_s1c_1" select="'0.0.0.0'"/>
+ <xsl:param name="mme2_s1c_2" select="'0.0.0.0'"/>
+ <xsl:param name="mme2_s1c_3" select="'0.0.0.0'"/>
+ <xsl:param name="mme3_s1c_0" select="'0.0.0.0'"/>
+ <xsl:param name="mme3_s1c_1" select="'0.0.0.0'"/>
+ <xsl:param name="mme3_s1c_2" select="'0.0.0.0'"/>
+ <xsl:param name="mme3_s1c_3" select="'0.0.0.0'"/>
<xsl:param name="ip_address" select="'0.0.0.0'"/>
@@ -39,30 +39,30 @@
<xsl:template name="reverse_ip">
<xsl:param name="ip_address"/>
<xsl:choose>
- <xsl:when test="$ip_address=$enb_s1c0">enb_s1c0</xsl:when>
- <xsl:when test="$ip_address=$enb_s1c1">enb_s1c1</xsl:when>
- <xsl:when test="$ip_address=$enb_s1c2">enb_s1c2</xsl:when>
- <xsl:when test="$ip_address=$enb_s1c3">enb_s1c3</xsl:when>
- <xsl:when test="$ip_address=$enb_s1c4">enb_s1c4</xsl:when>
- <xsl:when test="$ip_address=$enb_s1c5">enb_s1c5</xsl:when>
- <xsl:when test="$ip_address=$enb_s1c6">enb_s1c6</xsl:when>
- <xsl:when test="$ip_address=$enb_s1c7">enb_s1c7</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c0_0">mme_s1c0_0</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c0_1">mme_s1c0_1</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c0_2">mme_s1c0_2</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c0_3">mme_s1c0_3</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c1_0">mme_s1c1_0</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c1_1">mme_s1c1_1</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c1_2">mme_s1c1_2</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c1_3">mme_s1c1_3</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c2_0">mme_s1c2_0</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c2_1">mme_s1c2_1</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c2_2">mme_s1c2_2</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c2_3">mme_s1c2_3</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c3_0">mme_s1c3_0</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c3_1">mme_s1c3_1</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c3_2">mme_s1c3_2</xsl:when>
- <xsl:when test="$ip_address=$mme_s1c3_3">mme_s1c3_3</xsl:when>
+ <xsl:when test="$ip_address=$enb0_s1c">enb0_s1c</xsl:when>
+ <xsl:when test="$ip_address=$enb1_s1c">enb1_s1c</xsl:when>
+ <xsl:when test="$ip_address=$enb2_s1c">enb2_s1c</xsl:when>
+ <xsl:when test="$ip_address=$enb3_s1c">enb3_s1c</xsl:when>
+ <xsl:when test="$ip_address=$enb4_s1c">enb4_s1c</xsl:when>
+ <xsl:when test="$ip_address=$enb5_s1c">enb5_s1c</xsl:when>
+ <xsl:when test="$ip_address=$enb6_s1c">enb6_s1c</xsl:when>
+ <xsl:when test="$ip_address=$enb7_s1c">enb7_s1c</xsl:when>
+ <xsl:when test="$ip_address=$mme0_s1c_0">mme0_s1c_0</xsl:when>
+ <xsl:when test="$ip_address=$mme0_s1c_1">mme0_s1c_1</xsl:when>
+ <xsl:when test="$ip_address=$mme0_s1c_2">mme0_s1c_2</xsl:when>
+ <xsl:when test="$ip_address=$mme0_s1c_3">mme0_s1c_3</xsl:when>
+ <xsl:when test="$ip_address=$mme1_s1c_0">mme1_s1c_0</xsl:when>
+ <xsl:when test="$ip_address=$mme1_s1c_1">mme1_s1c_1</xsl:when>
+ <xsl:when test="$ip_address=$mme1_s1c_2">mme1_s1c_2</xsl:when>
+ <xsl:when test="$ip_address=$mme1_s1c_3">mme1_s1c_3</xsl:when>
+ <xsl:when test="$ip_address=$mme2_s1c_0">mme2_s1c_0</xsl:when>
+ <xsl:when test="$ip_address=$mme2_s1c_1">mme2_s1c_1</xsl:when>
+ <xsl:when test="$ip_address=$mme2_s1c_2">mme2_s1c_2</xsl:when>
+ <xsl:when test="$ip_address=$mme2_s1c_3">mme2_s1c_3</xsl:when>
+ <xsl:when test="$ip_address=$mme3_s1c_0">mme3_s1c_0</xsl:when>
+ <xsl:when test="$ip_address=$mme3_s1c_1">mme3_s1c_1</xsl:when>
+ <xsl:when test="$ip_address=$mme3_s1c_2">mme3_s1c_2</xsl:when>
+ <xsl:when test="$ip_address=$mme3_s1c_3">mme3_s1c_3</xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">ERROR: Cannot reverse resolv IP <xsl:value-of select="."/> !
</xsl:message>
@@ -70,6 +70,26 @@
</xsl:choose>
</xsl:template>
+ <xsl:template name="enb_ip_2_enb_instance">
+ <xsl:param name="ip_address"/>
+ <xsl:choose>
+ <xsl:when test="$ip_address=$enb0_s1c">0</xsl:when>
+ <xsl:when test="$ip_address=$enb1_s1c">1</xsl:when>
+ <xsl:when test="$ip_address=$enb2_s1c">2</xsl:when>
+ <xsl:when test="$ip_address=$enb3_s1c">3</xsl:when>
+ <xsl:when test="$ip_address=$enb4_s1c">4</xsl:when>
+ <xsl:when test="$ip_address=$enb5_s1c">5</xsl:when>
+ <xsl:when test="$ip_address=$enb6_s1c">6</xsl:when>
+ <xsl:when test="$ip_address=$enb7_s1c">7</xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">ERROR: Cannot set eNB instance <xsl:value-of select="."/> !
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+
+
<xsl:template name="chunktype2str">
<xsl:param name="chunk_type"/>
<xsl:choose>
@@ -120,8 +140,26 @@
</xsl:variable>
<xsl:variable name="action">
<xsl:choose>
- <xsl:when test="starts-with($ip_src,'enb_s1')">SEND</xsl:when>
- <xsl:when test="starts-with($ip_src,'mme_s1c')">RECEIVE</xsl:when>
+ <xsl:when test="starts-with($ip_src,'enb')">SEND</xsl:when>
+ <xsl:when test="starts-with($ip_src,'mme')">RECEIVE</xsl:when>
+ <xsl:otherwise>
+ <xsl:message terminate="yes">ERROR: UNKNOWN ACTION <xsl:value-of select="."/> !
+ </xsl:message>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="enb_instance">
+ <xsl:choose>
+ <xsl:when test="starts-with($ip_src,'enb')">
+ <xsl:call-template name="enb_ip_2_enb_instance">
+ <xsl:with-param name="ip_address" select="$ip/field[@name='ip.src']/@show"/>
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:when test="starts-with($ip_dst,'enb')">
+ <xsl:call-template name="enb_ip_2_enb_instance">
+ <xsl:with-param name="ip_address" select="$ip/field[@name='ip.dst']/@show"/>
+ </xsl:call-template>
+ </xsl:when>
<xsl:otherwise>
<xsl:message terminate="yes">ERROR: UNKNOWN ACTION <xsl:value-of select="."/> !
</xsl:message>
@@ -156,6 +194,7 @@
<pos_offset value="{$s1ap_pos_offset}"/>
<ip.src value="{$ip_src}"/>
<ip.dst value="{$ip_dst}"/>
+ <eNB.instance value="{$enb_instance}"/>
<!--sctp.data_sid value="{$sctp_data_sid}"/-->
<!--sctp.srcport value="{$sctp_srcport}"/-->
<!--sctp.dstport value="{$sctp_dstport}"/-->
@@ -177,6 +216,7 @@
<pos_offset value="{$sctp_pos_offset}"/>
<ip.src value="{$ip_src}"/>
<ip.dst value="{$ip_dst}"/>
+ <eNB.instance value="{$enb_instance}"/>
<!--sctp.srcport value="{$sctp_srcport}"/-->
<!--sctp.dstport value="{$sctp_dstport}"/-->
<!--sctp.init_nr_in_streams value="{$sctp_init_nr_in_streams}"/-->
@@ -197,6 +237,7 @@
<pos_offset value="{$sctp_pos_offset}"/>
<ip.src value="{$ip_src}"/>
<ip.dst value="{$ip_dst}"/>
+ <eNB.instance value="{$enb_instance}"/>
<!--sctp.data_sid value="{$sctp_data_sid}"/-->
<!--sctp.srcport value="{$sctp_srcport}"/-->
<!--sctp.dstport value="{$sctp_dstport}"/-->
@@ -218,6 +259,7 @@
<pos_offset value="{$sctp_pos_offset}"/>
<ip.src value="{$ip_src}"/>
<ip.dst value="{$ip_dst}"/>
+ <eNB.instance value="{$enb_instance}"/>
<!--sctp.data_sid value="{$sctp_data_sid}"/-->
<!--sctp.srcport value="{$sctp_srcport}"/-->
<!--sctp.dstport value="{$sctp_dstport}"/-->
@@ -233,6 +275,7 @@
<pos_offset value="{$sctp_pos_offset}"/>
<ip.src value="{$ip_src}"/>
<ip.dst value="{$ip_dst}"/>
+ <eNB.instance value="{$enb_instance}"/>
<!--sctp.data_sid value="{$sctp_data_sid}"/-->
<!--sctp.srcport value="{$sctp_srcport}"/-->
<!--sctp.dstport value="{$sctp_dstport}"/-->
@@ -249,6 +292,7 @@
<pos_offset value="{$sctp_pos_offset}"/>
<ip.src value="{$ip_src}"/>
<ip.dst value="{$ip_dst}"/>
+ <eNB.instance value="{$enb_instance}"/>
<!--sctp.data_sid value="{$sctp_data_sid}"/-->
<!--sctp.srcport value="{$sctp_srcport}"/-->
<!--sctp.dstport value="{$sctp_dstport}"/-->
diff --git a/openair3/TEST/EPC_TEST/play_scenario.c b/openair3/TEST/EPC_TEST/play_scenario.c
index fda38dbcb8..f29393f0e7 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.c
+++ b/openair3/TEST/EPC_TEST/play_scenario.c
@@ -48,6 +48,9 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
#include "intertask_interface_init.h"
@@ -63,11 +66,19 @@
#define GS_IS_FILE 1
#define GS_IS_DIR 2
//------------------------------------------------------------------------------
-char *g_openair_dir = NULL;
+char *g_openair_dir = NULL;
+Enb_properties_array_t g_enb_properties;
//------------------------------------------------------------------------------
-extern int xmlLoadExtDtdDefaultValue;
-extern int asn_debug;
-extern int asn1_xer_print;
+extern et_scenario_t *g_scenario;
+extern int xmlLoadExtDtdDefaultValue;
+extern int asn_debug;
+extern int asn1_xer_print;
+
+//------------------------------------------------------------------------------
+// MEMO:
+// Scenario with several eNBs: We may have to create ethx.y interfaces
+//
+
//------------------------------------------------------------------------------
@@ -159,6 +170,7 @@ void et_free_scenario(et_scenario_t* scenario)
packet = next_packet->next;
}
et_free_pointer(scenario);
+ pthread_mutex_destroy(&scenario->fsm_lock);
}
}
@@ -290,17 +302,250 @@ void et_ip_str2et_ip(const xmlChar * const ip_str, et_ip_t * const ip)
AssertFatal (0, "ERROR %s() Could not parse ip address %s!\n", __FUNCTION__, ip_str);
}
}
+#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;
+ 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, %uth 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, %u 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, %u th enb %u 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" : "");
+}
+/*------------------------------------------------------------------------------*/
+const Enb_properties_array_t *et_enb_config_get(void)
+{
+ return &g_enb_properties;
+}
/*------------------------------------------------------------------------------*/
uint32_t et_eNB_app_register(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;
+ 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;
@@ -318,7 +563,6 @@ uint32_t et_eNB_app_register(const Enb_properties_array_t *enb_properties)
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,
@@ -347,20 +591,16 @@ uint32_t et_eNB_app_register(const Enb_properties_array_t *enb_properties)
itti_send_msg_to_task (TASK_S1AP, ENB_MODULE_ID_TO_INSTANCE(enb_id), msg_p);
- register_enb_pending++;
+ g_scenario->register_enb_pending++;
}
}
- return register_enb_pending;
+ return g_scenario->register_enb_pending;
}
/*------------------------------------------------------------------------------*/
void *et_eNB_app_task(void *args_p)
{
- const Enb_properties_array_t *enb_properties_p = NULL;
- uint32_t register_enb_pending;
- uint32_t registered_enb;
- long enb_register_retry_timer_id;
- uint32_t enb_id;
+ et_scenario_t *scenario = (et_scenario_t*)args_p;
MessageDef *msg_p = NULL;
const char *msg_name = NULL;
instance_t instance;
@@ -369,14 +609,6 @@ void *et_eNB_app_task(void *args_p)
itti_mark_task_ready (TASK_ENB_APP);
- enb_properties_p = enb_config_get();
-
-
- /* Try to register each eNB */
- registered_enb = 0;
- register_enb_pending = et_eNB_app_register (enb_properties_p);
-
-
do {
// Wait for a message
itti_receive_msg (TASK_ENB_APP, &msg_p);
@@ -389,40 +621,40 @@ void *et_eNB_app_task(void *args_p)
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(register_enb_pending > 0);
- register_enb_pending--;
+ DevAssert(g_scenario->register_enb_pending > 0);
+ g_scenario->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++;
+ g_scenario->registered_enb++;
}
/* Check if all register eNB requests have been processed */
- if (register_enb_pending == 0) {
- if (registered_enb == enb_properties_p->number) {
+ if (scenario->register_enb_pending == 0) {
+ if (scenario->registered_enb == scenario->enb_properties->number) {
/* If all eNB are registered, start scenario */
-
+ et_event_t event;
+ event.code = ET_EVENT_S1C_CONNECTED;
+ et_scenario_fsm_notify_event(event);
} else {
- uint32_t not_associated = enb_properties_p->number - registered_enb;
+ 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, &enb_register_retry_timer_id) < 0) {
+ 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 */
- registered_enb = 0;
- register_enb_pending = et_eNB_app_register (enb_properties_p);
+ scenario->registered_enb = 0;
+ scenario->register_enb_pending = et_eNB_app_register (scenario->enb_properties);
}
}
}
@@ -439,10 +671,10 @@ void *et_eNB_app_task(void *args_p)
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) {
+ if (TIMER_HAS_EXPIRED (msg_p).timer_id == scenario->enb_register_retry_timer_id) {
/* Restart the registration process */
- registered_enb = 0;
- register_enb_pending = et_eNB_app_register (enb_properties_p);
+ scenario->registered_enb = 0;
+ scenario->register_enb_pending = et_eNB_app_register (scenario->enb_properties);
}
break;
@@ -476,7 +708,7 @@ int et_play_scenario(et_scenario_t* const scenario)
}
// create ENB_APP ITTI task: not as same as eNB code
- if (itti_create_task (TASK_ENB_APP, et_eNB_app_task, NULL) < 0) {
+ 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;
}
@@ -523,7 +755,6 @@ et_config_parse_opt_line (
{
int option;
int rv = 0;
- const Enb_properties_array_t *enb_properties_p = NULL;
enum long_option_e {
LONG_OPTION_START = 0x100, /* Start after regular single char options */
@@ -606,7 +837,7 @@ et_config_parse_opt_line (
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);
}
- enb_properties_p = enb_config_init(*enb_config_file_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);
diff --git a/openair3/TEST/EPC_TEST/play_scenario.h b/openair3/TEST/EPC_TEST/play_scenario.h
index 725b5abc0e..3a52c6a0b8 100644
--- a/openair3/TEST/EPC_TEST/play_scenario.h
+++ b/openair3/TEST/EPC_TEST/play_scenario.h
@@ -28,7 +28,7 @@
*******************************************************************************/
/*
- et_scenario.h
+ play_scenario.h
-------------------
AUTHOR : Lionel GAUTHIER
COMPANY : EURECOM
@@ -39,14 +39,121 @@
#define PLAY_SCENARIO_H_
# include <time.h>
# include <stdint.h>
+# include <pthread.h>
# include <libxml/tree.h>
# include <netinet/in.h>
-#include "enb_config.h"
+#include "S1AP-PDU.h"
#include "s1ap_ies_defs.h"
+#include "play_scenario_s1ap_eNB_defs.h"
+#include "hashtable.h"
-# define ET_ENB_REGISTER_RETRY_DELAY 3
+#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 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,
@@ -54,19 +161,17 @@ typedef enum {
ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT,
ET_PACKET_STATUS_SCHEDULED_FOR_SENDING,
ET_PACKET_STATUS_SENT,
- ET_PACKET_STATUS_SENT_WITH_ERRORS,
ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING,
ET_PACKET_STATUS_RECEIVED,
- ET_PACKET_STATUS_RECEIVED_WITH_ERRORS,
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_SCTP,
- ET_FSM_STATE_WAITING_TX_EVENT,
- ET_FSM_STATE_WAITING_RX_EVENT,
+ ET_FSM_STATE_CONNECTING_S1C,
+ ET_FSM_STATE_WAITING_EVENT,
+ ET_FSM_STATE_RUNNING,
ET_FSM_STATE_END
} et_fsm_state_t;
@@ -136,6 +241,7 @@ typedef struct sctp_datahdr_s {
uint16_t stream;
uint16_t ssn;
uint32_t ppid;
+ uint32_t assoc_id; // filled when running scenario
et_s1ap_t payload;
} sctp_datahdr_t;
@@ -182,11 +288,15 @@ typedef struct et_packet_s {
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;
@@ -203,24 +313,37 @@ typedef struct sctp_epoll_s {
} thread_desc_t;
typedef struct et_scenario_s {
- xmlChar *name;
- et_packet_t *list_packet;
-
+ xmlChar *name;
+ et_packet_t *list_packet;
+ //--------------------------
// playing scenario
- et_packet_t *waited_packet;
- et_packet_t *current_packet;
+ //--------------------------
+ Enb_properties_array_t *enb_properties;
+ uint32_t register_enb_pending;
+ uint32_t registered_enb;
+ long enb_register_retry_timer_id;
+
+ pthread_mutex_t fsm_lock;
+ et_fsm_state_t fsm_state;
+
+ hash_table_t *hash_mme2association_id;
+ hash_table_t *hash_old_ue_mme_id2ue_mme_id;
+ struct timeval time_last_tx_packet;
+ struct timeval time_last_rx_packet;
+ et_packet_t *last_rx_packet;
+ et_packet_t *last_tx_packet;
+ et_packet_t *next_packet;
} 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_X2AP,
ET_EVENT_RX_PACKET_TIME_OUT,
- ET_EVENT_TX_PACKET,
- ET_EVENT_STOP,
+ ET_EVENT_TX_TIMED_PACKET,
ET_EVENT_END
} et_event_code_t;
@@ -241,7 +364,8 @@ typedef struct et_event_s {
union {
et_event_init_t init;
et_event_s1ap_data_ind_t s1ap_data_ind;
- et_event_s1ap_data_req_t s1ap_data_req;
+ et_packet_t *tx_timed_packet;
+ et_packet_t *rx_packet_time_out;
} u;
} et_event_t;
@@ -266,16 +390,36 @@ int et_s1ap_decode_unsuccessful_outcome(s1ap_message *message, S1ap_Unsuccessful
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);
//-------------------------
-void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind);
+int et_s1ap_eNB_compare_assoc_id( struct s1ap_eNB_mme_data_s *p1, struct s1ap_eNB_mme_data_s *p2);
+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);
+void 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);
//-------------------------
-int et_scenario_fsm_notify_event_state_null(et_event_t event);
-int et_scenario_fsm_notify_event(et_event_t event);
+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(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);
@@ -297,6 +441,8 @@ 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);
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);
uint32_t 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);
diff --git a/openair3/TEST/EPC_TEST/play_scenario_fsm.c b/openair3/TEST/EPC_TEST/play_scenario_fsm.c
index 6c73793f4d..8e59a98258 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_fsm.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_fsm.c
@@ -35,74 +35,322 @@
EMAIL : Lionel.Gauthier@eurecom.fr
*/
#include <stdio.h>
+#include <sys/time.h>
#include "intertask_interface.h"
#include "platform_types.h"
#include "assertions.h"
#include "play_scenario.h"
+#include "s1ap_ies_defs.h"
+#include "play_scenario_s1ap_eNB_defs.h"
+#include "timer.h"
-
+//------------------------------------------------------------------------------
et_scenario_t *g_scenario = NULL;
-et_fsm_state_t g_fsm_state = ET_FSM_STATE_NULL;
//------------------------------------------------------------------------------
-int et_scenario_fsm_notify_event_state_null(et_event_t event)
+int timeval_subtract (struct timeval * const result, struct timeval * const a, struct timeval * const b)
+{
+ struct timeval b2;
+ b2.tv_sec = b->tv_sec;
+ b2.tv_usec = b->tv_usec;
+
+ /* Perform the carry for the later subtraction by updating y. */
+ if (a->tv_usec < b2.tv_usec) {
+ int nsec = (b2.tv_usec - a->tv_usec) / 1000000 + 1;
+ b2.tv_usec -= 1000000 * nsec;
+ b2.tv_sec += nsec;
+ }
+ if (a->tv_usec - b2.tv_usec > 1000000) {
+ int nsec = (a->tv_usec - b2.tv_usec) / 1000000;
+ b2.tv_usec += 1000000 * nsec;
+ b2.tv_sec -= nsec;
+ }
+
+ /* Compute the time remaining to wait.
+ tv_usec is certainly positive. */
+ result->tv_sec = a->tv_sec - b2.tv_sec;
+ result->tv_usec = a->tv_usec - b2.tv_usec;
+
+ /* Return 1 if result is negative. */
+ return a->tv_sec < b2.tv_sec;
+}
+
+
+//------------------------------------------------------------------------------
+void et_scenario_wait_rx_packet(et_packet_t * const packet)
+{
+ if (timer_setup (ET_FSM_STATE_WAITING_RX_EVENT_DELAY_SEC, 0, TASK_S1AP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
+ NULL, &packet->timer_id) < 0) {
+ AssertFatal(0, " Can not start waiting RX event timer\n");
+ }
+ g_scenario->fsm_state = ET_FSM_STATE_WAITING_EVENT;
+ packet->status = ET_PACKET_STATUS_SCHEDULED_FOR_RECEIVING;
+}
+//------------------------------------------------------------------------------
+void et_scenario_schedule_tx_packet(et_packet_t * const 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_tx = 0;
+ int we_are_too_early = 0;
+
+ 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);
+
+ g_scenario->fsm_state = ET_FSM_STATE_WAITING_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);
+ last_packet_was_tx = timeval_subtract(&offset_tx_rx,&offset_last_tx_packet,&offset_last_rx_packet);
+ if (last_packet_was_tx) {
+ we_are_too_early = timeval_subtract(&offset,&offset_last_tx_packet,&packet->time_relative_to_last_sent_packet);
+ } else {
+ we_are_too_early = timeval_subtract(&offset,&offset_last_rx_packet,&packet->time_relative_to_last_received_packet);
+ }
+ if (we_are_too_early > 0) {
+ // set timer
+ packet->status = ET_PACKET_STATUS_SCHEDULED_FOR_SENDING;
+ if (timer_setup (offset.tv_sec, offset.tv_usec, TASK_S1AP, INSTANCE_DEFAULT, TIMER_ONE_SHOT,
+ NULL, &packet->timer_id) < 0) {
+ AssertFatal(0, " Can not start TX event timer\n");
+ }
+ // Done g_scenario->fsm_state = ET_FSM_STATE_WAITING_TX_EVENT;
+ } else {
+ // send immediately
+ 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->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)
{
- et_packet_t *packet = NULL;
- const Enb_properties_array_t *enb_properties_p = NULL;
- uint32_t register_enb_pending;
+ switch (event.code){
+ 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:
+ AssertFatal(0, "TODO");
+ break;
+ default:
+ AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_RUNNING", event.code);
+ }
+ pthread_mutex_unlock(&g_scenario->fsm_lock);
+ return 0;
+}
+
+//------------------------------------------------------------------------------
+et_fsm_state_t et_scenario_fsm_notify_event_state_waiting(et_event_t event)
+{
+
+ switch (event.code){
+ 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:
+ et_s1ap_process_rx_packet(&event.u.s1ap_data_ind);
+ break;
+ case ET_EVENT_TX_TIMED_PACKET:
+ // send immediately
+ et_s1ap_eNB_itti_send_sctp_data_req(
+ event.u.tx_timed_packet->enb_instance,
+ event.u.tx_timed_packet->sctp_hdr.u.data_hdr.assoc_id,
+ event.u.tx_timed_packet->sctp_hdr.u.data_hdr.payload.binary_stream,
+ event.u.tx_timed_packet->sctp_hdr.u.data_hdr.payload.binary_stream_allocated_size,
+ event.u.tx_timed_packet->sctp_hdr.u.data_hdr.stream);
+ event.u.tx_timed_packet->status = ET_PACKET_STATUS_SENT;
+ g_scenario->fsm_state = ET_FSM_STATE_RUNNING;
+ break;
+
+
+ default:
+ AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_WAITING", event.code);
+ }
+ pthread_mutex_unlock(&g_scenario->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_S1C_CONNECTED:
+ // hack simulate we have been able to get the right timing values
+ AssertFatal(gettimeofday(&g_scenario->time_last_tx_packet, NULL) == 0, "gettimeofday failed");
+ 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_scenario->fsm_lock);
+ return g_scenario->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->next_packet = g_scenario->next_packet->next;
+ 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_scenario->fsm_lock);
+ return g_scenario->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_scenario->fsm_state = ET_FSM_STATE_NULL;
+ pthread_mutex_unlock(&g_scenario->fsm_lock);
+ return g_scenario->fsm_state;
+ break;
+
+ default:
+ AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_CONNECTING_S1C", event.code);
+ }
+ pthread_mutex_unlock(&g_scenario->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_INIT:
AssertFatal(NULL == g_scenario, "Current scenario not ended");
g_scenario = event.u.init.scenario;
- packet = g_scenario->list_packet;
- while (NULL != packet) {
- switch (packet->sctp_hdr.chunk_type) {
+ g_scenario->next_packet = g_scenario->list_packet;
+ 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 (packet->action == ET_PACKET_ACTION_S1C_SEND) {
- } else if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
- g_scenario->waited_packet = packet;
+ if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_SEND) {
+ et_scenario_schedule_tx_packet(g_scenario->next_packet);
+ pthread_mutex_unlock(&g_scenario->fsm_lock);
+ return g_scenario->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->next_packet = g_scenario->next_packet->next;
+ 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_scenario->fsm_lock);
+ return g_scenario->fsm_state;
+ } else {
+ AssertFatal(0, "Invalid packet status %d", g_scenario->next_packet->status);
+ }
} else {
- packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
- packet = packet->next;
+ AssertFatal(0, "Invalid packet action %d", g_scenario->next_packet->action);
}
break;
+
case SCTP_CID_INIT:
case SCTP_CID_INIT_ACK:
- enb_properties_p = enb_config_get();
- /* Try to register each eNB */
- g_fsm_state = ET_FSM_STATE_CONNECTING_SCTP;
- register_enb_pending = et_eNB_app_register (enb_properties_p);
+ 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_scenario->fsm_state = ET_FSM_STATE_CONNECTING_S1C;
+ g_scenario->register_enb_pending = et_eNB_app_register (g_scenario->enb_properties);
+ pthread_mutex_unlock(&g_scenario->fsm_lock);
+ return g_scenario->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:
- packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
- packet = packet->next;
+ 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(packet->sctp_hdr.chunk_type));
+ 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:
- packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
- packet = packet->next;
+ 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);
- return -1;
- break;
-
- case ET_EVENT_STOP:
+ fprintf(stderr, "No Useful packet found in this scenario: %s\n", g_scenario->name);
+ g_scenario->fsm_state = ET_FSM_STATE_NULL;
+ pthread_mutex_unlock(&g_scenario->fsm_lock);
+ return g_scenario->fsm_state;
break;
default:
@@ -112,16 +360,19 @@ int et_scenario_fsm_notify_event_state_null(et_event_t event)
}
//------------------------------------------------------------------------------
-int et_scenario_fsm_notify_event(et_event_t event)
+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);
- switch (g_fsm_state){
+ pthread_mutex_lock(&g_scenario->fsm_lock);
+ switch (g_scenario->fsm_state){
case ET_FSM_STATE_NULL: return et_scenario_fsm_notify_event_state_null(event); break;
- case ET_FSM_STATE_CONNECTING_SCTP: return et_scenario_fsm_notify_event_state_null(event); break;
- case ET_FSM_STATE_WAITING_TX_EVENT: return et_scenario_fsm_notify_event_state_null(event); break;
- case ET_FSM_STATE_WAITING_RX_EVENT: 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_EVENT: return et_scenario_fsm_notify_event_state_waiting(event); break;
+ case ET_FSM_STATE_RUNNING: return et_scenario_fsm_notify_event_state_running(event); break;
default:
- return -1;
+ AssertFatal(0, "Case fsm_state %d not handled", g_scenario->fsm_state);
}
+ pthread_mutex_unlock(&g_scenario->fsm_lock);
+ return g_scenario->fsm_state;
}
diff --git a/openair3/TEST/EPC_TEST/play_scenario_parse.c b/openair3/TEST/EPC_TEST/play_scenario_parse.c
index 236c17963a..f6d8aa73ac 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_parse.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_parse.c
@@ -47,17 +47,19 @@
#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 "enb_config.h"
#include "assertions.h"
#include "play_scenario.h"
//------------------------------------------------------------------------------
#define ENB_CONFIG_MAX_XSLT_PARAMS 32
//------------------------------------------------------------------------------
extern char *g_openair_dir;
-extern Enb_properties_array_t enb_properties;
+extern Enb_properties_array_t g_enb_properties;
//------------------------------------------------------------------------------
void et_parse_s1ap(xmlDocPtr doc, const xmlNode const *s1ap_node, et_s1ap_t * const s1ap)
{
@@ -407,6 +409,10 @@ et_packet_t* et_parse_xml_packet(xmlDocPtr doc, xmlNodePtr node) {
}
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);
}
//}
}
@@ -439,8 +445,11 @@ et_scenario_t* et_generate_scenario(
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
+ scenario = calloc(1, sizeof(*scenario));
+ scenario->name = xml_char; // nodup nofree
+ scenario->fsm_state = ET_FSM_STATE_NULL;
+ pthread_mutex_init(&scenario->fsm_lock, NULL);
+
next_packet = &scenario->list_packet;
for (node = root->children; node != NULL; node = node->next) {
if ((!xmlStrcmp(node->name, (const xmlChar *)"packet"))) {
@@ -509,21 +518,21 @@ int et_generate_xml_scenario(
fprintf(stdout, "Test scenario file: %s\n", xml_in_scenario_filename);
}
- for (i = 0; i < enb_properties.number; i++) {
+ for (i = 0; i < g_enb_properties.number; i++) {
// eNB S1-C IPv4 address
sprintf(astring, "enb_s1c%d", i);
params[nb_params++] = strdup(astring);
- addr.s_addr = enb_properties.properties[i]->enb_ipv4_address_for_S1_MME;
+ 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 < enb_properties.properties[i]->nb_mme; j++) {
+ for (j = 0; j < g_enb_properties.properties[i]->nb_mme; j++) {
sprintf(astring, "mme_s1c%d_%d", i, j);
params[nb_params++] = strdup(astring);
- AssertFatal (enb_properties.properties[i]->mme_ip_address[j].ipv4_address,
+ AssertFatal (g_enb_properties.properties[i]->mme_ip_address[j].ipv4_address,
"Only support MME IPv4 address\n");
- sprintf(astring, "\"%s\"", enb_properties.properties[i]->mme_ip_address[j].ipv4_address);
+ sprintf(astring, "\"%s\"", g_enb_properties.properties[i]->mme_ip_address[j].ipv4_address);
params[nb_params++] = strdup(astring);
}
}
diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
index cb5571c28b..7dd80904ae 100644
--- a/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
+++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap.c
@@ -38,29 +38,173 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
+#include <unistd.h>
+#include <crypt.h>
#include "tree.h"
#include "queue.h"
#include "intertask_interface.h"
-#include "messages_types.h"
+#include "timer.h"
#include "platform_types.h"
+#include "assertions.h"
+#include "conversions.h"
#include "s1ap_common.h"
-#include "s1ap_eNB_defs.h"
-#include "s1ap_eNB_default_values.h"
-#include "s1ap_eNB_management_procedures.h"
-#include "s1ap_eNB.h"
+#include "play_scenario_s1ap_eNB_defs.h"
#include "play_scenario.h"
#include "msc.h"
-#include "assertions.h"
-#include "conversions.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;
+//------------------------------------------------------------------------------
+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);
+}
//------------------------------------------------------------------------------
-extern void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
-extern void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB);
+void et_s1ap_process_rx_packet(et_event_s1ap_data_ind_t * const sctp_data_ind)
+{
+ et_packet_t * packet = NULL;
+ unsigned long int not_found = 1;
+
+ packet = g_scenario->next_packet;
+ // not_found threshold may sure depend on number of mme, may be not sure on number of UE
+ while ((NULL != packet) && (not_found < 5)) {
+ if (packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
+ //TODO
+ }
+ not_found += 1;
+ packet = packet->next;
+ }
+}
+
//------------------------------------------------------------------------------
-void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind)
+void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t * const sctp_data_ind)
{
int result = 0;
et_event_t event;
@@ -73,7 +217,8 @@ void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind)
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 = 18; // find constant
+ 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;
@@ -100,6 +245,253 @@ void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind)
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;
+ struct in6_addr s1c_mme_ipv6 = IN6ADDR_ANY_INIT;
+ in_addr_t s1c_mme_ipv4 = INADDR_ANY;
+ struct in6_addr s1c_enb_ipv6 = IN6ADDR_ANY_INIT;
+ in_addr_t s1c_enb_ipv4 = INADDR_ANY;
+
+ packet = g_scenario->next_packet;
+ while (NULL != packet) {
+ switch (packet->sctp_hdr.chunk_type) {
+
+ case SCTP_CID_DATA :
+ if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_SEND) {
+ // TODO compare addresses and ports
+ if (packet->ip_hdr.dst)
+ packet->sctp_hdr.dst_port == 0;
+ packet->sctp_hdr.src_port == 0;
+
+ } else if (g_scenario->next_packet->action == ET_PACKET_ACTION_S1C_RECEIVE) {
+ }
+ 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:
+ 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:
+ ;
+ }
+ 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 --;
+ }
+
+ 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);
+ } 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;
+
+ /* 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;
+ }
+
+ /* 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)
{
@@ -108,7 +500,7 @@ void *et_s1ap_eNB_task(void *arg)
S1AP_DEBUG("Starting S1AP layer\n");
- s1ap_eNB_prepare_internal_data();
+ et_s1ap_eNB_prepare_internal_data();
itti_mark_task_ready(TASK_S1AP);
MSC_START_USE();
@@ -127,13 +519,13 @@ void *et_s1ap_eNB_task(void *arg)
* Each eNB has to send an S1AP_REGISTER_ENB message with its
* own parameters.
*/
- s1ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
+ et_s1ap_eNB_handle_register_eNB(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&S1AP_REGISTER_ENB_REQ(received_msg));
}
break;
case SCTP_NEW_ASSOCIATION_RESP: {
- s1ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
+ et_s1ap_eNB_handle_sctp_association_resp(ITTI_MESSAGE_GET_INSTANCE(received_msg),
&received_msg->ittiMsg.sctp_new_association_resp);
}
break;
@@ -143,6 +535,31 @@ void *et_s1ap_eNB_task(void *arg)
}
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;
+ 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);
+ } 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);
+ }
+ }
+ if (TIMER_HAS_EXPIRED (received_msg).timer_id == g_scenario->enb_register_retry_timer_id) {
+ /* Restart the registration process */
+ g_scenario->registered_enb = 0;
+ g_scenario->register_enb_pending = et_eNB_app_register (g_scenario->enb_properties);
+ }
+ break;
default:
S1AP_ERROR("Received unhandled message: %d:%s\n",
diff --git a/openair3/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h b/openair3/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h
new file mode 100644
index 0000000000..ac77b88b24
--- /dev/null
+++ b/openair3/TEST/EPC_TEST/play_scenario_s1ap_eNB_defs.h
@@ -0,0 +1,250 @@
+/*******************************************************************************
+ OpenAirInterface
+ Copyright(c) 1999 - 2014 Eurecom
+
+ OpenAirInterface is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+
+ OpenAirInterface is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with OpenAirInterface.The full GNU General Public License is
+ included in this distribution in the file called "COPYING". If not,
+ see <http://www.gnu.org/licenses/>.
+
+ Contact Information
+ OpenAirInterface Admin: openair_admin@eurecom.fr
+ OpenAirInterface Tech : openair_tech@eurecom.fr
+ OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
+
+ Address : Eurecom, Compus SophiaTech 450, route des chappes, 06451 Biot, France.
+
+ *******************************************************************************/
+
+#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_ */
--
GitLab