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 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

@ -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]
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

@ -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 <strings.h>
#include <arpa/inet.h>
@ -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

@ -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{

@ -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<string>(&mme_code)->default_value("0x01"), "MME Code")
("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.tac", bpo::value<string>(&tac)->default_value("0x0"), "Tracking Area 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.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.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.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.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")
("log.s1ap_hex_limit", bpo::value<int>(&args->log_args.s1ap_hex_limit), "MME S1AP 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")
("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.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.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country 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.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")
("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.")
("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")
("pcap.enable", bpo::value<bool>(&args->mme_args.s1ap_args.pcap_enable)->default_value(false), "Enable S1AP PCAP")
("pcap.filename", bpo::value<string>(&args->mme_args.s1ap_args.pcap_filename)->default_value("/tmp/epc.pcap"), "PCAP filename")
("log.s1ap_level", bpo::value<string>(&args->log_args.s1ap_level), "MME S1AP log level")
("log.s1ap_hex_limit", bpo::value<int>(&args->log_args.s1ap_hex_limit), "MME S1AP 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.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_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.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_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit")
("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.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
@ -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;

@ -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<int32_t,std::set<uint32_t> >::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())
{

@ -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;i<MAX_ERABS_PER_UE;i++)
{
//Make sure E-RABS are marked as DEACTIVATED.
for (int i=0;i<MAX_ERABS_PER_UE;i++) {
ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
}
}

Loading…
Cancel
Save