Begin to begin sending packets (many things to do hash assoc id, mme_ue_id, nas security, etc)
This commit is contained in:
@@ -216,18 +216,20 @@ add_definitions("-DPACKAGE_BUGREPORT=\"openair4g-devel@lists.eurecom.fr\"")
|
||||
|
||||
# Debug related options
|
||||
#########################################
|
||||
add_boolean_option(MSG_PRINT False "print debug messages")
|
||||
add_boolean_option(DISABLE_XER_PRINT False "print XER Format")
|
||||
add_boolean_option(XER_PRINT False "print XER Format")
|
||||
add_boolean_option(RRC_MSG_PRINT False "print RRC messages")
|
||||
add_boolean_option(PDCP_MSG_PRINT False "print PDCP messages to /tmp/pdcp.log")
|
||||
add_boolean_option(DEBUG_PDCP_PAYLOAD False "print PDCP PDU to stdout") # if true, make sure that global and PDCP log levels are trace
|
||||
add_boolean_option(ASN_DEBUG False "ASN1 coder/decoder Debug")
|
||||
add_boolean_option(EMIT_ASN_DEBUG False "ASN1 coder/decoder Debug")
|
||||
add_boolean_option(MSG_PRINT False "print debug messages")
|
||||
add_boolean_option(DISABLE_XER_PRINT False "print XER Format")
|
||||
add_boolean_option(XER_PRINT False "print XER Format")
|
||||
add_boolean_option(RRC_MSG_PRINT False "print RRC messages")
|
||||
add_boolean_option(PDCP_MSG_PRINT False "print PDCP messages to /tmp/pdcp.log")
|
||||
add_boolean_option(DEBUG_PDCP_PAYLOAD False "print PDCP PDU to stdout") # if true, make sure that global and PDCP log levels are trace
|
||||
add_boolean_option(DEBUG_MAC_INTERFACE False "print MAC-RLC PDU exchange to stdout") # if true, make sure that global and PDCP log levels are trace
|
||||
add_boolean_option(TRACE_RLC_PAYLOAD False "print RLC PDU to stdout") # if true, make sure that global and PDCP log levels are trace
|
||||
add_boolean_option(TEST_OMG False "???")
|
||||
add_boolean_option(DEBUG_OMG False "???")
|
||||
add_boolean_option(XFORMS False "This adds the possibility to see the signal oscilloscope")
|
||||
add_boolean_option(PRINT_STATS False "This adds the possibility to see the status")
|
||||
add_boolean_option(TRACE_RLC_PAYLOAD False "print RLC PDU to stdout") # if true, make sure that global and PDCP log levels are trace
|
||||
add_boolean_option(TEST_OMG False "???")
|
||||
add_boolean_option(DEBUG_OMG False "???")
|
||||
add_boolean_option(XFORMS False "This adds the possibility to see the signal oscilloscope")
|
||||
add_boolean_option(PRINT_STATS False "This adds the possibility to see the status")
|
||||
|
||||
add_boolean_option(DEBUG_CONSOLE False "makes debugging easier, disables stdout/stderr buffering")
|
||||
|
||||
@@ -1660,6 +1662,12 @@ target_link_libraries (test_epc_generate_scenario
|
||||
|
||||
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_sctp.c
|
||||
${OPENAIR3_DIR}/TEST/EPC_TEST/play_scenario.h
|
||||
${OPENAIR2_DIR}/ENB_APP/enb_config.h
|
||||
${OPENAIR2_DIR}/COMMON/commonDef.h
|
||||
|
||||
@@ -7,7 +7,7 @@ set ( DEBUG_OMG False )
|
||||
set ( DISABLE_XER_PRINT False )
|
||||
set ( DRIVER2013 True )
|
||||
set ( EMOS False )
|
||||
set ( EMIT_ASN_DEBUG True )
|
||||
set ( EMIT_ASN_DEBUG False )
|
||||
set ( ENABLE_FXP True )
|
||||
set ( ENABLE_ITTI True )
|
||||
set ( ENABLE_NAS_UE_LOGGING True )
|
||||
@@ -76,4 +76,4 @@ set ( SMBV False )
|
||||
set ( TEST_OMG False )
|
||||
set ( USE_MME "R10" )
|
||||
set ( USER_MODE True )
|
||||
set ( XER_PRINT False )
|
||||
set ( XER_PRINT True )
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
# Contact Information
|
||||
# OpenAirInterface Admin: openair_admin@eurecom.fr
|
||||
# OpenAirInterface Tech : openair_tech@eurecom.fr
|
||||
# OpenAirInterface Dev : openair4g-devel@eurecom.fr
|
||||
# OpenAirInterface Dev : openair4g-devel@lists.eurecom.fr
|
||||
#
|
||||
# Address : Eurecom, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
#
|
||||
|
||||
@@ -72,9 +72,9 @@ s1ap_eNB_config_t s1ap_config;
|
||||
static int s1ap_eNB_generate_s1_setup_request(
|
||||
s1ap_eNB_instance_t *instance_p, s1ap_eNB_mme_data_t *s1ap_mme_data_p);
|
||||
|
||||
static
|
||||
|
||||
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB);
|
||||
static
|
||||
|
||||
void s1ap_eNB_handle_sctp_association_resp(instance_t instance, sctp_new_association_resp_t *sctp_new_association_resp);
|
||||
|
||||
uint32_t s1ap_generate_eNB_id(void)
|
||||
@@ -150,7 +150,7 @@ static void s1ap_eNB_register_mme(s1ap_eNB_instance_t *instance_p,
|
||||
itti_send_msg_to_task(TASK_SCTP, instance_p->instance, message_p);
|
||||
}
|
||||
|
||||
static
|
||||
|
||||
void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *s1ap_register_eNB)
|
||||
{
|
||||
s1ap_eNB_instance_t *new_instance;
|
||||
@@ -210,7 +210,6 @@ void s1ap_eNB_handle_register_eNB(instance_t instance, s1ap_register_enb_req_t *
|
||||
}
|
||||
}
|
||||
|
||||
static
|
||||
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;
|
||||
|
||||
+215
-1000
File diff suppressed because it is too large
Load Diff
@@ -28,7 +28,7 @@
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
play_scenario.h
|
||||
et_scenario.h
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
@@ -42,21 +42,44 @@
|
||||
# include <libxml/tree.h>
|
||||
# include <netinet/in.h>
|
||||
|
||||
#include "enb_config.h"
|
||||
#include "s1ap_ies_defs.h"
|
||||
|
||||
# define ET_ENB_REGISTER_RETRY_DELAY 3
|
||||
|
||||
/** @defgroup _enb_app ENB APP
|
||||
* @ingroup _oai2
|
||||
* @{
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
ACTION_S1C_START = 0,
|
||||
ACTION_S1C_NULL = ACTION_S1C_START,
|
||||
ACTION_S1C_SEND,
|
||||
ACTION_S1C_RECEIVE,
|
||||
ACTION_S1C_END
|
||||
} test_action_t;
|
||||
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_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_END
|
||||
} et_fsm_state_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 {
|
||||
@@ -94,16 +117,17 @@ typedef enum {
|
||||
TEST_S1AP_PDU_TYPE_SUCCESSFUL_OUTCOME,
|
||||
TEST_S1AP_PDU_TYPE_UNSUCCESSFUL_OUTCOME,
|
||||
TEST_S1AP_PDU_TYPE_END
|
||||
} test_s1ap_pdu_type_t;
|
||||
} et_s1ap_pdu_type_t;
|
||||
|
||||
|
||||
typedef struct test_s1ap_s {
|
||||
//test_s1ap_pdu_type_t pdu_type;
|
||||
typedef struct et_s1ap_s {
|
||||
//et_s1ap_pdu_type_t pdu_type;
|
||||
S1AP_PDU_t pdu; // decoded ASN1 C type: choice of initiatingMessage, successfulOutcome, unsuccessfulOutcome
|
||||
uint16_t binary_stream_pos;
|
||||
uint16_t binary_stream_allocated_size;
|
||||
uint8_t *binary_stream;
|
||||
s1ap_message message;
|
||||
} test_s1ap_t;
|
||||
s1ap_message message; // decoded message: information elements
|
||||
} et_s1ap_t;
|
||||
|
||||
|
||||
// from kernel source file 3.19/include/linux/sctp.h, Big Endians
|
||||
@@ -112,7 +136,7 @@ typedef struct sctp_datahdr_s {
|
||||
uint16_t stream;
|
||||
uint16_t ssn;
|
||||
uint32_t ppid;
|
||||
test_s1ap_t payload;
|
||||
et_s1ap_t payload;
|
||||
} sctp_datahdr_t;
|
||||
|
||||
// from kernel source file 3.19/include/linux/sctp.h, Big Endians
|
||||
@@ -127,7 +151,7 @@ typedef struct sctp_inithdr {
|
||||
|
||||
typedef sctp_inithdr_t sctp_initackhdr_t;
|
||||
|
||||
typedef struct test_sctp_hdr_s {
|
||||
typedef struct et_sctp_hdr_s {
|
||||
unsigned int src_port;
|
||||
unsigned int dst_port;
|
||||
sctp_cid_t chunk_type;
|
||||
@@ -136,38 +160,145 @@ typedef struct test_sctp_hdr_s {
|
||||
sctp_inithdr_t init_hdr;
|
||||
sctp_initackhdr_t init_ack_hdr;
|
||||
} u;
|
||||
} test_sctp_hdr_t;
|
||||
} et_sctp_hdr_t;
|
||||
|
||||
typedef struct test_ip_s {
|
||||
typedef struct et_ip_s {
|
||||
unsigned int address_family; // AF_INET, AF_INET6
|
||||
union {
|
||||
struct in6_addr ipv6;
|
||||
in_addr_t ipv4;
|
||||
}address;
|
||||
}test_ip_t;
|
||||
}et_ip_t;
|
||||
|
||||
typedef struct test_ip_hdr_s {
|
||||
test_ip_t src;
|
||||
test_ip_t dst;
|
||||
} test_ip_hdr_t;
|
||||
typedef struct et_ip_hdr_s {
|
||||
et_ip_t src;
|
||||
et_ip_t dst;
|
||||
} et_ip_hdr_t;
|
||||
|
||||
typedef struct test_packet_s {
|
||||
test_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;
|
||||
test_ip_hdr_t ip_hdr;
|
||||
test_sctp_hdr_t sctp_hdr;
|
||||
struct test_packet_s *next;
|
||||
}test_packet_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;
|
||||
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;
|
||||
}et_packet_t;
|
||||
|
||||
typedef struct test_scenario_s {
|
||||
|
||||
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;
|
||||
test_packet_t *list_packet;
|
||||
}test_scenario_t;
|
||||
et_packet_t *list_packet;
|
||||
|
||||
inline void free_pointer(void *p) {if (NULL != p) {free(p); p=NULL;}};
|
||||
#endif /* ENB_CONFIG_H_ */
|
||||
/** @} */
|
||||
// playing scenario
|
||||
et_packet_t *waited_packet;
|
||||
et_packet_t *current_packet;
|
||||
} et_scenario_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
ET_EVENT_START = 0,
|
||||
ET_EVENT_INIT = ET_EVENT_START,
|
||||
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_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_event_s1ap_data_req_t s1ap_data_req;
|
||||
} u;
|
||||
} et_event_t;
|
||||
|
||||
inline void et_free_pointer(void *p) {if (NULL != p) {free(p); p=NULL;}};
|
||||
|
||||
//-------------------------
|
||||
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);
|
||||
//-------------------------
|
||||
void et_s1ap_eNB_handle_sctp_data_ind(sctp_data_ind_t *sctp_data_ind);
|
||||
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);
|
||||
//-------------------------
|
||||
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 );
|
||||
//-------------------------
|
||||
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);
|
||||
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_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);
|
||||
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);
|
||||
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);
|
||||
|
||||
#endif /* PLAY_SCENARIO_H_ */
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*******************************************************************************
|
||||
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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
play_scenario_decode.c
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
*/
|
||||
|
||||
#include "intertask_interface.h"
|
||||
#include "platform_types.h"
|
||||
#include "s1ap_ies_defs.h"
|
||||
#include "s1ap_eNB_decoder.h"
|
||||
#include "assertions.h"
|
||||
#include "play_scenario.h"
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int et_s1ap_decode_initiating_message(s1ap_message *message, S1ap_InitiatingMessage_t *initiating_p)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
DevAssert(initiating_p != NULL);
|
||||
|
||||
message->procedureCode = initiating_p->procedureCode;
|
||||
message->criticality = initiating_p->criticality;
|
||||
|
||||
switch(initiating_p->procedureCode) {
|
||||
case S1ap_ProcedureCode_id_downlinkNASTransport:
|
||||
ret = s1ap_decode_s1ap_downlinknastransporties(&message->msg.s1ap_DownlinkNASTransportIEs,&initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_InitialContextSetup:
|
||||
ret = s1ap_decode_s1ap_initialcontextsetuprequesties(&message->msg.s1ap_InitialContextSetupRequestIEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_UEContextRelease:
|
||||
ret = s1ap_decode_s1ap_uecontextreleasecommandies(&message->msg.s1ap_UEContextReleaseCommandIEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_Paging:
|
||||
ret = s1ap_decode_s1ap_pagingies(&message->msg.s1ap_PagingIEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_uplinkNASTransport:
|
||||
ret = s1ap_decode_s1ap_uplinknastransporties (&message->msg.s1ap_UplinkNASTransportIEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_S1Setup:
|
||||
ret = s1ap_decode_s1ap_s1setuprequesties (&message->msg.s1ap_S1SetupRequestIEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_initialUEMessage:
|
||||
ret = s1ap_decode_s1ap_initialuemessageies (&message->msg.s1ap_InitialUEMessageIEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_UEContextReleaseRequest:
|
||||
ret = s1ap_decode_s1ap_uecontextreleaserequesties (&message->msg.s1ap_UEContextReleaseRequestIEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_UECapabilityInfoIndication:
|
||||
ret = s1ap_decode_s1ap_uecapabilityinfoindicationies (&message->msg.s1ap_UECapabilityInfoIndicationIEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_NASNonDeliveryIndication:
|
||||
ret = s1ap_decode_s1ap_nasnondeliveryindication_ies (&message->msg.s1ap_NASNonDeliveryIndication_IEs, &initiating_p->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal( 0 , "Unknown procedure ID (%d) for initiating message\n",
|
||||
(int)initiating_p->procedureCode);
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int et_s1ap_decode_successful_outcome(s1ap_message *message, S1ap_SuccessfulOutcome_t *successfullOutcome_p)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
DevAssert(successfullOutcome_p != NULL);
|
||||
|
||||
message->procedureCode = successfullOutcome_p->procedureCode;
|
||||
message->criticality = successfullOutcome_p->criticality;
|
||||
|
||||
switch(successfullOutcome_p->procedureCode) {
|
||||
case S1ap_ProcedureCode_id_S1Setup:
|
||||
ret = s1ap_decode_s1ap_s1setupresponseies(
|
||||
&message->msg.s1ap_S1SetupResponseIEs, &successfullOutcome_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_InitialContextSetup:
|
||||
ret = s1ap_decode_s1ap_initialcontextsetupresponseies (&message->msg.s1ap_InitialContextSetupResponseIEs, &successfullOutcome_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_UEContextRelease:
|
||||
ret = s1ap_decode_s1ap_uecontextreleasecompleteies (&message->msg.s1ap_UEContextReleaseCompleteIEs, &successfullOutcome_p->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(0, "Unknown procedure ID (%d) for successfull outcome message\n",
|
||||
(int)successfullOutcome_p->procedureCode);
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int et_s1ap_decode_unsuccessful_outcome(s1ap_message *message, S1ap_UnsuccessfulOutcome_t *unSuccessfullOutcome_p)
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
DevAssert(unSuccessfullOutcome_p != NULL);
|
||||
|
||||
message->procedureCode = unSuccessfullOutcome_p->procedureCode;
|
||||
message->criticality = unSuccessfullOutcome_p->criticality;
|
||||
|
||||
switch(unSuccessfullOutcome_p->procedureCode) {
|
||||
case S1ap_ProcedureCode_id_S1Setup:
|
||||
ret = s1ap_decode_s1ap_s1setupfailureies(&message->msg.s1ap_S1SetupFailureIEs, &unSuccessfullOutcome_p->value);
|
||||
break;
|
||||
|
||||
case S1ap_ProcedureCode_id_InitialContextSetup:
|
||||
ret = s1ap_decode_s1ap_initialcontextsetupfailureies (&message->msg.s1ap_InitialContextSetupFailureIEs, &unSuccessfullOutcome_p->value);
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(0,"Unknown procedure ID (%d) for unsuccessfull outcome message\n",
|
||||
(int)unSuccessfullOutcome_p->procedureCode);
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int et_s1ap_decode_pdu(S1AP_PDU_t * const pdu, s1ap_message * const message, const uint8_t * const buffer, const uint32_t length)
|
||||
{
|
||||
asn_dec_rval_t dec_ret;
|
||||
|
||||
DevAssert(buffer != NULL);
|
||||
|
||||
memset((void *)pdu, 0, sizeof(S1AP_PDU_t));
|
||||
|
||||
dec_ret = aper_decode(NULL,
|
||||
&asn_DEF_S1AP_PDU,
|
||||
(void **)&pdu,
|
||||
buffer,
|
||||
length,
|
||||
0,
|
||||
0);
|
||||
|
||||
if (dec_ret.code != RC_OK) {
|
||||
S1AP_ERROR("Failed to decode pdu\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
message->direction = pdu->present;
|
||||
|
||||
switch(pdu->present) {
|
||||
case S1AP_PDU_PR_initiatingMessage:
|
||||
return et_s1ap_decode_initiating_message(message,
|
||||
&pdu->choice.initiatingMessage);
|
||||
|
||||
case S1AP_PDU_PR_successfulOutcome:
|
||||
return et_s1ap_decode_successful_outcome(message,
|
||||
&pdu->choice.successfulOutcome);
|
||||
|
||||
case S1AP_PDU_PR_unsuccessfulOutcome:
|
||||
return et_s1ap_decode_unsuccessful_outcome(message,
|
||||
&pdu->choice.unsuccessfulOutcome);
|
||||
|
||||
default:
|
||||
AssertFatal(0, "Unknown presence (%d) or not implemented\n", (int)pdu->present);
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void et_decode_s1ap(et_s1ap_t * const s1ap)
|
||||
{
|
||||
if (NULL != s1ap) {
|
||||
if (et_s1ap_decode_pdu(&s1ap->pdu, &s1ap->message, s1ap->binary_stream, s1ap->binary_stream_allocated_size) < 0) {
|
||||
AssertFatal (0, "ERROR %s() Cannot decode S1AP message!\n", __FUNCTION__);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
/*******************************************************************************
|
||||
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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
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_ies_defs.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, " %04ld |", 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");
|
||||
s1ap_string_total_size = 0;
|
||||
switch(s1ap->pdu.present) {
|
||||
case 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_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_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");
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/*******************************************************************************
|
||||
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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
play_scenario_fsm.c
|
||||
-------------------
|
||||
AUTHOR : Lionel GAUTHIER
|
||||
COMPANY : EURECOM
|
||||
EMAIL : Lionel.Gauthier@eurecom.fr
|
||||
*/
|
||||
#include <stdio.h>
|
||||
|
||||
#include "intertask_interface.h"
|
||||
#include "platform_types.h"
|
||||
#include "assertions.h"
|
||||
#include "play_scenario.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)
|
||||
{
|
||||
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_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) {
|
||||
|
||||
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;
|
||||
} else {
|
||||
packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
|
||||
packet = packet->next;
|
||||
}
|
||||
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);
|
||||
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;
|
||||
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));
|
||||
break;
|
||||
|
||||
default:
|
||||
packet->status = ET_PACKET_STATUS_NOT_TAKEN_IN_ACCOUNT;
|
||||
packet = packet->next;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "No Packet found in this scenario: %s\n", g_scenario->name);
|
||||
return -1;
|
||||
break;
|
||||
|
||||
case ET_EVENT_STOP:
|
||||
break;
|
||||
|
||||
default:
|
||||
AssertFatal(0, "Case event %d not handled in ET_FSM_STATE_NULL", event.code);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
int 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){
|
||||
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;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,561 @@
|
||||
/*******************************************************************************
|
||||
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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
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 "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;
|
||||
//------------------------------------------------------------------------------
|
||||
void et_parse_s1ap(xmlDocPtr doc, const xmlNode const *s1ap_node, et_s1ap_t * const s1ap)
|
||||
{
|
||||
xmlNode *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)) {
|
||||
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 %s size %d 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 %s() in buffer size: binary_stream_pos %d xmlStrlen(xml_char)/2=%d\n", __FUNCTION__, 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 %s() in converting hex string %s len %d size %d rc %d\n", __FUNCTION__, 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_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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
} 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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
//}
|
||||
}
|
||||
}
|
||||
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 *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) {
|
||||
*next_packet = packet;
|
||||
next_packet = &packet->next;
|
||||
} else {
|
||||
fprintf(stdout, "WARNING omitted packet:\n");
|
||||
et_display_node(node, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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);
|
||||
}
|
||||
|
||||
memset(astring, 0, sizeof(astring));
|
||||
strcat(astring, g_openair_dir);
|
||||
strcat(astring, "/openair3/TEST/EPC_TEST/play_scenario.xsl");
|
||||
|
||||
xmlSubstituteEntitiesDefault(1);
|
||||
xmlLoadExtDtdDefaultValue = 1;
|
||||
cur = xsltParseStylesheetFile((const xmlChar *)astring);
|
||||
if (NULL == cur) {
|
||||
AssertFatal (0, "Could not parse stylesheet file %s (check OPENAIR_DIR env variable)!\n", astring);
|
||||
} else {
|
||||
fprintf(stdout, "XSLT style sheet: %s\n", astring);
|
||||
}
|
||||
|
||||
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 < 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;
|
||||
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++) {
|
||||
sprintf(astring, "mme_s1c%d_%d", i, j);
|
||||
params[nb_params++] = strdup(astring);
|
||||
AssertFatal (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);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
/*******************************************************************************
|
||||
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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
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 "tree.h"
|
||||
#include "queue.h"
|
||||
|
||||
|
||||
#include "intertask_interface.h"
|
||||
#include "messages_types.h"
|
||||
#include "platform_types.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.h"
|
||||
#include "msc.h"
|
||||
#include "assertions.h"
|
||||
#include "conversions.h"
|
||||
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
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_eNB_handle_sctp_data_ind(sctp_data_ind_t *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 = 18; // find constant
|
||||
|
||||
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 %s() Cannot decode RX S1AP message!\n", __FUNCTION__);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
void *et_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);
|
||||
MSC_START_USE();
|
||||
|
||||
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_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),
|
||||
&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;
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*******************************************************************************
|
||||
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, Campus SophiaTech, 450 Route des Chappes, CS 50193 - 06904 Biot Sophia Antipolis cedex, FRANCE
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
/*
|
||||
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"
|
||||
|
||||
@@ -275,7 +275,6 @@ do { \
|
||||
(bITsTRING)->size = 3; \
|
||||
(bITsTRING)->bits_unused = 4; \
|
||||
} while(0)
|
||||
/*
|
||||
/* TS 36.413 v10.9.0 section 9.2.1.38:
|
||||
* E-UTRAN CGI/Cell Identity
|
||||
* The leftmost bits of the Cell
|
||||
|
||||
Reference in New Issue
Block a user