Merge pull request #237 from softwareradiosystems/epc_pcap

Epc pcap
master
Andre Puschmann 7 years ago committed by GitHub
commit 4c59f52f9a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -35,7 +35,7 @@
#define MAC_LTE_DLT 147 #define MAC_LTE_DLT 147
#define NAS_LTE_DLT 148 #define NAS_LTE_DLT 148
#define RLC_LTE_DLT 149 // UDP needs to be selected as protocol #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 */ /* This structure gets written to the start of the file */
typedef struct pcap_hdr_s { typedef struct pcap_hdr_s {
@ -165,6 +165,10 @@ typedef struct {
#define RLC_LTE_PAYLOAD_TAG 0x01 #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 * * 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; 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 #endif // SRSLTE_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

@ -0,0 +1,34 @@
#include <stdint.h>
#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);
}
}
}
}

@ -45,8 +45,24 @@ db_file = user_db.csv
##################################################################### #####################################################################
[spgw] [spgw]
gtpu_bind_addr=127.0.1.100 gtpu_bind_addr = 127.0.1.100
sgi_if_addr=172.16.0.1 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 # Log configuration

@ -31,6 +31,7 @@
#include "srslte/asn1/liblte_mme.h" #include "srslte/asn1/liblte_mme.h"
#include "srslte/common/common.h" #include "srslte/common/common.h"
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/s1ap_pcap.h"
#include <strings.h> #include <strings.h>
#include <arpa/inet.h> #include <arpa/inet.h>
@ -66,6 +67,7 @@ public:
void delete_enb_ctx(int32_t assoc_id); 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_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_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri);
bool handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg); 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. //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; mme_gtpc *m_mme_gtpc;
//PCAP
bool m_pcap_enable;
srslte::s1ap_pcap m_pcap;
}; };
inline uint32_t inline uint32_t

@ -93,6 +93,8 @@ typedef struct{
std::string mme_name; std::string mme_name;
std::string dns_addr; std::string dns_addr;
std::string mme_apn; std::string mme_apn;
bool pcap_enable;
std::string pcap_filename;
} s1ap_args_t; } s1ap_args_t;
typedef struct{ typedef struct{

@ -100,35 +100,38 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
bpo::options_description common("Configuration options"); bpo::options_description common("Configuration options");
common.add_options() common.add_options()
("mme.mme_code", bpo::value<string>(&mme_code)->default_value("0x01"), "MME Code") ("mme.mme_code", bpo::value<string>(&mme_code)->default_value("0x01"), "MME Code")
("mme.name", bpo::value<string>(&mme_name)->default_value("srsmme01"), "MME Name") ("mme.name", bpo::value<string>(&mme_name)->default_value("srsmme01"), "MME Name")
("mme.mme_group", bpo::value<string>(&mme_group)->default_value("0x01"), "Cell ID") ("mme.mme_group", bpo::value<string>(&mme_group)->default_value("0x01"), "Cell ID")
("mme.tac", bpo::value<string>(&tac)->default_value("0x0"), "Tracking Area Code") ("mme.tac", bpo::value<string>(&tac)->default_value("0x0"), "Tracking Area Code")
("mme.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code") ("mme.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code")
("mme.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code") ("mme.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code")
("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection") ("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"), "IP address of MME for S1 connnection")
("mme.dns_addr", bpo::value<string>(&dns_addr)->default_value("8.8.8.8"),"IP address of the DNS server for the UEs") ("mme.dns_addr", bpo::value<string>(&dns_addr)->default_value("8.8.8.8"), "IP address of the DNS server for the UEs")
("mme.apn", bpo::value<string>(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services") ("mme.apn", bpo::value<string>(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services")
("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys") ("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"), ".csv file that stores UE's keys")
("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"),"HSS uthentication algorithm.") ("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"), "HSS uthentication algorithm.")
("spgw.gtpu_bind_addr", bpo::value<string>(&spgw_bind_addr)->default_value("127.0.0.1"),"IP address of SP-GW for the S1-U connection") ("spgw.gtpu_bind_addr", bpo::value<string>(&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<string>(&sgi_if_addr)->default_value("176.16.0.1"),"IP address of TUN interface for the SGi connection") ("spgw.sgi_if_addr", bpo::value<string>(&sgi_if_addr)->default_value("176.16.0.1"), "IP address of TUN interface for the SGi connection")
("log.s1ap_level", bpo::value<string>(&args->log_args.s1ap_level), "MME S1AP log level") ("pcap.enable", bpo::value<bool>(&args->mme_args.s1ap_args.pcap_enable)->default_value(false), "Enable S1AP PCAP")
("log.s1ap_hex_limit", bpo::value<int>(&args->log_args.s1ap_hex_limit), "MME S1AP log hex dump limit") ("pcap.filename", bpo::value<string>(&args->mme_args.s1ap_args.pcap_filename)->default_value("/tmp/epc.pcap"), "PCAP filename")
("log.gtpc_level", bpo::value<string>(&args->log_args.gtpc_level), "MME GTPC log level")
("log.gtpc_hex_limit", bpo::value<int>(&args->log_args.gtpc_hex_limit), "MME GTPC log hex dump limit") ("log.s1ap_level", bpo::value<string>(&args->log_args.s1ap_level), "MME S1AP log level")
("log.spgw_level", bpo::value<string>(&args->log_args.spgw_level), "SPGW log level") ("log.s1ap_hex_limit", bpo::value<int>(&args->log_args.s1ap_hex_limit), "MME S1AP log hex dump limit")
("log.spgw_hex_limit", bpo::value<int>(&args->log_args.spgw_hex_limit), "SPGW log hex dump limit") ("log.gtpc_level", bpo::value<string>(&args->log_args.gtpc_level), "MME GTPC log level")
("log.gtpc_hex_limit", bpo::value<int>(&args->log_args.gtpc_hex_limit), "MME GTPC log hex dump limit")
("log.spgw_level", bpo::value<string>(&args->log_args.spgw_level), "SPGW log level")
("log.spgw_hex_limit", bpo::value<int>(&args->log_args.spgw_hex_limit), "SPGW log hex dump limit")
//("log.gtpu_level", bpo::value<string>(&args->log.gtpu_level), "GTPU log level") //("log.gtpu_level", bpo::value<string>(&args->log.gtpu_level), "GTPU log level")
("log.hss_level", bpo::value<string>(&args->log_args.hss_level), "HSS log level") ("log.hss_level", bpo::value<string>(&args->log_args.hss_level), "HSS log level")
("log.hss_hex_limit", bpo::value<int>(&args->log_args.hss_hex_limit), "HSS log hex dump limit") ("log.hss_hex_limit", bpo::value<int>(&args->log_args.hss_hex_limit), "HSS log hex dump limit")
//("log.gtpu_hex_limit",bpo::value<int>(&args->log.gtpu_hex_limit), "GTPU log hex dump limit") //("log.gtpu_hex_limit",bpo::value<int>(&args->log.gtpu_hex_limit), "GTPU log hex dump limit")
("log.all_level", bpo::value<string>(&args->log_args.all_level)->default_value("info"), "ALL log level") ("log.all_level", bpo::value<string>(&args->log_args.all_level)->default_value("info"), "ALL log level")
("log.all_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit") ("log.all_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit")
("log.filename", bpo::value<string>(&args->log_args.filename)->default_value("/tmp/epc.log"),"Log filename") ("log.filename", bpo::value<string>(&args->log_args.filename)->default_value("/tmp/epc.log"),"Log filename")
; ;
// Positional options - config file location // Positional options - config file location
@ -291,7 +294,6 @@ main (int argc,char * argv[] )
srslte::logger_file logger_file; srslte::logger_file logger_file;
srslte::logger *logger; srslte::logger *logger;
/*Init logger*/ /*Init logger*/
if (!args.log_args.filename.compare("stdout")) { if (!args.log_args.filename.compare("stdout")) {
logger = &logger_stdout; logger = &logger_stdout;

@ -99,6 +99,11 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1
//Initialize S1-MME //Initialize S1-MME
m_s1mme = enb_listen(); 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"); m_s1ap_log->info("S1AP Initialized\n");
return 0; return 0;
} }
@ -130,6 +135,12 @@ s1ap::stop()
s1ap_mngmt_proc::cleanup(); s1ap_mngmt_proc::cleanup();
s1ap_nas_transport::cleanup(); s1ap_nas_transport::cleanup();
s1ap_ctx_mngmt_proc::cleanup(); s1ap_ctx_mngmt_proc::cleanup();
//PCAP
if(m_pcap_enable){
m_pcap.close();
}
return; return;
} }
@ -197,6 +208,20 @@ s1ap::enb_listen()
return sock_fd; 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 bool
s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri) 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; return false;
} }
if(m_pcap_enable){
m_pcap.write_s1ap(pdu->msg,pdu->N_bytes);
}
switch(rx_pdu.choice_type) { switch(rx_pdu.choice_type) {
case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE: case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE:
m_s1ap_log->info("Received initiating PDU\n"); 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; bool reply_flag = false;
srslte::byte_buffer_t * reply_buffer = m_pool->allocate(); srslte::byte_buffer_t * reply_buffer = m_pool->allocate();
bool ret = false;
switch(msg->choice_type) { switch(msg->choice_type) {
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST: case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST:
@ -257,20 +287,14 @@ 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->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]); m_s1ap_log->console("Unhandled S1APintiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
} }
//Send Reply to eNB //Send Reply to eNB
if(reply_flag == true) if(reply_flag == true){
{ ret = s1ap_tx_pdu(reply_buffer, enb_sri);
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;
}
} }
m_pool->deallocate(reply_buffer); m_pool->deallocate(reply_buffer);
return true; return ret;
} }
bool bool

@ -138,32 +138,26 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(ue_emm_ctx_t *emm_ctx,
//Set UE security capabilities and k_enb //Set UE security capabilities and k_enb
bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16); bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16);
bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16); bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16);
for(int i = 0; i<3; i++)
{ for (int i = 0; i<3; i++) {
if(emm_ctx->security_ctxt.ue_network_cap.eea[i+1] == true) if(emm_ctx->security_ctxt.ue_network_cap.eea[i+1] == true){
{
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; //EEA supported in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; //EEA supported
} } else {
else
{
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 0; //EEA not supported 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 in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; //EEA supported
} } else {
else
{
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 0; //EEA not supported in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 0; //EEA not supported
} }
} }
//Get K eNB //Get K eNB
liblte_unpack(emm_ctx->security_ctxt.k_enb, 32, in_ctxt_req->SecurityKey.buffer); 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"); 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(); 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 //Attach procedure initiated from an attach request
m_s1ap_log->console("Adding attach accept to Initial Context Setup Request\n"); 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"); 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); 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"); m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n");
return false; return false;
} }
//Send Reply to eNB if (!m_s1ap->s1ap_tx_pdu(reply_buffer,&ecm_ctx->enb_sri)) {
ssize_t n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ecm_ctx->enb_sri, 0); m_s1ap_log->error("Error sending Initial Context Setup Request.\n");
if(n_sent == -1) return false;
{
m_s1ap_log->error("Failed to send Initial Context Setup Request\n");
return false;
} }
//Change E-RAB state to Context Setup Requested and save S-GW control F-TEID //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; return false;
} }
//Send Reply to eNB //Send Reply to eNB
int n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ecm_ctx->enb_sri, 0); if(!m_s1ap->s1ap_tx_pdu(reply_buffer,&ecm_ctx->enb_sri))
if(n_sent == -1)
{ {
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 false;
} }
return true; return true;
} }
bool bool
s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *rel_comp) 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; 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); 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; ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx;
//Delete user plane context at the SPGW (but keep GTP-C connection). //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 //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->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_s1ap_log->info("There are active E-RABs, send release access mearers request");
m_mme_gtpc->send_release_access_bearers_request(ecm_ctx->imsi); 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 //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. //It will release the UEs downstream S1-u and keep the upstream S1-U connection active.
} } else {
else
{
//No ECM Context to release //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->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); 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. //Make sure E-RABS are marked as DEACTIVATED.
for(int i=0;i<MAX_ERABS_PER_UE;i++) for (int i=0;i<MAX_ERABS_PER_UE;i++) {
{
ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED; ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
} }
} }

Loading…
Cancel
Save