diff --git a/lib/include/srslte/common/pcap.h b/lib/include/srslte/common/pcap.h index 18b66a141..0f63ff11d 100644 --- a/lib/include/srslte/common/pcap.h +++ b/lib/include/srslte/common/pcap.h @@ -35,7 +35,7 @@ #define MAC_LTE_DLT 147 #define NAS_LTE_DLT 148 #define RLC_LTE_DLT 149 // UDP needs to be selected as protocol - +#define S1AP_LTE_DLT 150 /* This structure gets written to the start of the file */ typedef struct pcap_hdr_s { @@ -165,6 +165,10 @@ typedef struct { #define RLC_LTE_PAYLOAD_TAG 0x01 +/* Context information for every S1AP PDU that will be logged */ +typedef struct S1AP_Context_Info_s { + // No Context yet +} S1AP_Context_Info_t; /************************************************************************** * API functions for opening/closing LTE PCAP files * @@ -398,4 +402,37 @@ inline int LTE_PCAP_RLC_WritePDU(FILE *fd, RLC_Context_Info_t *context, return 1; } +/************************************************************************** + * API functions for writing S1AP PCAP files * + **************************************************************************/ + +/* Write an individual PDU (PCAP packet header + s1ap-context + s1ap-pdu) */ +inline int LTE_PCAP_S1AP_WritePDU(FILE *fd, S1AP_Context_Info_t *context, + const unsigned char *PDU, unsigned int length) +{ + pcaprec_hdr_t packet_header; + + /* Can't write if file wasn't successfully opened */ + if (fd == NULL) { + printf("Error: Can't write to empty file handle\n"); + return 0; + } + + /****************************************************************/ + /* PCAP Header */ + struct timeval t; + gettimeofday(&t, NULL); + packet_header.ts_sec = t.tv_sec; + packet_header.ts_usec = t.tv_usec; + packet_header.incl_len = length; + packet_header.orig_len = length; + + /***************************************************************/ + /* Now write everything to the file */ + fwrite(&packet_header, sizeof(pcaprec_hdr_t), 1, fd); + fwrite(PDU, 1, length, fd); + + return 1; +} + #endif // SRSLTE_PCAP_H diff --git a/lib/include/srslte/common/s1ap_pcap.h b/lib/include/srslte/common/s1ap_pcap.h new file mode 100644 index 000000000..b00d44394 --- /dev/null +++ b/lib/include/srslte/common/s1ap_pcap.h @@ -0,0 +1,23 @@ +#ifndef SRSLTE_S1AP_PCAP_H +#define SRSLTE_S1AP_PCAP_H + +#include "srslte/common/pcap.h" + +namespace srslte { + +class s1ap_pcap +{ +public: + s1ap_pcap() {enable_write=false; pcap_file = NULL; } + void enable(); + void open(const char *filename); + void close(); + void write_s1ap(uint8_t *pdu, uint32_t pdu_len_bytes); +private: + bool enable_write; + FILE *pcap_file; +}; + +} //namespace srslte + +#endif // SRSLTE_NAS_PCAP_H diff --git a/lib/src/common/s1ap_pcap.cc b/lib/src/common/s1ap_pcap.cc new file mode 100644 index 000000000..5b32be7f1 --- /dev/null +++ b/lib/src/common/s1ap_pcap.cc @@ -0,0 +1,34 @@ +#include +#include "srslte/srslte.h" +#include "srslte/common/pcap.h" +#include "srslte/common/s1ap_pcap.h" + + +namespace srslte { + +void s1ap_pcap::enable() +{ + enable_write = true; +} +void s1ap_pcap::open(const char* filename) +{ + pcap_file = LTE_PCAP_Open(S1AP_LTE_DLT, filename); + enable_write = true; +} +void s1ap_pcap::close() +{ + fprintf(stdout, "Saving S1AP PCAP file\n"); + LTE_PCAP_Close(pcap_file); +} + +void s1ap_pcap::write_s1ap(uint8_t *pdu, uint32_t pdu_len_bytes) +{ + if (enable_write) { + S1AP_Context_Info_t context; + if (pdu) { + LTE_PCAP_S1AP_WritePDU(pcap_file, &context, pdu, pdu_len_bytes); + } + } +} + +} diff --git a/srsepc/epc.conf.example b/srsepc/epc.conf.example index 02ef797ef..6d857f78a 100644 --- a/srsepc/epc.conf.example +++ b/srsepc/epc.conf.example @@ -45,8 +45,24 @@ db_file = user_db.csv ##################################################################### [spgw] -gtpu_bind_addr=127.0.1.100 -sgi_if_addr=172.16.0.1 +gtpu_bind_addr = 127.0.1.100 +sgi_if_addr = 172.16.0.1 + +#################################################################### +# PCAP configuration +# +# Packets are captured to file in the compact format decoded by +# the Wireshark s1ap dissector and with DLT 150. +# To use the dissector, edit the preferences for DLT_USER to +# add an entry with DLT=150, Payload Protocol=s1ap. +# +# enable: Enable or disable the PCAP. +# filename: File name where to save the PCAP. +# +#################################################################### +[pcap] +enable = false +filename = /tmp/epc.pcap #################################################################### # Log configuration diff --git a/srsepc/hdr/mme/s1ap.h b/srsepc/hdr/mme/s1ap.h index ebedc9fec..4cb8385e0 100644 --- a/srsepc/hdr/mme/s1ap.h +++ b/srsepc/hdr/mme/s1ap.h @@ -31,6 +31,7 @@ #include "srslte/asn1/liblte_mme.h" #include "srslte/common/common.h" #include "srslte/common/log.h" +#include "srslte/common/s1ap_pcap.h" #include #include @@ -66,6 +67,7 @@ public: void delete_enb_ctx(int32_t assoc_id); + bool s1ap_tx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri); bool handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri); bool handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri); bool handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg); @@ -125,6 +127,10 @@ private: //FIXME the GTP-C should be moved to the MME class, when the packaging of GTP-C messages is done. mme_gtpc *m_mme_gtpc; + + //PCAP + bool m_pcap_enable; + srslte::s1ap_pcap m_pcap; }; inline uint32_t diff --git a/srsepc/hdr/mme/s1ap_common.h b/srsepc/hdr/mme/s1ap_common.h index 262d034b1..e5c198748 100644 --- a/srsepc/hdr/mme/s1ap_common.h +++ b/srsepc/hdr/mme/s1ap_common.h @@ -93,6 +93,8 @@ typedef struct{ std::string mme_name; std::string dns_addr; std::string mme_apn; + bool pcap_enable; + std::string pcap_filename; } s1ap_args_t; typedef struct{ diff --git a/srsepc/src/main.cc b/srsepc/src/main.cc index beed67709..e5c998ed7 100644 --- a/srsepc/src/main.cc +++ b/srsepc/src/main.cc @@ -100,35 +100,38 @@ parse_args(all_args_t *args, int argc, char* argv[]) { bpo::options_description common("Configuration options"); common.add_options() - ("mme.mme_code", bpo::value(&mme_code)->default_value("0x01"), "MME Code") - ("mme.name", bpo::value(&mme_name)->default_value("srsmme01"), "MME Name") - ("mme.mme_group", bpo::value(&mme_group)->default_value("0x01"), "Cell ID") - ("mme.tac", bpo::value(&tac)->default_value("0x0"), "Tracking Area Code") - ("mme.mcc", bpo::value(&mcc)->default_value("001"), "Mobile Country Code") - ("mme.mnc", bpo::value(&mnc)->default_value("01"), "Mobile Network Code") - ("mme.mme_bind_addr", bpo::value(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection") - ("mme.dns_addr", bpo::value(&dns_addr)->default_value("8.8.8.8"),"IP address of the DNS server for the UEs") - ("mme.apn", bpo::value(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services") - ("hss.db_file", bpo::value(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys") - ("hss.auth_algo", bpo::value(&hss_auth_algo)->default_value("milenage"),"HSS uthentication algorithm.") - ("spgw.gtpu_bind_addr", bpo::value(&spgw_bind_addr)->default_value("127.0.0.1"),"IP address of SP-GW for the S1-U connection") - ("spgw.sgi_if_addr", bpo::value(&sgi_if_addr)->default_value("176.16.0.1"),"IP address of TUN interface for the SGi connection") - - ("log.s1ap_level", bpo::value(&args->log_args.s1ap_level), "MME S1AP log level") - ("log.s1ap_hex_limit", bpo::value(&args->log_args.s1ap_hex_limit), "MME S1AP log hex dump limit") - ("log.gtpc_level", bpo::value(&args->log_args.gtpc_level), "MME GTPC log level") - ("log.gtpc_hex_limit", bpo::value(&args->log_args.gtpc_hex_limit), "MME GTPC log hex dump limit") - ("log.spgw_level", bpo::value(&args->log_args.spgw_level), "SPGW log level") - ("log.spgw_hex_limit", bpo::value(&args->log_args.spgw_hex_limit), "SPGW log hex dump limit") + ("mme.mme_code", bpo::value(&mme_code)->default_value("0x01"), "MME Code") + ("mme.name", bpo::value(&mme_name)->default_value("srsmme01"), "MME Name") + ("mme.mme_group", bpo::value(&mme_group)->default_value("0x01"), "Cell ID") + ("mme.tac", bpo::value(&tac)->default_value("0x0"), "Tracking Area Code") + ("mme.mcc", bpo::value(&mcc)->default_value("001"), "Mobile Country Code") + ("mme.mnc", bpo::value(&mnc)->default_value("01"), "Mobile Network Code") + ("mme.mme_bind_addr", bpo::value(&mme_bind_addr)->default_value("127.0.0.1"), "IP address of MME for S1 connnection") + ("mme.dns_addr", bpo::value(&dns_addr)->default_value("8.8.8.8"), "IP address of the DNS server for the UEs") + ("mme.apn", bpo::value(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services") + ("hss.db_file", bpo::value(&hss_db_file)->default_value("ue_db.csv"), ".csv file that stores UE's keys") + ("hss.auth_algo", bpo::value(&hss_auth_algo)->default_value("milenage"), "HSS uthentication algorithm.") + ("spgw.gtpu_bind_addr", bpo::value(&spgw_bind_addr)->default_value("127.0.0.1"), "IP address of SP-GW for the S1-U connection") + ("spgw.sgi_if_addr", bpo::value(&sgi_if_addr)->default_value("176.16.0.1"), "IP address of TUN interface for the SGi connection") + + ("pcap.enable", bpo::value(&args->mme_args.s1ap_args.pcap_enable)->default_value(false), "Enable S1AP PCAP") + ("pcap.filename", bpo::value(&args->mme_args.s1ap_args.pcap_filename)->default_value("/tmp/epc.pcap"), "PCAP filename") + + ("log.s1ap_level", bpo::value(&args->log_args.s1ap_level), "MME S1AP log level") + ("log.s1ap_hex_limit", bpo::value(&args->log_args.s1ap_hex_limit), "MME S1AP log hex dump limit") + ("log.gtpc_level", bpo::value(&args->log_args.gtpc_level), "MME GTPC log level") + ("log.gtpc_hex_limit", bpo::value(&args->log_args.gtpc_hex_limit), "MME GTPC log hex dump limit") + ("log.spgw_level", bpo::value(&args->log_args.spgw_level), "SPGW log level") + ("log.spgw_hex_limit", bpo::value(&args->log_args.spgw_hex_limit), "SPGW log hex dump limit") //("log.gtpu_level", bpo::value(&args->log.gtpu_level), "GTPU log level") - ("log.hss_level", bpo::value(&args->log_args.hss_level), "HSS log level") - ("log.hss_hex_limit", bpo::value(&args->log_args.hss_hex_limit), "HSS log hex dump limit") + ("log.hss_level", bpo::value(&args->log_args.hss_level), "HSS log level") + ("log.hss_hex_limit", bpo::value(&args->log_args.hss_hex_limit), "HSS log hex dump limit") //("log.gtpu_hex_limit",bpo::value(&args->log.gtpu_hex_limit), "GTPU log hex dump limit") - ("log.all_level", bpo::value(&args->log_args.all_level)->default_value("info"), "ALL log level") - ("log.all_hex_limit", bpo::value(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit") + ("log.all_level", bpo::value(&args->log_args.all_level)->default_value("info"), "ALL log level") + ("log.all_hex_limit", bpo::value(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit") - ("log.filename", bpo::value(&args->log_args.filename)->default_value("/tmp/epc.log"),"Log filename") + ("log.filename", bpo::value(&args->log_args.filename)->default_value("/tmp/epc.log"),"Log filename") ; // Positional options - config file location @@ -141,7 +144,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) { // these options are allowed on the command line bpo::options_description cmdline_options; - cmdline_options.add(common).add(position).add(general); + cmdline_options.add(common).add(position).add(general); // parse the command line and store result in vm bpo::variables_map vm; @@ -278,7 +281,7 @@ level(std::string l) int main (int argc,char * argv[] ) -{ +{ cout << endl <<"--- Software Radio Systems EPC ---" << endl << endl; signal(SIGINT, sig_int_handler); signal(SIGTERM, sig_int_handler); @@ -286,12 +289,11 @@ main (int argc,char * argv[] ) all_args_t args; parse_args(&args, argc, argv); - + srslte::logger_stdout logger_stdout; srslte::logger_file logger_file; srslte::logger *logger; - /*Init logger*/ if (!args.log_args.filename.compare("stdout")) { logger = &logger_stdout; diff --git a/srsepc/src/mme/s1ap.cc b/srsepc/src/mme/s1ap.cc index 180859f08..3c6e6dbe3 100644 --- a/srsepc/src/mme/s1ap.cc +++ b/srsepc/src/mme/s1ap.cc @@ -99,6 +99,11 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1 //Initialize S1-MME m_s1mme = enb_listen(); + //Init PCAP + m_pcap_enable = s1ap_args.pcap_enable; + if(m_pcap_enable){ + m_pcap.open(s1ap_args.pcap_filename.c_str()); + } m_s1ap_log->info("S1AP Initialized\n"); return 0; } @@ -130,6 +135,12 @@ s1ap::stop() s1ap_mngmt_proc::cleanup(); s1ap_nas_transport::cleanup(); s1ap_ctx_mngmt_proc::cleanup(); + + //PCAP + if(m_pcap_enable){ + m_pcap.close(); + } + return; } @@ -174,7 +185,7 @@ s1ap::enb_listen() //S1-MME bind bzero(&s1mme_addr, sizeof(s1mme_addr)); - s1mme_addr.sin_family = AF_INET; + s1mme_addr.sin_family = AF_INET; inet_pton(AF_INET, m_s1ap_args.mme_bind_addr.c_str(), &(s1mme_addr.sin_addr) ); s1mme_addr.sin_port = htons(S1MME_PORT); err = bind(sock_fd, (struct sockaddr*) &s1mme_addr, sizeof (s1mme_addr)); @@ -197,6 +208,20 @@ s1ap::enb_listen() return sock_fd; } +bool +s1ap::s1ap_tx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri) +{ + ssize_t n_sent = sctp_send(m_s1mme, pdu->msg, pdu->N_bytes, enb_sri, 0); + if(n_sent == -1){ + m_s1ap_log->console("Failed to send S1AP PDU.\n"); + m_s1ap_log->error("Failed to send S1AP PDU. \n"); + return false; + } + if(m_pcap_enable){ + m_pcap.write_s1ap(pdu->msg,pdu->N_bytes); + } + return true; +} bool s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri) @@ -208,6 +233,10 @@ s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb return false; } + if(m_pcap_enable){ + m_pcap.write_s1ap(pdu->msg,pdu->N_bytes); + } + switch(rx_pdu.choice_type) { case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE: m_s1ap_log->info("Received initiating PDU\n"); @@ -235,6 +264,7 @@ s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, stru { bool reply_flag = false; srslte::byte_buffer_t * reply_buffer = m_pool->allocate(); + bool ret = false; switch(msg->choice_type) { case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST: @@ -257,23 +287,17 @@ s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, stru m_s1ap_log->error("Unhandled S1AP intiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]); m_s1ap_log->console("Unhandled S1APintiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]); } + //Send Reply to eNB - if(reply_flag == true) - { - ssize_t n_sent = sctp_send(m_s1mme,reply_buffer->msg, reply_buffer->N_bytes, enb_sri, 0); - if(n_sent == -1) - { - m_s1ap_log->console("Failed to send S1AP Initiating Reply.\n"); - m_s1ap_log->error("Failed to send S1AP Initiating Reply. \n"); - m_pool->deallocate(reply_buffer); - return false; - } + if(reply_flag == true){ + ret = s1ap_tx_pdu(reply_buffer, enb_sri); } + m_pool->deallocate(reply_buffer); - return true; + return ret; } -bool +bool s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg) { switch(msg->choice_type) { @@ -496,7 +520,7 @@ s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id) m_s1ap_log->error("Could not find eNB for UE release request.\n"); return false; } - uint16_t enb_id = it->second; + uint16_t enb_id = it->second; std::map >::iterator ue_set = m_enb_assoc_to_ue_ids.find(ecm_ctx->enb_sri.sinfo_assoc_id); if(ue_set == m_enb_assoc_to_ue_ids.end()) { diff --git a/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc b/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc index b9d599d3e..37abf06f4 100644 --- a/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc +++ b/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc @@ -96,7 +96,7 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(ue_emm_ctx_t *emm_ctx, init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST; LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *in_ctxt_req = &init->choice.InitialContextSetupRequest; - + LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab_ctx_req = &in_ctxt_req->E_RABToBeSetupListCtxtSUReq.buffer[0]; //FIXME support more than one erab srslte::byte_buffer_t *reply_buffer = m_pool->allocate(); @@ -136,34 +136,28 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(ue_emm_ctx_t *emm_ctx, memcpy(erab_ctx_req->gTP_TEID.buffer, &sgw_s1u_teid, sizeof(uint32_t)); //Set UE security capabilities and k_enb - bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16); - bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16); - for(int i = 0; i<3; i++) - { - if(emm_ctx->security_ctxt.ue_network_cap.eea[i+1] == true) - { + bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16); + bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16); + + for (int i = 0; i<3; i++) { + if(emm_ctx->security_ctxt.ue_network_cap.eea[i+1] == true){ in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; //EEA supported - } - else - { + } else { in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 0; //EEA not supported } - if(emm_ctx->security_ctxt.ue_network_cap.eia[i+1] == true) - { + if(emm_ctx->security_ctxt.ue_network_cap.eia[i+1] == true){ in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; //EEA supported - } - else - { + } else { in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 0; //EEA not supported } } + //Get K eNB liblte_unpack(emm_ctx->security_ctxt.k_enb, 32, in_ctxt_req->SecurityKey.buffer); m_s1ap_log->info_hex(emm_ctx->security_ctxt.k_enb, 32, "Initial Context Setup Request -- Key eNB (k_enb)\n"); srslte::byte_buffer_t *nas_buffer = m_pool->allocate(); - if(emm_ctx->state == EMM_STATE_DEREGISTERED) - { + if (emm_ctx->state == EMM_STATE_DEREGISTERED) { //Attach procedure initiated from an attach request m_s1ap_log->console("Adding attach accept to Initial Context Setup Request\n"); m_s1ap_log->info("Adding attach accept to Initial Context Setup Request\n"); @@ -172,18 +166,14 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(ue_emm_ctx_t *emm_ctx, LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer); - if(err != LIBLTE_SUCCESS) - { + if (err != LIBLTE_SUCCESS) { m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n"); return false; } - //Send Reply to eNB - ssize_t n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ecm_ctx->enb_sri, 0); - if(n_sent == -1) - { - m_s1ap_log->error("Failed to send Initial Context Setup Request\n"); - return false; + if (!m_s1ap->s1ap_tx_pdu(reply_buffer,&ecm_ctx->enb_sri)) { + m_s1ap_log->error("Error sending Initial Context Setup Request.\n"); + return false; } //Change E-RAB state to Context Setup Requested and save S-GW control F-TEID @@ -345,31 +335,18 @@ s1ap_ctx_mngmt_proc::send_ue_context_release_command(ue_ecm_ctx_t *ecm_ctx, srsl return false; } //Send Reply to eNB - int n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ecm_ctx->enb_sri, 0); - if(n_sent == -1) + if(!m_s1ap->s1ap_tx_pdu(reply_buffer,&ecm_ctx->enb_sri)) { - m_s1ap_log->error("Failed to send Initial Context Setup Request\n"); + m_s1ap_log->error("Error sending UE Context Release command.\n"); return false; } - return true; } bool s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *rel_comp) { - /* - typedef struct{ - bool ext; - LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID; - LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID; - LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics; - bool CriticalityDiagnostics_present; - LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT UserLocationInformation; - bool UserLocationInformation_present; - }LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT; - */ uint32_t mme_ue_s1ap_id = rel_comp->MME_UE_S1AP_ID.MME_UE_S1AP_ID; m_s1ap_log->info("Received UE Context Release Complete. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id); @@ -385,23 +362,19 @@ s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECO ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; //Delete user plane context at the SPGW (but keep GTP-C connection). - if (ecm_ctx->state == ECM_STATE_CONNECTED) - { + if (ecm_ctx->state == ECM_STATE_CONNECTED) { //There are active E-RABs, send release access mearers request m_s1ap_log->console("There are active E-RABs, send release access mearers request"); m_s1ap_log->info("There are active E-RABs, send release access mearers request"); m_mme_gtpc->send_release_access_bearers_request(ecm_ctx->imsi); //The handle_releease_access_bearers_response function will make sure to mark E-RABS DEACTIVATED //It will release the UEs downstream S1-u and keep the upstream S1-U connection active. - } - else - { + } else { //No ECM Context to release m_s1ap_log->info("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id); m_s1ap_log->console("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id); - //Make sure E-RABS are merked as DEACTIVATED. - for(int i=0;ierabs_ctx[i].state = ERAB_DEACTIVATED; } }