Merge branch 'next' into rlc_updates

master
Andre Puschmann 7 years ago
commit c93ea1dd10

@ -52,16 +52,15 @@ const uint8_t GTPC_V2 = 2;
* n+2 | Sequence | * n+2 | Sequence |
* n+3 | Spare | * n+3 | Spare |
***************************************************************************/ ***************************************************************************/
typedef struct gtpc_header
typedef struct gtpc_header {
{
uint8_t version; uint8_t version;
bool piggyback; bool piggyback;
bool teid_present; bool teid_present;
uint8_t type; uint8_t type;
uint64_t teid; uint64_t teid;
uint64_t sequence; uint64_t sequence;
} gtpc_header_t; }gtpc_header_t;
/**************************************************************************** /****************************************************************************
* GTP-C v2 Payload * GTP-C v2 Payload
@ -69,16 +68,17 @@ const uint8_t GTPC_V2 = 2;
* *
* Union that hold the different structures for the possible message types. * 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_request create_session_request;
struct gtpc_create_session_response create_session_response; struct gtpc_create_session_response create_session_response;
struct gtpc_modify_bearer_request modify_bearer_request; struct gtpc_modify_bearer_request modify_bearer_request;
struct gtpc_modify_bearer_response modify_bearer_response; struct gtpc_modify_bearer_response modify_bearer_response;
struct gtpc_release_access_bearers_request release_access_bearers_request;
struct gtpc_release_access_bearers_response release_access_bearers_response;
struct gtpc_delete_session_request delete_session_request; struct gtpc_delete_session_request delete_session_request;
struct gtpc_delete_session_response delete_session_response; struct gtpc_delete_session_response delete_session_response;
} gtpc_msg_choice_t; }gtpc_msg_choice_t;
/**************************************************************************** /****************************************************************************
* GTP-C v2 Message * GTP-C v2 Message
@ -88,15 +88,10 @@ typedef union gtpc_msg_choice
* of one GTP-C header and one union of structures, which can hold * of one GTP-C header and one union of structures, which can hold
* all the possible GTP-C messages * all the possible GTP-C messages
***************************************************************************/ ***************************************************************************/
typedef struct gtpc_pdu typedef struct gtpc_pdu
{ {
struct gtpc_header header; struct gtpc_header header;
union gtpc_msg_choice choice; union gtpc_msg_choice choice;
} gtpc_pdu_t; }gtpc_pdu_t;
}//namespace
};
#endif #endif

@ -400,7 +400,8 @@ enum gtpc_interface_type
S2B_U_PGW_GTP_U_INTERFACE S2B_U_PGW_GTP_U_INTERFACE
}; };
struct gtpc_f_teid_ie
typedef struct gtpc_f_teid_ie
{ {
bool ipv4_present; bool ipv4_present;
bool ipv6_present; bool ipv6_present;
@ -408,7 +409,7 @@ struct gtpc_f_teid_ie
uint32_t teid; uint32_t teid;
in_addr_t ipv4; in_addr_t ipv4;
struct in6_addr ipv6; //FIXME struct in6_addr ipv6; //FIXME
}; } gtp_fteid_t;
//TODO //TODO
//TODO IEs between 8.22 and 8.28 missing //TODO IEs between 8.22 and 8.28 missing

@ -410,5 +410,36 @@ struct gtpc_delete_session_response
//Private extension //Private extension
}; };
/****************************************************************************
*
* GTP-C v2 Release Access Bearers Request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.21.1-1
*
***************************************************************************/
struct gtpc_release_access_bearers_request
{
bool list_of_rabs_present;
//Linked EPS Bearer ID
bool originating_node_present;
//Indication Flags
//Private Extension
};
/****************************************************************************
*
* GTP-C v2 Delete Session Response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.22.1-1
*
***************************************************************************/
struct gtpc_release_access_bearers_response
{
struct gtpc_cause_ie cause;
//Recovery
//Private extension
};
} //namespace } //namespace
#endif //GTPC_V2_MSG_H #endif //GTPC_V2_MSG_H

@ -175,6 +175,7 @@ typedef struct{
uint8 imsi[15]; uint8 imsi[15];
uint8 imei[15]; uint8 imei[15];
uint8 imeisv[16]; uint8 imeisv[16];
uint32 tmsi;
}LIBLTE_MME_MOBILE_ID_STRUCT; }LIBLTE_MME_MOBILE_ID_STRUCT;
// Functions // Functions
LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mobile_id, LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mobile_id,

@ -296,9 +296,10 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
uint8 **ie_ptr) uint8 **ie_ptr)
{ {
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS; LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *id; uint8 *id = NULL;
uint32 id32 = 0;
uint32 i; uint32 i;
uint8 length; uint8 length = 0;
bool odd = false; bool odd = false;
if(mobile_id != NULL && if(mobile_id != NULL &&
@ -317,6 +318,11 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
id = mobile_id->imeisv; id = mobile_id->imeisv;
length = 9; length = 9;
odd = false; odd = false;
}else if(LIBLTE_MME_MOBILE_ID_TYPE_TMSI == mobile_id->type_of_id){
id32 = mobile_id->tmsi;
length = 4;
odd = false;
}
}else{ }else{
// FIXME: Not handling these IDs // FIXME: Not handling these IDs
return(err); return(err);
@ -325,7 +331,8 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
// Length // Length
**ie_ptr = length; **ie_ptr = length;
*ie_ptr += 1; *ie_ptr += 1;
if(LIBLTE_MME_MOBILE_ID_TYPE_TMSI != mobile_id->type_of_id)
{
// | Identity digit 1 | odd/even | Id type | // | Identity digit 1 | odd/even | Id type |
if(odd) if(odd)
{ {
@ -335,6 +342,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
} }
*ie_ptr += 1; *ie_ptr += 1;
// | Identity digit p+1 | Identity digit p | // | Identity digit p+1 | Identity digit p |
for(i=0; i<7; i++) for(i=0; i<7; i++)
{ {
@ -349,6 +357,22 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
err = LIBLTE_SUCCESS; err = LIBLTE_SUCCESS;
} }
else{
**ie_ptr = (0xFF << 4) | (0 << 3) | mobile_id->type_of_id;
*ie_ptr += 1;
//4-Byte based ids
**ie_ptr = (id32 >> 24) & 0xFF;
*ie_ptr += 1;
**ie_ptr = (id32 >> 16) & 0xFF;
*ie_ptr += 1;
**ie_ptr = (id32 >> 8) & 0xFF;
*ie_ptr += 1;
**ie_ptr = id32 & 0xFF;
*ie_ptr += 1;
err = LIBLTE_SUCCESS;
}
return(err); return(err);
} }

@ -188,7 +188,7 @@ private:
srslte::logger *logger; srslte::logger *logger;
srslte::log_filter rf_log; srslte::log_filter rf_log;
std::vector<void*> phy_log; std::vector<srslte::log_filter*> phy_log;
srslte::log_filter mac_log; srslte::log_filter mac_log;
srslte::log_filter rlc_log; srslte::log_filter rlc_log;
srslte::log_filter pdcp_log; srslte::log_filter pdcp_log;

@ -28,6 +28,7 @@
#define ENBPHY_H #define ENBPHY_H
#include "srslte/common/log.h" #include "srslte/common/log.h"
#include "srslte/common/log_filter.h"
#include "phy/txrx.h" #include "phy/txrx.h"
#include "phy/phch_worker.h" #include "phy/phch_worker.h"
#include "phy/phch_common.h" #include "phy/phch_common.h"
@ -54,8 +55,8 @@ class phy : public phy_interface_mac,
public: public:
phy(); phy();
bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log* log_h); bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, srslte::log_filter* log_h);
bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, std::vector<void*> log_vec); bool init(phy_args_t *args, phy_cfg_t *common_cfg, srslte::radio *radio_handler, mac_interface_phy *mac, std::vector<srslte::log_filter *> log_vec);
void stop(); void stop();
/* MAC->PHY interface */ /* MAC->PHY interface */

@ -32,26 +32,27 @@
namespace srsenb { namespace srsenb {
enb* enb::instance = NULL; enb* enb::instance = NULL;
boost::mutex enb_instance_mutex; pthread_mutex_t enb_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
enb* enb::get_instance(void) enb* enb::get_instance(void)
{ {
boost::mutex::scoped_lock lock(enb_instance_mutex); pthread_mutex_lock(&enb_instance_mutex);
if(NULL == instance) { if(NULL == instance) {
instance = new enb(); instance = new enb();
} }
pthread_mutex_unlock(&enb_instance_mutex);
return(instance); return(instance);
} }
void enb::cleanup(void) void enb::cleanup(void)
{ {
srslte_dft_exit(); srslte_dft_exit();
srslte::byte_buffer_pool::cleanup(); srslte::byte_buffer_pool::cleanup();
boost::mutex::scoped_lock lock(enb_instance_mutex); pthread_mutex_lock(&enb_instance_mutex);
if(NULL != instance) { if(NULL != instance) {
delete instance; delete instance;
instance = NULL; instance = NULL;
} }
pthread_mutex_unlock(&enb_instance_mutex);
} }
enb::enb() : started(false) { enb::enb() : started(false) {
@ -66,6 +67,9 @@ enb::enb() : started(false) {
enb::~enb() enb::~enb()
{ {
for (uint32_t i = 0; i < phy_log.size(); i++) {
delete (phy_log[i]);
}
} }
bool enb::init(all_args_t *args_) bool enb::init(all_args_t *args_)
@ -88,7 +92,7 @@ bool enb::init(all_args_t *args_)
char tmp[16]; char tmp[16];
sprintf(tmp, "PHY%d",i); sprintf(tmp, "PHY%d",i);
mylog->init(tmp, logger, true); mylog->init(tmp, logger, true);
phy_log.push_back((void*) mylog); phy_log.push_back(mylog);
} }
mac_log.init("MAC ", logger, true); mac_log.init("MAC ", logger, true);
rlc_log.init("RLC ", logger); rlc_log.init("RLC ", logger);

@ -93,11 +93,11 @@ bool phy::init(phy_args_t *args,
phy_cfg_t *cfg, phy_cfg_t *cfg,
srslte::radio* radio_handler_, srslte::radio* radio_handler_,
mac_interface_phy *mac, mac_interface_phy *mac,
srslte::log* log_h) srslte::log_filter* log_h)
{ {
std::vector<void*> log_vec; std::vector<srslte::log_filter*> log_vec;
for (int i=0;i<args->nof_phy_threads;i++) { for (int i=0;i<args->nof_phy_threads;i++) {
log_vec.push_back((void*)log_h); log_vec.push_back(log_h);
} }
init(args, cfg, radio_handler_, mac, log_vec); init(args, cfg, radio_handler_, mac, log_vec);
return true; return true;
@ -107,7 +107,7 @@ bool phy::init(phy_args_t *args,
phy_cfg_t *cfg, phy_cfg_t *cfg,
srslte::radio* radio_handler_, srslte::radio* radio_handler_,
mac_interface_phy *mac, mac_interface_phy *mac,
std::vector<void*> log_vec) std::vector<srslte::log_filter*> log_vec)
{ {
mlockall(MCL_CURRENT | MCL_FUTURE); mlockall(MCL_CURRENT | MCL_FUTURE);

@ -10,8 +10,9 @@
# tac: 16-bit Tracking Area Code. # tac: 16-bit Tracking Area Code.
# mcc: Mobile Country Code # mcc: Mobile Country Code
# mnc: Mobile Network Code # mnc: Mobile Network Code
# mme_bindx_addr: IP subnet to listen for eNB S1 connnections
# apn: Set Access Point Name (APN) # apn: Set Access Point Name (APN)
# mme_bind_addr: IP bind addr to listen for eNB S1-MME connnections
# dns_addr: DNS server address for the UEs
# #
##################################################################### #####################################################################
[mme] [mme]
@ -21,7 +22,8 @@ tac = 0x0007
mcc = 001 mcc = 001
mnc = 01 mnc = 01
mme_bind_addr = 127.0.1.100 mme_bind_addr = 127.0.1.100
apn = test123 apn = srsapn
dns_addr = 8.8.8.8
##################################################################### #####################################################################
# HSS configuration # HSS configuration

@ -42,17 +42,22 @@ class mme_gtpc
{ {
public: public:
typedef struct gtpc_ctx{
srslte::gtp_fteid_t mme_ctr_fteid;
srslte::gtp_fteid_t sgw_ctr_fteid;
}gtpc_ctx_t;
static mme_gtpc* get_instance(void); static mme_gtpc* get_instance(void);
static void cleanup(void); static void cleanup(void);
bool init(srslte::log_filter *mme_gtpc_log); bool init(srslte::log_filter *mme_gtpc_log);
uint32_t get_new_ctrl_teid(); uint32_t get_new_ctrl_teid();
void send_create_session_request(uint64_t imsi, uint32_t mme_s1ap_id); void send_create_session_request(uint64_t imsi);
void handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu); void handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu);
void send_modify_bearer_request(erab_ctx_t *bearer_ctx); void send_modify_bearer_request(uint64_t imsi, erab_ctx_t *bearer_ctx);
void handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu); void handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu);
void send_delete_session_request(ue_ctx_t *ue_ctx); void send_release_access_bearers_request(uint64_t imsi);
void send_delete_session_request(uint64_t imsi);
private: private:
@ -68,7 +73,8 @@ private:
in_addr_t m_mme_gtpc_ip; in_addr_t m_mme_gtpc_ip;
uint32_t m_next_ctrl_teid; uint32_t m_next_ctrl_teid;
std::map<uint32_t,uint32_t> m_teid_to_mme_s1ap_id; std::map<uint32_t,uint64_t> m_mme_ctr_teid_to_imsi;
std::map<uint64_t,struct gtpc_ctx> m_imsi_to_gtpc_ctx;
}; };

@ -65,13 +65,12 @@ public:
int get_s1_mme(); int get_s1_mme();
void delete_enb_ctx(int32_t assoc_id); void delete_enb_ctx(int32_t assoc_id);
void delete_ues_in_enb(uint16_t enb_id);
bool handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri); bool handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri);
bool handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri); bool handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri);
bool handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg); bool handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg);
void activate_eps_bearer(uint32_t mme_s1ap_id, uint8_t ebi); void activate_eps_bearer(uint64_t imsi, uint8_t ebi);
void print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx); void print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx);
@ -79,11 +78,32 @@ public:
uint32_t get_next_mme_ue_s1ap_id(); uint32_t get_next_mme_ue_s1ap_id();
enb_ctx_t* find_enb_ctx(uint16_t enb_id); enb_ctx_t* find_enb_ctx(uint16_t enb_id);
void add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo* enb_sri); void add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo* enb_sri);
ue_ctx_t* find_ue_ctx(uint32_t mme_ue_s1ap_id);
void add_new_ue_ctx(const ue_ctx_t &ue_ctx);
bool delete_ue_ctx(ue_ctx_t *ue_ctx);
uint32_t allocate_m_tmsi(uint32_t mme_ue_s1ap_id); bool add_ue_ctx_to_imsi_map(ue_ctx_t *ue_ctx);
bool add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx_t *ue_ctx);
ue_ctx_t* find_ue_ctx_from_imsi(uint64_t imsi);
ue_ctx_t* find_ue_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id);
bool release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id);
void release_ues_ecm_ctx_in_enb(uint16_t enb_id);
bool delete_ue_ctx(uint64_t imsi);
//ue_ctx_t* find_ue_ctx(uint32_t mme_ue_s1ap_id);
//void add_new_ue_ctx(const ue_ctx_t &ue_ctx);
//void add_new_ue_emm_ctx(const ue_emm_ctx_t &ue_emm_ctx);
//void add_new_ue_ecm_ctx(const ue_ecm_ctx_t &ue_ecm_ctx);
//ue_emm_ctx_t* find_ue_emm_ctx_from_imsi(uint64_t imsi);
//ue_ecm_ctx_t* find_ue_ecm_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id);
//bool delete_ue_emm_ctx(uint64_t imsi);
//bool delete_ue_ecm_ctx(uint32_t mme_ue_s1ap_id);
//void delete_ues_ecm_ctx_in_enb(uint16_t enb_id);
//void store_tmp_ue_emm_ctx(const ue_emm_ctx_t &ue_ecm_ctx);
//bool get_tmp_ue_emm_ctx(uint32_t mme_ue_s1ap_id, ue_emm_ctx_t* ue_emm_ptr);
uint32_t allocate_m_tmsi(uint64_t imsi);
s1ap_args_t m_s1ap_args; s1ap_args_t m_s1ap_args;
srslte::log_filter *m_s1ap_log; srslte::log_filter *m_s1ap_log;
@ -92,7 +112,7 @@ public:
s1ap_nas_transport* m_s1ap_nas_transport; s1ap_nas_transport* m_s1ap_nas_transport;
s1ap_ctx_mngmt_proc* m_s1ap_ctx_mngmt_proc; s1ap_ctx_mngmt_proc* m_s1ap_ctx_mngmt_proc;
std::map<uint32_t, uint32_t> m_tmsi_to_s1ap_id; std::map<uint32_t, uint64_t> m_tmsi_to_imsi;
private: private:
s1ap(); s1ap();
@ -107,12 +127,20 @@ private:
int m_s1mme; int m_s1mme;
std::map<uint16_t, enb_ctx_t*> m_active_enbs; std::map<uint16_t, enb_ctx_t*> m_active_enbs;
std::map<int32_t, uint16_t> m_sctp_to_enb_id; std::map<int32_t, uint16_t> m_sctp_to_enb_id;
std::map<uint32_t, ue_ctx_t*> m_active_ues;
std::map<uint16_t,std::set<uint32_t> > m_enb_id_to_ue_ids; std::map<uint16_t,std::set<uint32_t> > m_enb_id_to_ue_ids;
std::map<uint64_t, ue_ctx_t*> m_imsi_to_ue_ctx;
std::map<uint32_t, ue_ctx_t*> m_mme_ue_s1ap_id_to_ue_ctx;
//std::map<uint64_t, ue_emm_ctx_t*> m_imsi_to_ue_emm_ctx;
//std::map<uint32_t, ue_ecm_ctx_t*> m_mme_ue_s1ap_id_to_ue_ecm_ctx;
//std::map<int32_t,ue_emm_ctx_t*> m_mme_ue_s1ap_id_to_tmp_ue_emm_ctx;
uint32_t m_next_mme_ue_s1ap_id; uint32_t m_next_mme_ue_s1ap_id;
uint32_t m_next_m_tmsi; uint32_t m_next_m_tmsi;
//FIXME the GTP-C should be moved to the MME class, the the packaging of GTP-C messages is done. //FIXME the GTP-C should be moved to the MME class, when the packaging of GTP-C messages is done.
mme_gtpc *m_mme_gtpc; mme_gtpc *m_mme_gtpc;
}; };

@ -33,6 +33,47 @@ static const uint8_t MAX_TA=255; //Maximum TA supported
static const uint8_t MAX_BPLMN=6; //Maximum broadcasted PLMNs per TAC static const uint8_t MAX_BPLMN=6; //Maximum broadcasted PLMNs per TAC
static const uint8_t MAX_ERABS_PER_UE = 16; static const uint8_t MAX_ERABS_PER_UE = 16;
// MME EMM states (3GPP 24.301 v10.0.0, section 5.1.3.4)
typedef enum {
EMM_STATE_DEREGISTERED = 0,
EMM_STATE_COMMON_PROCEDURE_INITIATED,
EMM_STATE_REGISTERED,
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",
"DEREGISTERED INITIATED"};
// MME ECM states (3GPP 23.401 v10.0.0, section 4.6.3)
typedef enum {
ECM_STATE_IDLE = 0,
ECM_STATE_CONNECTED,
ECM_STATE_N_ITEMS,
} ecm_state_t;
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 {
ESM_BEARER_CONTEXT_INACTIVE = 0,
ESM_BEARER_CONTEXT_ACTIVE_PENDING,
ESM_BEARER_CONTEXT_ACTIVE,
ESM_BEARER_CONTEXT_INACTIVE_PENDING,
ESM_BEARER_CONTEXT_MODIFY_PENDING,
ESM_BEARER_PROCEDURE_TRANSACTION_INACTIVE,
ESM_BEARER_PROCEDURE_TRANSACTION_PENDING,
ESM_STATE_N_ITEMS,
} esm_state_t;
static const char esm_state_text[ESM_STATE_N_ITEMS][100] = {"CONTEXT INACTIVE",
"CONTEXT ACTIVE PENDING",
"CONTEXT ACTIVE",
"CONTEXT_INACTIVE_PENDING",
"CONTEXT_MODIFY_PENDING",
"PROCEDURE_TRANSACTION_INACTIVE"
"PROCEDURE_TRANSACTION_PENDING"};
enum erab_state enum erab_state
{ {
ERAB_DEACTIVATED, ERAB_DEACTIVATED,
@ -41,6 +82,7 @@ enum erab_state
ERAB_ACTIVE ERAB_ACTIVE
}; };
typedef struct{ typedef struct{
uint8_t mme_code; uint8_t mme_code;
uint16_t mme_group; uint16_t mme_group;
@ -49,6 +91,7 @@ typedef struct{
uint16_t mnc; // BCD-coded with 0xF filler uint16_t mnc; // BCD-coded with 0xF filler
std::string mme_bind_addr; std::string mme_bind_addr;
std::string mme_name; std::string mme_name;
std::string dns_addr;
std::string mme_apn; std::string mme_apn;
} s1ap_args_t; } s1ap_args_t;
@ -75,29 +118,48 @@ typedef struct{
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo; srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
uint8_t k_nas_enc[32]; uint8_t k_nas_enc[32];
uint8_t k_nas_int[32]; uint8_t k_nas_int[32];
} eps_security_ctx_t; uint8_t k_enb[32];
LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT ue_network_cap;
bool ms_network_cap_present;
LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT ms_network_cap;
} eps_sec_ctx_t;
typedef struct{ typedef struct{
enum erab_state state; enum erab_state state;
uint8_t erab_id; uint8_t erab_id;
srslte::gtpc_f_teid_ie enb_fteid; srslte::gtpc_f_teid_ie enb_fteid;
srslte::gtpc_f_teid_ie sgw_ctrl_fteid; srslte::gtpc_f_teid_ie sgw_s1u_fteid;
srslte::gtpc_pdn_address_allocation_ie pdn_addr_alloc;
} erab_ctx_t; } erab_ctx_t;
typedef struct{
uint64_t imsi;
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
eps_sec_ctx_t security_ctxt;
uint8_t procedure_transaction_id;
emm_state_t state;
uint32_t mme_ue_s1ap_id;
uint8_t attach_type;
struct in_addr ue_ip;
srslte::gtpc_f_teid_ie sgw_ctrl_fteid;
} ue_emm_ctx_t;
typedef struct{ typedef struct{
uint64_t imsi; uint64_t imsi;
uint32_t enb_ue_s1ap_id; uint32_t enb_ue_s1ap_id;
uint32_t mme_ue_s1ap_id; uint32_t mme_ue_s1ap_id;
uint16_t enb_id;
struct sctp_sndrcvinfo enb_sri; struct sctp_sndrcvinfo enb_sri;
eps_security_ctx_t security_ctxt; ecm_state_t state;
erab_ctx_t erabs_ctx[MAX_ERABS_PER_UE]; erab_ctx_t erabs_ctx[MAX_ERABS_PER_UE];
LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT ue_network_cap;
bool ms_network_cap_present;
LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT ms_network_cap;
bool eit; bool eit;
uint8_t procedure_transaction_id; } ue_ecm_ctx_t;
uint8_t attach_type;
typedef struct{
ue_emm_ctx_t emm_ctx;
eps_sec_ctx_t sec_ctx;
ue_ecm_ctx_t ecm_ctx;
erab_ctx_t erabs_ctx[MAX_ERABS_PER_UE];
} ue_ctx_t; } ue_ctx_t;
}//namespace }//namespace
#endif #endif

@ -47,9 +47,12 @@ public:
void init(void); void init(void);
bool send_initial_context_setup_request(uint32_t mme_ue_s1ap_id, struct srslte::gtpc_create_session_response *cs_resp, struct srslte::gtpc_f_teid_ie sgw_ctrl_fteid); //bool send_initial_context_setup_request(uint32_t mme_ue_s1ap_id, struct srslte::gtpc_create_session_response *cs_resp, struct srslte::gtpc_f_teid_ie sgw_ctrl_fteid);
bool send_initial_context_setup_request(ue_emm_ctx_t *emm_ctx, ue_ecm_ctx_t *ecm_ctx, erab_ctx_t *erab_ctx);
bool handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *in_ctxt_resp); 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(ue_ecm_ctx_t *ecm_ctx, srslte::byte_buffer_t *reply_buffer);
bool handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *rel_comp);
private: private:
s1ap_ctx_mngmt_proc(); s1ap_ctx_mngmt_proc();

@ -47,9 +47,9 @@ public:
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, 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, bool *reply_flag);
//Initial UE messages
bool handle_nas_attach_request( uint32_t enb_ue_s1ap_id, bool handle_nas_attach_request( uint32_t enb_ue_s1ap_id,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req, srslte::byte_buffer_t *nas_msg,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
srslte::byte_buffer_t *reply_buffer, srslte::byte_buffer_t *reply_buffer,
bool* reply_flag, bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri); struct sctp_sndrcvinfo *enb_sri);
@ -62,28 +62,48 @@ public:
bool handle_nas_guti_attach_request(uint32_t enb_ue_s1ap_id, bool handle_nas_guti_attach_request(uint32_t enb_ue_s1ap_id,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req, const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req, const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
srslte::byte_buffer_t *nas_msg,
srslte::byte_buffer_t *reply_buffer,
bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_service_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
srslte::byte_buffer_t *nas_msg,
srslte::byte_buffer_t *reply_buffer,
bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_detach_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
srslte::byte_buffer_t *nas_msg,
srslte::byte_buffer_t *reply_buffer, srslte::byte_buffer_t *reply_buffer,
bool* reply_flag, bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri); struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_authentication_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool* reply_flag); bool handle_nas_authentication_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool* reply_flag);
bool handle_nas_security_mode_complete(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool *reply_flag); bool handle_nas_security_mode_complete(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_nas_attach_complete(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool *reply_flag); bool handle_nas_attach_complete(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_esm_information_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag); bool handle_esm_information_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag); bool handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool handle_tracking_area_update_request(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag); bool handle_tracking_area_update_request(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool handle_authentication_failure(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag); bool handle_authentication_failure(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_nas_detach_request(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool integrity_check(ue_emm_ctx_t *emm_ctx, srslte::byte_buffer_t *pdu);
bool short_integrity_check(ue_emm_ctx_t *emm_ctx, srslte::byte_buffer_t *pdu);
bool pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t *autn,uint8_t *rand); bool pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t *autn,uint8_t *rand);
bool pack_authentication_reject(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id); bool pack_authentication_reject(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
bool unpack_authentication_response(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp); bool unpack_authentication_response(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp);
bool pack_security_mode_command(srslte::byte_buffer_t *reply_msg, ue_ctx_t *ue_ctx); bool pack_security_mode_command(srslte::byte_buffer_t *reply_msg, ue_emm_ctx_t *ue_emm_ctx, ue_ecm_ctx_t *ue_ecm_ctx);
bool pack_esm_information_request(srslte::byte_buffer_t *reply_msg, ue_ctx_t *ue_ctx); bool pack_esm_information_request(srslte::byte_buffer_t *reply_msg, ue_emm_ctx_t *ue_emm_ctx, ue_ecm_ctx_t *ue_ecm_ctx);
bool pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab_ctxt, struct srslte::gtpc_pdn_address_allocation_ie *paa, srslte::byte_buffer_t *nas_buffer); bool pack_attach_accept(ue_emm_ctx_t *ue_emm_ctx, ue_ecm_ctx_t *ue_ecm_ctx, LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab_ctxt, struct srslte::gtpc_pdn_address_allocation_ie *paa, srslte::byte_buffer_t *nas_buffer);
bool pack_identity_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id); bool pack_identity_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
bool pack_emm_information(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id); bool pack_emm_information(ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg);
bool pack_service_reject(srslte::byte_buffer_t *reply_msg, uint8_t emm_cause, uint32_t enb_ue_s1ap_id); bool pack_service_reject(srslte::byte_buffer_t *reply_msg, uint8_t emm_cause, uint32_t enb_ue_s1ap_id);
void log_unhandled_attach_request_ies(const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req); void log_unhandled_attach_request_ies(const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req);
@ -102,7 +122,5 @@ private:
hss_interface_s1ap* m_hss; hss_interface_s1ap* m_hss;
mme_gtpc* m_mme_gtpc; mme_gtpc* m_mme_gtpc;
}; };
} //namespace srsepc } //namespace srsepc
#endif //S1AP_NAS_TRANSPORT #endif //S1AP_NAS_TRANSPORT

@ -76,6 +76,7 @@ public:
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_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_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_sgi_pdu(srslte::byte_buffer_t *msg); void handle_sgi_pdu(srslte::byte_buffer_t *msg);
void handle_s1u_pdu(srslte::byte_buffer_t *msg); void handle_s1u_pdu(srslte::byte_buffer_t *msg);
@ -94,6 +95,10 @@ private:
uint64_t get_new_user_teid(); uint64_t get_new_user_teid();
in_addr_t get_new_ue_ipv4(); in_addr_t get_new_ue_ipv4();
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; bool m_running;
srslte::byte_buffer_pool *m_pool; srslte::byte_buffer_pool *m_pool;
mme_gtpc *m_mme_gtpc; mme_gtpc *m_mme_gtpc;
@ -112,11 +117,17 @@ private:
sockaddr_in m_s1u_addr; sockaddr_in m_s1u_addr;
pthread_mutex_t m_mutex; 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<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 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; uint32_t m_h_next_ue_ip;
/*Time*/
struct timeval m_t_last_dl;
struct timeval m_t_last_ul;
/*Logs*/ /*Logs*/
srslte::log_filter *m_spgw_log; srslte::log_filter *m_spgw_log;

@ -37,7 +37,7 @@ using namespace srslte;
namespace srsepc{ namespace srsepc{
hss* hss::m_instance = NULL; hss* hss::m_instance = NULL;
boost::mutex hss_instance_mutex; pthread_mutex_t hss_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
hss::hss() hss::hss()
{ {
@ -53,21 +53,23 @@ hss::~hss()
hss* hss*
hss::get_instance(void) hss::get_instance(void)
{ {
boost::mutex::scoped_lock lock(hss_instance_mutex); pthread_mutex_lock(&hss_instance_mutex);
if(NULL == m_instance) { if(NULL == m_instance) {
m_instance = new hss(); m_instance = new hss();
} }
pthread_mutex_unlock(&hss_instance_mutex);
return(m_instance); return(m_instance);
} }
void void
hss::cleanup(void) hss::cleanup(void)
{ {
boost::mutex::scoped_lock lock(hss_instance_mutex); pthread_mutex_lock(&hss_instance_mutex);
if(NULL != m_instance) { if(NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&hss_instance_mutex);
} }
int int

@ -52,7 +52,6 @@ typedef struct {
int spgw_hex_limit; int spgw_hex_limit;
std::string hss_level; std::string hss_level;
int hss_hex_limit; int hss_hex_limit;
std::string all_level; std::string all_level;
int all_hex_limit; int all_hex_limit;
std::string filename; std::string filename;
@ -84,6 +83,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
string mme_apn; string mme_apn;
string spgw_bind_addr; string spgw_bind_addr;
string sgi_if_addr; string sgi_if_addr;
string dns_addr;
string hss_db_file; string hss_db_file;
string hss_auth_algo; string hss_auth_algo;
string log_filename; string log_filename;
@ -106,6 +106,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
("mme.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code") ("mme.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code")
("mme.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code") ("mme.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code")
("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection") ("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection")
("mme.dns_addr", bpo::value<string>(&dns_addr)->default_value("8.8.8.8"),"IP address of the DNS server for the UEs")
("mme.apn", bpo::value<string>(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services") ("mme.apn", bpo::value<string>(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services")
("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys") ("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys")
("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"),"HSS uthentication algorithm.") ("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"),"HSS uthentication algorithm.")
@ -206,6 +207,8 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
} }
args->mme_args.s1ap_args.mme_bind_addr = mme_bind_addr; args->mme_args.s1ap_args.mme_bind_addr = mme_bind_addr;
args->mme_args.s1ap_args.mme_name = mme_name;
args->mme_args.s1ap_args.dns_addr = dns_addr;
args->mme_args.s1ap_args.mme_apn = mme_apn; args->mme_args.s1ap_args.mme_apn = mme_apn;
args->spgw_args.gtpu_bind_addr = spgw_bind_addr; args->spgw_args.gtpu_bind_addr = spgw_bind_addr;
args->spgw_args.sgi_if_addr = sgi_if_addr; args->spgw_args.sgi_if_addr = sgi_if_addr;

@ -29,13 +29,12 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/sctp.h> #include <netinet/sctp.h>
#include <boost/thread/mutex.hpp>
#include "mme/mme.h" #include "mme/mme.h"
namespace srsepc{ namespace srsepc{
mme* mme::m_instance = NULL; mme* mme::m_instance = NULL;
boost::mutex mme_instance_mutex; pthread_mutex_t mme_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
mme::mme(): mme::mme():
m_running(false) m_running(false)
@ -52,21 +51,23 @@ mme::~mme()
mme* mme*
mme::get_instance(void) mme::get_instance(void)
{ {
boost::mutex::scoped_lock lock(mme_instance_mutex); pthread_mutex_lock(&mme_instance_mutex);
if(NULL == m_instance) { if(NULL == m_instance) {
m_instance = new mme(); m_instance = new mme();
} }
pthread_mutex_unlock(&mme_instance_mutex);
return(m_instance); return(m_instance);
} }
void void
mme::cleanup(void) mme::cleanup(void)
{ {
boost::mutex::scoped_lock lock(mme_instance_mutex); pthread_mutex_lock(&mme_instance_mutex);
if(NULL != m_instance) { if(NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&mme_instance_mutex);
} }
int int

@ -33,7 +33,8 @@
namespace srsepc{ namespace srsepc{
mme_gtpc* mme_gtpc::m_instance = NULL; mme_gtpc* mme_gtpc::m_instance = NULL;
boost::mutex mme_gtpc_instance_mutex; pthread_mutex_t mme_gtpc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
mme_gtpc::mme_gtpc() mme_gtpc::mme_gtpc()
{ {
@ -46,21 +47,23 @@ mme_gtpc::~mme_gtpc()
mme_gtpc* mme_gtpc*
mme_gtpc::get_instance(void) mme_gtpc::get_instance(void)
{ {
boost::mutex::scoped_lock lock(mme_gtpc_instance_mutex); pthread_mutex_lock(&mme_gtpc_instance_mutex);
if(NULL == m_instance) { if(NULL == m_instance) {
m_instance = new mme_gtpc(); m_instance = new mme_gtpc();
} }
pthread_mutex_unlock(&mme_gtpc_instance_mutex);
return(m_instance); return(m_instance);
} }
void void
mme_gtpc::cleanup(void) mme_gtpc::cleanup(void)
{ {
boost::mutex::scoped_lock lock(mme_gtpc_instance_mutex); pthread_mutex_lock(&mme_gtpc_instance_mutex);
if(NULL != m_instance) { if(NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&mme_gtpc_instance_mutex);
} }
@ -88,7 +91,7 @@ mme_gtpc::get_new_ctrl_teid()
return m_next_ctrl_teid++; //FIXME Use a Id pool? return m_next_ctrl_teid++; //FIXME Use a Id pool?
} }
void void
mme_gtpc::send_create_session_request(uint64_t imsi, uint32_t mme_ue_s1ap_id) mme_gtpc::send_create_session_request(uint64_t imsi)
{ {
m_mme_gtpc_log->info("Sending Create Session Request.\n"); m_mme_gtpc_log->info("Sending Create Session Request.\n");
m_mme_gtpc_log->console("Sending Create Session Request.\n"); m_mme_gtpc_log->console("Sending Create Session Request.\n");
@ -97,7 +100,6 @@ mme_gtpc::send_create_session_request(uint64_t imsi, uint32_t mme_ue_s1ap_id)
struct srslte::gtpc_pdu cs_resp_pdu; struct srslte::gtpc_pdu cs_resp_pdu;
//Initialize GTP-C message to zero //Initialize GTP-C message to zero
bzero(&cs_req_pdu, sizeof(struct srslte::gtpc_pdu)); bzero(&cs_req_pdu, sizeof(struct srslte::gtpc_pdu));
@ -113,19 +115,45 @@ mme_gtpc::send_create_session_request(uint64_t imsi, uint32_t mme_ue_s1ap_id)
cs_req->sender_f_teid.teid = get_new_ctrl_teid(); cs_req->sender_f_teid.teid = get_new_ctrl_teid();
cs_req->sender_f_teid.ipv4 = m_mme_gtpc_ip; cs_req->sender_f_teid.ipv4 = m_mme_gtpc_ip;
m_mme_gtpc_log->info("Next control TEID: %lu \n", m_next_ctrl_teid); m_mme_gtpc_log->info("Next MME control TEID: %lu \n", m_next_ctrl_teid);
m_mme_gtpc_log->info("Allocated control TEID: %lu \n", cs_req->sender_f_teid.teid); m_mme_gtpc_log->info("Allocated MME control TEID: %lu \n", cs_req->sender_f_teid.teid);
m_mme_gtpc_log->console("Creating Session Response -- IMSI: %015lu \n", imsi); m_mme_gtpc_log->console("Creating Session Response -- IMSI: %015lu \n", imsi);
m_mme_gtpc_log->console("Creating Session Response -- MME control TEID: %lu \n", cs_req->sender_f_teid.teid); m_mme_gtpc_log->console("Creating Session Response -- MME control TEID: %lu \n", cs_req->sender_f_teid.teid);
// APN // APN
strncpy(cs_req->apn, m_s1ap->m_s1ap_args.mme_apn.c_str(), sizeof(cs_req->apn)-1); strncpy(cs_req->apn, m_s1ap->m_s1ap_args.mme_apn.c_str(), sizeof(cs_req->apn)-1);
cs_req->apn[sizeof(cs_req->apn)-1] = 0; cs_req->apn[sizeof(cs_req->apn)-1] = 0;
// RAT Type // RAT Type
//cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN; //cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN;
//Check whether this UE is already registed
std::map<uint64_t, struct gtpc_ctx>::iterator it = m_imsi_to_gtpc_ctx.find(imsi);
if(it != m_imsi_to_gtpc_ctx.end())
{
m_mme_gtpc_log->warning("Create Session Request being called for an UE with an active GTP-C connection.\n");
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);
}
else
{
m_mme_ctr_teid_to_imsi.erase(jt);
}
m_imsi_to_gtpc_ctx.erase(it);
//No need to send delete session request to the SPGW.
//The create session request will be interpreted as a new request and SPGW will delete locally in existing context.
}
//Save RX Control TEID //Save RX Control TEID
m_teid_to_mme_s1ap_id.insert(std::pair<uint32_t,uint32_t>(cs_req->sender_f_teid.teid, mme_ue_s1ap_id)); m_mme_ctr_teid_to_imsi.insert(std::pair<uint32_t,uint64_t>(cs_req->sender_f_teid.teid, imsi));
//Save GTP-C context
gtpc_ctx_t gtpc_ctx;
bzero(&gtpc_ctx,sizeof(gtpc_ctx_t));
gtpc_ctx.mme_ctr_fteid = cs_req->sender_f_teid;
m_imsi_to_gtpc_ctx.insert(std::pair<uint64_t,gtpc_ctx_t>(imsi,gtpc_ctx));
m_spgw->handle_create_session_request(cs_req, &cs_resp_pdu); m_spgw->handle_create_session_request(cs_req, &cs_resp_pdu);
} }
@ -139,7 +167,7 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
if (cs_resp_pdu->header.type != srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE) if (cs_resp_pdu->header.type != srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE)
{ {
m_mme_gtpc_log->warning("Could not create GTPC session. Not a create session response\n"); m_mme_gtpc_log->warning("Could not create GTPC session. Not a create session response\n");
//TODO Handle err //TODO Handle error
return; return;
} }
if (cs_resp->cause.cause_value != srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED){ if (cs_resp->cause.cause_value != srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED){
@ -148,40 +176,99 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
return; return;
} }
//Get MME_UE_S1AP_ID from the control TEID //Get IMSI from the control TEID
std::map<uint32_t,uint32_t>::iterator id_it = m_teid_to_mme_s1ap_id.find(cs_resp_pdu->header.teid); std::map<uint32_t,uint64_t>::iterator id_it = m_mme_ctr_teid_to_imsi.find(cs_resp_pdu->header.teid);
if(id_it == m_teid_to_mme_s1ap_id.end()) if(id_it == m_mme_ctr_teid_to_imsi.end())
{ {
//Could not find MME UE S1AP TEID m_mme_gtpc_log->warning("Could not find IMSI from Ctrl TEID.\n");
m_mme_gtpc_log->warning("Could not find MME UE S1AP TEID.\n");
return; return;
} }
uint32_t mme_s1ap_id = id_it->second; uint64_t imsi = id_it->second;
m_mme_gtpc_log->info("MME GTPC Ctrl TEID %d, IMSI %d\n", cs_resp_pdu->header.teid, imsi);
//Get S-GW Control F-TEID //Get S-GW Control F-TEID
srslte::gtpc_f_teid_ie sgw_ctrl_fteid; srslte::gtp_fteid_t sgw_ctr_fteid;
sgw_ctrl_fteid.teid = cs_resp_pdu->header.teid; sgw_ctr_fteid.teid = cs_resp_pdu->header.teid;
sgw_ctrl_fteid.ipv4 = 0; //FIXME This is not used for now. In the future it will be obtained from the socket addr_info sgw_ctr_fteid.ipv4 = 0; //FIXME This is not used for now. In the future it will be obtained from the socket addr_info
m_mme_gtpc_log->console("Create Session Response -- SPGW control TEID %d\n", sgw_ctrl_fteid.teid); //Get S-GW S1-u F-TEID
if (cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present == false){
m_mme_gtpc_log->error("Did not receive SGW S1-U F-TEID in create session response\n");
return;
}
m_mme_gtpc_log->console("Create Session Response -- SPGW control TEID %d\n", sgw_ctr_fteid.teid);
m_mme_gtpc_log->info("Create Session Response -- SPGW control TEID %d\n", sgw_ctr_fteid.teid);
in_addr s1u_addr; in_addr s1u_addr;
s1u_addr.s_addr = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4; s1u_addr.s_addr = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4;
m_mme_gtpc_log->console("Create Session Response -- SPGW S1-U Address: %s\n", inet_ntoa(s1u_addr)); m_mme_gtpc_log->console("Create Session Response -- SPGW S1-U Address: %s\n", inet_ntoa(s1u_addr));
m_s1ap->m_s1ap_ctx_mngmt_proc->send_initial_context_setup_request(mme_s1ap_id, cs_resp, sgw_ctrl_fteid); m_mme_gtpc_log->info("Create Session Response -- SPGW S1-U Address: %s\n", inet_ntoa(s1u_addr));
//Check UE Ipv4 address was allocated
if(cs_resp->paa_present != true)
{
m_mme_gtpc_log->error("PDN Adress Allocation not present\n");
return;
}
if(cs_resp->paa.pdn_type != srslte::GTPC_PDN_TYPE_IPV4)
{
m_mme_gtpc_log->error("IPv6 not supported yet\n");
return;
}
//Save create session response info to E-RAB context
ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx_from_imsi(imsi);
if(ue_ctx == NULL){
m_mme_gtpc_log->error("Could not find UE context. IMSI %015lu\n", imsi);
return;
}
ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx;
ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx;
//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())
{
//Could not find GTP-C Context
m_mme_gtpc_log->error("Could not find GTP-C context\n");
return;
}
gtpc_ctx_t *gtpc_ctx = &it_g->second;
gtpc_ctx->sgw_ctr_fteid = sgw_ctr_fteid;
//Set EPS bearer context
//FIXME default EPS bearer is hard-coded
int default_bearer=5;
erab_ctx_t *erab_ctx = &ecm_ctx->erabs_ctx[default_bearer];
erab_ctx->pdn_addr_alloc= cs_resp->paa;
erab_ctx->sgw_s1u_fteid = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid;
m_s1ap->m_s1ap_ctx_mngmt_proc->send_initial_context_setup_request(emm_ctx, ecm_ctx, erab_ctx);
return;
} }
void void
mme_gtpc::send_modify_bearer_request(erab_ctx_t *erab_ctx) mme_gtpc::send_modify_bearer_request(uint64_t imsi, erab_ctx_t *erab_ctx)
{ {
m_mme_gtpc_log->info("Sending GTP-C Modify bearer request\n"); m_mme_gtpc_log->info("Sending GTP-C Modify bearer request\n");
srslte::gtpc_pdu mb_req_pdu; srslte::gtpc_pdu mb_req_pdu;
srslte::gtpc_f_teid_ie *enb_fteid = &erab_ctx->enb_fteid; srslte::gtp_fteid_t *enb_fteid = &erab_ctx->enb_fteid;
srslte::gtpc_f_teid_ie *sgw_ctrl_fteid = &erab_ctx->sgw_ctrl_fteid;
std::map<uint64_t,gtpc_ctx_t>::iterator it = m_imsi_to_gtpc_ctx.find(imsi);
if(it == m_imsi_to_gtpc_ctx.end())
{
m_mme_gtpc_log->error("Modify bearer request for UE without GTP-C connection\n");
return;
}
srslte::gtp_fteid_t sgw_ctr_fteid = it->second.sgw_ctr_fteid;
srslte::gtpc_header *header = &mb_req_pdu.header; srslte::gtpc_header *header = &mb_req_pdu.header;
header->teid_present = true; header->teid_present = true;
header->teid = sgw_ctrl_fteid->teid; header->teid = sgw_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST; header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST;
srslte::gtpc_modify_bearer_request *mb_req = &mb_req_pdu.choice.modify_bearer_request; srslte::gtpc_modify_bearer_request *mb_req = &mb_req_pdu.choice.modify_bearer_request;
@ -189,7 +276,7 @@ mme_gtpc::send_modify_bearer_request(erab_ctx_t *erab_ctx)
mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.ipv4 = enb_fteid->ipv4; mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.ipv4 = enb_fteid->ipv4;
mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid = enb_fteid->teid; mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid = enb_fteid->teid;
m_mme_gtpc_log->info("GTP-C Modify bearer request -- S-GW Control TEID %d\n", sgw_ctrl_fteid->teid ); m_mme_gtpc_log->info("GTP-C Modify bearer request -- S-GW Control TEID %d\n", sgw_ctr_fteid.teid );
struct in_addr addr; struct in_addr addr;
addr.s_addr = enb_fteid->ipv4; 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) ); m_mme_gtpc_log->info("GTP-C Modify bearer request -- S1-U TEID 0x%x, IP %s\n", enb_fteid->teid, inet_ntoa(addr) );
@ -205,54 +292,93 @@ void
mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu) mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu)
{ {
uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid; uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid;
std::map<uint32_t,uint32_t>::iterator mme_s1ap_id_it = m_teid_to_mme_s1ap_id.find(mme_ctrl_teid); std::map<uint32_t,uint64_t>::iterator imsi_it = m_mme_ctr_teid_to_imsi.find(mme_ctrl_teid);
if(mme_s1ap_id_it == m_teid_to_mme_s1ap_id.end()) if(imsi_it == m_mme_ctr_teid_to_imsi.end())
{ {
m_mme_gtpc_log->error("Could not find MME S1AP Id from control TEID\n"); m_mme_gtpc_log->error("Could not find IMSI from control TEID\n");
return; return;
} }
uint8_t ebi = mb_resp_pdu->choice.modify_bearer_response.eps_bearer_context_modified.ebi; uint8_t ebi = mb_resp_pdu->choice.modify_bearer_response.eps_bearer_context_modified.ebi;
m_mme_gtpc_log->debug("Activating EPS bearer with id %d\n", ebi); m_mme_gtpc_log->debug("Activating EPS bearer with id %d\n", ebi);
m_s1ap->activate_eps_bearer(mme_s1ap_id_it->second,ebi); m_s1ap->activate_eps_bearer(imsi_it->second,ebi);
return; return;
} }
void void
mme_gtpc::send_delete_session_request(ue_ctx_t *ue_ctx) mme_gtpc::send_delete_session_request(uint64_t imsi)
{ {
m_mme_gtpc_log->info("Sending GTP-C Delete Session Request request\n"); m_mme_gtpc_log->info("Sending GTP-C Delete Session Request request. IMSI %d\n",imsi);
srslte::gtpc_pdu del_req_pdu; srslte::gtpc_pdu del_req_pdu;
srslte::gtpc_f_teid_ie *sgw_ctrl_fteid = NULL; srslte::gtp_fteid_t sgw_ctr_fteid;
srslte::gtp_fteid_t mme_ctr_fteid;
//FIXME the UE control TEID sould be stored in the UE ctxt, not in the E-RAB ctxt //Get S-GW Ctr TEID
//Maybe a mme_s1ap_id to ctrl teid map as well? 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())
for(int i = 0; i<MAX_ERABS_PER_UE; i++)
{ {
if(ue_ctx->erabs_ctx[i].state != ERAB_DEACTIVATED) m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
{ return;
sgw_ctrl_fteid = &ue_ctx->erabs_ctx[i].sgw_ctrl_fteid;
break;
}
} }
//FIXME: add proper error handling sgw_ctr_fteid = it_ctx->second.sgw_ctr_fteid;
assert(sgw_ctrl_fteid != NULL); mme_ctr_fteid = it_ctx->second.mme_ctr_fteid;
srslte::gtpc_header *header = &del_req_pdu.header; srslte::gtpc_header *header = &del_req_pdu.header;
header->teid_present = true; header->teid_present = true;
header->teid = sgw_ctrl_fteid->teid; header->teid = sgw_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_DELETE_SESSION_REQUEST; header->type = srslte::GTPC_MSG_TYPE_DELETE_SESSION_REQUEST;
srslte::gtpc_delete_session_request *del_req = &del_req_pdu.choice.delete_session_request; srslte::gtpc_delete_session_request *del_req = &del_req_pdu.choice.delete_session_request;
del_req->cause.cause_value = srslte::GTPC_CAUSE_VALUE_ISR_DEACTIVATION; del_req->cause.cause_value = srslte::GTPC_CAUSE_VALUE_ISR_DEACTIVATION;
m_mme_gtpc_log->info("GTP-C Delete Session Request -- S-GW Control TEID %d\n", sgw_ctrl_fteid->teid ); m_mme_gtpc_log->info("GTP-C Delete Session Request -- S-GW Control TEID %d\n", sgw_ctr_fteid.teid );
srslte::gtpc_pdu del_resp_pdu; srslte::gtpc_pdu del_resp_pdu;
m_spgw->handle_delete_session_request(&del_req_pdu, &del_resp_pdu); m_spgw->handle_delete_session_request(&del_req_pdu, &del_resp_pdu);
//TODO Handle delete session response //TODO Handle delete session response
//Delete GTP-C context
std::map<uint32_t,uint64_t>::iterator it_imsi = m_mme_ctr_teid_to_imsi.find(mme_ctr_fteid.teid);
if(it_imsi == m_mme_ctr_teid_to_imsi.end())
{
m_mme_gtpc_log->error("Could not find IMSI from MME ctr TEID");
}
else
{
m_mme_ctr_teid_to_imsi.erase(it_imsi);
}
m_imsi_to_gtpc_ctx.erase(it_ctx);
return;
}
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;
srslte::gtp_fteid_t sgw_ctr_fteid;
//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())
{
m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
return;
}
sgw_ctr_fteid = it_ctx->second.sgw_ctr_fteid;
//Set GTP-C header
srslte::gtpc_header *header = &rel_req_pdu.header;
header->teid_present = true;
header->teid = sgw_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_REQUEST;
srslte::gtpc_release_access_bearers_request *rel_req = &rel_req_pdu.choice.release_access_bearers_request;
m_mme_gtpc_log->info("GTP-C Release Access Berarers Request -- S-GW Control TEID %d\n", sgw_ctr_fteid.teid );
srslte::gtpc_pdu rel_resp_pdu;
m_spgw->handle_release_access_bearers_request(&rel_req_pdu, &rel_resp_pdu);
//The GTP-C connection will not be torn down, just the user plane bearers.
return; return;
} }
} //namespace srsepc } //namespace srsepc

@ -34,7 +34,7 @@
namespace srsepc{ namespace srsepc{
s1ap* s1ap::m_instance = NULL; s1ap* s1ap::m_instance = NULL;
boost::mutex s1ap_instance_mutex; pthread_mutex_t s1ap_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap::s1ap(): s1ap::s1ap():
m_s1mme(-1), m_s1mme(-1),
@ -51,21 +51,24 @@ s1ap::~s1ap()
s1ap* s1ap*
s1ap::get_instance(void) s1ap::get_instance(void)
{ {
boost::mutex::scoped_lock lock(s1ap_instance_mutex);
if(NULL == m_instance) { pthread_mutex_lock(&s1ap_instance_mutex);
if(m_instance == NULL) {
m_instance = new s1ap(); m_instance = new s1ap();
} }
pthread_mutex_unlock(&s1ap_instance_mutex);
return(m_instance); return(m_instance);
} }
void void
s1ap::cleanup(void) s1ap::cleanup(void)
{ {
boost::mutex::scoped_lock lock(s1ap_instance_mutex); pthread_mutex_lock(&s1ap_instance_mutex);
if(NULL != m_instance) { if(NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&s1ap_instance_mutex);
} }
int int
@ -75,7 +78,7 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1
m_s1ap_args = s1ap_args; m_s1ap_args = s1ap_args;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &m_plmn); srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &m_plmn);
m_next_m_tmsi = rand(); m_next_m_tmsi = 0xF000;
//Init log //Init log
m_s1ap_log = s1ap_log; m_s1ap_log = s1ap_log;
@ -90,10 +93,8 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures
m_s1ap_ctx_mngmt_proc->init(); m_s1ap_ctx_mngmt_proc->init();
//Get pointer to GTP-C class //Get pointer to GTP-C class
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
//Initialize S1-MME //Initialize S1-MME
m_s1mme = enb_listen(); m_s1mme = enb_listen();
@ -107,16 +108,23 @@ s1ap::stop()
if (m_s1mme != -1){ if (m_s1mme != -1){
close(m_s1mme); close(m_s1mme);
} }
std::map<uint16_t,enb_ctx_t*>::iterator it = m_active_enbs.begin(); std::map<uint16_t,enb_ctx_t*>::iterator enb_it = m_active_enbs.begin();
while(it!=m_active_enbs.end()) while(enb_it!=m_active_enbs.end())
{ {
m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", it->second->enb_id); m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", enb_it->second->enb_id);
m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", it->second->enb_id); m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", enb_it->second->enb_id);
delete_ues_in_enb(it->second->enb_id); delete enb_it->second;
delete it->second; m_active_enbs.erase(enb_it++);
m_active_enbs.erase(it++);
} }
std::map<uint64_t,ue_ctx_t*>::iterator ue_it = m_imsi_to_ue_ctx.begin();
while(ue_it!=m_imsi_to_ue_ctx.end())
{
m_s1ap_log->info("Deleting UE EMM context. IMSI: %015lu\n", ue_it->first);
m_s1ap_log->console("Deleting UE EMM context. IMSI: %015lu\n", ue_it->first);
delete ue_it->second;
m_imsi_to_ue_ctx.erase(ue_it++);
}
//Cleanup message handlers //Cleanup message handlers
s1ap_mngmt_proc::cleanup(); s1ap_mngmt_proc::cleanup();
s1ap_nas_transport::cleanup(); s1ap_nas_transport::cleanup();
@ -124,55 +132,18 @@ s1ap::stop()
return; return;
} }
void int
s1ap::delete_enb_ctx(int32_t assoc_id) s1ap::get_s1_mme()
{ {
std::map<int32_t,uint16_t>::iterator it_assoc = m_sctp_to_enb_id.find(assoc_id); return m_s1mme;
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())
{
m_s1ap_log->error("Could not find eNB to delete. Association: %d\n",assoc_id);
return;
}
m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
//Delete connected UEs ctx
delete_ues_in_enb(enb_id);
//Delete eNB
delete it_ctx->second;
m_active_enbs.erase(it_ctx);
m_sctp_to_enb_id.erase(it_assoc);
return;
} }
void uint32_t
s1ap::delete_ues_in_enb(uint16_t enb_id) s1ap::get_next_mme_ue_s1ap_id()
{ {
//delete UEs ctx return m_next_mme_ue_s1ap_id++;
std::map<uint16_t,std::set<uint32_t> >::iterator ues_in_enb = m_enb_id_to_ue_ids.find(enb_id);
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.begin();
while(ue_id != ues_in_enb->second.end() )
{
std::map<uint32_t, ue_ctx_t*>::iterator ue_ctx = m_active_ues.find(*ue_id);
m_s1ap_log->info("Deleting UE context. UE IMSI: %lu\n", ue_ctx->second->imsi);
m_s1ap_log->console("Deleting UE context. UE IMSI: %lu\n", ue_ctx->second->imsi);
delete ue_ctx->second; //delete UE context
m_active_ues.erase(ue_ctx); //remove from general MME map
ues_in_enb->second.erase(ue_id++); //erase from the eNB's UE set
}
} }
int
s1ap::get_s1_mme()
{
return m_s1mme;
}
int int
s1ap::enb_listen() s1ap::enb_listen()
@ -282,7 +253,8 @@ s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, stru
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; break;
default: default:
m_s1ap_log->error("Unhandled intiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]); m_s1ap_log->error("Unhandled S1AP intiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
m_s1ap_log->console("Unhandled S1APintiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
} }
//Send Reply to eNB //Send Reply to eNB
if(reply_flag == true) if(reply_flag == true)
@ -290,7 +262,8 @@ s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, stru
ssize_t n_sent = sctp_send(m_s1mme,reply_buffer->msg, reply_buffer->N_bytes, enb_sri, 0); ssize_t n_sent = sctp_send(m_s1mme,reply_buffer->msg, reply_buffer->N_bytes, enb_sri, 0);
if(n_sent == -1) if(n_sent == -1)
{ {
m_s1ap_log->console("Failed to send S1 Setup Setup Reply\n"); m_s1ap_log->console("Failed to send S1AP Initiating Reply.\n");
m_s1ap_log->error("Failed to send S1AP Initiating Reply. \n");
m_pool->deallocate(reply_buffer); m_pool->deallocate(reply_buffer);
return false; return false;
} }
@ -306,53 +279,128 @@ s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE: case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE:
m_s1ap_log->info("Received Initial Context Setup Response.\n"); m_s1ap_log->info("Received Initial Context Setup Response.\n");
return m_s1ap_ctx_mngmt_proc->handle_initial_context_setup_response(&msg->choice.InitialContextSetupResponse); return m_s1ap_ctx_mngmt_proc->handle_initial_context_setup_response(&msg->choice.InitialContextSetupResponse);
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTRELEASECOMPLETE:
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: 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; return true;
} }
//eNB Context Managment
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;
enb_ctx_t *enb_ptr = new enb_ctx_t;
memcpy(enb_ptr,&enb_ctx,sizeof(enb_ctx_t));
m_active_enbs.insert(std::pair<uint16_t,enb_ctx_t*>(enb_ptr->enb_id,enb_ptr));
m_sctp_to_enb_id.insert(std::pair<int32_t,uint16_t>(enb_sri->sinfo_assoc_id, enb_ptr->enb_id));
m_enb_id_to_ue_ids.insert(std::pair<uint16_t,std::set<uint32_t> >(enb_ptr->enb_id,ue_set));
return;
}
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())
{
return NULL;
}
else
{
return it->second;
}
}
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())
{
m_s1ap_log->error("Could not find eNB to delete. Association: %d\n",assoc_id);
return;
}
m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
//Delete connected UEs ctx
release_ues_ecm_ctx_in_enb(enb_id);
//Delete eNB
delete it_ctx->second;
m_active_enbs.erase(it_ctx);
m_sctp_to_enb_id.erase(it_assoc);
return;
}
//UE Context Management
bool bool
s1ap::delete_ue_ctx(ue_ctx_t *ue_ctx) s1ap::add_ue_ctx_to_imsi_map(ue_ctx_t *ue_ctx)
{ {
uint32_t mme_ue_s1ap_id = ue_ctx->mme_ue_s1ap_id; std::map<uint64_t, ue_ctx_t*>::iterator ctx_it = m_imsi_to_ue_ctx.find(ue_ctx->emm_ctx.imsi);
std::map<uint32_t, ue_ctx_t*>::iterator ue_ctx_it = m_active_ues.find(mme_ue_s1ap_id); if(ctx_it != m_imsi_to_ue_ctx.end())
if(ue_ctx_it == m_active_ues.end() )
{ {
m_s1ap_log->info("UE not found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id); m_s1ap_log->error("UE Context already exists. IMSI %015lu",ue_ctx->emm_ctx.imsi);
return false; return false;
} }
if(ue_ctx->ecm_ctx.mme_ue_s1ap_id != 0)
{
std::map<uint32_t,ue_ctx_t*>::iterator ctx_it2 = m_mme_ue_s1ap_id_to_ue_ctx.find(ue_ctx->ecm_ctx.mme_ue_s1ap_id);
if(ctx_it2 != m_mme_ue_s1ap_id_to_ue_ctx.end() && ctx_it2->second != ue_ctx)
{
m_s1ap_log->error("Context identified with IMSI does not match context identified by MME UE S1AP Id.\n");
return false;
}
}
m_imsi_to_ue_ctx.insert(std::pair<uint64_t,ue_ctx_t*>(ue_ctx->emm_ctx.imsi, ue_ctx));
m_s1ap_log->debug("Saved UE context corresponding to IMSI %015lu\n",ue_ctx->emm_ctx.imsi);
return true;
}
//Delete UE within eNB UE set bool
std::map<int32_t,uint16_t>::iterator it = m_sctp_to_enb_id.find(ue_ctx->enb_sri.sinfo_assoc_id); s1ap::add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx_t *ue_ctx)
if(it == m_sctp_to_enb_id.end() ) {
if(ue_ctx->ecm_ctx.mme_ue_s1ap_id == 0)
{ {
m_s1ap_log->error("Could not find eNB for this request.\n"); m_s1ap_log->error("Could not add UE context to MME UE S1AP map. MME UE S1AP ID 0 is not valid.");
return false; return false;
} }
uint16_t enb_id = it->second; std::map<uint32_t, ue_ctx_t*>::iterator ctx_it = m_mme_ue_s1ap_id_to_ue_ctx.find(ue_ctx->ecm_ctx.mme_ue_s1ap_id);
std::map<uint16_t,std::set<uint32_t> >::iterator ue_set = m_enb_id_to_ue_ids.find(enb_id); if(ctx_it != m_mme_ue_s1ap_id_to_ue_ctx.end())
if(ue_set == m_enb_id_to_ue_ids.end())
{ {
m_s1ap_log->error("Could not find the eNB's UEs.\n"); m_s1ap_log->error("UE Context already exists. MME UE S1AP Id %015lu",ue_ctx->emm_ctx.imsi);
return false; return false;
} }
ue_set->second.erase(mme_ue_s1ap_id); if(ue_ctx->ecm_ctx.imsi != 0)
{
//Delete UE context std::map<uint32_t,ue_ctx_t*>::iterator ctx_it2 = m_mme_ue_s1ap_id_to_ue_ctx.find(ue_ctx->ecm_ctx.mme_ue_s1ap_id);
delete ue_ctx; if(ctx_it2 != m_mme_ue_s1ap_id_to_ue_ctx.end() && ctx_it2->second != ue_ctx)
m_active_ues.erase(ue_ctx_it); {
m_s1ap_log->info("Deleted UE Context.\n"); m_s1ap_log->error("Context identified with MME UE S1AP Id does not match context identified by IMSI.\n");
return false;
}
}
m_mme_ue_s1ap_id_to_ue_ctx.insert(std::pair<uint32_t,ue_ctx_t*>(ue_ctx->ecm_ctx.mme_ue_s1ap_id, ue_ctx));
m_s1ap_log->debug("Saved UE context corresponding to MME UE S1AP Id %d\n",ue_ctx->ecm_ctx.mme_ue_s1ap_id);
return true; return true;
} }
enb_ctx_t* ue_ctx_t*
s1ap::find_enb_ctx(uint16_t enb_id) s1ap::find_ue_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
{ {
std::map<uint16_t,enb_ctx_t*>::iterator it = m_active_enbs.find(enb_id); std::map<uint32_t, ue_ctx_t*>::iterator it = m_mme_ue_s1ap_id_to_ue_ctx.find(mme_ue_s1ap_id);
if(it == m_active_enbs.end()) if(it == m_mme_ue_s1ap_id_to_ue_ctx.end())
{ {
return NULL; return NULL;
} }
@ -362,25 +410,11 @@ s1ap::find_enb_ctx(uint16_t enb_id)
} }
} }
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;
enb_ctx_t *enb_ptr = new enb_ctx_t;
memcpy(enb_ptr,&enb_ctx,sizeof(enb_ctx_t));
m_active_enbs.insert(std::pair<uint16_t,enb_ctx_t*>(enb_ptr->enb_id,enb_ptr));
m_sctp_to_enb_id.insert(std::pair<int32_t,uint16_t>(enb_sri->sinfo_assoc_id, enb_ptr->enb_id));
m_enb_id_to_ue_ids.insert(std::pair<uint16_t,std::set<uint32_t> >(enb_ptr->enb_id,ue_set));
return;
}
ue_ctx_t* ue_ctx_t*
s1ap::find_ue_ctx(uint32_t mme_ue_s1ap_id) s1ap::find_ue_ctx_from_imsi(uint64_t imsi)
{ {
std::map<uint32_t, ue_ctx_t*>::iterator it = m_active_ues.find(mme_ue_s1ap_id); std::map<uint64_t, ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.find(imsi);
if(it == m_active_ues.end()) if(it == m_imsi_to_ue_ctx.end())
{ {
return NULL; return NULL;
} }
@ -391,58 +425,127 @@ s1ap::find_ue_ctx(uint32_t mme_ue_s1ap_id)
} }
void void
s1ap::add_new_ue_ctx(const ue_ctx_t &ue_ctx) s1ap::release_ues_ecm_ctx_in_enb(uint16_t enb_id)
{
//delete UEs ctx
std::map<uint16_t,std::set<uint32_t> >::iterator ues_in_enb = m_enb_id_to_ue_ids.find(enb_id);
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.begin();
while(ue_id != ues_in_enb->second.end() )
{
std::map<uint32_t, ue_ctx_t*>::iterator ue_ctx = m_mme_ue_s1ap_id_to_ue_ctx.find(*ue_id);
ue_ecm_ctx_t *ecm_ctx = &ue_ctx->second->ecm_ctx;
m_s1ap_log->info("Releasing UE ECM context. UE-MME S1AP Id: %d\n", ecm_ctx->mme_ue_s1ap_id);
m_s1ap_log->console("Releasing UE ECM context. UE-MME S1AP Id: %d\n", ecm_ctx->mme_ue_s1ap_id);
ues_in_enb->second.erase(ecm_ctx->mme_ue_s1ap_id);
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->mme_ue_s1ap_id = 0;
ecm_ctx->enb_ue_s1ap_id = 0;
}
}
bool
s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
{ {
ue_ctx_t *ue_ptr = new ue_ctx_t; ue_ctx_t *ue_ctx = find_ue_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
memcpy(ue_ptr,&ue_ctx,sizeof(ue_ctx)); if(ue_ctx == NULL)
m_active_ues.insert(std::pair<uint32_t,ue_ctx_t*>(ue_ptr->mme_ue_s1ap_id,ue_ptr));
std::map<int32_t,uint16_t>::iterator it_enb = m_sctp_to_enb_id.find(ue_ptr->enb_sri.sinfo_assoc_id);
uint16_t enb_id = it_enb->second;
std::map<uint16_t,std::set<uint32_t> >::iterator it_ue_id = m_enb_id_to_ue_ids.find(enb_id);
if(it_ue_id==m_enb_id_to_ue_ids.end())
{ {
m_s1ap_log->error("Could not find eNB's UEs\n"); m_s1ap_log->error("Cannot release UE ECM context, UE not found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
return; return false;
} }
it_ue_id->second.insert(ue_ptr->mme_ue_s1ap_id); ue_ecm_ctx_t* ecm_ctx = &ue_ctx->ecm_ctx;
return;
//Delete UE within eNB UE set
std::map<int32_t,uint16_t>::iterator it = m_sctp_to_enb_id.find(ecm_ctx->enb_sri.sinfo_assoc_id);
if(it == m_sctp_to_enb_id.end() )
{
m_s1ap_log->error("Could not find eNB for UE release request.\n");
return false;
}
uint16_t enb_id = it->second;
std::map<uint16_t,std::set<uint32_t> >::iterator ue_set = m_enb_id_to_ue_ids.find(enb_id);
if(ue_set == m_enb_id_to_ue_ids.end())
{
m_s1ap_log->error("Could not find the eNB's UEs.\n");
return false;
}
ue_set->second.erase(mme_ue_s1ap_id);
//Release UE ECM context
m_mme_ue_s1ap_id_to_ue_ctx.erase(mme_ue_s1ap_id);
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->mme_ue_s1ap_id = 0;
ecm_ctx->enb_ue_s1ap_id = 0;
m_s1ap_log->info("Released UE ECM Context.\n");
return true;
} }
uint32_t bool
s1ap::get_next_mme_ue_s1ap_id() s1ap::delete_ue_ctx(uint64_t imsi)
{ {
return m_next_mme_ue_s1ap_id++; ue_ctx_t *ue_ctx = find_ue_ctx_from_imsi(imsi);
if(ue_ctx == NULL)
{
m_s1ap_log->info("Cannot delete UE context, UE not found. IMSI: %d\n", imsi);
return false;
}
//Make sure to release ECM ctx
if(ue_ctx->ecm_ctx.mme_ue_s1ap_id != 0)
{
release_ue_ecm_ctx(ue_ctx->ecm_ctx.mme_ue_s1ap_id);
}
//Delete UE context
m_imsi_to_ue_ctx.erase(imsi);
delete ue_ctx;
m_s1ap_log->info("Deleted UE Context.\n");
return true;
} }
//UE Bearer Managment
void void
s1ap::activate_eps_bearer(uint32_t mme_s1ap_id, uint8_t ebi) s1ap::activate_eps_bearer(uint64_t imsi, uint8_t ebi)
{ {
std::map<uint32_t,ue_ctx_t*>::iterator ue_ctx_it = m_active_ues.find(mme_s1ap_id); std::map<uint64_t,ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_active_ues.end()) if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
m_s1ap_log->error("Could not activate EPS bearer: Could not find UE context\n");
return;
}
//Make sure NAS is active
uint32_t mme_ue_s1ap_id = ue_ctx_it->second->ecm_ctx.mme_ue_s1ap_id;
std::map<uint32_t,ue_ctx_t*>::iterator it = m_mme_ue_s1ap_id_to_ue_ctx.find(mme_ue_s1ap_id);
if(it == m_mme_ue_s1ap_id_to_ue_ctx.end())
{ {
m_s1ap_log->error("Could not find UE context\n"); m_s1ap_log->error("Could not activate EPS bearer: ECM context seems to be missing\n");
return; return;
} }
ue_ctx_t * ue_ctx = ue_ctx_it->second;
if (ue_ctx->erabs_ctx[ebi].state != ERAB_CTX_SETUP) ue_ecm_ctx_t * ecm_ctx = &ue_ctx_it->second->ecm_ctx;
if (ecm_ctx->erabs_ctx[ebi].state != ERAB_CTX_SETUP)
{ {
m_s1ap_log->error("EPS Bearer could not be activated. MME S1AP Id %d, EPS Bearer id %d, state %d\n",mme_s1ap_id,ebi,ue_ctx->erabs_ctx[ebi].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,ecm_ctx->erabs_ctx[ebi].state);
m_s1ap_log->console("EPS Bearer could not be activated. MME S1AP Id %d, EPS Bearer id %d\n",mme_s1ap_id,ebi,ue_ctx->erabs_ctx[ebi].state); m_s1ap_log->console("Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d\n",mme_ue_s1ap_id,ebi,ecm_ctx->erabs_ctx[ebi].state);
return; return;
} }
ue_ctx->erabs_ctx[ebi].state = ERAB_ACTIVE; ecm_ctx->erabs_ctx[ebi].state = ERAB_ACTIVE;
m_s1ap_log->info("Activated EPS Bearer\n"); ecm_ctx->state = ECM_STATE_CONNECTED;
m_s1ap_log->info("Activated EPS Bearer: Bearer id %d\n",ebi);
return; return;
} }
uint32_t uint32_t
s1ap::allocate_m_tmsi(uint32_t mme_ue_s1ap_id) s1ap::allocate_m_tmsi(uint64_t imsi)
{ {
//uint32_t m_tmsi = m_next_m_tmsi++; // uint32_t m_tmsi = m_next_m_tmsi++;
//m_tmsi_to_s1ap_id.insert(std::pair<uint32_t,uint32_t>(m_tmsi,mme_ue_s1ap_id)); uint32_t m_tmsi = m_next_m_tmsi;
uint32_t m_tmsi = 0x0123; m_tmsi_to_imsi.insert(std::pair<uint32_t,uint64_t>(m_tmsi,imsi));
m_s1ap_log->debug("Allocated M-TMSI 0x%x to IMSI %015lu,\n",m_tmsi,imsi);
return m_tmsi; return m_tmsi;
} }
@ -478,3 +581,4 @@ s1ap::print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx)
} }
} //namespace srsepc } //namespace srsepc

@ -34,7 +34,7 @@
namespace srsepc{ namespace srsepc{
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL; s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL;
boost::mutex s1ap_ctx_mngmt_proc_instance_mutex; 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()
@ -48,21 +48,23 @@ s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc()
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc*
s1ap_ctx_mngmt_proc::get_instance(void) s1ap_ctx_mngmt_proc::get_instance(void)
{ {
boost::mutex::scoped_lock lock(s1ap_ctx_mngmt_proc_instance_mutex); pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if(NULL == m_instance) { if(NULL == m_instance) {
m_instance = new s1ap_ctx_mngmt_proc(); m_instance = new s1ap_ctx_mngmt_proc();
} }
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
return(m_instance); return(m_instance);
} }
void void
s1ap_ctx_mngmt_proc::cleanup(void) s1ap_ctx_mngmt_proc::cleanup(void)
{ {
boost::mutex::scoped_lock lock(s1ap_ctx_mngmt_proc_instance_mutex); pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if(NULL != m_instance) { if(NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
} }
void void
@ -77,8 +79,11 @@ s1ap_ctx_mngmt_proc::init(void)
} }
bool bool
s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id, struct srslte::gtpc_create_session_response *cs_resp, struct srslte::gtpc_f_teid_ie sgw_ctrl_fteid) s1ap_ctx_mngmt_proc::send_initial_context_setup_request(ue_emm_ctx_t *emm_ctx,
ue_ecm_ctx_t *ecm_ctx,
erab_ctx_t *erab_ctx)
{ {
int s1mme = m_s1ap->get_s1_mme(); int s1mme = m_s1ap->get_s1_mme();
//Prepare reply PDU //Prepare reply PDU
@ -92,58 +97,50 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id,
LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *in_ctxt_req = &init->choice.InitialContextSetupRequest; LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *in_ctxt_req = &init->choice.InitialContextSetupRequest;
LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab_ctxt = &in_ctxt_req->E_RABToBeSetupListCtxtSUReq.buffer[0]; //FIXME support more than one erab LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab_ctx_req = &in_ctxt_req->E_RABToBeSetupListCtxtSUReq.buffer[0]; //FIXME support more than one erab
srslte::byte_buffer_t *reply_buffer = m_pool->allocate(); srslte::byte_buffer_t *reply_buffer = m_pool->allocate();
m_s1ap_log->info("Preparing to send Initial Context Setup request\n"); m_s1ap_log->info("Preparing to send Initial Context Setup request\n");
//Find UE Context
ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx(mme_ue_s1ap_id);
if(ue_ctx == NULL)
{
m_s1ap_log->error("Could not find UE to send Setup Context Request. MME S1AP Id: %d", mme_ue_s1ap_id);
return false;
}
//Add MME and eNB S1AP Ids //Add MME and eNB S1AP Ids
in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctx->mme_ue_s1ap_id; in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ecm_ctx->mme_ue_s1ap_id;
in_ctxt_req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctx->enb_ue_s1ap_id; in_ctxt_req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ecm_ctx->enb_ue_s1ap_id;
//Set UE-AMBR //Set UE-AMBR
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL.BitRate=1000000000;//2^32-1 in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL.BitRate=1000000000;
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL.BitRate=1000000000;//FIXME Get UE-AMBR from HSS in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL.BitRate=1000000000;//FIXME Get UE-AMBR from HSS
//Setup eRAB context //Setup eRAB context
in_ctxt_req->E_RABToBeSetupListCtxtSUReq.len = 1; in_ctxt_req->E_RABToBeSetupListCtxtSUReq.len = 1;
erab_ctxt->e_RAB_ID.E_RAB_ID = cs_resp->eps_bearer_context_created.ebi; erab_ctx_req->e_RAB_ID.E_RAB_ID = erab_ctx->erab_id;
//Setup E-RAB QoS parameters //Setup E-RAB QoS parameters
erab_ctxt->e_RABlevelQoSParameters.qCI.QCI = 9; erab_ctx_req->e_RABlevelQoSParameters.qCI.QCI = 9;
erab_ctxt->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel.PriorityLevel = 15 ;//Lowest erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel.PriorityLevel = 15 ;//Lowest
erab_ctxt->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability = LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION; erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability = LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION;
erab_ctxt->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability = LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_PRE_EMPTABLE; erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability = LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_PRE_EMPTABLE;
erab_ctxt->e_RABlevelQoSParameters.gbrQosInformation_present=false; erab_ctx_req->e_RABlevelQoSParameters.gbrQosInformation_present=false;
//Set E-RAB S-GW F-TEID //Set E-RAB S-GW F-TEID
if (cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present == false){ //if (cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present == false){
m_s1ap_log->error("Did not receive S1-U TEID in create session response\n"); // m_s1ap_log->error("Did not receive S1-U TEID in create session response\n");
return false; // return false;
} //}
erab_ctxt->transportLayerAddress.n_bits = 32; //IPv4 erab_ctx_req->transportLayerAddress.n_bits = 32; //IPv4
uint32_t sgw_s1u_ip = htonl(cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4); uint32_t sgw_s1u_ip = htonl(erab_ctx->sgw_s1u_fteid.ipv4);
//uint32_t sgw_s1u_ip = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4; //uint32_t sgw_s1u_ip = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4;
uint8_t *tmp_ptr = erab_ctxt->transportLayerAddress.buffer; uint8_t *tmp_ptr = erab_ctx_req->transportLayerAddress.buffer;
liblte_value_2_bits(sgw_s1u_ip, &tmp_ptr, 32);//FIXME consider ipv6 liblte_value_2_bits(sgw_s1u_ip, &tmp_ptr, 32);//FIXME consider ipv6
uint32_t tmp_teid = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.teid; uint32_t sgw_s1u_teid = erab_ctx->sgw_s1u_fteid.teid;
memcpy(erab_ctxt->gTP_TEID.buffer, &tmp_teid, sizeof(uint32_t)); memcpy(erab_ctx_req->gTP_TEID.buffer, &sgw_s1u_teid, sizeof(uint32_t));
//Set UE security capabilities and k_enb //Set UE security capabilities and k_enb
bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16); bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16);
bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16); bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16);
for(int i = 0; i<3; i++) for(int i = 0; i<3; i++)
{ {
if(ue_ctx->ue_network_cap.eea[i+1] == true) if(emm_ctx->security_ctxt.ue_network_cap.eea[i+1] == true)
{ {
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; //EEA supported in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; //EEA supported
} }
@ -151,7 +148,7 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id,
{ {
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 0; //EEA not supported in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 0; //EEA not supported
} }
if(ue_ctx->ue_network_cap.eia[i+1] == true) if(emm_ctx->security_ctxt.ue_network_cap.eia[i+1] == true)
{ {
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; //EEA supported in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; //EEA supported
} }
@ -159,25 +156,19 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id,
{ {
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 0; //EEA not supported in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 0; //EEA not supported
} }
// in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[0] = 1; //EIA1
}
uint8_t key_enb[32];
liblte_security_generate_k_enb(ue_ctx->security_ctxt.k_asme, ue_ctx->security_ctxt.ul_nas_count, key_enb);
liblte_unpack(key_enb, 32, in_ctxt_req->SecurityKey.buffer);
m_s1ap_log->info("Generating KeNB with UL NAS COUNT: %d\n",ue_ctx->security_ctxt.ul_nas_count);
//Set Attach accepted and activat default bearer NAS messages
if(cs_resp->paa_present != true)
{
m_s1ap_log->error("PAA not present\n");
return false;
} }
if(cs_resp->paa.pdn_type != srslte::GTPC_PDN_TYPE_IPV4) //Get K eNB
liblte_unpack(emm_ctx->security_ctxt.k_enb, 32, in_ctxt_req->SecurityKey.buffer);
m_s1ap_log->info_hex(emm_ctx->security_ctxt.k_enb, 32, "Initial Context Setup Request -- Key eNB\n");
srslte::byte_buffer_t *nas_buffer = m_pool->allocate();
if(emm_ctx->state == EMM_STATE_DEREGISTERED)
{ {
m_s1ap_log->error("IPv6 not supported yet\n"); //Attach procedure initiated from an attach request
return false; m_s1ap_log->console("Adding attach accept to Initial Context Setup Request\n");
m_s1ap_log->info("Adding attach accept to Initial Context Setup Request\n");
m_s1ap_nas_transport->pack_attach_accept(emm_ctx, ecm_ctx, erab_ctx_req, &erab_ctx->pdn_addr_alloc, nas_buffer);
} }
srslte::byte_buffer_t *nas_buffer = m_pool->allocate();
m_s1ap_nas_transport->pack_attach_accept(ue_ctx, erab_ctxt, &cs_resp->paa, nas_buffer);
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer); LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer);
@ -186,8 +177,9 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id,
m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n"); m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n");
return false; return false;
} }
//Send Reply to eNB //Send Reply to eNB
ssize_t n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ue_ctx->enb_sri, 0); ssize_t n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ecm_ctx->enb_sri, 0);
if(n_sent == -1) if(n_sent == -1)
{ {
m_s1ap_log->error("Failed to send Initial Context Setup Request\n"); m_s1ap_log->error("Failed to send Initial Context Setup Request\n");
@ -195,16 +187,18 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id,
} }
//Change E-RAB state to Context Setup Requested and save S-GW control F-TEID //Change E-RAB state to Context Setup Requested and save S-GW control F-TEID
ue_ctx->erabs_ctx[erab_ctxt->e_RAB_ID.E_RAB_ID].state = ERAB_CTX_REQUESTED; ecm_ctx->erabs_ctx[erab_ctx_req->e_RAB_ID.E_RAB_ID].state = ERAB_CTX_REQUESTED;
ue_ctx->erabs_ctx[erab_ctxt->e_RAB_ID.E_RAB_ID].sgw_ctrl_fteid.teid = sgw_ctrl_fteid.teid; //ecm_ctx->erabs_ctx[erab_ctx_req->e_RAB_ID.E_RAB_ID].sgw_ctrl_fteid.teid = sgw_ctrl_fteid.teid;
ue_ctx->erabs_ctx[erab_ctxt->e_RAB_ID.E_RAB_ID].sgw_ctrl_fteid.ipv4 = sgw_ctrl_fteid.ipv4; //ecm_ctx->erabs_ctx[erab_ctx_req->e_RAB_ID.E_RAB_ID].sgw_ctrl_fteid.ipv4 = sgw_ctrl_fteid.ipv4;
struct in_addr addr; struct in_addr addr;
addr.s_addr = htonl(sgw_s1u_ip); addr.s_addr = htonl(sgw_s1u_ip);
m_s1ap_log->info("Sent Intial Context Setup Request. E-RAB id %d \n",erab_ctxt->e_RAB_ID.E_RAB_ID); m_s1ap_log->info("Sent Intial Context Setup Request. E-RAB id %d \n",erab_ctx_req->e_RAB_ID.E_RAB_ID);
m_s1ap_log->info("Initial Context -- S1-U TEID 0x%x. IP %s \n", tmp_teid,inet_ntoa(addr)); m_s1ap_log->info("Initial Context -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid,inet_ntoa(addr));
m_s1ap_log->console("Sent Intial Context Setup Request, E-RAB id %d\n",erab_ctxt->e_RAB_ID.E_RAB_ID); m_s1ap_log->console("Initial Context Setup Request -- eNB UE S1AP Id %d, MME UE S1AP Id %d\n",in_ctxt_req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID, in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID);
m_s1ap_log->console("Initial Context -- S1-U TEID 0x%x. IP %s \n", tmp_teid,inet_ntoa(addr)); m_s1ap_log->console("Initial Context Setup Request -- E-RAB id %d\n",erab_ctx_req->e_RAB_ID.E_RAB_ID);
m_s1ap_log->console("Initial Context Setup Request -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid,inet_ntoa(addr));
m_s1ap_log->console("Initial Context Setup Request -- S1-U TEID 0x%x. IP %s \n", sgw_s1u_teid,inet_ntoa(addr));
m_pool->deallocate(reply_buffer); m_pool->deallocate(reply_buffer);
m_pool->deallocate(nas_buffer); m_pool->deallocate(nas_buffer);
@ -214,23 +208,25 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id,
bool bool
s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *in_ctxt_resp) s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *in_ctxt_resp)
{ {
uint32_t mme_ue_s1ap_id = in_ctxt_resp->MME_UE_S1AP_ID.MME_UE_S1AP_ID; uint32_t mme_ue_s1ap_id = in_ctxt_resp->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx(mme_ue_s1ap_id); ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (ue_ctx == NULL) if (ue_ctx == NULL)
{ {
m_s1ap_log->error("Could not find UE's context in active UE's map\n"); m_s1ap_log->error("Could not find UE's context in active UE's map\n");
return false; return false;
} }
ue_emm_ctx_t * emm_ctx = &ue_ctx->emm_ctx;
ue_ecm_ctx_t * ecm_ctx = &ue_ctx->ecm_ctx;
m_s1ap_log->console("Received Initial Context Setup Response\n");
//Setup E-RABs //Setup E-RABs
for(uint32_t i=0; i<in_ctxt_resp->E_RABSetupListCtxtSURes.len;i++) for(uint32_t i=0; i<in_ctxt_resp->E_RABSetupListCtxtSURes.len;i++)
{ {
uint8_t erab_id = in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].e_RAB_ID.E_RAB_ID; uint8_t erab_id = in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].e_RAB_ID.E_RAB_ID;
erab_ctx_t *erab_ctx = &ue_ctx->erabs_ctx[erab_id]; erab_ctx_t *erab_ctx = &ecm_ctx->erabs_ctx[erab_id];
if (erab_ctx->state != ERAB_CTX_REQUESTED) if (erab_ctx->state != ERAB_CTX_REQUESTED)
{ {
m_s1ap_log->error("E-RAB requested was not active %d\n",erab_id); m_s1ap_log->error("E-RAB requested was not previously requested %d\n",erab_id);
return false; return false;
} }
//Mark E-RAB with context setup //Mark E-RAB with context setup
@ -255,6 +251,12 @@ s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_I
m_s1ap_log->console("E-RAB Context -- eNB TEID 0x%x; eNB GTP-U Address %s\n", erab_ctx->enb_fteid.teid, enb_addr_str); m_s1ap_log->console("E-RAB Context -- eNB TEID 0x%x; eNB GTP-U Address %s\n", erab_ctx->enb_fteid.teid, enb_addr_str);
} }
if(emm_ctx->state == EMM_STATE_REGISTERED)
{
m_s1ap_log->console("Initial Context Setup Response triggered from Service Request.\n");
m_s1ap_log->console("Sending Modify Bearer Request.\n");
m_mme_gtpc->send_modify_bearer_request(emm_ctx->imsi, &ecm_ctx->erabs_ctx[5]);
}
return true; return true;
} }
@ -262,41 +264,155 @@ 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) 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)
{ {
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT ue_rel_req;
uint32_t mme_ue_s1ap_id = ue_rel->MME_UE_S1AP_ID.MME_UE_S1AP_ID; uint32_t mme_ue_s1ap_id = ue_rel->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
m_s1ap_log->info("Received UE Context Release Request. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id); m_s1ap_log->info("Received UE Context Release Request. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("Received UE Context Release Request. MME-UE S1AP Id %d\n", mme_ue_s1ap_id); m_s1ap_log->console("Received UE Context Release Request. MME-UE S1AP Id %d\n", mme_ue_s1ap_id);
ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx(mme_ue_s1ap_id); ue_ctx_t * ue_ctx = m_s1ap->find_ue_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if(ue_ctx == NULL) if(ue_ctx == NULL)
{ {
m_s1ap_log->info("UE not found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id); m_s1ap_log->info("No UE context to release found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("No UE context to release found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
return false; return false;
} }
ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx;
//Delete any context at the SPGW //Delete user plane context at the SPGW (but keep GTP-C connection).
bool active = false; if (ecm_ctx->state == ECM_STATE_CONNECTED)
{
//There are active E-RABs, send release access mearers request
m_s1ap_log->console("There are active E-RABs, send release access mearers request");
m_s1ap_log->info("There are active E-RABs, send release access mearers request");
//The handle_release_access_bearers_response function will make sure to mark E-RABS DEACTIVATED
//It will release the UEs downstream S1-u and keep the upstream S1-U connection active.
m_mme_gtpc->send_release_access_bearers_request(ecm_ctx->imsi);
//Send release context command to enb, so that it can release it's bearers
send_ue_context_release_command(ecm_ctx,reply_buffer);
}
else
{
//No ECM Context to release
m_s1ap_log->info("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id);
//Make sure E-RABS are merked as DEACTIVATED.
for(int i=0;i<MAX_ERABS_PER_UE;i++) for(int i=0;i<MAX_ERABS_PER_UE;i++)
{ {
if(ue_ctx->erabs_ctx[i].state != ERAB_DEACTIVATED) ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
}
}
//Delete UE context
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->enb_ue_s1ap_id = 0;
ecm_ctx->mme_ue_s1ap_id = 0;
m_s1ap_log->info("UE is ECM IDLE.\n");
m_s1ap_log->console("UE is ECM IDLE.\n");
return true;
}
bool
s1ap_ctx_mngmt_proc::send_ue_context_release_command(ue_ecm_ctx_t *ecm_ctx, srslte::byte_buffer_t *reply_buffer)
{
int s1mme = m_s1ap->get_s1_mme();
//Prepare reply PDU
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_UECONTEXTRELEASE;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASECOMMAND;
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMMAND_STRUCT *ctx_rel_cmd = &init->choice.UEContextReleaseCommand;
ctx_rel_cmd->UE_S1AP_IDs.choice_type = LIBLTE_S1AP_UE_S1AP_IDS_CHOICE_UE_S1AP_ID_PAIR;
ctx_rel_cmd->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.mME_UE_S1AP_ID.MME_UE_S1AP_ID = ecm_ctx->mme_ue_s1ap_id;
ctx_rel_cmd->UE_S1AP_IDs.choice.uE_S1AP_ID_pair.eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ecm_ctx->enb_ue_s1ap_id;
ctx_rel_cmd->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_NAS;
ctx_rel_cmd->Cause.choice.nas.ext = false;
ctx_rel_cmd->Cause.choice.nas.e = LIBLTE_S1AP_CAUSENAS_NORMAL_RELEASE;
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer);
if(err != LIBLTE_SUCCESS)
{ {
active = true; m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n");
//ue_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED; return false;
break; }
//Send Reply to eNB
int n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ecm_ctx->enb_sri, 0);
if(n_sent == -1)
{
m_s1ap_log->error("Failed to send Initial Context Setup Request\n");
return false;
} }
return true;
}
bool
s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT *rel_comp)
{
/*
typedef struct{
bool ext;
LIBLTE_S1AP_MME_UE_S1AP_ID_STRUCT MME_UE_S1AP_ID;
LIBLTE_S1AP_ENB_UE_S1AP_ID_STRUCT eNB_UE_S1AP_ID;
LIBLTE_S1AP_CRITICALITYDIAGNOSTICS_STRUCT CriticalityDiagnostics;
bool CriticalityDiagnostics_present;
LIBLTE_S1AP_USERLOCATIONINFORMATION_STRUCT UserLocationInformation;
bool UserLocationInformation_present;
}LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASECOMPLETE_STRUCT;
*/
uint32_t mme_ue_s1ap_id = rel_comp->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
m_s1ap_log->info("Received UE Context Release Complete. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("Received UE Context Release Complete. MME-UE S1AP Id %d\n", mme_ue_s1ap_id);
ue_ctx_t * ue_ctx = m_s1ap->find_ue_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if(ue_ctx == NULL)
{
m_s1ap_log->info("No UE context to release found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("No UE context to release found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
return false;
} }
if(active == true) ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx;
//Delete user plane context at the SPGW (but keep GTP-C connection).
if (ecm_ctx->state == ECM_STATE_CONNECTED)
{ {
//There are active E-RABs, send delete session request //There are active E-RABs, send release access mearers request
m_mme_gtpc->send_delete_session_request(ue_ctx); m_s1ap_log->console("There are active E-RABs, send release access mearers request");
m_s1ap_log->info("There are active E-RABs, send release access mearers request");
m_mme_gtpc->send_release_access_bearers_request(ecm_ctx->imsi);
//The handle_releease_access_bearers_response function will make sure to mark E-RABS DEACTIVATED
//It will release the UEs downstream S1-u and keep the upstream S1-U connection active.
} }
//m_s1ap->delete_ue_ctx(ue_ctx); else
{
//No ECM Context to release
m_s1ap_log->info("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id);
//Make sure E-RABS are merked as DEACTIVATED.
for(int i=0;i<MAX_ERABS_PER_UE;i++) for(int i=0;i<MAX_ERABS_PER_UE;i++)
{ {
ue_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED; ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
}
} }
//Delete UE context //Delete UE context
m_s1ap_log->info("Deleted UE Context.\n"); m_s1ap->release_ue_ecm_ctx(ue_ctx->ecm_ctx.mme_ue_s1ap_id);
m_s1ap_log->info("UE Context Release Completed.\n");
m_s1ap_log->console("UE Context Release Completed.\n");
return true; return true;
} }
} //namespace srsepc } //namespace srsepc

@ -32,7 +32,7 @@
namespace srsepc{ namespace srsepc{
s1ap_mngmt_proc* s1ap_mngmt_proc::m_instance = NULL; s1ap_mngmt_proc* s1ap_mngmt_proc::m_instance = NULL;
boost::mutex s1ap_mngmt_proc_instance_mutex; pthread_mutex_t s1ap_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_mngmt_proc::s1ap_mngmt_proc() s1ap_mngmt_proc::s1ap_mngmt_proc()
@ -46,21 +46,23 @@ s1ap_mngmt_proc::~s1ap_mngmt_proc()
s1ap_mngmt_proc* s1ap_mngmt_proc*
s1ap_mngmt_proc::get_instance(void) s1ap_mngmt_proc::get_instance(void)
{ {
boost::mutex::scoped_lock lock(s1ap_mngmt_proc_instance_mutex); pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex);
if(NULL == m_instance) { if(NULL == m_instance) {
m_instance = new s1ap_mngmt_proc(); m_instance = new s1ap_mngmt_proc();
} }
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
return(m_instance); return(m_instance);
} }
void void
s1ap_mngmt_proc::cleanup(void) s1ap_mngmt_proc::cleanup(void)
{ {
boost::mutex::scoped_lock lock(s1ap_mngmt_proc_instance_mutex); pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex);
if(NULL != m_instance) { if(NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
} }
void void
@ -102,6 +104,7 @@ s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
{ {
//eNB already registered //eNB already registered
//TODO replace enb_ctx //TODO replace enb_ctx
m_s1ap_log->warning("eNB Already registered\n");
} }
else else
{ {
@ -234,7 +237,7 @@ s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buff
LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *serv_gummei = &s1_resp->ServedGUMMEIs.buffer[0]; LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *serv_gummei = &s1_resp->ServedGUMMEIs.buffer[0];
serv_gummei->ext=false; serv_gummei->ext=false;
//serv_gummei->iE_Extensions=false; serv_gummei->iE_Extensions_present = false;
uint32_t plmn=0; uint32_t plmn=0;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn); srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn);
@ -258,6 +261,8 @@ s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buff
//Relay Unsupported //Relay Unsupported
s1_resp->MMERelaySupportIndicator_present=false; s1_resp->MMERelaySupportIndicator_present=false;
s1_resp->CriticalityDiagnostics_present = false;
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg); liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
return true; return true;

File diff suppressed because it is too large Load Diff

@ -41,7 +41,7 @@
namespace srsepc{ namespace srsepc{
spgw* spgw::m_instance = NULL; spgw* spgw::m_instance = NULL;
boost::mutex spgw_instance_mutex; pthread_mutex_t spgw_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
const uint16_t SPGW_BUFFER_SIZE = 2500; const uint16_t SPGW_BUFFER_SIZE = 2500;
@ -63,21 +63,23 @@ spgw::~spgw()
spgw* spgw*
spgw::get_instance(void) spgw::get_instance(void)
{ {
boost::mutex::scoped_lock lock(spgw_instance_mutex); pthread_mutex_lock(&spgw_instance_mutex);
if(NULL == m_instance) { if(NULL == m_instance) {
m_instance = new spgw(); m_instance = new spgw();
} }
pthread_mutex_unlock(&spgw_instance_mutex);
return(m_instance); return(m_instance);
} }
void void
spgw::cleanup(void) spgw::cleanup(void)
{ {
boost::mutex::scoped_lock lock(spgw_instance_mutex); pthread_mutex_lock(&spgw_instance_mutex);
if(NULL != m_instance) { if(NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&spgw_instance_mutex);
} }
int int
@ -144,8 +146,8 @@ spgw::stop()
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. 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()) while(it!=m_teid_to_tunnel_ctx.end())
{ {
m_spgw_log->info("Deleting SP-GW Tunnel. IMSI: %lu\n", it->second->imsi); m_spgw_log->info("Deleting SP-GW GTP-C Tunnel. IMSI: %lu\n", it->second->imsi);
m_spgw_log->console("Deleting SP-GW 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; delete it->second;
m_teid_to_tunnel_ctx.erase(it++); m_teid_to_tunnel_ctx.erase(it++);
} }
@ -224,6 +226,9 @@ spgw::init_sgi_if(spgw_args_t *args)
return srslte::ERROR_CANT_START; return srslte::ERROR_CANT_START;
} }
//Set initial time of setup
gettimeofday(&m_t_last_dl, NULL);
m_sgi_up = true; m_sgi_up = true;
return(srslte::ERROR_NONE); return(srslte::ERROR_NONE);
} }
@ -297,15 +302,11 @@ spgw::run_thread()
if (FD_ISSET(m_s1u, &set)) if (FD_ISSET(m_s1u, &set))
{ {
msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen ); msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen );
//m_spgw_log->console("Received PDU from S1-U. Bytes %d\n", msg->N_bytes);
//m_spgw_log->debug("Received PDU from S1-U. Bytes %d\n", msg->N_bytes);
handle_s1u_pdu(msg); handle_s1u_pdu(msg);
} }
if (FD_ISSET(m_sgi_if, &set)) if (FD_ISSET(m_sgi_if, &set))
{ {
msg->N_bytes = read(sgi, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES); msg->N_bytes = read(sgi, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES);
//m_spgw_log->console("Received PDU from SGi. Bytes %d\n", msg->N_bytes);
//m_spgw_log->debug("Received PDU from SGi. Bytes %d\n", msg->N_bytes);
handle_sgi_pdu(msg); handle_sgi_pdu(msg);
} }
} }
@ -328,6 +329,8 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
bool ip_found = false; bool ip_found = false;
srslte::gtpc_f_teid_ie enb_fteid; srslte::gtpc_f_teid_ie enb_fteid;
struct timeval t_now, t_delta;
version = msg->msg[0]>>4; version = msg->msg[0]>>4;
((uint8_t*)&dest_ip)[0] = msg->msg[16]; ((uint8_t*)&dest_ip)[0] = msg->msg[16];
((uint8_t*)&dest_ip)[1] = msg->msg[17]; ((uint8_t*)&dest_ip)[1] = msg->msg[17];
@ -380,8 +383,10 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
m_spgw_log->error("Error sending packet to eNB\n"); m_spgw_log->error("Error sending packet to eNB\n");
return; return;
} }
//m_spgw_log->console("Sent packet to %s:%d. Bytes=%d/%d\n",inet_ntoa(enb_addr.sin_addr), GTPU_RX_PORT,n,msg->N_bytes); else if((unsigned int) n!=msg->N_bytes)
{
m_spgw_log->error("Mis-match between packet bytes and sent bytes: Sent: %d, Packet: %d \n",n,msg->N_bytes);
}
return; return;
} }
@ -405,6 +410,10 @@ spgw::handle_s1u_pdu(srslte::byte_buffer_t *msg)
} }
return; return;
} }
/*
* Helper Functions
*/
uint64_t uint64_t
spgw::get_new_ctrl_teid() spgw::get_new_ctrl_teid()
{ {
@ -424,25 +433,29 @@ spgw::get_new_ue_ipv4()
return ntohl(m_h_next_ue_ip);//FIXME Tmp hack return ntohl(m_h_next_ue_ip);//FIXME Tmp hack
} }
void spgw_tunnel_ctx_t*
spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu) spgw::create_gtp_ctx(struct srslte::gtpc_create_session_request *cs_req)
{ {
srslte::gtpc_header *header = &cs_resp_pdu->header;
srslte::gtpc_create_session_response *cs_resp = &cs_resp_pdu->choice.create_session_response;
m_spgw_log->info("Received Create Session Request\n");
//Setup uplink control TEID //Setup uplink control TEID
uint64_t spgw_uplink_ctrl_teid = get_new_ctrl_teid(); uint64_t spgw_uplink_ctrl_teid = get_new_ctrl_teid();
//Setup uplink user TEID //Setup uplink user TEID
uint64_t spgw_uplink_user_teid = get_new_user_teid(); uint64_t spgw_uplink_user_teid = get_new_user_teid();
//Allocate UE IP //Allocate UE IP
in_addr_t ue_ip = get_new_ue_ipv4(); 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; uint8_t default_bearer_id = 5;
m_spgw_log->console("SPGW: Allocated Ctrl TEID %d\n", spgw_uplink_ctrl_teid);
m_spgw_log->console("SPGW: Allocated User TEID %d\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 //Save the UE IP to User TEID map
spgw_tunnel_ctx_t *tunnel_ctx = new spgw_tunnel_ctx_t; 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->imsi = cs_req->imsi;
tunnel_ctx->ebi = default_bearer_id; tunnel_ctx->ebi = default_bearer_id;
tunnel_ctx->up_user_fteid.teid = spgw_uplink_user_teid; tunnel_ctx->up_user_fteid.teid = spgw_uplink_user_teid;
@ -453,32 +466,82 @@ spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *
tunnel_ctx->up_ctrl_fteid.teid = spgw_uplink_ctrl_teid; tunnel_ctx->up_ctrl_fteid.teid = spgw_uplink_ctrl_teid;
tunnel_ctx->ue_ipv4 = ue_ip; 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_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)
{
m_spgw_log->info("Received Create Session Request\n");
spgw_tunnel_ctx_t *tunnel_ctx;
int default_bearer_id = 5;
//Check if IMSI has active GTP-C and/or GTP-U
bool gtpc_present = m_imsi_to_ctr_teid.count(cs_req->imsi);
if(gtpc_present)
{
m_spgw_log->console("SPGW: GTP-C context for IMSI %015lu already exists.\n", cs_req->imsi);
delete_gtp_ctx(m_imsi_to_ctr_teid[cs_req->imsi]);
m_spgw_log->console("SPGW: Deleted previous context.\n");
}
m_spgw_log->info("Creating new GTP-C context\n");
tunnel_ctx = create_gtp_ctx(cs_req);
//Create session response message //Create session response message
srslte::gtpc_header *header = &cs_resp_pdu->header;
srslte::gtpc_create_session_response *cs_resp = &cs_resp_pdu->choice.create_session_response;
//Setup GTP-C header //Setup GTP-C header
header->piggyback = false; header->piggyback = false;
header->teid_present = true; header->teid_present = true;
header->teid = cs_req->sender_f_teid.teid; //Send create session requesponse to the CS Request TEID header->teid = tunnel_ctx->dw_ctrl_fteid.teid; //Send create session requesponse to the UE's MME Ctrl TEID
header->type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE; header->type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE;
//Initialize to zero //Initialize to zero
bzero(cs_resp,sizeof(struct srslte::gtpc_create_session_response)); bzero(cs_resp,sizeof(struct srslte::gtpc_create_session_response));
//Setup Cause //Setup Cause
cs_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED; cs_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
//Setup sender F-TEID (ctrl) //Setup sender F-TEID (ctrl)
cs_resp->sender_f_teid.ipv4_present = true; cs_resp->sender_f_teid.ipv4_present = true;
cs_resp->sender_f_teid.teid = spgw_uplink_ctrl_teid; cs_resp->sender_f_teid = tunnel_ctx->up_ctrl_fteid;
cs_resp->sender_f_teid.ipv4 = 0;//FIXME This is not relevant, as the GTP-C is not transmitted over sockets yet.
//Bearer context created //Bearer context created
cs_resp->eps_bearer_context_created.ebi = default_bearer_id; cs_resp->eps_bearer_context_created.ebi = default_bearer_id;
cs_resp->eps_bearer_context_created.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED; cs_resp->eps_bearer_context_created.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present=true; cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present=true;
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.teid = spgw_uplink_user_teid; cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid = tunnel_ctx->up_user_fteid;
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4 = m_s1u_addr.sin_addr.s_addr;
//Fill in the PAA //Fill in the PAA
cs_resp->paa_present = true; cs_resp->paa_present = true;
cs_resp->paa.pdn_type = srslte::GTPC_PDN_TYPE_IPV4; cs_resp->paa.pdn_type = srslte::GTPC_PDN_TYPE_IPV4;
cs_resp->paa.ipv4_present = true; cs_resp->paa.ipv4_present = true;
cs_resp->paa.ipv4 = ue_ip; cs_resp->paa.ipv4 = tunnel_ctx->ue_ipv4;
m_spgw_log->info("Sending Create Session Response\n"); m_spgw_log->info("Sending Create Session Response\n");
m_mme_gtpc->handle_create_session_response(cs_resp_pdu); m_mme_gtpc->handle_create_session_response(cs_resp_pdu);
return; return;
@ -523,8 +586,10 @@ spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct s
m_spgw_log->info("eNB Rx User TEID 0x%x, eNB Rx User IP %s\n", tunnel_ctx->dw_user_fteid.teid, inet_ntoa(addr3)); m_spgw_log->info("eNB Rx User TEID 0x%x, eNB Rx User IP %s\n", tunnel_ctx->dw_user_fteid.teid, inet_ntoa(addr3));
//Setup IP to F-TEID map //Setup IP to F-TEID map
//bool ret = false;
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
m_ip_to_teid.insert(std::pair<uint32_t,srslte::gtpc_f_teid_ie>(tunnel_ctx->ue_ipv4, tunnel_ctx->dw_user_fteid)); 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));
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
//Setting up Modify bearer response PDU //Setting up Modify bearer response PDU
@ -559,7 +624,7 @@ spgw::handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct
//Delete data tunnel //Delete data tunnel
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
std::map<in_addr_t,srslte::gtpc_f_teid_ie>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4); std::map<in_addr_t,srslte::gtp_fteid_t>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4);
if(data_it != m_ip_to_teid.end()) if(data_it != m_ip_to_teid.end())
{ {
m_ip_to_teid.erase(data_it); m_ip_to_teid.erase(data_it);
@ -571,4 +636,31 @@ spgw::handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct
return; return;
} }
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;
std::map<uint32_t,spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
if(tunnel_it == m_teid_to_tunnel_ctx.end())
{
m_spgw_log->warning("Could not find TEID %d to release bearers from\n",ctrl_teid);
return;
}
spgw_tunnel_ctx_t *tunnel_ctx = tunnel_it->second;
in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4;
//Delete data tunnel
pthread_mutex_lock(&m_mutex);
std::map<in_addr_t,srslte::gtpc_f_teid_ie>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4);
if(data_it != m_ip_to_teid.end())
{
m_ip_to_teid.erase(data_it);
}
pthread_mutex_unlock(&m_mutex);
//Do NOT delete control tunnel
return;
}
} //namespace srsepc } //namespace srsepc

@ -376,6 +376,7 @@ bool nas::integrity_check(byte_buffer_t *pdu)
return true; return true;
} else { } else {
nas_log->error("Invalid integrity check PDU size (%d)\n", pdu->N_bytes); nas_log->error("Invalid integrity check PDU size (%d)\n", pdu->N_bytes);
return false;
} }
} }

Loading…
Cancel
Save