Applied clang-format to the EPC.

master
Pedro Alvarez 6 years ago committed by Andre Puschmann
parent d8814a05f0
commit add60c1288

@ -52,8 +52,7 @@ const uint8_t GTPC_V2 = 2;
* n+2 | Sequence |
* n+3 | Spare |
***************************************************************************/
typedef struct gtpc_header
{
typedef struct gtpc_header {
uint8_t version;
bool piggyback;
bool teid_present;
@ -68,8 +67,7 @@ typedef struct gtpc_header
*
* Union that hold the different structures for the possible message types.
***************************************************************************/
typedef union gtpc_msg_choice
{
typedef union gtpc_msg_choice {
struct gtpc_create_session_request create_session_request;
struct gtpc_create_session_response create_session_response;
struct gtpc_modify_bearer_request modify_bearer_request;
@ -88,10 +86,9 @@ typedef union gtpc_msg_choice
* of one GTP-C header and one union of structures, which can hold
* all the possible GTP-C messages
***************************************************************************/
typedef struct gtpc_pdu
{
typedef struct gtpc_pdu {
struct gtpc_header header;
union gtpc_msg_choice choice;
} gtpc_pdu_t;
}//namespace
} // namespace srslte
#endif // SRSLTE_GTPC_H

@ -148,9 +148,7 @@ const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_RESPONSE = 236;
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.1-1
*
***************************************************************************/
struct gtpc_create_session_request
{
struct gtpc_create_session_request {
bool imsi_present;
uint64_t imsi; // C
// bool msidn_present;
@ -202,8 +200,8 @@ struct gtpc_create_session_request
struct gtpc_f_teid_ie s12_rnc_f_teid;
bool s2b_u_epdg_f_teid_present;
struct gtpc_f_teid_ie s2b_u_epdg_f_teid;
struct gtpc_bearer_qos_ie bearer_qos; // M
} eps_bearer_context_created; // M
struct gtpc_bearer_qos_ie bearer_qos;
} eps_bearer_context_created;
// bool bearer_context_deleted_present;
// struct bearer_context_ bearer_context_deleted; // C
// bool trace_information_present;
@ -241,8 +239,7 @@ struct gtpc_create_session_request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.2-1
*
***************************************************************************/
struct gtpc_create_session_response
{
struct gtpc_create_session_response {
struct gtpc_cause_ie cause; // M
// Change Reporting Action //C
// CSG Information Reporting Action //CO
@ -255,8 +252,7 @@ struct gtpc_create_session_response
// apn_ambr
// linked_eps_bearer_id
// pco
struct gtpc_bearer_context_created_ie
{
struct gtpc_bearer_context_created_ie {
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_sgw_f_teid_present;
@ -281,7 +277,6 @@ struct gtpc_create_session_response
struct gtpc_bearer_context_removed_ie
{
uint8_t ebi;
//
} bearer_context_removed; //C
*/
// recovery; //C
@ -301,9 +296,7 @@ struct gtpc_create_session_response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.7-1, 7.2.7-2 and 7.2.7-3
*
***************************************************************************/
struct gtpc_modify_bearer_request
{
struct gtpc_modify_bearer_request {
// ME Identity (MEI)//C
// User Location Information (ULI)//C
// Serving Network //CO
@ -312,8 +305,7 @@ struct gtpc_modify_bearer_request
// Sender F-TEID for Control Plane
// APN-AMBR
// Delay Downlink Packet Notification Request
struct gtpc_bearer_context_modified_ie
{
struct gtpc_bearer_context_modified_ie {
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_enb_f_teid_present;
@ -341,9 +333,7 @@ struct gtpc_modify_bearer_request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.8-1
*
***************************************************************************/
struct gtpc_modify_bearer_response
{
struct gtpc_modify_bearer_response {
struct gtpc_cause_ie cause;
// MSISDN
// Linked EPS Bearer ID
@ -351,8 +341,7 @@ struct gtpc_modify_bearer_response
// APN Restriction
// Protocol Configuration Options
struct gtpc_bearer_context_modified_ie
{
struct gtpc_bearer_context_modified_ie {
uint8_t ebi;
struct gtpc_cause_ie cause;
bool s1_u_sgw_f_teid_present;
@ -384,9 +373,7 @@ struct gtpc_modify_bearer_response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.9.1-1
*
***************************************************************************/
struct gtpc_delete_session_request
{
struct gtpc_delete_session_request {
struct gtpc_cause_ie cause;
// Linked EPS Bearer ID
// User Location Information
@ -402,9 +389,7 @@ struct gtpc_delete_session_request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.10.1-1
*
***************************************************************************/
struct gtpc_delete_session_response
{
struct gtpc_delete_session_response {
struct gtpc_cause_ie cause;
// Recovery
// Protocol Configuration Options
@ -417,8 +402,7 @@ struct gtpc_delete_session_response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.21.1-1
*
***************************************************************************/
struct gtpc_release_access_bearers_request
{
struct gtpc_release_access_bearers_request {
bool list_of_rabs_present;
// Linked EPS Bearer ID
bool originating_node_present;
@ -432,15 +416,11 @@ struct gtpc_release_access_bearers_request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.22.1-1
*
***************************************************************************/
struct gtpc_release_access_bearers_response
{
struct gtpc_release_access_bearers_response {
struct gtpc_cause_ie cause;
// Recovery
// Private extension
};
} //namespace
} // namespace srslte
#endif // SRSLTE_GTPC_MSG_H

@ -27,24 +27,24 @@ namespace srsepc {
class nas;
//NAS -> GTP-C
class gtpc_interface_nas
/******************
* MME Interfaces *
******************/
class gtpc_interface_nas // NAS -> GTP-C
{
public:
virtual bool send_create_session_request(uint64_t imsi) = 0;
virtual bool send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, struct srslte::gtpc_f_teid_ie *enb_fteid) = 0;
virtual bool send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t* enb_fteid) = 0;
virtual bool send_delete_session_request(uint64_t imsi) = 0;
};
//GTP-C -> S1AP
class s1ap_interface_gtpc
class s1ap_interface_gtpc // GTP-C -> S1AP
{
public:
virtual bool send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup) = 0;
};
//NAS -> S1AP
class s1ap_interface_nas
class s1ap_interface_nas // NAS -> S1AP
{
public:
virtual uint32_t allocate_m_tmsi(uint64_t imsi) = 0;
@ -58,11 +58,13 @@ public:
virtual nas* find_nas_ctx_from_imsi(uint64_t imsi) = 0;
virtual bool send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup) = 0;
virtual bool send_ue_context_release_command(uint32_t mme_ue_s1ap_id) = 0;
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri) = 0;
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri) = 0;
};
//NAS -> HSS
class hss_interface_nas
class hss_interface_nas // NAS -> HSS
{
public:
virtual bool gen_auth_info_answer(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres) = 0;
@ -70,5 +72,5 @@ public:
virtual bool resync_sqn(uint64_t imsi, uint8_t* auts) = 0;
};
}
} // namespace srsepc
#endif // SRSLTE_EPC_INTERFACES_H

@ -1,5 +1,4 @@
/**
*
/*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
@ -29,12 +28,9 @@
namespace srslte {
int
gtpc_pack_create_session_request(struct gtpc_create_session_request *cs_req, srslte::byte_buffer_t)
int gtpc_pack_create_session_request(struct gtpc_create_session_request* cs_req, srslte::byte_buffer_t)
{
//FIXME
// TODO
return 0;
}
};
} // namespace srslte

@ -69,10 +69,7 @@ typedef struct{
uint8_t last_rand[16];
} hss_ue_ctx_t;
enum hss_auth_algo {
HSS_ALGO_XOR,
HSS_ALGO_MILENAGE
};
enum hss_auth_algo { HSS_ALGO_XOR, HSS_ALGO_MILENAGE };
class hss : public hss_interface_nas
{
@ -88,16 +85,12 @@ public:
virtual bool resync_sqn(uint64_t imsi, uint8_t* auts);
private:
hss();
virtual ~hss();
static hss* m_instance;
srslte::byte_buffer_pool *m_pool;
std::map<uint64_t, hss_ue_ctx_t*> m_imsi_to_ue_ctx;
void gen_rand(uint8_t rand_[16]);
bool get_k_amf_opc_sqn(uint64_t imsi, uint8_t* k, uint8_t* amf, uint8_t* opc, uint8_t* sqn);
@ -127,6 +120,7 @@ private:
enum hss_auth_algo m_auth_algo;
std::string db_file;
/*Logs*/
srslte::log_filter* m_hss_log;
@ -135,5 +129,4 @@ private:
};
} // namespace srsepc
#endif // SRSEPC_HSS_H

@ -41,7 +41,6 @@
#include "srslte/common/threads.h"
#include "s1ap.h"
namespace srsepc {
typedef struct {
@ -50,20 +49,21 @@ typedef struct{
// gtpc_args_t gtpc_args;
} mme_args_t;
class mme:
public thread
class mme : public thread
{
public:
static mme* get_instance(void);
static void cleanup(void);
int init(mme_args_t* args, srslte::log_filter *nas_log, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log, hss_interface_nas * hss);
int init(mme_args_t* args,
srslte::log_filter* nas_log,
srslte::log_filter* s1ap_log,
srslte::log_filter* mme_gtpc_log);
void stop();
int get_s1_mme();
void run_thread();
private:
mme();
virtual ~mme();
static mme* m_instance;
@ -80,5 +80,4 @@ private:
};
} // namespace srsepc
#endif // SRSEPC_MME_H

@ -26,23 +26,20 @@
#ifndef SRSEPC_MME_GTPC_H
#define SRSEPC_MME_GTPC_H
#include "nas.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/asn1/gtpc.h"
#include "nas.h"
namespace srsepc
{
namespace srsepc {
class spgw;
class s1ap;
class mme_gtpc
: public gtpc_interface_nas
class mme_gtpc : public gtpc_interface_nas
{
public:
typedef struct gtpc_ctx {
srslte::gtp_fteid_t mme_ctr_fteid;
srslte::gtp_fteid_t sgw_ctr_fteid;
@ -61,7 +58,6 @@ public:
virtual bool send_delete_session_request(uint64_t imsi);
private:
mme_gtpc();
virtual ~mme_gtpc();
static mme_gtpc* m_instance;
@ -76,8 +72,7 @@ private:
uint32_t m_next_ctrl_teid;
std::map<uint32_t, uint64_t> m_mme_ctr_teid_to_imsi;
std::map<uint64_t, struct gtpc_ctx> m_imsi_to_gtpc_ctx;
};
}
} // namespace srsepc
#endif // SRSEPC_MME_GTPC_H

@ -21,14 +21,13 @@
#ifndef SRSEPC_NAS_H
#define SRSEPC_NAS_H
#include <netinet/sctp.h>
#include "srslte/common/security.h"
#include "srslte/asn1/gtpc_ies.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/asn1/liblte_mme.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/security.h"
#include "srslte/interfaces/epc_interfaces.h"
#include <netinet/sctp.h>
namespace srsepc {
@ -42,9 +41,7 @@ typedef enum {
EMM_STATE_DEREGISTERED_INITIATED,
EMM_STATE_N_ITEMS,
} emm_state_t;
static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"DEREGISTERED",
"COMMON PROCEDURE INITIATED",
"REGISTERED",
static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"DEREGISTERED", "COMMON PROCEDURE INITIATED", "REGISTERED",
"DEREGISTERED INITIATED"};
// MME ECM states (3GPP 23.401 v10.0.0, section 4.6.3)
@ -53,8 +50,8 @@ typedef enum {
ECM_STATE_CONNECTED,
ECM_STATE_N_ITEMS,
} ecm_state_t;
static const char ecm_state_text[ECM_STATE_N_ITEMS][100] = {"IDLE",
"CONNECTED"};
static const char ecm_state_text[ECM_STATE_N_ITEMS][100] = {"IDLE", "CONNECTED"};
/*
// MME ESM states (3GPP 23.401 v10.0.0, section 4.6.3)
typedef enum {
@ -75,13 +72,7 @@ static const char esm_state_text[ESM_STATE_N_ITEMS][100] = {"CONTEXT INACTIVE",
"PROCEDURE_TRANSACTION_INACTIVE"
"PROCEDURE_TRANSACTION_PENDING"};
*/
typedef enum
{
ERAB_DEACTIVATED,
ERAB_CTX_REQUESTED,
ERAB_CTX_SETUP,
ERAB_ACTIVE
} esm_state_t;
typedef enum { ERAB_DEACTIVATED, ERAB_CTX_REQUESTED, ERAB_CTX_SETUP, ERAB_ACTIVE } esm_state_t;
/*
* EMM, ECM, ESM and EPS Security context definitions
@ -191,7 +182,6 @@ public:
hss_interface_nas* hss,
srslte::log* nas_log);
static bool handle_guti_attach_request_unknown_ue(uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
@ -213,6 +203,7 @@ public:
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
// Service request messages
static bool handle_service_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
@ -295,5 +286,5 @@ private:
std::string m_dns;
};
}//namespace
} // namespace srsepc
#endif // SRSEPC_NAS_H

@ -26,44 +26,40 @@
#ifndef SRSEPC_S1AP_H
#define SRSEPC_S1AP_H
#include "mme_gtpc.h"
#include "nas.h"
#include "s1ap_ctx_mngmt_proc.h"
#include "s1ap_mngmt_proc.h"
#include "s1ap_nas_transport.h"
#include "srsepc/hdr/hss/hss.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/asn1/liblte_mme.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/s1ap_pcap.h"
#include "srslte/interfaces/epc_interfaces.h"
#include <strings.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/sctp.h>
#include <unistd.h>
#include <map>
#include <netinet/sctp.h>
#include <set>
#include "nas.h"
#include "s1ap_mngmt_proc.h"
#include "s1ap_nas_transport.h"
#include "s1ap_ctx_mngmt_proc.h"
#include "mme_gtpc.h"
#include "srsepc/hdr/hss/hss.h"
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
namespace srsepc {
const uint16_t S1MME_PORT = 36412;
class s1ap:
public s1ap_interface_nas,
public s1ap_interface_gtpc
class s1ap : public s1ap_interface_nas, public s1ap_interface_gtpc
{
public:
static s1ap* get_instance();
static void cleanup();
int enb_listen();
int init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, srslte::log_filter *nas_log, hss_interface_nas * hss_);
int init(s1ap_args_t s1ap_args, srslte::log_filter* s1ap_log, srslte::log_filter* nas_log);
void stop();
int get_s1_mme();
@ -112,7 +108,11 @@ public:
// Interfaces
virtual bool send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup);
virtual bool send_ue_context_release_command(uint32_t mme_ue_s1ap_id);
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri);
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri);
private:
s1ap();
virtual ~s1ap();
@ -142,13 +142,10 @@ private:
srslte::s1ap_pcap m_pcap;
};
inline uint32_t
s1ap::get_plmn()
inline uint32_t s1ap::get_plmn()
{
return m_plmn;
}
} // namespace srsepc
#endif // SRSEPC_S1AP_H

@ -26,12 +26,12 @@
#ifndef SRSEPC_S1AP_CTX_MNGMT_PROC_H
#define SRSEPC_S1AP_CTX_MNGMT_PROC_H
#include "mme_gtpc.h"
#include "s1ap_common.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/common.h"
#include "s1ap_common.h"
#include "srslte/common/log_filter.h"
#include "mme_gtpc.h"
#include "srslte/common/buffer_pool.h"
namespace srsepc {
@ -40,7 +40,6 @@ class s1ap;
class s1ap_ctx_mngmt_proc
{
public:
static s1ap_ctx_mngmt_proc* m_instance;
static s1ap_ctx_mngmt_proc* get_instance(void);
static void cleanup(void);
@ -49,7 +48,10 @@ public:
bool send_initial_context_setup_request(nas* nas_ctx, uint16_t erab_to_setup);
bool handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT* in_ctxt_resp);
bool handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *ue_rel, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT* ue_rel,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag);
bool send_ue_context_release_command(nas* nas_ctx);
bool handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT* rel_comp);
@ -58,7 +60,6 @@ private:
virtual ~s1ap_ctx_mngmt_proc();
s1ap* m_s1ap;
s1ap_nas_transport* m_s1ap_nas_transport;
srslte::log_filter* m_s1ap_log;
s1ap_args_t m_s1ap_args;
@ -68,5 +69,4 @@ private:
};
} // namespace srsepc
#endif // SRSEPC_S1AP_CTX_MNGMT_PROC_H

@ -26,12 +26,12 @@
#ifndef SRSEPC_S1AP_NAS_TRANSPORT_H
#define SRSEPC_S1AP_NAS_TRANSPORT_H
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/buffer_pool.h"
#include "mme_gtpc.h"
#include "s1ap_common.h"
#include "srslte/asn1/gtpc.h"
#include "srsepc/hdr/hss/hss.h"
#include "mme_gtpc.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/buffer_pool.h"
namespace srsepc {
@ -39,16 +39,21 @@ class s1ap_nas_transport
{
public:
static s1ap_nas_transport* m_instance;
static s1ap_nas_transport* get_instance(void);
static void cleanup(void);
void init(hss_interface_nas * hss_);
static s1ap_nas_transport* get_instance();
static void cleanup();
void init();
bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT* init_ue, struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer, bool* reply_flag);
bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT* init_ue,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag);
bool handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT* ul_xport,
struct sctp_sndrcvinfo* enb_sri, srslte::byte_buffer_t* reply_buffer,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag);
bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t* nas_msg,
bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri);
private:
@ -62,5 +67,6 @@ private:
hss_interface_nas* m_hss;
mme_gtpc* m_mme_gtpc;
};
} // namespace srsepc
#endif // SRSEPC_S1AP_NAS_TRANSPORT_H

@ -53,19 +53,17 @@ typedef struct {
std::string sgi_if_name;
} spgw_args_t;
typedef struct spgw_tunnel_ctx {
uint64_t imsi;
in_addr_t ue_ipv4;
uint8_t ebi;
struct srslte::gtpc_f_teid_ie up_ctrl_fteid;
struct srslte::gtpc_f_teid_ie up_user_fteid;
struct srslte::gtpc_f_teid_ie dw_ctrl_fteid;
struct srslte::gtpc_f_teid_ie dw_user_fteid;
srslte::gtp_fteid_t up_ctrl_fteid;
srslte::gtp_fteid_t up_user_fteid;
srslte::gtp_fteid_t dw_ctrl_fteid;
srslte::gtp_fteid_t dw_user_fteid;
} spgw_tunnel_ctx_t;
class spgw:
public thread
class spgw : public thread
{
public:
static spgw* get_instance(void);
@ -74,16 +72,17 @@ public:
void stop();
void run_thread();
void handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu);
void handle_create_session_request(struct srslte::gtpc_create_session_request* cs_req,
struct srslte::gtpc_pdu* cs_resp_pdu);
void handle_modify_bearer_request(struct srslte::gtpc_pdu* mb_req_pdu, struct srslte::gtpc_pdu* mb_resp_pdu);
void handle_delete_session_request(struct srslte::gtpc_pdu* del_req_pdu, struct srslte::gtpc_pdu* del_resp_pdu);
void handle_release_access_bearers_request(struct srslte::gtpc_pdu *rel_req_pdu, struct srslte::gtpc_pdu *rel_resp_pdu);
void handle_release_access_bearers_request(struct srslte::gtpc_pdu* rel_req_pdu,
struct srslte::gtpc_pdu* rel_resp_pdu);
void handle_sgi_pdu(srslte::byte_buffer_t* msg);
void handle_s1u_pdu(srslte::byte_buffer_t* msg);
private:
spgw();
virtual ~spgw();
static spgw* m_instance;
@ -99,12 +98,10 @@ private:
spgw_tunnel_ctx_t* create_gtp_ctx(struct srslte::gtpc_create_session_request* cs_req);
bool delete_gtp_ctx(uint32_t ctrl_teid);
bool m_running;
srslte::byte_buffer_pool* m_pool;
mme_gtpc* m_mme_gtpc;
bool m_sgi_up;
int m_sgi_if;
int m_sgi_sock;
@ -119,21 +116,19 @@ private:
pthread_mutex_t m_mutex;
std::map<uint64_t,uint32_t> m_imsi_to_ctr_teid; //IMSI to control TEID map. Important to check if UE is previously connected
std::map<uint32_t,spgw_tunnel_ctx*> m_teid_to_tunnel_ctx; //Map control TEID to tunnel ctx. Usefull to get reply ctrl TEID, UE IP, etc.
std::map<uint64_t, uint32_t> m_imsi_to_ctr_teid; // IMSI to control TEID map.
// Important to check if UE is previously connected
std::map<uint32_t, spgw_tunnel_ctx*> m_teid_to_tunnel_ctx; // Map control TEID to tunnel ctx.
// Usefull to get reply ctrl TEID, UE IP, etc.
std::map<in_addr_t, srslte::gtpc_f_teid_ie> m_ip_to_teid; // Map IP to User-plane TEID for downlink traffic
uint32_t m_h_next_ue_ip;
/*Time*/
struct timeval m_t_last_dl;
struct timeval m_t_last_ul;
/*Logs*/
srslte::log_filter* m_spgw_log;
};
} // namespace srsepc
#endif // SRSEPC_SPGW_H

@ -23,16 +23,14 @@
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <string>
#include <sstream>
#include <iomanip>
#include <inttypes.h> // for printing uint64_t
#include "srsepc/hdr/hss/hss.h"
#include "srslte/common/security.h"
using namespace srslte;
#include <inttypes.h> // for printing uint64_t
#include <iomanip>
#include <sstream>
#include <stdlib.h> /* srand, rand */
#include <string>
#include <time.h>
namespace srsepc {
@ -41,7 +39,6 @@ pthread_mutex_t hss_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
hss::hss()
{
m_pool = srslte::byte_buffer_pool::get_instance();
return;
}
@ -50,8 +47,7 @@ hss::~hss()
return;
}
hss*
hss::get_instance(void)
hss* hss::get_instance()
{
pthread_mutex_lock(&hss_instance_mutex);
if (NULL == m_instance) {
@ -61,8 +57,7 @@ hss::get_instance(void)
return (m_instance);
}
void
hss::cleanup(void)
void hss::cleanup()
{
pthread_mutex_lock(&hss_instance_mutex);
if (NULL != m_instance) {
@ -72,21 +67,18 @@ hss::cleanup(void)
pthread_mutex_unlock(&hss_instance_mutex);
}
int
hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
int hss::init(hss_args_t* hss_args, srslte::log_filter* hss_log)
{
srand(time(NULL));
/*Init loggers*/
m_hss_log = hss_log;
/*Set authentication algorithm*/
if(set_auth_algo(hss_args->auth_algo) == false)
{
if (set_auth_algo(hss_args->auth_algo) == false) {
return -1;
}
/*Read user information from DB*/
if(read_db_file(hss_args->db_file) == false)
{
if (read_db_file(hss_args->db_file) == false) {
m_hss_log->console("Error reading user database file %s\n", hss_args->db_file.c_str());
return -1;
}
@ -96,18 +88,17 @@ hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
db_file = hss_args->db_file;
m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s, MCC: %d, MNC: %d\n", hss_args->db_file.c_str(),hss_args->auth_algo.c_str(), mcc, mnc);
m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s, MCC: %d, MNC: %d\n",
hss_args->db_file.c_str(), hss_args->auth_algo.c_str(), mcc, mnc);
m_hss_log->console("HSS Initialized.\n");
return 0;
}
void
hss::stop(void)
void hss::stop()
{
write_db_file(db_file);
std::map<uint64_t, hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end())
{
while (it != m_imsi_to_ue_ctx.end()) {
m_hss_log->info("Deleting UE context in HSS. IMSI: %015" PRIu64 "\n", it->second->imsi);
m_hss_log->console("Deleting UE context in HSS. IMSI: %015" PRIu64 "\n", it->second->imsi);
delete it->second;
@ -116,47 +107,36 @@ hss::stop(void)
return;
}
bool
hss::set_auth_algo(std::string auth_algo)
{
if(auth_algo != "xor" && auth_algo != "milenage" )
bool hss::set_auth_algo(std::string auth_algo)
{
if (auth_algo != "xor" && auth_algo != "milenage") {
m_hss_log->error("Unrecognized authentication algorithm. auth_algo = %s\n", auth_algo.c_str());
return false;
}
if(auth_algo == "xor")
{
if (auth_algo == "xor") {
m_auth_algo = HSS_ALGO_XOR;
}
else
{
} else {
m_auth_algo = HSS_ALGO_MILENAGE;
}
return true;
}
bool
hss::read_db_file(std::string db_filename)
bool hss::read_db_file(std::string db_filename)
{
std::ifstream m_db_file;
m_db_file.open(db_filename.c_str(), std::ifstream::in);
if(!m_db_file.is_open())
{
if (!m_db_file.is_open()) {
return false;
}
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str());
std::string line;
while (std::getline(m_db_file, line))
{
if(line[0] != '#')
{
while (std::getline(m_db_file, line)) {
if (line[0] != '#') {
uint column_size = 8;
std::vector<std::string> split = split_string(line, ',');
if(split.size() != column_size)
{
if (split.size() != column_size) {
m_hss_log->error("Error parsing UE database. Wrong number of columns in .csv\n");
m_hss_log->error("Columns: %zd, Expected %d.\n", split.size(), column_size);
return false;
@ -165,19 +145,14 @@ hss::read_db_file(std::string db_filename)
ue_ctx->name = split[0];
ue_ctx->imsi = atoll(split[1].c_str());
get_uint_vec_from_hex_str(split[2], ue_ctx->key, 16);
if(split[3] == std::string("op"))
{
if (split[3] == std::string("op")) {
ue_ctx->op_configured = true;
get_uint_vec_from_hex_str(split[4], ue_ctx->op, 16);
compute_opc(ue_ctx->key,ue_ctx->op,ue_ctx->opc);
}
else if (split[3] == std::string("opc"))
{
srslte::compute_opc(ue_ctx->key, ue_ctx->op, ue_ctx->opc);
} else if (split[3] == std::string("opc")) {
ue_ctx->op_configured = false;
get_uint_vec_from_hex_str(split[4], ue_ctx->opc, 16);
}
else
{
} else {
m_hss_log->error("Neither OP nor OPc configured.\n");
return false;
}
@ -198,8 +173,7 @@ hss::read_db_file(std::string db_filename)
}
}
if(m_db_file.is_open())
{
if (m_db_file.is_open()) {
m_db_file.close();
}
@ -217,8 +191,7 @@ bool hss::write_db_file(std::string db_filename)
std::ofstream m_db_file;
m_db_file.open(db_filename.c_str(), std::ofstream::out);
if(!m_db_file.is_open())
{
if (!m_db_file.is_open()) {
return false;
}
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str());
@ -240,8 +213,7 @@ bool hss::write_db_file(std::string db_filename)
<< "# Note: Lines starting by '#' are ignored and will be overwritten " << std::endl;
std::map<uint64_t, hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end())
{
while (it != m_imsi_to_ue_ctx.end()) {
m_db_file << it->second->name;
m_db_file << ",";
m_db_file << std::setfill('0') << std::setw(15) << it->second->imsi;
@ -251,8 +223,7 @@ bool hss::write_db_file(std::string db_filename)
if (it->second->op_configured) {
m_db_file << "op,";
m_db_file << hex_string(it->second->op, 16);
}
else{
} else {
m_db_file << "opc,";
m_db_file << hex_string(it->second->opc, 16);
}
@ -265,19 +236,16 @@ bool hss::write_db_file(std::string db_filename)
m_db_file << std::endl;
it++;
}
if(m_db_file.is_open())
{
if (m_db_file.is_open()) {
m_db_file.close();
}
return true;
}
bool
hss::gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
bool hss::gen_auth_info_answer(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres)
{
bool ret = false;
switch (m_auth_algo)
{
switch (m_auth_algo) {
case HSS_ALGO_XOR:
ret = gen_auth_info_answer_xor(imsi, k_asme, autn, rand, xres);
break;
@ -287,13 +255,9 @@ hss::gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t
}
increment_ue_sqn(imsi);
return ret;
}
bool
hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
bool hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres)
{
uint8_t k[16];
uint8_t amf[2];
@ -305,20 +269,12 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
uint8_t ak[6];
uint8_t mac[8];
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
if (!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn)) {
return false;
}
gen_rand(rand);
security_milenage_f2345( k,
opc,
rand,
xres,
ck,
ik,
ak);
srslte::security_milenage_f2345(k, opc, rand, xres, ck, ik, ak);
m_hss_log->debug_hex(k, 16, "User Key : ");
m_hss_log->debug_hex(opc, 16, "User OPc : ");
@ -328,51 +284,34 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
m_hss_log->debug_hex(ik, 16, "User IK: ");
m_hss_log->debug_hex(ak, 6, "User AK: ");
security_milenage_f1( k,
opc,
rand,
sqn,
amf,
mac);
srslte::security_milenage_f1(k, opc, rand, sqn, amf, mac);
m_hss_log->debug_hex(sqn, 6, "User SQN : ");
m_hss_log->debug_hex(mac, 8, "User MAC : ");
// Generate K_asme
security_generate_k_asme( ck,
ik,
ak,
sqn,
mcc,
mnc,
k_asme);
srslte::security_generate_k_asme(ck, ik, ak, sqn, mcc, mnc, k_asme);
m_hss_log->debug("User MCC : %x MNC : %x \n", mcc, mnc);
m_hss_log->debug_hex(k_asme, 32, "User k_asme : ");
// Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
for (int i = 0; i < 6; i++) {
autn[i] = sqn[i] ^ ak[i];
}
for(int i=0;i<2;i++)
{
for (int i = 0; i < 2; i++) {
autn[6 + i] = amf[i];
}
for(int i=0;i<8;i++)
{
for (int i = 0; i < 8; i++) {
autn[8 + i] = mac[i];
}
m_hss_log->debug_hex(autn, 16, "User AUTN: ");
set_last_rand(imsi, rand);
return true;
}
bool
hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
bool hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres)
{
uint8_t k[16];
uint8_t amf[2];
@ -389,8 +328,7 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
int i = 0;
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
if (!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn)) {
return false;
}
gen_rand(rand);
@ -434,42 +372,30 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
m_hss_log->debug_hex(mac, 8, "User MAC : ");
// Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
for (int i = 0; i < 6; i++) {
autn[i] = sqn[i] ^ ak[i];
}
for(int i=0;i<2;i++)
{
for (int i = 0; i < 2; i++) {
autn[6 + i] = amf[i];
}
for(int i=0;i<8;i++)
{
for (int i = 0; i < 8; i++) {
autn[8 + i] = mac[i];
}
// Generate K_asme
security_generate_k_asme( ck,
ik,
ak,
sqn,
mcc,
mnc,
k_asme);
srslte::security_generate_k_asme(ck, ik, ak, sqn, mcc, mnc, k_asme);
m_hss_log->debug("User MCC : %x MNC : %x \n", mcc, mnc);
m_hss_log->debug_hex(k_asme, 32, "User k_asme : ");
// Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
for (int i = 0; i < 6; i++) {
autn[i] = sqn[i] ^ ak[i];
}
for(int i=0;i<2;i++)
{
for (int i = 0; i < 2; i++) {
autn[6 + i] = amf[i];
}
for(int i=0;i<8;i++)
{
for (int i = 0; i < 8; i++) {
autn[8 + i] = mac[i];
}
@ -480,12 +406,10 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
return true;
}
bool
hss::gen_update_loc_answer(uint64_t imsi, uint8_t* qci)
bool hss::gen_update_loc_answer(uint64_t imsi, uint8_t* qci)
{
std::map<uint64_t, hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
if (ue_ctx_it == m_imsi_to_ue_ctx.end()) {
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n", imsi);
m_hss_log->console("User not found at HSS. IMSI: %015" PRIu64 "\n", imsi);
return false;
@ -496,15 +420,10 @@ hss::gen_update_loc_answer(uint64_t imsi, uint8_t* qci)
return true;
}
bool
hss::get_k_amf_opc_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *opc, uint8_t *sqn)
bool hss::get_k_amf_opc_sqn(uint64_t imsi, uint8_t* k, uint8_t* amf, uint8_t* opc, uint8_t* sqn)
{
std::map<uint64_t, hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
if (ue_ctx_it == m_imsi_to_ue_ctx.end()) {
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n", imsi);
m_hss_log->console("User not found at HSS. IMSI: %015" PRIu64 "\n", imsi);
return false;
@ -515,16 +434,13 @@ hss::get_k_amf_opc_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *opc, ui
memcpy(amf, ue_ctx->amf, 2);
memcpy(opc, ue_ctx->opc, 16);
memcpy(sqn, ue_ctx->sqn, 6);
return true;
}
bool
hss::resync_sqn(uint64_t imsi, uint8_t *auts)
bool hss::resync_sqn(uint64_t imsi, uint8_t* auts)
{
bool ret = false;
switch (m_auth_algo)
{
switch (m_auth_algo) {
case HSS_ALGO_XOR:
ret = resync_sqn_xor(imsi, auts);
break;
@ -536,17 +452,14 @@ hss::resync_sqn(uint64_t imsi, uint8_t *auts)
return ret;
}
bool
hss::resync_sqn_xor(uint64_t imsi, uint8_t *auts)
bool hss::resync_sqn_xor(uint64_t imsi, uint8_t* auts)
{
m_hss_log->error("XOR SQN synchronization not supported yet\n");
m_hss_log->console("XOR SQNs synchronization not supported yet\n");
return false;
}
bool
hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
bool hss::resync_sqn_milenage(uint64_t imsi, uint8_t* auts)
{
uint8_t last_rand[16];
uint8_t ak[6];
@ -558,8 +471,7 @@ hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
uint8_t opc[16];
uint8_t sqn[6];
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
if (!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn)) {
return false;
}
@ -580,7 +492,7 @@ hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
m_hss_log->debug_hex(sqn_ms_xor_ak, 6, "SQN xor AK : ");
m_hss_log->debug_hex(mac_s, 8, "MAC : ");
security_milenage_f5_star(k, opc, last_rand, ak);
srslte::security_milenage_f5_star(k, opc, last_rand, ak);
m_hss_log->debug_hex(ak, 6, "Resynch AK : ");
uint8_t sqn_ms[6];
@ -598,22 +510,18 @@ hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
amf[i] = 0;
}
security_milenage_f1_star(k, opc, last_rand, sqn_ms, amf, mac_s_tmp);
srslte::security_milenage_f1_star(k, opc, last_rand, sqn_ms, amf, mac_s_tmp);
m_hss_log->debug_hex(mac_s_tmp, 8, "MAC calc : ");
set_sqn(imsi, sqn_ms);
return true;
}
void
hss::increment_ue_sqn(uint64_t imsi)
void hss::increment_ue_sqn(uint64_t imsi)
{
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
if (ret == false) {
return;
}
@ -622,19 +530,16 @@ hss::increment_ue_sqn(uint64_t imsi)
m_hss_log->debug_hex(ue_ctx->sqn, 6, "SQN: ");
}
void
hss::increment_sqn(uint8_t *sqn, uint8_t *next_sqn)
void hss::increment_sqn(uint8_t* sqn, uint8_t* next_sqn)
{
// The following SQN incrementation function is implemented according to 3GPP TS 33.102 version 11.5.1 Annex C
uint64_t seq;
uint64_t ind;
uint64_t sqn64;
sqn64 = 0;
for(int i=0; i<6; i++)
{
for (int i = 0; i < 6; i++) {
sqn64 |= (uint64_t)sqn[i] << (5 - i) * 8;
}
@ -649,26 +554,18 @@ hss::increment_sqn(uint8_t *sqn, uint8_t *next_sqn)
nextind = (ind + 1) % LTE_FDD_ENB_IND_HE_MAX_VALUE;
nextsqn = (nextseq << LTE_FDD_ENB_IND_HE_N_BITS) | nextind;
for(int i=0; i<6; i++)
{
for (int i = 0; i < 6; i++) {
next_sqn[i] = (nextsqn >> (5 - i) * 8) & 0xFF;
}
return;
}
void
hss::increment_seq_after_resync(uint64_t imsi)
void hss::increment_seq_after_resync(uint64_t imsi)
{
// This function only increment the SEQ part of the SQN for resynchronization purpose
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
if (ret == false) {
return;
}
@ -680,8 +577,7 @@ hss::increment_seq_after_resync(uint64_t imsi)
sqn64 = 0;
for(int i=0; i<6; i++)
{
for (int i = 0; i < 6; i++) {
sqn64 |= (uint64_t)sqn[i] << (5 - i) * 8;
}
@ -694,59 +590,45 @@ hss::increment_seq_after_resync(uint64_t imsi)
nextseq = (seq + 1) % LTE_FDD_ENB_SEQ_HE_MAX_VALUE;
nextsqn = (nextseq << LTE_FDD_ENB_IND_HE_N_BITS) | ind;
for(int i=0; i<6; i++)
{
for (int i = 0; i < 6; i++) {
sqn[i] = (nextsqn >> (5 - i) * 8) & 0xFF;
}
return;
}
void
hss::set_sqn(uint64_t imsi, uint8_t *sqn)
void hss::set_sqn(uint64_t imsi, uint8_t* sqn)
{
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
if (ret == false) {
return;
}
memcpy(ue_ctx->sqn, sqn, 6);
}
void
hss::set_last_rand(uint64_t imsi, uint8_t *rand)
void hss::set_last_rand(uint64_t imsi, uint8_t* rand)
{
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
if (ret == false) {
return;
}
memcpy(ue_ctx->last_rand, rand, 16);
}
void
hss::get_last_rand(uint64_t imsi, uint8_t *rand)
void hss::get_last_rand(uint64_t imsi, uint8_t* rand)
{
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
if (ret == false) {
return;
}
memcpy(rand, ue_ctx->last_rand, 16);
}
void
hss::gen_rand(uint8_t rand_[16])
{
for(int i=0;i<16;i++)
void hss::gen_rand(uint8_t rand_[16])
{
for (int i = 0; i < 16; i++) {
rand_[i] = rand() % 256; // Pulls on byte at a time. It's slow, but does not depend on RAND_MAX.
}
return;
@ -755,8 +637,7 @@ hss::gen_rand(uint8_t rand_[16])
bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t** ue_ctx)
{
std::map<uint64_t, hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
if (ue_ctx_it == m_imsi_to_ue_ctx.end()) {
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n", imsi);
return false;
}
@ -766,22 +647,19 @@ bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx)
}
/* Helper functions*/
std::vector<std::string>
hss::split_string(const std::string &str, char delimiter)
std::vector<std::string> hss::split_string(const std::string& str, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, delimiter))
{
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
void
hss::get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len)
void hss::get_uint_vec_from_hex_str(const std::string& key_str, uint8_t* key, uint len)
{
const char* pos = key_str.c_str();
@ -789,13 +667,10 @@ hss::get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint le
sscanf(pos, "%2hhx", &key[count]);
pos += 2;
}
return;
}
std::string
hss::hex_string(uint8_t *hex, int size)
std::string hss::hex_string(uint8_t* hex, int size)
{
std::stringstream ss;

@ -21,20 +21,20 @@
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include <sstream>
#include <fstream>
#include <errno.h>
#include <signal.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "srslte/common/crash_handler.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/config_file.h"
#include "srslte/build_info.h"
#include "srsepc/hdr/mme/mme.h"
#include "srsepc/hdr/hss/hss.h"
#include "srsepc/hdr/mme/mme.h"
#include "srsepc/hdr/spgw/spgw.h"
#include "srslte/build_info.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/config_file.h"
#include "srslte/common/crash_handler.h"
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <sstream>
using namespace std;
using namespace srsepc;
@ -42,8 +42,8 @@ namespace bpo = boost::program_options;
bool running = true;
void
sig_int_handler(int signo){
void sig_int_handler(int signo)
{
running = false;
}
@ -63,7 +63,6 @@ typedef struct {
std::string filename;
} log_args_t;
typedef struct {
mme_args_t mme_args;
hss_args_t hss_args;
@ -76,9 +75,8 @@ typedef struct{
***********************************************************************/
string config_file;
void
parse_args(all_args_t *args, int argc, char* argv[]) {
void parse_args(all_args_t* args, int argc, char* argv[])
{
string mme_name;
string mme_code;
string mme_group;
@ -107,7 +105,6 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
// Command line or config file options
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")
@ -136,10 +133,8 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
("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.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")
@ -212,6 +207,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
sstr << std::hex << vm["mme.tac"].as<std::string>();
sstr >> args->mme_args.s1ap_args.tac;
}
// Convert MCC/MNC strings
if (!srslte::string_to_mcc(mcc, &args->mme_args.s1ap_args.mcc)) {
cout << "Error parsing mme.mcc:" << mcc << " - must be a 3-digit string." << endl;
@ -242,7 +238,8 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
if (boost::iequals(integrity_algo, "eia0")) {
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_EIA0;
cout << "Warning parsing mme.integrity_algo:" << encryption_algo << " - EIA0 will not supported by UEs use EIA1 or EIA2" << endl;
cout << "Warning parsing mme.integrity_algo:" << encryption_algo
<< " - EIA0 will not supported by UEs use EIA1 or EIA2" << endl;
} else if (boost::iequals(integrity_algo, "eia1")) {
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1;
} else if (boost::iequals(integrity_algo, "eia2")) {
@ -310,8 +307,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
return;
}
srslte::LOG_LEVEL_ENUM
level(std::string l)
srslte::LOG_LEVEL_ENUM level(std::string l)
{
boost::to_upper(l);
if ("NONE" == l) {
@ -349,8 +345,7 @@ std::string get_build_string()
return ss.str();
}
int
main (int argc,char * argv[] )
int main(int argc, char* argv[])
{
signal(SIGINT, sig_int_handler);
signal(SIGTERM, sig_int_handler);
@ -405,7 +400,6 @@ main (int argc,char * argv[] )
spgw_log.set_level(level(args.log_args.spgw_level));
spgw_log.set_hex_limit(args.log_args.spgw_hex_limit);
hss* hss = hss::get_instance();
if (hss->init(&args.hss_args, &hss_log)) {
cout << "Error initializing HSS" << endl;
@ -413,7 +407,7 @@ main (int argc,char * argv[] )
}
mme* mme = mme::get_instance();
if (mme->init(&args.mme_args, &nas_log, &s1ap_log, &mme_gtpc_log, hss)) {
if (mme->init(&args.mme_args, &nas_log, &s1ap_log, &mme_gtpc_log)) {
cout << "Error initializing MME" << endl;
exit(1);
}

@ -24,20 +24,19 @@
*
*/
#include <iostream> //TODO Remove
#include "srsepc/hdr/mme/mme.h"
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <inttypes.h> // for printing uint64_t
#include <netinet/sctp.h>
#include "srsepc/hdr/mme/mme.h"
#include <sys/socket.h>
#include <sys/types.h>
namespace srsepc {
mme* mme::m_instance = NULL;
pthread_mutex_t mme_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
mme::mme():
m_running(false)
mme::mme() : m_running(false)
{
m_pool = srslte::byte_buffer_pool::get_instance();
return;
@ -48,8 +47,7 @@ mme::~mme()
return;
}
mme*
mme::get_instance(void)
mme* mme::get_instance(void)
{
pthread_mutex_lock(&mme_instance_mutex);
if (NULL == m_instance) {
@ -59,8 +57,7 @@ mme::get_instance(void)
return (m_instance);
}
void
mme::cleanup(void)
void mme::cleanup(void)
{
pthread_mutex_lock(&mme_instance_mutex);
if (NULL != m_instance) {
@ -70,10 +67,11 @@ mme::cleanup(void)
pthread_mutex_unlock(&mme_instance_mutex);
}
int
mme::init(mme_args_t* args, srslte::log_filter *nas_log, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log, hss_interface_nas * hss)
int mme::init(mme_args_t* args,
srslte::log_filter* nas_log,
srslte::log_filter* s1ap_log,
srslte::log_filter* mme_gtpc_log)
{
/*Init logger*/
m_nas_log = nas_log;
m_s1ap_log = s1ap_log;
@ -81,7 +79,7 @@ mme::init(mme_args_t* args, srslte::log_filter *nas_log, srslte::log_filter *s1a
/*Init S1AP*/
m_s1ap = s1ap::get_instance();
if (m_s1ap->init(args->s1ap_args, nas_log, s1ap_log, hss)) {
if (m_s1ap->init(args->s1ap_args, nas_log, s1ap_log)) {
m_s1ap_log->error("Error initializing MME S1APP\n");
exit(-1);
}
@ -99,8 +97,7 @@ mme::init(mme_args_t* args, srslte::log_filter *nas_log, srslte::log_filter *s1a
return 0;
}
void
mme::stop()
void mme::stop()
{
if (m_running) {
m_s1ap->stop();
@ -112,8 +109,7 @@ mme::stop()
return;
}
void
mme::run_thread()
void mme::run_thread()
{
srslte::byte_buffer_t* pdu = m_pool->allocate("mme::run_thread");
uint32_t sz = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET;
@ -130,15 +126,13 @@ mme::run_thread()
// Get S1-MME socket
int s1mme = m_s1ap->get_s1_mme();
while(m_running)
{
while (m_running) {
m_s1ap_log->debug("Waiting for SCTP Msg\n");
pdu->reset();
rd_sz = sctp_recvmsg(s1mme, pdu->msg, sz, (struct sockaddr*)&enb_addr, &fromlen, &sri, &msg_flags);
if (rd_sz == -1 && errno != EAGAIN) {
m_s1ap_log->error("Error reading from SCTP socket: %s", strerror(errno));
}
else if (rd_sz == -1 && errno == EAGAIN){
} else if (rd_sz == -1 && errno == EAGAIN) {
m_s1ap_log->debug("Socket timeout reached");
} else {
if (msg_flags & MSG_NOTIFICATION) {

@ -24,29 +24,28 @@
*
*/
#include <iostream>
#include <inttypes.h> // for printing uint64_t
#include "srslte/asn1/gtpc.h"
#include "srsepc/hdr/mme/mme_gtpc.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/spgw/spgw.h"
#include "srslte/asn1/gtpc.h"
#include <inttypes.h> // for printing uint64_t
namespace srsepc {
mme_gtpc* mme_gtpc::m_instance = NULL;
pthread_mutex_t mme_gtpc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
mme_gtpc::mme_gtpc()
{
return;
}
mme_gtpc::~mme_gtpc()
{
return;
}
mme_gtpc*
mme_gtpc::get_instance(void)
mme_gtpc* mme_gtpc::get_instance(void)
{
pthread_mutex_lock(&mme_gtpc_instance_mutex);
if (NULL == m_instance) {
@ -56,8 +55,7 @@ mme_gtpc::get_instance(void)
return (m_instance);
}
void
mme_gtpc::cleanup(void)
void mme_gtpc::cleanup(void)
{
pthread_mutex_lock(&mme_gtpc_instance_mutex);
if (NULL != m_instance) {
@ -67,9 +65,7 @@ mme_gtpc::cleanup(void)
pthread_mutex_unlock(&mme_gtpc_instance_mutex);
}
bool
mme_gtpc::init(srslte::log_filter *mme_gtpc_log)
bool mme_gtpc::init(srslte::log_filter* mme_gtpc_log)
{
/*Init log*/
@ -78,7 +74,6 @@ mme_gtpc::init(srslte::log_filter *mme_gtpc_log)
m_next_ctrl_teid = 1;
m_s1ap = s1ap::get_instance();
m_mme_gtpc_ip = inet_addr("127.0.0.1");//FIXME At the moment, the GTP-C messages are not sent over the wire. So this parameter is not used.
m_spgw = spgw::get_instance();
m_mme_gtpc_log->info("MME GTP-C Initialized\n");
@ -86,14 +81,12 @@ mme_gtpc::init(srslte::log_filter *mme_gtpc_log)
return true;
}
uint32_t
mme_gtpc::get_new_ctrl_teid()
uint32_t mme_gtpc::get_new_ctrl_teid()
{
return m_next_ctrl_teid++; // FIXME Use a Id pool?
}
bool
mme_gtpc::send_create_session_request(uint64_t imsi)
bool mme_gtpc::send_create_session_request(uint64_t imsi)
{
m_mme_gtpc_log->info("Sending Create Session Request.\n");
m_mme_gtpc_log->console("Sending Create Session Request.\n");
@ -139,7 +132,8 @@ mme_gtpc::send_create_session_request(uint64_t imsi)
m_mme_gtpc_log->warning("Deleting previous GTP-C connection.\n");
std::map<uint32_t, uint64_t>::iterator jt = m_mme_ctr_teid_to_imsi.find(it->second.mme_ctr_fteid.teid);
if (jt == m_mme_ctr_teid_to_imsi.end()) {
m_mme_gtpc_log->error("Could not find IMSI from MME Ctrl TEID. MME Ctr TEID: %d\n", it->second.mme_ctr_fteid.teid);
m_mme_gtpc_log->error("Could not find IMSI from MME Ctrl TEID. MME Ctr TEID: %d\n",
it->second.mme_ctr_fteid.teid);
} else {
m_mme_ctr_teid_to_imsi.erase(jt);
}
@ -160,8 +154,7 @@ mme_gtpc::send_create_session_request(uint64_t imsi)
return true;
}
bool
mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
bool mme_gtpc::handle_create_session_response(srslte::gtpc_pdu* cs_resp_pdu)
{
struct srslte::gtpc_create_session_response* cs_resp = &cs_resp_pdu->choice.create_session_response;
m_mme_gtpc_log->info("Received Create Session Response\n");
@ -226,6 +219,7 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
// Save UE IP to nas ctxt
emm_ctx->ue_ip.s_addr = cs_resp->paa.ipv4;
m_mme_gtpc_log->console("SPGW Allocated IP %s to ISMI %015lu\n", inet_ntoa(emm_ctx->ue_ip), emm_ctx->imsi);
// Save SGW ctrl F-TEID in GTP-C context
std::map<uint64_t, struct gtpc_ctx>::iterator it_g = m_imsi_to_gtpc_ctx.find(imsi);
if (it_g == m_imsi_to_gtpc_ctx.end()) {
@ -246,9 +240,7 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
return true;
}
bool
mme_gtpc::send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t *enb_fteid)
bool mme_gtpc::send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t* enb_fteid)
{
m_mme_gtpc_log->info("Sending GTP-C Modify bearer request\n");
srslte::gtpc_pdu mb_req_pdu;
@ -275,15 +267,13 @@ mme_gtpc::send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srs
addr.s_addr = enb_fteid->ipv4;
m_mme_gtpc_log->info("GTP-C Modify bearer request -- S1-U TEID 0x%x, IP %s\n", enb_fteid->teid, inet_ntoa(addr));
//
srslte::gtpc_pdu mb_resp_pdu;
m_spgw->handle_modify_bearer_request(&mb_req_pdu, &mb_resp_pdu);
handle_modify_bearer_response(&mb_resp_pdu);
return true;
}
void
mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu)
void mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu* mb_resp_pdu)
{
uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid;
std::map<uint32_t, uint64_t>::iterator imsi_it = m_mme_ctr_teid_to_imsi.find(mme_ctrl_teid);
@ -299,8 +289,7 @@ mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu)
return;
}
bool
mme_gtpc::send_delete_session_request(uint64_t imsi)
bool mme_gtpc::send_delete_session_request(uint64_t imsi)
{
m_mme_gtpc_log->info("Sending GTP-C Delete Session Request request. IMSI %" PRIu64 "\n", imsi);
srslte::gtpc_pdu del_req_pdu;
@ -341,8 +330,7 @@ mme_gtpc::send_delete_session_request(uint64_t imsi)
return true;
}
void
mme_gtpc::send_release_access_bearers_request(uint64_t imsi)
void mme_gtpc::send_release_access_bearers_request(uint64_t imsi)
{
m_mme_gtpc_log->info("Sending GTP-C Delete Access Bearers Request\n");
srslte::gtpc_pdu rel_req_pdu;
@ -350,8 +338,7 @@ mme_gtpc::send_release_access_bearers_request(uint64_t imsi)
// Get S-GW Ctr TEID
std::map<uint64_t, gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi);
if(it_ctx == m_imsi_to_gtpc_ctx.end())
{
if (it_ctx == m_imsi_to_gtpc_ctx.end()) {
m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
return;
}

@ -24,26 +24,22 @@
*
*/
#include <iostream>
#include <cmath>
#include <inttypes.h> // for printing uint64_t
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/mme/s1ap_nas_transport.h"
#include "srslte/common/security.h"
#include "srslte/common/liblte_security.h"
#include "srslte/common/security.h"
#include <cmath>
#include <inttypes.h> // for printing uint64_t
namespace srsepc {
nas::nas() {
nas::nas()
{
m_pool = srslte::byte_buffer_pool::get_instance();
}
void
nas::init(nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log)
void nas::init(
nas_init_t args, s1ap_interface_nas* s1ap, gtpc_interface_nas* gtpc, hss_interface_nas* hss, srslte::log* nas_log)
{
m_mcc = args.mcc;
m_mnc = args.mnc;
@ -68,8 +64,7 @@ nas::init(nas_init_t args,
* Handle UE Initiating Messages
*
********************************/
bool
nas::handle_attach_request( uint32_t enb_ue_s1ap_id,
bool nas::handle_attach_request(uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* nas_rx,
nas_init_t args,
@ -123,35 +118,44 @@ nas::handle_attach_request( uint32_t enb_ue_s1ap_id,
nas_log->console("Attach request -- Attach type: %d\n", attach_req.eps_attach_type);
nas_log->info("Attach request -- Attach type: %d\n", attach_req.eps_attach_type);
nas_log->console("Attach Request -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n",
attach_req.ue_network_cap.eea[0], attach_req.ue_network_cap.eea[1], attach_req.ue_network_cap.eea[2], attach_req.ue_network_cap.eea[3],
attach_req.ue_network_cap.eea[4], attach_req.ue_network_cap.eea[5], attach_req.ue_network_cap.eea[6], attach_req.ue_network_cap.eea[7]);
nas_log->info("Attach Request -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n",
attach_req.ue_network_cap.eea[0], attach_req.ue_network_cap.eea[1], attach_req.ue_network_cap.eea[2], attach_req.ue_network_cap.eea[3],
attach_req.ue_network_cap.eea[4], attach_req.ue_network_cap.eea[5], attach_req.ue_network_cap.eea[6], attach_req.ue_network_cap.eea[7]);
attach_req.ue_network_cap.eea[0], attach_req.ue_network_cap.eea[1], attach_req.ue_network_cap.eea[2],
attach_req.ue_network_cap.eea[3], attach_req.ue_network_cap.eea[4], attach_req.ue_network_cap.eea[5],
attach_req.ue_network_cap.eea[6], attach_req.ue_network_cap.eea[7]);
nas_log->info("Attach Request -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n", attach_req.ue_network_cap.eea[0],
attach_req.ue_network_cap.eea[1], attach_req.ue_network_cap.eea[2], attach_req.ue_network_cap.eea[3],
attach_req.ue_network_cap.eea[4], attach_req.ue_network_cap.eea[5], attach_req.ue_network_cap.eea[6],
attach_req.ue_network_cap.eea[7]);
nas_log->console("Attach Request -- UE Network Capabilities EIA: %d%d%d%d%d%d%d%d\n",
attach_req.ue_network_cap.eia[0], attach_req.ue_network_cap.eia[1], attach_req.ue_network_cap.eia[2], attach_req.ue_network_cap.eia[3],
attach_req.ue_network_cap.eia[4], attach_req.ue_network_cap.eia[5], attach_req.ue_network_cap.eia[6], attach_req.ue_network_cap.eia[7]);
nas_log->info("Attach Request -- UE Network Capabilities EIA: %d%d%d%d%d%d%d%d\n",
attach_req.ue_network_cap.eia[0], attach_req.ue_network_cap.eia[1], attach_req.ue_network_cap.eia[2], attach_req.ue_network_cap.eia[3],
attach_req.ue_network_cap.eia[4], attach_req.ue_network_cap.eia[5], attach_req.ue_network_cap.eia[6], attach_req.ue_network_cap.eia[7]);
nas_log->console("Attach Request -- MS Network Capabilities Present: %s\n", attach_req.ms_network_cap_present ? "true" : "false");
nas_log->info("Attach Request -- MS Network Capabilities Present: %s\n", attach_req.ms_network_cap_present ? "true" : "false");
attach_req.ue_network_cap.eia[0], attach_req.ue_network_cap.eia[1], attach_req.ue_network_cap.eia[2],
attach_req.ue_network_cap.eia[3], attach_req.ue_network_cap.eia[4], attach_req.ue_network_cap.eia[5],
attach_req.ue_network_cap.eia[6], attach_req.ue_network_cap.eia[7]);
nas_log->info("Attach Request -- UE Network Capabilities EIA: %d%d%d%d%d%d%d%d\n", attach_req.ue_network_cap.eia[0],
attach_req.ue_network_cap.eia[1], attach_req.ue_network_cap.eia[2], attach_req.ue_network_cap.eia[3],
attach_req.ue_network_cap.eia[4], attach_req.ue_network_cap.eia[5], attach_req.ue_network_cap.eia[6],
attach_req.ue_network_cap.eia[7]);
nas_log->console("Attach Request -- MS Network Capabilities Present: %s\n",
attach_req.ms_network_cap_present ? "true" : "false");
nas_log->info("Attach Request -- MS Network Capabilities Present: %s\n",
attach_req.ms_network_cap_present ? "true" : "false");
nas_log->console("PDN Connectivity Request -- EPS Bearer Identity requested: %d\n", pdn_con_req.eps_bearer_id);
nas_log->info("PDN Connectivity Request -- EPS Bearer Identity requested: %d\n", pdn_con_req.eps_bearer_id);
nas_log->console("PDN Connectivity Request -- Procedure Transaction Id: %d\n", pdn_con_req.proc_transaction_id);
nas_log->info("PDN Connectivity Request -- Procedure Transaction Id: %d\n", pdn_con_req.proc_transaction_id);
nas_log->console("PDN Connectivity Request -- ESM Information Transfer requested: %s\n", pdn_con_req.esm_info_transfer_flag_present ? "true" : "false");
nas_log->info("PDN Connectivity Request -- ESM Information Transfer requested: %s\n", pdn_con_req.esm_info_transfer_flag_present ? "true" : "false");
nas_log->console("PDN Connectivity Request -- ESM Information Transfer requested: %s\n",
pdn_con_req.esm_info_transfer_flag_present ? "true" : "false");
nas_log->info("PDN Connectivity Request -- ESM Information Transfer requested: %s\n",
pdn_con_req.esm_info_transfer_flag_present ? "true" : "false");
// Get NAS Context if UE is known
nas* nas_ctx = s1ap->find_nas_ctx_from_imsi(imsi);
if (nas_ctx == NULL)
{
if (nas_ctx == NULL) {
// Get attach type from attach request
if (attach_req.eps_mobile_id.type_of_id == LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI) {
nas::handle_imsi_attach_request_unknown_ue(enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, args, s1ap, gtpc, hss, nas_log);
nas::handle_imsi_attach_request_unknown_ue(enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, args, s1ap, gtpc,
hss, nas_log);
} else if (attach_req.eps_mobile_id.type_of_id == LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI) {
nas::handle_guti_attach_request_unknown_ue(enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, args, s1ap, gtpc, hss, nas_log);
nas::handle_guti_attach_request_unknown_ue(enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, args, s1ap, gtpc,
hss, nas_log);
} else {
return false;
}
@ -159,9 +163,11 @@ nas::handle_attach_request( uint32_t enb_ue_s1ap_id,
nas_log->info("Attach Request -- Found previously attached UE.\n");
nas_log->console("Attach Request -- Found previously attach UE.\n");
if (attach_req.eps_mobile_id.type_of_id == LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI) {
nas::handle_imsi_attach_request_known_ue(nas_ctx, enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, nas_rx, args, s1ap, gtpc, hss, nas_log);
nas::handle_imsi_attach_request_known_ue(nas_ctx, enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, nas_rx, args,
s1ap, gtpc, hss, nas_log);
} else if (attach_req.eps_mobile_id.type_of_id == LIBLTE_MME_EPS_MOBILE_ID_TYPE_GUTI) {
nas::handle_guti_attach_request_known_ue(nas_ctx, enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, nas_rx, args, s1ap, gtpc, hss, nas_log);
nas::handle_guti_attach_request_known_ue(nas_ctx, enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, nas_rx, args,
s1ap, gtpc, hss, nas_log);
} else {
return false;
}
@ -169,8 +175,7 @@ nas::handle_attach_request( uint32_t enb_ue_s1ap_id,
return true;
}
bool
nas::handle_imsi_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
bool nas::handle_imsi_attach_request_unknown_ue(uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT& pdn_con_req,
@ -179,7 +184,6 @@ nas::handle_imsi_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log)
{
nas* nas_ctx;
srslte::byte_buffer_t* nas_tx;
@ -202,10 +206,12 @@ nas::handle_imsi_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
nas_ctx->m_ecm_ctx.mme_ue_s1ap_id = s1ap->get_next_mme_ue_s1ap_id();
// Save UE network capabilities
memcpy(&nas_ctx->m_sec_ctx.ue_network_cap, &attach_req.ue_network_cap, sizeof(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT));
memcpy(&nas_ctx->m_sec_ctx.ue_network_cap, &attach_req.ue_network_cap,
sizeof(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT));
nas_ctx->m_sec_ctx.ms_network_cap_present = attach_req.ms_network_cap_present;
if (attach_req.ms_network_cap_present) {
memcpy(&nas_ctx->m_sec_ctx.ms_network_cap, &attach_req.ms_network_cap, sizeof(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT));
memcpy(&nas_ctx->m_sec_ctx.ms_network_cap, &attach_req.ms_network_cap,
sizeof(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT));
}
uint8_t eps_bearer_id = pdn_con_req.eps_bearer_id; // TODO: Unused
@ -231,7 +237,8 @@ nas::handle_imsi_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
nas_ctx->m_emm_ctx.attach_type = attach_req.eps_attach_type;
// Get Authentication Vectors from HSS
if (!hss->gen_auth_info_answer(nas_ctx->m_emm_ctx.imsi, nas_ctx->m_sec_ctx.k_asme, nas_ctx->m_sec_ctx.autn, nas_ctx->m_sec_ctx.rand, nas_ctx->m_sec_ctx.xres)) {
if (!hss->gen_auth_info_answer(nas_ctx->m_emm_ctx.imsi, nas_ctx->m_sec_ctx.k_asme, nas_ctx->m_sec_ctx.autn,
nas_ctx->m_sec_ctx.rand, nas_ctx->m_sec_ctx.xres)) {
nas_log->console("User not found. IMSI %015" PRIu64 "\n", nas_ctx->m_emm_ctx.imsi);
nas_log->info("User not found. IMSI %015" PRIu64 "\n", nas_ctx->m_emm_ctx.imsi);
delete nas_ctx;
@ -252,7 +259,8 @@ nas::handle_imsi_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
nas_ctx->pack_authentication_request(nas_tx);
// Send reply to eNB
s1ap->send_downlink_nas_transport(nas_ctx->m_ecm_ctx.enb_ue_s1ap_id, nas_ctx->m_ecm_ctx.mme_ue_s1ap_id, nas_tx, nas_ctx->m_ecm_ctx.enb_sri);
s1ap->send_downlink_nas_transport(nas_ctx->m_ecm_ctx.enb_ue_s1ap_id, nas_ctx->m_ecm_ctx.mme_ue_s1ap_id, nas_tx,
nas_ctx->m_ecm_ctx.enb_sri);
pool->deallocate(nas_tx);
nas_log->info("Downlink NAS: Sending Authentication Request\n");
@ -260,8 +268,7 @@ nas::handle_imsi_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
return true;
}
bool
nas::handle_imsi_attach_request_known_ue( nas *nas_ctx,
bool nas::handle_imsi_attach_request_known_ue(nas* nas_ctx,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
@ -285,12 +292,12 @@ nas::handle_imsi_attach_request_known_ue( nas *nas_ctx,
s1ap->delete_ue_ctx(nas_ctx->m_emm_ctx.imsi);
// Handle new attach
err = nas::handle_imsi_attach_request_unknown_ue(enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, args, s1ap, gtpc, hss, nas_log);
err = nas::handle_imsi_attach_request_unknown_ue(enb_ue_s1ap_id, enb_sri, attach_req, pdn_con_req, args, s1ap, gtpc,
hss, nas_log);
return err;
}
bool
nas::handle_guti_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
bool nas::handle_guti_attach_request_unknown_ue(uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT& pdn_con_req,
@ -316,10 +323,12 @@ nas::handle_guti_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
nas_ctx->m_emm_ctx.state = EMM_STATE_DEREGISTERED;
// Save UE network capabilities
memcpy(&nas_ctx->m_sec_ctx.ue_network_cap, &attach_req.ue_network_cap, sizeof(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT));
memcpy(&nas_ctx->m_sec_ctx.ue_network_cap, &attach_req.ue_network_cap,
sizeof(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT));
nas_ctx->m_sec_ctx.ms_network_cap_present = attach_req.ms_network_cap_present;
if (attach_req.ms_network_cap_present) {
memcpy(&nas_ctx->m_sec_ctx.ms_network_cap, &attach_req.ms_network_cap, sizeof(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT));
memcpy(&nas_ctx->m_sec_ctx.ms_network_cap, &attach_req.ms_network_cap,
sizeof(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT));
}
// Initialize NAS count
nas_ctx->m_sec_ctx.ul_nas_count = 0;
@ -354,14 +363,14 @@ nas::handle_guti_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
// Send Identity Request
nas_tx = pool->allocate();
nas_ctx->pack_identity_request(nas_tx);
s1ap->send_downlink_nas_transport(nas_ctx->m_ecm_ctx.enb_ue_s1ap_id, nas_ctx->m_ecm_ctx.mme_ue_s1ap_id, nas_tx, nas_ctx->m_ecm_ctx.enb_sri);
s1ap->send_downlink_nas_transport(nas_ctx->m_ecm_ctx.enb_ue_s1ap_id, nas_ctx->m_ecm_ctx.mme_ue_s1ap_id, nas_tx,
nas_ctx->m_ecm_ctx.enb_sri);
pool->deallocate(nas_tx);
return true;
}
bool
nas::handle_guti_attach_request_known_ue( nas *nas_ctx,
bool nas::handle_guti_attach_request_known_ue(nas* nas_ctx,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
@ -381,13 +390,16 @@ nas::handle_guti_attach_request_known_ue( nas *nas_ctx,
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
sec_ctx_t* sec_ctx = &nas_ctx->m_sec_ctx;
nas_log->console("Found UE context. IMSI: %015" PRIu64 ", old eNB UE S1ap Id %d, old MME UE S1AP Id %d\n", emm_ctx->imsi, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id);
nas_log->console("Found UE context. IMSI: %015" PRIu64 ", old eNB UE S1ap Id %d, old MME UE S1AP Id %d\n",
emm_ctx->imsi, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id);
// Check NAS integrity
msg_valid = nas_ctx->integrity_check(nas_rx);
if (msg_valid == true && emm_ctx->state == EMM_STATE_DEREGISTERED) {
nas_log->console("GUTI Attach -- NAS Integrity OK. UL count %d, DL count %d\n",sec_ctx->ul_nas_count, sec_ctx->dl_nas_count);
nas_log->info ("GUTI Attach -- NAS Integrity OK. UL count %d, DL count %d\n",sec_ctx->ul_nas_count, sec_ctx->dl_nas_count);
nas_log->console("GUTI Attach -- NAS Integrity OK. UL count %d, DL count %d\n", sec_ctx->ul_nas_count,
sec_ctx->dl_nas_count);
nas_log->info("GUTI Attach -- NAS Integrity OK. UL count %d, DL count %d\n", sec_ctx->ul_nas_count,
sec_ctx->dl_nas_count);
// Create new MME UE S1AP Identity
ecm_ctx->mme_ue_s1ap_id = s1ap->get_next_mme_ue_s1ap_id();
@ -509,8 +521,7 @@ nas::handle_guti_attach_request_known_ue( nas *nas_ctx,
}
// Service Requests
bool
nas::handle_service_request( uint32_t m_tmsi,
bool nas::handle_service_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* nas_rx,
@ -574,7 +585,8 @@ nas::handle_service_request( uint32_t m_tmsi,
nas_log->error("Service Request -- User is ECM CONNECTED\n");
// Release previous context
nas_log->info("Service Request -- Releasing previouse ECM context. eNB S1AP Id %d, MME UE S1AP Id %d\n", ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id);
nas_log->info("Service Request -- Releasing previouse ECM context. eNB S1AP Id %d, MME UE S1AP Id %d\n",
ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id);
s1ap->send_ue_context_release_command(ecm_ctx->mme_ue_s1ap_id);
s1ap->release_ue_ecm_ctx(ecm_ctx->mme_ue_s1ap_id);
}
@ -620,8 +632,7 @@ nas::handle_service_request( uint32_t m_tmsi,
return true;
}
bool
nas::handle_detach_request( uint32_t m_tmsi,
bool nas::handle_detach_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* nas_rx,
@ -676,8 +687,7 @@ nas::handle_detach_request( uint32_t m_tmsi,
return true;
}
bool
nas::handle_tracking_area_update_request( uint32_t m_tmsi,
bool nas::handle_tracking_area_update_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* nas_rx,
@ -717,8 +727,7 @@ nas::handle_tracking_area_update_request( uint32_t m_tmsi,
* Handle Uplink NAS Transport messages
*
***************************************/
bool
nas::handle_authentication_response(srslte::byte_buffer_t *nas_rx)
bool nas::handle_authentication_response(srslte::byte_buffer_t* nas_rx)
{
srslte::byte_buffer_t* nas_tx;
LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_resp;
@ -770,8 +779,7 @@ nas::handle_authentication_response(srslte::byte_buffer_t *nas_rx)
return true;
}
bool
nas::handle_security_mode_complete(srslte::byte_buffer_t *nas_rx)
bool nas::handle_security_mode_complete(srslte::byte_buffer_t* nas_rx)
{
srslte::byte_buffer_t* nas_tx;
LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sm_comp;
@ -810,9 +818,7 @@ nas::handle_security_mode_complete(srslte::byte_buffer_t *nas_rx)
return true;
}
bool
nas::handle_attach_complete(srslte::byte_buffer_t *nas_rx)
bool nas::handle_attach_complete(srslte::byte_buffer_t* nas_rx)
{
LIBLTE_MME_ATTACH_COMPLETE_MSG_STRUCT attach_comp;
uint8_t pd, msg_type;
@ -826,7 +832,8 @@ nas::handle_attach_complete(srslte::byte_buffer_t *nas_rx)
return false;
}
err = liblte_mme_unpack_activate_default_eps_bearer_context_accept_msg( (LIBLTE_BYTE_MSG_STRUCT *) &attach_comp.esm_msg, &act_bearer);
err = liblte_mme_unpack_activate_default_eps_bearer_context_accept_msg((LIBLTE_BYTE_MSG_STRUCT*)&attach_comp.esm_msg,
&act_bearer);
if (err != LIBLTE_SUCCESS) {
m_nas_log->error("Error unpacking Activate EPS Bearer Context Accept Msg. Error: %s\n", liblte_error_text[err]);
return false;
@ -841,7 +848,8 @@ nas::handle_attach_complete(srslte::byte_buffer_t *nas_rx)
}
if (m_emm_ctx.state == EMM_STATE_DEREGISTERED) {
// Attach requested from attach request
m_gtpc->send_modify_bearer_request(m_emm_ctx.imsi, act_bearer.eps_bearer_id, &m_esm_ctx[act_bearer.eps_bearer_id].enb_fteid);
m_gtpc->send_modify_bearer_request(m_emm_ctx.imsi, act_bearer.eps_bearer_id,
&m_esm_ctx[act_bearer.eps_bearer_id].enb_fteid);
// Send reply to EMM Info to UE
nas_tx = m_pool->allocate();
@ -857,13 +865,13 @@ nas::handle_attach_complete(srslte::byte_buffer_t *nas_rx)
return true;
}
bool
nas::handle_esm_information_response(srslte::byte_buffer_t *nas_rx)
bool nas::handle_esm_information_response(srslte::byte_buffer_t* nas_rx)
{
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT esm_info_resp;
// Get NAS authentication response
LIBLTE_ERROR_ENUM err = srslte_mme_unpack_esm_information_response_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_rx, &esm_info_resp);
LIBLTE_ERROR_ENUM err =
srslte_mme_unpack_esm_information_response_msg((LIBLTE_BYTE_MSG_STRUCT*)nas_rx, &esm_info_resp);
if (err != LIBLTE_SUCCESS) {
m_nas_log->error("Error unpacking NAS authentication response. Error: %s\n", liblte_error_text[err]);
return false;
@ -891,8 +899,7 @@ nas::handle_esm_information_response(srslte::byte_buffer_t *nas_rx)
return true;
}
bool
nas::handle_identity_response(srslte::byte_buffer_t *nas_rx)
bool nas::handle_identity_response(srslte::byte_buffer_t* nas_rx)
{
srslte::byte_buffer_t* nas_tx;
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT id_resp;
@ -939,9 +946,7 @@ nas::handle_identity_response(srslte::byte_buffer_t *nas_rx)
return true;
}
bool
nas::handle_tracking_area_update_request(srslte::byte_buffer_t *nas_rx)
bool nas::handle_tracking_area_update_request(srslte::byte_buffer_t* nas_rx)
{
m_nas_log->console("Warning: Tracking Area Update Request messages not handled yet.\n");
m_nas_log->warning("Warning: Tracking Area Update Request messages not handled yet.\n");
@ -949,9 +954,7 @@ nas::handle_tracking_area_update_request(srslte::byte_buffer_t *nas_rx)
return true;
}
bool
nas::handle_authentication_failure(srslte::byte_buffer_t *nas_rx)
bool nas::handle_authentication_failure(srslte::byte_buffer_t* nas_rx)
{
m_nas_log->info("Received Authentication Failure\n");
@ -987,7 +990,8 @@ nas::handle_authentication_failure(srslte::byte_buffer_t *nas_rx)
return false;
}
// Get Authentication Vectors from HSS
if (!m_hss->gen_auth_info_answer(m_emm_ctx.imsi, m_sec_ctx.k_asme, m_sec_ctx.autn, m_sec_ctx.rand, m_sec_ctx.xres)) {
if (!m_hss->gen_auth_info_answer(m_emm_ctx.imsi, m_sec_ctx.k_asme, m_sec_ctx.autn, m_sec_ctx.rand,
m_sec_ctx.xres)) {
m_nas_log->console("User not found. IMSI %015" PRIu64 "\n", m_emm_ctx.imsi);
m_nas_log->info("User not found. IMSI %015" PRIu64 "\n", m_emm_ctx.imsi);
return false;
@ -1001,7 +1005,8 @@ nas::handle_authentication_failure(srslte::byte_buffer_t *nas_rx)
pack_authentication_request(nas_tx);
// Send reply to eNB
m_s1ap->send_downlink_nas_transport(m_ecm_ctx.enb_ue_s1ap_id, m_ecm_ctx.mme_ue_s1ap_id, nas_tx, m_ecm_ctx.enb_sri);
m_s1ap->send_downlink_nas_transport(m_ecm_ctx.enb_ue_s1ap_id, m_ecm_ctx.mme_ue_s1ap_id, nas_tx,
m_ecm_ctx.enb_sri);
m_pool->deallocate(nas_tx);
m_nas_log->info("Downlink NAS: Sent Authentication Request\n");
@ -1012,8 +1017,7 @@ nas::handle_authentication_failure(srslte::byte_buffer_t *nas_rx)
return true;
}
bool
nas::handle_detach_request(srslte::byte_buffer_t *nas_msg)
bool nas::handle_detach_request(srslte::byte_buffer_t* nas_msg)
{
m_nas_log->console("Detach request -- IMSI %015" PRIu64 "\n", m_emm_ctx.imsi);
@ -1035,8 +1039,7 @@ nas::handle_detach_request(srslte::byte_buffer_t *nas_msg)
}
/*Packing/Unpacking helper functions*/
bool
nas::pack_authentication_request(srslte::byte_buffer_t *nas_buffer)
bool nas::pack_authentication_request(srslte::byte_buffer_t* nas_buffer)
{
m_nas_log->info("Packing Authentication Request\n");
@ -1056,8 +1059,7 @@ nas::pack_authentication_request(srslte::byte_buffer_t *nas_buffer)
return true;
}
bool
nas::pack_authentication_reject(srslte::byte_buffer_t *nas_buffer)
bool nas::pack_authentication_reject(srslte::byte_buffer_t* nas_buffer)
{
m_nas_log->info("Packing Authentication Reject\n");
@ -1071,8 +1073,7 @@ nas::pack_authentication_reject(srslte::byte_buffer_t *nas_buffer)
return true;
}
bool
nas::pack_security_mode_command(srslte::byte_buffer_t *nas_buffer)
bool nas::pack_security_mode_command(srslte::byte_buffer_t* nas_buffer)
{
m_nas_log->info("Packing Security Mode Command\n");
@ -1103,19 +1104,16 @@ nas::pack_security_mode_command(srslte::byte_buffer_t *nas_buffer)
sm_cmd.nonce_mme_present = false;
uint8_t sec_hdr_type = 3;
LIBLTE_ERROR_ENUM err = liblte_mme_pack_security_mode_command_msg(&sm_cmd,sec_hdr_type, m_sec_ctx.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
LIBLTE_ERROR_ENUM err = liblte_mme_pack_security_mode_command_msg(&sm_cmd, sec_hdr_type, m_sec_ctx.dl_nas_count,
(LIBLTE_BYTE_MSG_STRUCT*)nas_buffer);
if (err != LIBLTE_SUCCESS) {
m_nas_log->console("Error packing Authentication Request\n");
return false;
}
// Generate EPS security context
srslte::security_generate_k_nas( m_sec_ctx.k_asme,
m_sec_ctx.cipher_algo,
m_sec_ctx.integ_algo,
m_sec_ctx.k_nas_enc,
m_sec_ctx.k_nas_int
);
srslte::security_generate_k_nas(m_sec_ctx.k_asme, m_sec_ctx.cipher_algo, m_sec_ctx.integ_algo, m_sec_ctx.k_nas_enc,
m_sec_ctx.k_nas_int);
m_nas_log->info_hex(m_sec_ctx.k_nas_enc, 32, "Key NAS Encryption (k_nas_enc)\n");
m_nas_log->info_hex(m_sec_ctx.k_nas_int, 32, "Key NAS Integrity (k_nas_int)\n");
@ -1133,8 +1131,7 @@ nas::pack_security_mode_command(srslte::byte_buffer_t *nas_buffer)
return true;
}
bool
nas::pack_esm_information_request(srslte::byte_buffer_t *nas_buffer)
bool nas::pack_esm_information_request(srslte::byte_buffer_t* nas_buffer)
{
m_nas_log->info("Packing ESM Information request\n");
@ -1145,7 +1142,8 @@ nas::pack_esm_information_request(srslte::byte_buffer_t *nas_buffer)
uint8_t sec_hdr_type = LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED;
m_sec_ctx.dl_nas_count++;
LIBLTE_ERROR_ENUM err = srslte_mme_pack_esm_information_request_msg(&esm_info_req, sec_hdr_type, m_sec_ctx.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
LIBLTE_ERROR_ENUM err = srslte_mme_pack_esm_information_request_msg(
&esm_info_req, sec_hdr_type, m_sec_ctx.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT*)nas_buffer);
if (err != LIBLTE_SUCCESS) {
m_nas_log->error("Error packing ESM information request\n");
m_nas_log->console("Error packing ESM information request\n");
@ -1160,8 +1158,7 @@ nas::pack_esm_information_request(srslte::byte_buffer_t *nas_buffer)
return true;
}
bool
nas::pack_attach_accept(srslte::byte_buffer_t *nas_buffer)
bool nas::pack_attach_accept(srslte::byte_buffer_t* nas_buffer)
{
m_nas_log->info("Packing Attach Accept\n");
@ -1209,11 +1206,8 @@ nas::pack_attach_accept(srslte::byte_buffer_t *nas_buffer)
attach_accept.guti.guti.mme_code = m_mme_code;
attach_accept.guti.guti.m_tmsi = m_s1ap->allocate_m_tmsi(m_emm_ctx.imsi);
m_nas_log->debug("Allocated GUTI: MCC %d, MNC %d, MME Group Id %d, MME Code 0x%x, M-TMSI 0x%x\n",
attach_accept.guti.guti.mcc,
attach_accept.guti.guti.mnc,
attach_accept.guti.guti.mme_group_id,
attach_accept.guti.guti.mme_code,
attach_accept.guti.guti.m_tmsi);
attach_accept.guti.guti.mcc, attach_accept.guti.guti.mnc, attach_accept.guti.guti.mme_group_id,
attach_accept.guti.guti.mme_code, attach_accept.guti.guti.m_tmsi);
// Set up LAI for combined EPS/IMSI attach
attach_accept.lai_present = true;
@ -1272,8 +1266,10 @@ nas::pack_attach_accept(srslte::byte_buffer_t *nas_buffer)
uint8_t sec_hdr_type = 2;
m_sec_ctx.dl_nas_count++;
liblte_mme_pack_activate_default_eps_bearer_context_request_msg(&act_def_eps_bearer_context_req, &attach_accept.esm_msg);
liblte_mme_pack_attach_accept_msg(&attach_accept, sec_hdr_type, m_sec_ctx.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
liblte_mme_pack_activate_default_eps_bearer_context_request_msg(&act_def_eps_bearer_context_req,
&attach_accept.esm_msg);
liblte_mme_pack_attach_accept_msg(&attach_accept, sec_hdr_type, m_sec_ctx.dl_nas_count,
(LIBLTE_BYTE_MSG_STRUCT*)nas_buffer);
// Encrypt NAS message
cipher_encrypt(nas_buffer);
@ -1288,8 +1284,7 @@ nas::pack_attach_accept(srslte::byte_buffer_t *nas_buffer)
return true;
}
bool
nas::pack_identity_request(srslte::byte_buffer_t *nas_buffer)
bool nas::pack_identity_request(srslte::byte_buffer_t* nas_buffer)
{
m_nas_log->info("Packing Identity Request\n");
@ -1304,8 +1299,7 @@ nas::pack_identity_request(srslte::byte_buffer_t *nas_buffer)
return true;
}
bool
nas::pack_emm_information(srslte::byte_buffer_t *nas_buffer)
bool nas::pack_emm_information(srslte::byte_buffer_t* nas_buffer)
{
m_nas_log->info("Packing EMM Information\n");
@ -1323,7 +1317,8 @@ nas::pack_emm_information(srslte::byte_buffer_t *nas_buffer)
uint8_t sec_hdr_type = LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED;
m_sec_ctx.dl_nas_count++;
LIBLTE_ERROR_ENUM err = liblte_mme_pack_emm_information_msg(&emm_info, sec_hdr_type, m_sec_ctx.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
LIBLTE_ERROR_ENUM err = liblte_mme_pack_emm_information_msg(&emm_info, sec_hdr_type, m_sec_ctx.dl_nas_count,
(LIBLTE_BYTE_MSG_STRUCT*)nas_buffer);
if (err != LIBLTE_SUCCESS) {
m_nas_log->error("Error packing EMM Information\n");
m_nas_log->console("Error packing EMM Information\n");
@ -1342,8 +1337,7 @@ nas::pack_emm_information(srslte::byte_buffer_t *nas_buffer)
return true;
}
bool
nas::pack_service_reject(srslte::byte_buffer_t *nas_buffer)
bool nas::pack_service_reject(srslte::byte_buffer_t* nas_buffer)
{
uint8_t emm_cause = LIBLTE_MME_EMM_CAUSE_IMPLICITLY_DETACHED;
@ -1355,7 +1349,8 @@ nas::pack_service_reject(srslte::byte_buffer_t *nas_buffer)
service_rej.t3446 = 0;
service_rej.emm_cause = emm_cause;
LIBLTE_ERROR_ENUM err = liblte_mme_pack_service_reject_msg(&service_rej, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, 0, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer);
LIBLTE_ERROR_ENUM err = liblte_mme_pack_service_reject_msg(&service_rej, LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS, 0,
(LIBLTE_BYTE_MSG_STRUCT*)nas_buffer);
if (err != LIBLTE_SUCCESS) {
m_nas_log->error("Error packing Service Reject\n");
m_nas_log->console("Error packing Service Reject\n");
@ -1380,27 +1375,16 @@ bool nas::short_integrity_check(srslte::byte_buffer_t* pdu)
return false;
}
switch (m_sec_ctx.integ_algo)
{
switch (m_sec_ctx.integ_algo) {
case srslte::INTEGRITY_ALGORITHM_ID_EIA0:
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA1:
srslte::security_128_eia1(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.ul_nas_count,
0,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[0],
2,
&exp_mac[0]);
srslte::security_128_eia1(&m_sec_ctx.k_nas_int[16], m_sec_ctx.ul_nas_count, 0, SECURITY_DIRECTION_UPLINK,
&pdu->msg[0], 2, &exp_mac[0]);
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA2:
srslte::security_128_eia2(&m_sec_ctx.k_nas_int[16],
m_sec_ctx.ul_nas_count,
0,
SECURITY_DIRECTION_UPLINK,
&pdu->msg[0],
2,
&exp_mac[0]);
srslte::security_128_eia2(&m_sec_ctx.k_nas_int[16], m_sec_ctx.ul_nas_count, 0, SECURITY_DIRECTION_UPLINK,
&pdu->msg[0], 2, &exp_mac[0]);
break;
default:
break;
@ -1426,8 +1410,7 @@ bool nas::integrity_check(srslte::byte_buffer_t *pdu)
uint8_t* mac = &pdu->msg[1];
int i;
switch (m_sec_ctx.integ_algo)
{
switch (m_sec_ctx.integ_algo) {
case srslte::INTEGRITY_ALGORITHM_ID_EIA0:
break;
case srslte::INTEGRITY_ALGORITHM_ID_128_EIA1:
@ -1462,8 +1445,7 @@ bool nas::integrity_check(srslte::byte_buffer_t *pdu)
return false;
}
}
m_nas_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n",
m_sec_ctx.ul_nas_count, pdu->msg[5]);
m_nas_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n", m_sec_ctx.ul_nas_count, pdu->msg[5]);
return true;
}
@ -1498,8 +1480,7 @@ void nas::integrity_generate(srslte::byte_buffer_t* pdu, uint8_t* mac)
void nas::cipher_decrypt(srslte::byte_buffer_t* pdu)
{
srslte::byte_buffer_t tmp_pdu;
switch(m_sec_ctx.cipher_algo)
{
switch (m_sec_ctx.cipher_algo) {
case srslte::CIPHERING_ALGORITHM_ID_EEA0:
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA1:
@ -1533,8 +1514,7 @@ void nas::cipher_decrypt(srslte::byte_buffer_t *pdu)
void nas::cipher_encrypt(srslte::byte_buffer_t* pdu)
{
srslte::byte_buffer_t pdu_tmp;
switch(m_sec_ctx.cipher_algo)
{
switch (m_sec_ctx.cipher_algo) {
case srslte::CIPHERING_ALGORITHM_ID_EEA0:
break;
case srslte::CIPHERING_ALGORITHM_ID_128_EEA1:
@ -1564,5 +1544,4 @@ void nas::cipher_encrypt(srslte::byte_buffer_t *pdu)
break;
}
}
} // namespace srsepc

@ -24,33 +24,29 @@
*
*/
#include <iostream>
#include <cmath>
#include <inttypes.h> // for printing uint64_t
#include "srslte/common/bcd_helpers.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/liblte_security.h"
#include <cmath>
#include <inttypes.h> // for printing uint64_t
namespace srsepc {
s1ap* s1ap::m_instance = NULL;
pthread_mutex_t s1ap_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap::s1ap():
m_s1mme(-1),
m_next_mme_ue_s1ap_id(1),
m_mme_gtpc(NULL),
m_pool(NULL)
s1ap::s1ap() : m_s1mme(-1), m_next_mme_ue_s1ap_id(1), m_mme_gtpc(NULL), m_pool(NULL)
{
return;
}
s1ap::~s1ap()
{
return;
}
s1ap*
s1ap::get_instance(void)
s1ap* s1ap::get_instance(void)
{
pthread_mutex_lock(&s1ap_instance_mutex);
if (m_instance == NULL) {
@ -60,8 +56,7 @@ s1ap::get_instance(void)
return (m_instance);
}
void
s1ap::cleanup(void)
void s1ap::cleanup(void)
{
pthread_mutex_lock(&s1ap_instance_mutex);
if (NULL != m_instance) {
@ -71,26 +66,26 @@ s1ap::cleanup(void)
pthread_mutex_unlock(&s1ap_instance_mutex);
}
int
s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *nas_log, srslte::log_filter *s1ap_log, hss_interface_nas * hss)
int s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter* nas_log, srslte::log_filter* s1ap_log)
{
m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_args = s1ap_args;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &m_plmn);
m_next_m_tmsi = rand();
// Init log
m_nas_log = nas_log;
m_s1ap_log = s1ap_log;
// Get pointer to the HSS
m_hss = hss;
m_hss = hss::get_instance();
// Init message handlers
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); // Managment procedures
m_s1ap_mngmt_proc->init();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); // NAS Transport procedures
m_s1ap_nas_transport->init(m_hss);
m_s1ap_nas_transport->init();
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); // Context Management Procedures
m_s1ap_ctx_mngmt_proc->init();
@ -108,8 +103,7 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *nas_log, srslte::log_filte
return 0;
}
void
s1ap::stop()
void s1ap::stop()
{
if (m_s1mme != -1) {
close(m_s1mme);
@ -139,25 +133,20 @@ s1ap::stop()
if (m_pcap_enable) {
m_pcap.close();
}
return;
}
int
s1ap::get_s1_mme()
int s1ap::get_s1_mme()
{
return m_s1mme;
}
uint32_t
s1ap::get_next_mme_ue_s1ap_id()
uint32_t s1ap::get_next_mme_ue_s1ap_id()
{
return m_next_mme_ue_s1ap_id++;
}
int
s1ap::enb_listen()
int s1ap::enb_listen()
{
/*This function sets up the SCTP socket for eNBs to connect to*/
int sock_fd, err;
@ -207,8 +196,7 @@ s1ap::enb_listen()
return sock_fd;
}
bool
s1ap::s1ap_tx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri)
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) {
@ -222,8 +210,7 @@ s1ap::s1ap_tx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri)
return true;
}
bool
s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri)
bool s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t* pdu, struct sctp_sndrcvinfo* enb_sri)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT rx_pdu;
@ -255,11 +242,9 @@ s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb
}
return true;
}
bool
s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri)
bool s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* msg, struct sctp_sndrcvinfo* enb_sri)
{
bool reply_flag = false;
srslte::byte_buffer_t* reply_buffer = m_pool->allocate();
@ -272,19 +257,24 @@ s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, stru
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE:
m_s1ap_log->info("Received Initial UE Message.\n");
m_s1ap_nas_transport->handle_initial_ue_message(&msg->choice.InitialUEMessage, enb_sri, reply_buffer, &reply_flag);
m_s1ap_nas_transport->handle_initial_ue_message(&msg->choice.InitialUEMessage, enb_sri, reply_buffer,
&reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT:
m_s1ap_log->info("Received Uplink NAS Transport Message.\n");
m_s1ap_nas_transport->handle_uplink_nas_transport(&msg->choice.UplinkNASTransport, enb_sri, reply_buffer, &reply_flag);
m_s1ap_nas_transport->handle_uplink_nas_transport(&msg->choice.UplinkNASTransport, enb_sri, reply_buffer,
&reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST:
m_s1ap_log->info("Received UE Context Release Request Message.\n");
m_s1ap_ctx_mngmt_proc->handle_ue_context_release_request(&msg->choice.UEContextReleaseRequest, enb_sri, reply_buffer, &reply_flag);
m_s1ap_ctx_mngmt_proc->handle_ue_context_release_request(&msg->choice.UEContextReleaseRequest, enb_sri,
reply_buffer, &reply_flag);
break;
default:
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->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
@ -296,8 +286,7 @@ s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, stru
return ret;
}
bool
s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
bool s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT* msg)
{
switch (msg->choice_type) {
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE:
@ -307,14 +296,14 @@ s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
m_s1ap_log->info("Received UE Context Release Complete\n");
return m_s1ap_ctx_mngmt_proc->handle_ue_context_release_complete(&msg->choice.UEContextReleaseComplete);
default:
m_s1ap_log->error("Unhandled successful outcome message: %s\n", liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]);
m_s1ap_log->error("Unhandled successful outcome message: %s\n",
liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]);
}
return true;
}
// eNB Context Managment
void
s1ap::add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo *enb_sri)
void s1ap::add_new_enb_ctx(const enb_ctx_t& enb_ctx, const struct sctp_sndrcvinfo* enb_sri)
{
m_s1ap_log->info("Adding new eNB context. eNB ID %d\n", enb_ctx.enb_id);
std::set<uint32_t> ue_set;
@ -327,29 +316,23 @@ s1ap::add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo *en
return;
}
enb_ctx_t*
s1ap::find_enb_ctx(uint16_t enb_id)
enb_ctx_t* s1ap::find_enb_ctx(uint16_t enb_id)
{
std::map<uint16_t, enb_ctx_t*>::iterator it = m_active_enbs.find(enb_id);
if(it == m_active_enbs.end())
{
if (it == m_active_enbs.end()) {
return NULL;
}
else
{
} else {
return it->second;
}
}
void
s1ap::delete_enb_ctx(int32_t assoc_id)
void s1ap::delete_enb_ctx(int32_t assoc_id)
{
std::map<int32_t, uint16_t>::iterator it_assoc = m_sctp_to_enb_id.find(assoc_id);
uint16_t enb_id = it_assoc->second;
std::map<uint16_t, enb_ctx_t*>::iterator it_ctx = m_active_enbs.find(enb_id);
if(it_ctx == m_active_enbs.end() || it_assoc == m_sctp_to_enb_id.end())
{
if (it_ctx == m_active_enbs.end() || it_assoc == m_sctp_to_enb_id.end()) {
m_s1ap_log->error("Could not find eNB to delete. Association: %d\n", assoc_id);
return;
}
@ -367,10 +350,8 @@ s1ap::delete_enb_ctx(int32_t assoc_id)
return;
}
//UE Context Management
bool
s1ap::add_nas_ctx_to_imsi_map(nas *nas_ctx)
bool s1ap::add_nas_ctx_to_imsi_map(nas* nas_ctx)
{
std::map<uint64_t, nas*>::iterator ctx_it = m_imsi_to_nas_ctx.find(nas_ctx->m_emm_ctx.imsi);
if (ctx_it != m_imsi_to_nas_ctx.end()) {
@ -389,8 +370,7 @@ s1ap::add_nas_ctx_to_imsi_map(nas *nas_ctx)
return true;
}
bool
s1ap::add_nas_ctx_to_mme_ue_s1ap_id_map(nas *nas_ctx)
bool s1ap::add_nas_ctx_to_mme_ue_s1ap_id_map(nas* nas_ctx)
{
if (nas_ctx->m_ecm_ctx.mme_ue_s1ap_id == 0) {
m_s1ap_log->error("Could not add UE context to MME UE S1AP map. MME UE S1AP ID 0 is not valid.");
@ -413,8 +393,7 @@ s1ap::add_nas_ctx_to_mme_ue_s1ap_id_map(nas *nas_ctx)
return true;
}
bool
s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
bool s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
{
std::map<int32_t, std::set<uint32_t> >::iterator ues_in_enb = m_enb_assoc_to_ue_ids.find(enb_assoc);
if (ues_in_enb == m_enb_assoc_to_ue_ids.end()) {
@ -422,8 +401,7 @@ s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
return false;
}
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.find(mme_ue_s1ap_id);
if(ue_id != ues_in_enb->second.end())
{
if (ue_id != ues_in_enb->second.end()) {
m_s1ap_log->error("UE with MME UE S1AP Id already exists %d", mme_ue_s1ap_id);
return false;
}
@ -432,8 +410,7 @@ s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
return true;
}
nas*
s1ap::find_nas_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
nas* s1ap::find_nas_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
{
std::map<uint32_t, nas*>::iterator it = m_mme_ue_s1ap_id_to_nas_ctx.find(mme_ue_s1ap_id);
if (it == m_mme_ue_s1ap_id_to_nas_ctx.end()) {
@ -443,8 +420,7 @@ s1ap::find_nas_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
}
}
nas*
s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
nas* s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
{
std::map<uint64_t, nas*>::iterator it = m_imsi_to_nas_ctx.find(imsi);
if (it == m_imsi_to_nas_ctx.end()) {
@ -454,8 +430,7 @@ s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
}
}
void
s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
void s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
{
m_s1ap_log->console("Releasing UEs context\n");
std::map<int32_t, std::set<uint32_t> >::iterator ues_in_enb = m_enb_assoc_to_ue_ids.find(enb_assoc);
@ -468,7 +443,8 @@ s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
emm_ctx_t* emm_ctx = &nas_ctx->second->m_emm_ctx;
ecm_ctx_t* ecm_ctx = &nas_ctx->second->m_ecm_ctx;
m_s1ap_log->info("Releasing UE context. IMSI: %015" PRIu64 ", UE-MME S1AP Id: %d\n", emm_ctx->imsi, ecm_ctx->mme_ue_s1ap_id);
m_s1ap_log->info("Releasing UE context. IMSI: %015" PRIu64 ", UE-MME S1AP Id: %d\n", emm_ctx->imsi,
ecm_ctx->mme_ue_s1ap_id);
if (emm_ctx->state == EMM_STATE_REGISTERED) {
m_mme_gtpc->send_delete_session_request(emm_ctx->imsi);
emm_ctx->state = EMM_STATE_DEREGISTERED;
@ -482,8 +458,7 @@ s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
}
}
bool
s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
bool s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
{
nas* nas_ctx = find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == NULL) {
@ -516,8 +491,7 @@ s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
return true;
}
bool
s1ap::delete_ue_ctx(uint64_t imsi)
bool s1ap::delete_ue_ctx(uint64_t imsi)
{
nas* nas_ctx = find_nas_ctx_from_imsi(imsi);
if (nas_ctx == NULL) {
@ -537,12 +511,8 @@ s1ap::delete_ue_ctx(uint64_t imsi)
return true;
}
//UE Bearer Managment
void
s1ap::activate_eps_bearer(uint64_t imsi, uint8_t ebi)
void s1ap::activate_eps_bearer(uint64_t imsi, uint8_t ebi)
{
std::map<uint64_t, nas*>::iterator ue_ctx_it = m_imsi_to_nas_ctx.find(imsi);
if (ue_ctx_it == m_imsi_to_nas_ctx.end()) {
@ -560,8 +530,12 @@ s1ap::activate_eps_bearer(uint64_t imsi, uint8_t ebi)
ecm_ctx_t* ecm_ctx = &ue_ctx_it->second->m_ecm_ctx;
esm_ctx_t* esm_ctx = &ue_ctx_it->second->m_esm_ctx[ebi];
if (esm_ctx->state != ERAB_CTX_SETUP) {
m_s1ap_log->error("Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d, state %d\n", mme_ue_s1ap_id, ebi, esm_ctx->state);
m_s1ap_log->console("Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d, state %d\n", mme_ue_s1ap_id, ebi, esm_ctx->state);
m_s1ap_log->error(
"Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d, state %d\n",
mme_ue_s1ap_id, ebi, esm_ctx->state);
m_s1ap_log->console(
"Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d, state %d\n",
mme_ue_s1ap_id, ebi, esm_ctx->state);
return;
}
@ -571,8 +545,7 @@ s1ap::activate_eps_bearer(uint64_t imsi, uint8_t ebi)
return;
}
uint32_t
s1ap::allocate_m_tmsi(uint64_t imsi)
uint32_t s1ap::allocate_m_tmsi(uint64_t imsi)
{
uint32_t m_tmsi = m_next_m_tmsi;
m_next_m_tmsi = (m_next_m_tmsi + 1) % UINT32_MAX;
@ -582,8 +555,7 @@ s1ap::allocate_m_tmsi(uint64_t imsi)
return m_tmsi;
}
uint64_t
s1ap::find_imsi_from_m_tmsi(uint32_t m_tmsi)
uint64_t s1ap::find_imsi_from_m_tmsi(uint32_t m_tmsi)
{
std::map<uint32_t, uint64_t>::iterator it = m_tmsi_to_imsi.find(m_tmsi);
if (it != m_tmsi_to_imsi.end()) {
@ -595,8 +567,7 @@ s1ap::find_imsi_from_m_tmsi(uint32_t m_tmsi)
}
}
void
s1ap::print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx)
void s1ap::print_enb_ctx_info(const std::string& prefix, const enb_ctx_t& enb_ctx)
{
std::string mnc_str, mcc_str;
@ -610,7 +581,8 @@ s1ap::print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx)
srslte::mcc_to_string(enb_ctx.mcc, &mcc_str);
srslte::mnc_to_string(enb_ctx.mnc, &mnc_str);
m_s1ap_log->info("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(), enb_ctx.plmn);
m_s1ap_log->console("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(), enb_ctx.plmn);
m_s1ap_log->console("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(),
enb_ctx.plmn);
for (int i = 0; i < enb_ctx.nof_supported_ta; i++) {
for (int j = 0; i < enb_ctx.nof_supported_ta; i++) {
m_s1ap_log->info("%s - TAC %d, B-PLMN %d\n", prefix.c_str(), enb_ctx.tac[i], enb_ctx.bplmns[i][j]);
@ -625,8 +597,7 @@ s1ap::print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx)
* Interfaces
*/
/* GTP-C || NAS -> S1AP interface */
bool
s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
bool s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
{
nas* nas_ctx = find_nas_ctx_from_imsi(imsi);
if (nas_ctx == NULL) {
@ -638,8 +609,7 @@ s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
}
/* NAS -> S1AP interface */
bool
s1ap::send_ue_context_release_command(uint32_t mme_ue_s1ap_id)
bool s1ap::send_ue_context_release_command(uint32_t mme_ue_s1ap_id)
{
nas* nas_ctx = find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == NULL) {
@ -650,8 +620,10 @@ s1ap::send_ue_context_release_command(uint32_t mme_ue_s1ap_id)
return true;
}
bool
s1ap::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri)
bool s1ap::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri)
{
return m_s1ap_nas_transport->send_downlink_nas_transport(enb_ue_s1ap_id, mme_ue_s1ap_id, nas_msg, enb_sri);
}

@ -24,22 +24,28 @@
*
*/
#include "srslte/common/bcd_helpers.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/mme/s1ap_ctx_mngmt_proc.h"
#include "srslte/common/liblte_security.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/int_helpers.h"
#include "srslte/common/liblte_security.h"
namespace srsepc {
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL;
pthread_mutex_t s1ap_ctx_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_ctx_mngmt_proc::s1ap_ctx_mngmt_proc() {}
s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc() {}
s1ap_ctx_mngmt_proc::s1ap_ctx_mngmt_proc()
{
return;
}
s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc()
{
return;
}
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance(void)
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance()
{
pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if (NULL == m_instance) {
@ -49,7 +55,7 @@ s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance(void)
return (m_instance);
}
void s1ap_ctx_mngmt_proc::cleanup(void)
void s1ap_ctx_mngmt_proc::cleanup()
{
pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if (NULL != m_instance) {
@ -59,14 +65,13 @@ void s1ap_ctx_mngmt_proc::cleanup(void)
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
}
void s1ap_ctx_mngmt_proc::init(void)
void s1ap_ctx_mngmt_proc::init()
{
m_s1ap = s1ap::get_instance();
m_mme_gtpc = mme_gtpc::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1ap_args = m_s1ap->m_s1ap_args;
m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance();
}
bool s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas* nas_ctx, uint16_t erab_to_setup)
@ -238,7 +243,8 @@ bool s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(
bool s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT* ue_rel,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer, bool* reply_flag)
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT ue_rel_req;

@ -24,27 +24,26 @@
*
*/
//#include "srslte/upper/s1ap_common.h"
#include "srslte/common/bcd_helpers.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/mme/s1ap_mngmt_proc.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/common/bcd_helpers.h"
namespace srsepc {
s1ap_mngmt_proc* s1ap_mngmt_proc::m_instance = NULL;
pthread_mutex_t s1ap_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_mngmt_proc::s1ap_mngmt_proc()
{
return;
}
s1ap_mngmt_proc::~s1ap_mngmt_proc()
{
return;
}
s1ap_mngmt_proc*
s1ap_mngmt_proc::get_instance(void)
s1ap_mngmt_proc* s1ap_mngmt_proc::get_instance(void)
{
pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex);
if (NULL == m_instance) {
@ -54,8 +53,7 @@ s1ap_mngmt_proc::get_instance(void)
return (m_instance);
}
void
s1ap_mngmt_proc::cleanup(void)
void s1ap_mngmt_proc::cleanup(void)
{
pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex);
if (NULL != m_instance) {
@ -65,8 +63,7 @@ s1ap_mngmt_proc::cleanup(void)
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
}
void
s1ap_mngmt_proc::init(void)
void s1ap_mngmt_proc::init(void)
{
m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
@ -74,15 +71,15 @@ s1ap_mngmt_proc::init(void)
m_s1ap_args = m_s1ap->m_s1ap_args;
}
bool
s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag)
bool s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT* msg,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{
enb_ctx_t enb_ctx;
LIBLTE_S1AP_S1AP_PDU_STRUCT reply_pdu;
if(!unpack_s1_setup_request(msg, &enb_ctx))
{
if (!unpack_s1_setup_request(msg, &enb_ctx)) {
m_s1ap_log->error("Malformed S1 Setup Request\n");
return false;
}
@ -93,21 +90,16 @@ s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
// Check matching PLMNs
if (enb_ctx.plmn != m_s1ap->get_plmn()) {
m_s1ap_log->console("Sending S1 Setup Failure - Unknown PLMN\n");
m_s1ap_log->warning("Sending S1 Setup Failure - Unknown PLMN\n");
pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_UNKNOWN_PLMN, reply_buffer);
}
else{
} else {
enb_ctx_t* enb_ptr = m_s1ap->find_enb_ctx(enb_ctx.enb_id);
if(enb_ptr != NULL)
{
if (enb_ptr != NULL) {
// eNB already registered
// TODO replace enb_ctx
m_s1ap_log->warning("eNB Already registered\n");
}
else
{
} else {
// new eNB
m_s1ap->add_new_enb_ctx(enb_ctx, enb_sri);
}
@ -121,12 +113,10 @@ s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
return true;
}
/*
* Packing/Unpacking helper functions.
*/
bool
s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, enb_ctx_t* enb_ctx)
bool s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT* msg, enb_ctx_t* enb_ctx)
{
uint8_t enb_id_bits[32];
@ -136,14 +126,14 @@ s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
uint32_t tmp32 = 0;
// eNB Name
enb_ctx->enb_name_present = msg->eNBname_present;
if(msg->eNBname_present)
{
if (msg->eNBname_present) {
bzero(enb_ctx->enb_name, sizeof(enb_ctx->enb_name));
memcpy(enb_ctx->enb_name, &msg->eNBname.buffer, msg->eNBname.n_octets);
}
// eNB Id
bzero(enb_id_bits, sizeof(enb_id_bits));
memcpy(&enb_id_bits[32-LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], msg->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer, LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
memcpy(&enb_id_bits[32 - LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], msg->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer,
LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
liblte_pack(enb_id_bits, 32, (uint8_t*)&tmp32);
enb_ctx->enb_id = ntohl(tmp32);
@ -157,15 +147,13 @@ s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
// SupportedTAs
enb_ctx->nof_supported_ta = msg->SupportedTAs.len;
for(uint16_t i=0; i<msg->SupportedTAs.len; i++)
{
for (uint16_t i = 0; i < msg->SupportedTAs.len; i++) {
// TAC
((uint8_t*)&enb_ctx->tac[i])[0] = msg->SupportedTAs.buffer[i].tAC.buffer[0];
((uint8_t*)&enb_ctx->tac[i])[1] = msg->SupportedTAs.buffer[i].tAC.buffer[1];
enb_ctx->tac[i] = ntohs(enb_ctx->tac[i]);
enb_ctx->nof_supported_bplmns[i] = msg->SupportedTAs.buffer[i].broadcastPLMNs.len;
for (uint16_t j=0; j<msg->SupportedTAs.buffer[i].broadcastPLMNs.len; j++)
{
for (uint16_t j = 0; j < msg->SupportedTAs.buffer[i].broadcastPLMNs.len; j++) {
// BPLMNs
((uint8_t*)&enb_ctx->bplmns[i][j])[1] = msg->SupportedTAs.buffer[i].broadcastPLMNs.buffer[j].buffer[0];
((uint8_t*)&enb_ctx->bplmns[i][j])[2] = msg->SupportedTAs.buffer[i].broadcastPLMNs.buffer[j].buffer[1];
@ -181,8 +169,7 @@ s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
return true;
}
bool
s1ap_mngmt_proc::pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte::byte_buffer_t *msg)
bool s1ap_mngmt_proc::pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte::byte_buffer_t* msg)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
@ -207,9 +194,7 @@ s1ap_mngmt_proc::pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte:
return true;
}
bool
s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buffer_t *msg)
bool s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buffer_t* msg)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
@ -255,16 +240,11 @@ s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buff
serv_gummei->servedMMECs.len = 1; // Only one MMEC served
serv_gummei->servedMMECs.buffer[0].buffer[0] = s1ap_args.mme_code;
//Relative MME Capacity
s1_resp->RelativeMMECapacity.RelativeMMECapacity = 255;
//Relay Unsupported
s1_resp->MMERelaySupportIndicator_present = false;
s1_resp->CriticalityDiagnostics_present = false;
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
return true;
}

@ -24,22 +24,28 @@
*
*/
#include <iostream>
#include <cmath>
#include <inttypes.h> // for printing uint64_t
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/mme/s1ap_nas_transport.h"
#include "srslte/common/security.h"
#include "srslte/common/liblte_security.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/common/int_helpers.h"
#include "srslte/common/liblte_security.h"
#include "srslte/common/security.h"
#include <cmath>
#include <inttypes.h> // for printing uint64_t
namespace srsepc {
s1ap_nas_transport* s1ap_nas_transport::m_instance = NULL;
pthread_mutex_t s1ap_nas_transport_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_nas_transport::s1ap_nas_transport() {}
s1ap_nas_transport::~s1ap_nas_transport() {}
s1ap_nas_transport::s1ap_nas_transport()
{
return;
}
s1ap_nas_transport::~s1ap_nas_transport()
{
return;
}
s1ap_nas_transport* s1ap_nas_transport::get_instance(void)
{
@ -61,18 +67,19 @@ void s1ap_nas_transport::cleanup(void)
pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex);
}
void s1ap_nas_transport::init(hss_interface_nas* hss_)
void s1ap_nas_transport::init()
{
m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_pool = srslte::byte_buffer_pool::get_instance();
m_hss = hss_;
m_hss = hss::get_instance();
m_mme_gtpc = mme_gtpc::get_instance();
}
bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT* init_ue,
struct sctp_sndrcvinfo* enb_sri, srslte::byte_buffer_t* reply_buffer,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{
bool err, mac_valid;
@ -140,7 +147,8 @@ bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUE
bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT* ul_xport,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer, bool* reply_flag)
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{
uint8_t pd, msg_type, sec_hdr_type;
uint32_t enb_ue_s1ap_id = ul_xport->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID;
@ -174,8 +182,7 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT ||
sec_hdr_type ==LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT))
{
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT)) {
m_s1ap_log->error("Unhandled security header type in Uplink NAS Transport: %d\n", sec_hdr_type);
m_pool->deallocate(nas_msg);
return false;
@ -186,18 +193,17 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT)
{
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT) {
mac_valid = nas_ctx->integrity_check(nas_msg);
if (mac_valid == false) {
m_s1ap_log->warning("Invalid MAC message. Even if security header indicates integrity protection (Maybe: Identity Response or Authenticatio Response)\n" );
m_s1ap_log->warning("Invalid MAC message. Even if security header indicates integrity protection (Maybe: "
"Identity Response or Authenticatio Response)\n");
}
}
// Decrypt message if indicated
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT)
{
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT) {
m_s1ap_log->debug_hex(nas_msg->msg, nas_msg->N_bytes, "Encrypted");
nas_ctx->cipher_decrypt(nas_msg);
msg_encrypted = true;
@ -207,15 +213,17 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
// Now parse message header and handle message
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &msg_type);
// Find UE EMM context if message is security protected.
if (sec_hdr_type != LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS) {
// Make sure EMM context is set-up, to do integrity check/de-chiphering
if (emm_ctx->imsi == 0) {
// No EMM context found. Perhaps a temporary context is being created?
// This can happen with integrity protected identity reponse messages
if ( !(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) ) {
m_s1ap_log->warning("Uplink NAS: could not find security context for integrity protected message. MME-UE S1AP id: %d\n",mme_ue_s1ap_id);
if (!(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE &&
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY)) {
m_s1ap_log->warning(
"Uplink NAS: could not find security context for integrity protected message. MME-UE S1AP id: %d\n",
mme_ue_s1ap_id);
m_pool->deallocate(nas_msg);
return false;
}
@ -237,8 +245,7 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
liblte_nas_sec_hdr_type_to_string(sec_hdr_type), mac_valid == true ? "yes" : "no",
msg_encrypted == true ? "yes" : "no");
switch (msg_type)
{
switch (msg_type) {
case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE:
m_s1ap_log->info("UL NAS: Received Identity Response\n");
m_s1ap_log->console("UL NAS: Received Identity Response\n");
@ -270,12 +277,15 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE:
m_s1ap_log->info("UL NAS: Received Security Mode Complete\n");
m_s1ap_log->console("UL NAS: Received Security Mode Complete\n");
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT && mac_valid == true){
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT &&
mac_valid == true) {
nas_ctx->handle_security_mode_complete(nas_msg);
} else {
// Security Mode Complete was not integrity protected
m_s1ap_log->console("Security Mode Complete %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
m_s1ap_log->warning("Security Mode Complete %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
m_s1ap_log->console("Security Mode Complete %s. Discard message.\n",
(mac_valid ? "not integrity protected" : "invalid integrity"));
m_s1ap_log->warning("Security Mode Complete %s. Discard message.\n",
(mac_valid ? "not integrity protected" : "invalid integrity"));
increase_ul_nas_cnt = false;
}
break;
@ -298,8 +308,10 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
nas_ctx->handle_esm_information_response(nas_msg);
} else {
// Attach Complete was not integrity protected
m_s1ap_log->console("ESM Information Response %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
m_s1ap_log->warning("ESM Information Response %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
m_s1ap_log->console("ESM Information Response %s. Discard message.\n",
(mac_valid ? "not integrity protected" : "invalid integrity"));
m_s1ap_log->warning("ESM Information Response %s. Discard message.\n",
(mac_valid ? "not integrity protected" : "invalid integrity"));
increase_ul_nas_cnt = false;
}
break;
@ -315,7 +327,8 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
return false;
}
//Increment UL NAS count. if counter not resetted in function, e.g., DL Security mode command after Authentication response
// Increment UL NAS count. if counter not resetted in function, e.g., DL Security mode command after Authentication
// response
if (increase_ul_nas_cnt == true) {
sec_ctx->ul_nas_count++;
}
@ -323,8 +336,10 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
return true;
}
bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg, struct sctp_sndrcvinfo enb_sri)
bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri)
{
// Allocate Reply buffer
srslte::byte_buffer_t* reply_msg = m_pool->allocate();
@ -365,5 +380,4 @@ bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, ui
return true;
}
} // namespace srsepc

@ -24,19 +24,18 @@
*
*/
#include <iostream>
#include "srsepc/hdr/spgw/spgw.h"
#include "srsepc/hdr/mme/mme_gtpc.h"
#include "srslte/upper/gtpu.h"
#include <algorithm>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <inttypes.h> // for printing uint64_t
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include <inttypes.h> // for printing uint64_t
#include "srsepc/hdr/spgw/spgw.h"
#include "srsepc/hdr/mme/mme_gtpc.h"
#include "srslte/upper/gtpu.h"
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
namespace srsepc {
@ -45,12 +44,7 @@ pthread_mutex_t spgw_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
const uint16_t SPGW_BUFFER_SIZE = 2500;
spgw::spgw():
m_running(false),
m_sgi_up(false),
m_s1u_up(false),
m_next_ctrl_teid(1),
m_next_user_teid(1)
spgw::spgw() : m_running(false), m_sgi_up(false), m_s1u_up(false), m_next_ctrl_teid(1), m_next_user_teid(1)
{
return;
}
@ -60,8 +54,7 @@ spgw::~spgw()
return;
}
spgw*
spgw::get_instance(void)
spgw* spgw::get_instance()
{
pthread_mutex_lock(&spgw_instance_mutex);
if (NULL == m_instance) {
@ -71,8 +64,7 @@ spgw::get_instance(void)
return (m_instance);
}
void
spgw::cleanup(void)
void spgw::cleanup()
{
pthread_mutex_lock(&spgw_instance_mutex);
if (NULL != m_instance) {
@ -82,8 +74,7 @@ spgw::cleanup(void)
pthread_mutex_unlock(&spgw_instance_mutex);
}
int
spgw::init(spgw_args_t* args, srslte::log_filter *spgw_log)
int spgw::init(spgw_args_t* args, srslte::log_filter* spgw_log)
{
srslte::error_t err;
m_pool = srslte::byte_buffer_pool::get_instance();
@ -94,23 +85,20 @@ spgw::init(spgw_args_t* args, srslte::log_filter *spgw_log)
// Init SGi interface
err = init_sgi_if(args);
if (err != srslte::ERROR_NONE)
{
if (err != srslte::ERROR_NONE) {
m_spgw_log->console("Could not initialize the SGi interface.\n");
return -1;
}
// Init S1-U
err = init_s1u(args);
if (err != srslte::ERROR_NONE)
{
if (err != srslte::ERROR_NONE) {
m_spgw_log->console("Could not initialize the S1-U interface.\n");
return -1;
}
// Initialize UE ip pool
err = init_ue_ip(args);
if (err != srslte::ERROR_NONE)
{
if (err != srslte::ERROR_NONE) {
m_spgw_log->console("Could not initialize the S1-U interface.\n");
return -1;
}
@ -122,30 +110,27 @@ spgw::init(spgw_args_t* args, srslte::log_filter *spgw_log)
return 0;
}
void
spgw::stop()
{
if(m_running)
void spgw::stop()
{
if (m_running) {
m_running = false;
thread_cancel();
wait_thread_finish();
// Clean up SGi interface
if(m_sgi_up)
{
if (m_sgi_up) {
close(m_sgi_if);
close(m_sgi_sock);
}
// Clean up S1-U socket
if(m_s1u_up)
{
if (m_s1u_up) {
close(m_s1u);
}
}
std::map<uint32_t,spgw_tunnel_ctx*>::iterator it = m_teid_to_tunnel_ctx.begin(); //Map control TEID to tunnel ctx. Usefull to get reply ctrl TEID, UE IP, etc.
while(it!=m_teid_to_tunnel_ctx.end())
{
//Delete GTP-C tunnel
std::map<uint32_t, spgw_tunnel_ctx*>::iterator it = m_teid_to_tunnel_ctx.begin();
while (it != m_teid_to_tunnel_ctx.end()) {
m_spgw_log->info("Deleting SP-GW GTP-C Tunnel. IMSI: %lu\n", it->second->imsi);
m_spgw_log->console("Deleting SP-GW GTP-C Tunnel. IMSI: %lu\n", it->second->imsi);
delete it->second;
@ -154,16 +139,12 @@ spgw::stop()
return;
}
srslte::error_t
spgw::init_sgi_if(spgw_args_t *args)
srslte::error_t spgw::init_sgi_if(spgw_args_t* args)
{
struct ifreq ifr;
if (m_sgi_up) {
return (srslte::ERROR_ALREADY_STARTED);
}
// Construct the TUN device
m_sgi_if = open("/dev/net/tun", O_RDWR);
m_spgw_log->info("TUN file descriptor = %d\n", m_sgi_if);
@ -172,9 +153,11 @@ spgw::init_sgi_if(spgw_args_t *args)
return (srslte::ERROR_CANT_START);
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, args->sgi_if_name.c_str(), std::min(args->sgi_if_name.length(), (size_t)(IFNAMSIZ-1)));
strncpy(ifr.ifr_ifrn.ifrn_name, args->sgi_if_name.c_str(),
std::min(args->sgi_if_name.length(), (size_t)(IFNAMSIZ - 1)));
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = '\0';
if (ioctl(m_sgi_if, TUNSETIFF, &ifr) < 0) {
@ -206,7 +189,8 @@ spgw::init_sgi_if(spgw_args_t *args)
addr->sin_port = 0;
if (ioctl(m_sgi_sock, SIOCSIFADDR, &ifr) < 0) {
m_spgw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_if_addr.c_str(), strerror(errno));
m_spgw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_if_addr.c_str(),
strerror(errno));
close(m_sgi_if);
close(m_sgi_sock);
return srslte::ERROR_CANT_START;
@ -221,15 +205,11 @@ spgw::init_sgi_if(spgw_args_t *args)
return srslte::ERROR_CANT_START;
}
//Set initial time of setup
gettimeofday(&m_t_last_dl, NULL);
m_sgi_up = true;
return (srslte::ERROR_NONE);
}
srslte::error_t
spgw::init_s1u(spgw_args_t *args)
srslte::error_t spgw::init_s1u(spgw_args_t* args)
{
// Open S1-U socket
m_s1u = socket(AF_INET, SOCK_DGRAM, 0);
@ -254,15 +234,13 @@ spgw::init_s1u(spgw_args_t *args)
return srslte::ERROR_NONE;
}
srslte::error_t
spgw::init_ue_ip(spgw_args_t *args)
srslte::error_t spgw::init_ue_ip(spgw_args_t* args)
{
m_h_next_ue_ip = ntohl(inet_addr(args->sgi_if_addr.c_str()));
return srslte::ERROR_NONE;
}
void
spgw::run_thread()
void spgw::run_thread()
{
// Mark the thread as running
m_running = true;
@ -304,8 +282,7 @@ spgw::run_thread()
return;
}
void
spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
void spgw::handle_sgi_pdu(srslte::byte_buffer_t* msg)
{
uint8_t version = 0;
uint32_t dest_ip;
@ -353,7 +330,6 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
m_spgw_log->console("Error writing GTP-U header on PDU\n");
}
// Send packet to destination
int n = sendto(m_s1u, msg->msg, msg->N_bytes, 0, (struct sockaddr*)&enb_addr, sizeof(enb_addr));
if (n < 0) {
@ -366,9 +342,7 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
return;
}
void
spgw::handle_s1u_pdu(srslte::byte_buffer_t *msg)
void spgw::handle_s1u_pdu(srslte::byte_buffer_t* msg)
{
// m_spgw_log->console("Received PDU from S1-U. Bytes=%d\n",msg->N_bytes);
srslte::gtpu_header_t header;
@ -384,93 +358,12 @@ spgw::handle_s1u_pdu(srslte::byte_buffer_t *msg)
return;
}
/*
* Helper Functions
* GTP-C Handler Functions
*/
uint64_t
spgw::get_new_ctrl_teid()
{
return m_next_ctrl_teid++;
}
uint64_t
spgw::get_new_user_teid()
{
return m_next_user_teid++;
}
in_addr_t
spgw::get_new_ue_ipv4()
{
m_h_next_ue_ip++;
return ntohl(m_h_next_ue_ip);//FIXME Tmp hack
}
spgw_tunnel_ctx_t*
spgw::create_gtp_ctx(struct srslte::gtpc_create_session_request *cs_req)
{
//Setup uplink control TEID
uint64_t spgw_uplink_ctrl_teid = get_new_ctrl_teid();
//Setup uplink user TEID
uint64_t spgw_uplink_user_teid = get_new_user_teid();
//Allocate UE IP
in_addr_t ue_ip = get_new_ue_ipv4();
//in_addr_t ue_ip = inet_addr("172.16.0.2");
uint8_t default_bearer_id = 5;
m_spgw_log->console("SPGW: Allocated Ctrl TEID %" PRIu64 "\n", spgw_uplink_ctrl_teid);
m_spgw_log->console("SPGW: Allocated User TEID %" PRIu64 "\n", spgw_uplink_user_teid);
struct in_addr ue_ip_;
ue_ip_.s_addr=ue_ip;
m_spgw_log->console("SPGW: Allocate UE IP %s\n", inet_ntoa(ue_ip_));
//Save the UE IP to User TEID map
spgw_tunnel_ctx_t *tunnel_ctx = new spgw_tunnel_ctx_t;
bzero(tunnel_ctx,sizeof(spgw_tunnel_ctx_t));
tunnel_ctx->imsi = cs_req->imsi;
tunnel_ctx->ebi = default_bearer_id;
tunnel_ctx->up_user_fteid.teid = spgw_uplink_user_teid;
tunnel_ctx->up_user_fteid.ipv4 = m_s1u_addr.sin_addr.s_addr;
tunnel_ctx->dw_ctrl_fteid.teid = cs_req->sender_f_teid.teid;
tunnel_ctx->dw_ctrl_fteid.ipv4 = cs_req->sender_f_teid.ipv4;
tunnel_ctx->up_ctrl_fteid.teid = spgw_uplink_ctrl_teid;
tunnel_ctx->ue_ipv4 = ue_ip;
m_teid_to_tunnel_ctx.insert(std::pair<uint32_t,spgw_tunnel_ctx_t*>(spgw_uplink_ctrl_teid,tunnel_ctx));
m_imsi_to_ctr_teid.insert(std::pair<uint64_t,uint32_t>(cs_req->imsi,spgw_uplink_ctrl_teid));
return tunnel_ctx;
}
bool
spgw::delete_gtp_ctx(uint32_t ctrl_teid)
{
spgw_tunnel_ctx_t *tunnel_ctx;
if (!m_teid_to_tunnel_ctx.count(ctrl_teid)) {
m_spgw_log->error("Could not find GTP context to delete.\n");
return false;
}
tunnel_ctx = m_teid_to_tunnel_ctx[ctrl_teid];
//Remove GTP-U connections, if any.
if (m_ip_to_teid.count(tunnel_ctx->ue_ipv4)) {
pthread_mutex_lock(&m_mutex);
m_ip_to_teid.erase(tunnel_ctx->ue_ipv4);
pthread_mutex_unlock(&m_mutex);
}
//Remove Ctrl TEID from IMSI to control TEID map
m_imsi_to_ctr_teid.erase(tunnel_ctx->imsi);
//Remove GTP context from control TEID mapping
m_teid_to_tunnel_ctx.erase(ctrl_teid);
delete tunnel_ctx;
return true;
}
void
spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu)
void spgw::handle_create_session_request(struct srslte::gtpc_create_session_request* cs_req,
struct srslte::gtpc_pdu* cs_resp_pdu)
{
m_spgw_log->info("Received Create Session Request\n");
spgw_tunnel_ctx_t* tunnel_ctx;
@ -520,8 +413,7 @@ spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *
return;
}
void
spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct srslte::gtpc_pdu *mb_resp_pdu)
void spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu* mb_req_pdu, struct srslte::gtpc_pdu* mb_resp_pdu)
{
m_spgw_log->info("Received Modified Bearer Request\n");
@ -543,7 +435,8 @@ spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct s
struct in_addr addr;
addr.s_addr = tunnel_ctx->ue_ipv4;
m_spgw_log->info("IMSI: %lu, UE IP, %s \n", tunnel_ctx->imsi, inet_ntoa(addr));
m_spgw_log->info("S-GW Rx Ctrl TEID 0x%x, MME Rx Ctrl TEID 0x%x\n", tunnel_ctx->up_ctrl_fteid.teid, tunnel_ctx->dw_ctrl_fteid.teid);
m_spgw_log->info("S-GW Rx Ctrl TEID 0x%x, MME Rx Ctrl TEID 0x%x\n", tunnel_ctx->up_ctrl_fteid.teid,
tunnel_ctx->dw_ctrl_fteid.teid);
m_spgw_log->info("S-GW Rx Ctrl IP (NA), MME Rx Ctrl IP (NA)\n");
struct in_addr addr2;
@ -558,7 +451,8 @@ spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct s
// bool ret = false;
pthread_mutex_lock(&m_mutex);
m_ip_to_teid[tunnel_ctx->ue_ipv4] = tunnel_ctx->dw_user_fteid;
//ret = m_ip_to_teid.insert(std::pair<uint32_t,srslte::gtpc_f_teid_ie>(tunnel_ctx->ue_ipv4, tunnel_ctx->dw_user_fteid));
// ret = m_ip_to_teid.insert(std::pair<uint32_t,srslte::gtpc_f_teid_ie>(tunnel_ctx->ue_ipv4,
// tunnel_ctx->dw_user_fteid));
pthread_mutex_unlock(&m_mutex);
// Setting up Modify bearer response PDU
@ -578,8 +472,7 @@ spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct s
return;
}
void
spgw::handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct srslte::gtpc_pdu *del_resp_pdu)
void spgw::handle_delete_session_request(struct srslte::gtpc_pdu* del_req_pdu, struct srslte::gtpc_pdu* del_resp_pdu)
{
// Find tunel ctxt
uint32_t ctrl_teid = del_req_pdu->header.teid;
@ -604,8 +497,8 @@ spgw::handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct
return;
}
void
spgw::handle_release_access_bearers_request(struct srslte::gtpc_pdu *rel_req_pdu, struct srslte::gtpc_pdu *rel_resp_pdu)
void spgw::handle_release_access_bearers_request(struct srslte::gtpc_pdu* rel_req_pdu,
struct srslte::gtpc_pdu* rel_resp_pdu)
{
// Find tunel ctxt
uint32_t ctrl_teid = rel_req_pdu->header.teid;
@ -629,4 +522,83 @@ spgw::handle_release_access_bearers_request(struct srslte::gtpc_pdu *rel_req_pdu
return;
}
/*
* Helper Functions
*/
uint64_t spgw::get_new_ctrl_teid()
{
return m_next_ctrl_teid++;
}
uint64_t spgw::get_new_user_teid()
{
return m_next_user_teid++;
}
in_addr_t spgw::get_new_ue_ipv4()
{
m_h_next_ue_ip++;
return ntohl(m_h_next_ue_ip); // FIXME Tmp hack
}
spgw_tunnel_ctx_t* spgw::create_gtp_ctx(struct srslte::gtpc_create_session_request* cs_req)
{
// Setup uplink control TEID
uint64_t spgw_uplink_ctrl_teid = get_new_ctrl_teid();
// Setup uplink user TEID
uint64_t spgw_uplink_user_teid = get_new_user_teid();
// Allocate UE IP
in_addr_t ue_ip = get_new_ue_ipv4();
// in_addr_t ue_ip = inet_addr("172.16.0.2");
uint8_t default_bearer_id = 5;
m_spgw_log->console("SPGW: Allocated Ctrl TEID %" PRIu64 "\n", spgw_uplink_ctrl_teid);
m_spgw_log->console("SPGW: Allocated User TEID %" PRIu64 "\n", spgw_uplink_user_teid);
struct in_addr ue_ip_;
ue_ip_.s_addr = ue_ip;
m_spgw_log->console("SPGW: Allocate UE IP %s\n", inet_ntoa(ue_ip_));
// Save the UE IP to User TEID map
spgw_tunnel_ctx_t* tunnel_ctx = new spgw_tunnel_ctx_t;
bzero(tunnel_ctx, sizeof(spgw_tunnel_ctx_t));
tunnel_ctx->imsi = cs_req->imsi;
tunnel_ctx->ebi = default_bearer_id;
tunnel_ctx->up_user_fteid.teid = spgw_uplink_user_teid;
tunnel_ctx->up_user_fteid.ipv4 = m_s1u_addr.sin_addr.s_addr;
tunnel_ctx->dw_ctrl_fteid.teid = cs_req->sender_f_teid.teid;
tunnel_ctx->dw_ctrl_fteid.ipv4 = cs_req->sender_f_teid.ipv4;
tunnel_ctx->up_ctrl_fteid.teid = spgw_uplink_ctrl_teid;
tunnel_ctx->ue_ipv4 = ue_ip;
m_teid_to_tunnel_ctx.insert(std::pair<uint32_t, spgw_tunnel_ctx_t*>(spgw_uplink_ctrl_teid, tunnel_ctx));
m_imsi_to_ctr_teid.insert(std::pair<uint64_t, uint32_t>(cs_req->imsi, spgw_uplink_ctrl_teid));
return tunnel_ctx;
}
bool spgw::delete_gtp_ctx(uint32_t ctrl_teid)
{
spgw_tunnel_ctx_t* tunnel_ctx;
if (!m_teid_to_tunnel_ctx.count(ctrl_teid)) {
m_spgw_log->error("Could not find GTP context to delete.\n");
return false;
}
tunnel_ctx = m_teid_to_tunnel_ctx[ctrl_teid];
// Remove GTP-U connections, if any.
if (m_ip_to_teid.count(tunnel_ctx->ue_ipv4)) {
pthread_mutex_lock(&m_mutex);
m_ip_to_teid.erase(tunnel_ctx->ue_ipv4);
pthread_mutex_unlock(&m_mutex);
}
// Remove Ctrl TEID from IMSI to control TEID map
m_imsi_to_ctr_teid.erase(tunnel_ctx->imsi);
// Remove GTP context from control TEID mapping
m_teid_to_tunnel_ctx.erase(ctrl_teid);
delete tunnel_ctx;
return true;
}
} // namespace srsepc

Loading…
Cancel
Save