mirror of https://github.com/PentHertz/srsLTE.git
Merge pull request #170 from softwareradiosystems/epc
Better handling of service request and GUTI attach procedures
This commit is contained in:
commit
7c0ffaf768
|
@ -52,16 +52,15 @@ const uint8_t GTPC_V2 = 2;
|
|||
* n+2 | Sequence |
|
||||
* n+3 | Spare |
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct gtpc_header
|
||||
{
|
||||
uint8_t version;
|
||||
bool piggyback;
|
||||
bool teid_present;
|
||||
uint8_t type;
|
||||
uint64_t teid;
|
||||
uint64_t sequence;
|
||||
} gtpc_header_t;
|
||||
typedef struct gtpc_header
|
||||
{
|
||||
uint8_t version;
|
||||
bool piggyback;
|
||||
bool teid_present;
|
||||
uint8_t type;
|
||||
uint64_t teid;
|
||||
uint64_t sequence;
|
||||
}gtpc_header_t;
|
||||
|
||||
/****************************************************************************
|
||||
* 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.
|
||||
***************************************************************************/
|
||||
|
||||
typedef union gtpc_msg_choice
|
||||
{
|
||||
struct gtpc_create_session_request create_session_request;
|
||||
struct gtpc_create_session_response create_session_response;
|
||||
struct gtpc_modify_bearer_request modify_bearer_request;
|
||||
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_response delete_session_response;
|
||||
} gtpc_msg_choice_t;
|
||||
}gtpc_msg_choice_t;
|
||||
|
||||
/****************************************************************************
|
||||
* 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
|
||||
* all the possible GTP-C messages
|
||||
***************************************************************************/
|
||||
|
||||
typedef struct gtpc_pdu
|
||||
{
|
||||
struct gtpc_header header;
|
||||
union gtpc_msg_choice choice;
|
||||
} gtpc_pdu_t;
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
}gtpc_pdu_t;
|
||||
}//namespace
|
||||
#endif
|
||||
|
|
|
@ -400,7 +400,8 @@ enum gtpc_interface_type
|
|||
S2B_U_PGW_GTP_U_INTERFACE
|
||||
};
|
||||
|
||||
struct gtpc_f_teid_ie
|
||||
|
||||
typedef struct gtpc_f_teid_ie
|
||||
{
|
||||
bool ipv4_present;
|
||||
bool ipv6_present;
|
||||
|
@ -408,7 +409,7 @@ struct gtpc_f_teid_ie
|
|||
uint32_t teid;
|
||||
in_addr_t ipv4;
|
||||
struct in6_addr ipv6; //FIXME
|
||||
};
|
||||
} gtp_fteid_t;
|
||||
|
||||
//TODO
|
||||
//TODO IEs between 8.22 and 8.28 missing
|
||||
|
|
|
@ -410,5 +410,36 @@ struct gtpc_delete_session_response
|
|||
//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
|
||||
#endif //GTPC_V2_MSG_H
|
||||
|
|
|
@ -175,6 +175,7 @@ typedef struct{
|
|||
uint8 imsi[15];
|
||||
uint8 imei[15];
|
||||
uint8 imeisv[16];
|
||||
uint32 tmsi;
|
||||
}LIBLTE_MME_MOBILE_ID_STRUCT;
|
||||
// Functions
|
||||
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)
|
||||
{
|
||||
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
|
||||
uint8 *id;
|
||||
uint8 *id = NULL;
|
||||
uint32 id32 = 0;
|
||||
uint32 i;
|
||||
uint8 length;
|
||||
uint8 length = 0;
|
||||
bool odd = false;
|
||||
|
||||
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;
|
||||
length = 9;
|
||||
odd = false;
|
||||
}else if(LIBLTE_MME_MOBILE_ID_TYPE_TMSI == mobile_id->type_of_id){
|
||||
id32 = mobile_id->tmsi;
|
||||
length = 4;
|
||||
odd = false;
|
||||
}
|
||||
}else{
|
||||
// FIXME: Not handling these IDs
|
||||
return(err);
|
||||
|
@ -325,30 +331,48 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_mobile_id_ie(LIBLTE_MME_MOBILE_ID_STRUCT *mob
|
|||
// Length
|
||||
**ie_ptr = length;
|
||||
*ie_ptr += 1;
|
||||
|
||||
// | Identity digit 1 | odd/even | Id type |
|
||||
if(odd)
|
||||
if(LIBLTE_MME_MOBILE_ID_TYPE_TMSI != mobile_id->type_of_id)
|
||||
{
|
||||
**ie_ptr = (id[0] << 4) | (1 << 3) | mobile_id->type_of_id;
|
||||
}else{
|
||||
**ie_ptr = (id[0] << 4) | (0 << 3) | mobile_id->type_of_id;
|
||||
}
|
||||
*ie_ptr += 1;
|
||||
// | Identity digit 1 | odd/even | Id type |
|
||||
if(odd)
|
||||
{
|
||||
**ie_ptr = (id[0] << 4) | (1 << 3) | mobile_id->type_of_id;
|
||||
}else{
|
||||
**ie_ptr = (id[0] << 4) | (0 << 3) | mobile_id->type_of_id;
|
||||
}
|
||||
*ie_ptr += 1;
|
||||
|
||||
// | Identity digit p+1 | Identity digit p |
|
||||
for(i=0; i<7; i++)
|
||||
{
|
||||
(*ie_ptr)[i] = (id[i*2+2] << 4) | id[i*2+1];
|
||||
}
|
||||
*ie_ptr += 7;
|
||||
if(!odd)
|
||||
{
|
||||
**ie_ptr = 0xF0 | id[15];
|
||||
*ie_ptr += 1;
|
||||
}
|
||||
|
||||
// | Identity digit p+1 | Identity digit p |
|
||||
for(i=0; i<7; i++)
|
||||
{
|
||||
(*ie_ptr)[i] = (id[i*2+2] << 4) | id[i*2+1];
|
||||
}
|
||||
*ie_ptr += 7;
|
||||
if(!odd)
|
||||
{
|
||||
**ie_ptr = 0xF0 | id[15];
|
||||
*ie_ptr += 1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -32,26 +32,27 @@
|
|||
namespace srsenb {
|
||||
|
||||
enb* enb::instance = NULL;
|
||||
boost::mutex enb_instance_mutex;
|
||||
|
||||
pthread_mutex_t enb_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
enb* enb::get_instance(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(enb_instance_mutex);
|
||||
pthread_mutex_lock(&enb_instance_mutex);
|
||||
if(NULL == instance) {
|
||||
instance = new enb();
|
||||
instance = new enb();
|
||||
}
|
||||
pthread_mutex_unlock(&enb_instance_mutex);
|
||||
return(instance);
|
||||
}
|
||||
void enb::cleanup(void)
|
||||
{
|
||||
srslte_dft_exit();
|
||||
srslte::byte_buffer_pool::cleanup();
|
||||
boost::mutex::scoped_lock lock(enb_instance_mutex);
|
||||
pthread_mutex_lock(&enb_instance_mutex);
|
||||
if(NULL != instance) {
|
||||
delete instance;
|
||||
instance = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&enb_instance_mutex);
|
||||
}
|
||||
|
||||
enb::enb() : started(false) {
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# mnc: Mobile Network Code
|
||||
# mme_bindx_addr: IP subnet to listen for eNB S1 connnections
|
||||
# apn: Set Access Point Name (APN)
|
||||
# mme_bind_addr: IP bind addr to listen for eNB S1 connnections
|
||||
#
|
||||
#####################################################################
|
||||
[mme]
|
||||
|
@ -21,7 +22,7 @@ tac = 0x0007
|
|||
mcc = 001
|
||||
mnc = 01
|
||||
mme_bind_addr = 127.0.1.100
|
||||
apn = test123
|
||||
apn = srsapn
|
||||
|
||||
#####################################################################
|
||||
# HSS configuration
|
||||
|
|
|
@ -42,17 +42,22 @@ class mme_gtpc
|
|||
{
|
||||
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 void cleanup(void);
|
||||
|
||||
bool init(srslte::log_filter *mme_gtpc_log);
|
||||
|
||||
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 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 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:
|
||||
|
||||
|
@ -68,7 +73,8 @@ private:
|
|||
in_addr_t m_mme_gtpc_ip;
|
||||
|
||||
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();
|
||||
|
||||
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_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri);
|
||||
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);
|
||||
|
||||
|
@ -79,20 +78,41 @@ public:
|
|||
uint32_t get_next_mme_ue_s1ap_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);
|
||||
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;
|
||||
srslte::log_filter *m_s1ap_log;
|
||||
|
||||
s1ap_mngmt_proc* m_s1ap_mngmt_proc;
|
||||
s1ap_nas_transport* m_s1ap_nas_transport;
|
||||
s1ap_ctx_mngmt_proc* m_s1ap_ctx_mngmt_proc;
|
||||
s1ap_nas_transport* m_s1ap_nas_transport;
|
||||
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:
|
||||
s1ap();
|
||||
|
@ -107,12 +127,20 @@ private:
|
|||
int m_s1mme;
|
||||
std::map<uint16_t, enb_ctx_t*> m_active_enbs;
|
||||
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<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_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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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_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
|
||||
{
|
||||
ERAB_DEACTIVATED,
|
||||
|
@ -41,6 +82,7 @@ enum erab_state
|
|||
ERAB_ACTIVE
|
||||
};
|
||||
|
||||
|
||||
typedef struct{
|
||||
uint8_t mme_code;
|
||||
uint16_t mme_group;
|
||||
|
@ -49,6 +91,7 @@ typedef struct{
|
|||
uint16_t mnc; // BCD-coded with 0xF filler
|
||||
std::string mme_bind_addr;
|
||||
std::string mme_name;
|
||||
std::string dns_addr;
|
||||
std::string mme_apn;
|
||||
} s1ap_args_t;
|
||||
|
||||
|
@ -75,29 +118,48 @@ typedef struct{
|
|||
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
|
||||
uint8_t k_nas_enc[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{
|
||||
enum erab_state state;
|
||||
uint8_t erab_id;
|
||||
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;
|
||||
|
||||
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{
|
||||
uint64_t imsi;
|
||||
uint32_t enb_ue_s1ap_id;
|
||||
uint32_t mme_ue_s1ap_id;
|
||||
uint16_t enb_id;
|
||||
struct sctp_sndrcvinfo enb_sri;
|
||||
eps_security_ctx_t security_ctxt;
|
||||
ecm_state_t state;
|
||||
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;
|
||||
uint8_t procedure_transaction_id;
|
||||
uint8_t attach_type;
|
||||
} ue_ecm_ctx_t;
|
||||
|
||||
|
||||
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;
|
||||
}//namespace
|
||||
#endif
|
||||
|
|
|
@ -47,9 +47,12 @@ public:
|
|||
|
||||
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_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:
|
||||
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_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,
|
||||
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_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);
|
||||
|
@ -62,28 +62,48 @@ public:
|
|||
bool handle_nas_guti_attach_request(uint32_t enb_ue_s1ap_id,
|
||||
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_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,
|
||||
bool* reply_flag,
|
||||
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_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_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_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_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 pack_security_mode_command(srslte::byte_buffer_t *reply_msg, ue_ctx_t *ue_ctx);
|
||||
bool pack_esm_information_request(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_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_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);
|
||||
|
||||
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;
|
||||
mme_gtpc* m_mme_gtpc;
|
||||
};
|
||||
|
||||
} //namespace srsepc
|
||||
|
||||
#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_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct srslte::gtpc_pdu *mb_resp_pdu);
|
||||
void handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct srslte::gtpc_pdu *del_resp_pdu);
|
||||
void handle_release_access_bearers_request(struct srslte::gtpc_pdu *rel_req_pdu, struct srslte::gtpc_pdu *rel_resp_pdu);
|
||||
|
||||
void handle_sgi_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();
|
||||
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;
|
||||
srslte::byte_buffer_pool *m_pool;
|
||||
mme_gtpc *m_mme_gtpc;
|
||||
|
@ -112,11 +117,17 @@ private:
|
|||
sockaddr_in m_s1u_addr;
|
||||
|
||||
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<in_addr_t,srslte::gtpc_f_teid_ie> m_ip_to_teid; //Map IP to User-plane TEID for downlink traffic
|
||||
|
||||
uint32_t m_h_next_ue_ip;
|
||||
|
||||
/*Time*/
|
||||
struct timeval m_t_last_dl;
|
||||
struct timeval m_t_last_ul;
|
||||
|
||||
/*Logs*/
|
||||
srslte::log_filter *m_spgw_log;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ using namespace srslte;
|
|||
namespace srsepc{
|
||||
|
||||
hss* hss::m_instance = NULL;
|
||||
boost::mutex hss_instance_mutex;
|
||||
pthread_mutex_t hss_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
hss::hss()
|
||||
{
|
||||
|
@ -52,22 +52,24 @@ hss::~hss()
|
|||
|
||||
hss*
|
||||
hss::get_instance(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(hss_instance_mutex);
|
||||
{
|
||||
pthread_mutex_lock(&hss_instance_mutex);
|
||||
if(NULL == m_instance) {
|
||||
m_instance = new hss();
|
||||
}
|
||||
pthread_mutex_unlock(&hss_instance_mutex);
|
||||
return(m_instance);
|
||||
}
|
||||
|
||||
void
|
||||
hss::cleanup(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(hss_instance_mutex);
|
||||
pthread_mutex_lock(&hss_instance_mutex);
|
||||
if(NULL != m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&hss_instance_mutex);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -52,7 +52,6 @@ typedef struct {
|
|||
int spgw_hex_limit;
|
||||
std::string hss_level;
|
||||
int hss_hex_limit;
|
||||
|
||||
std::string all_level;
|
||||
int all_hex_limit;
|
||||
std::string filename;
|
||||
|
@ -84,6 +83,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
|
|||
string mme_apn;
|
||||
string spgw_bind_addr;
|
||||
string sgi_if_addr;
|
||||
string dns_addr;
|
||||
string hss_db_file;
|
||||
string hss_auth_algo;
|
||||
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.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code")
|
||||
("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection")
|
||||
("mme.dns_addr", bpo::value<string>(&dns_addr)->default_value("8.8.8.8"),"IP address of the DNS server for the UEs")
|
||||
("mme.apn", bpo::value<string>(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services")
|
||||
("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys")
|
||||
("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"),"HSS uthentication algorithm.")
|
||||
|
@ -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_name = mme_name;
|
||||
args->mme_args.s1ap_args.dns_addr = dns_addr;
|
||||
args->mme_args.s1ap_args.mme_apn = mme_apn;
|
||||
args->spgw_args.gtpu_bind_addr = spgw_bind_addr;
|
||||
args->spgw_args.sgi_if_addr = sgi_if_addr;
|
||||
|
|
|
@ -29,13 +29,12 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/sctp.h>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "mme/mme.h"
|
||||
|
||||
namespace srsepc{
|
||||
|
||||
mme* mme::m_instance = NULL;
|
||||
boost::mutex mme_instance_mutex;
|
||||
pthread_mutex_t mme_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
mme::mme():
|
||||
m_running(false)
|
||||
|
@ -52,21 +51,23 @@ mme::~mme()
|
|||
mme*
|
||||
mme::get_instance(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mme_instance_mutex);
|
||||
pthread_mutex_lock(&mme_instance_mutex);
|
||||
if(NULL == m_instance) {
|
||||
m_instance = new mme();
|
||||
}
|
||||
pthread_mutex_unlock(&mme_instance_mutex);
|
||||
return(m_instance);
|
||||
}
|
||||
|
||||
void
|
||||
mme::cleanup(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mme_instance_mutex);
|
||||
pthread_mutex_lock(&mme_instance_mutex);
|
||||
if(NULL != m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&mme_instance_mutex);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -33,7 +33,8 @@
|
|||
namespace srsepc{
|
||||
|
||||
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()
|
||||
{
|
||||
|
@ -46,21 +47,23 @@ mme_gtpc::~mme_gtpc()
|
|||
mme_gtpc*
|
||||
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) {
|
||||
m_instance = new mme_gtpc();
|
||||
}
|
||||
pthread_mutex_unlock(&mme_gtpc_instance_mutex);
|
||||
return(m_instance);
|
||||
}
|
||||
|
||||
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) {
|
||||
delete m_instance;
|
||||
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?
|
||||
}
|
||||
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->console("Sending Create Session Request.\n");
|
||||
|
@ -96,7 +99,6 @@ mme_gtpc::send_create_session_request(uint64_t imsi, uint32_t mme_ue_s1ap_id)
|
|||
struct srslte::gtpc_create_session_request *cs_req = &cs_req_pdu.choice.create_session_request;
|
||||
|
||||
struct srslte::gtpc_pdu cs_resp_pdu;
|
||||
|
||||
|
||||
//Initialize GTP-C message to zero
|
||||
bzero(&cs_req_pdu, sizeof(struct srslte::gtpc_pdu));
|
||||
|
@ -113,21 +115,47 @@ 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.ipv4 = m_mme_gtpc_ip;
|
||||
|
||||
m_mme_gtpc_log->info("Next 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("Next MME control TEID: %lu \n", m_next_ctrl_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 -- MME control TEID: %lu \n", cs_req->sender_f_teid.teid);
|
||||
|
||||
// APN
|
||||
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;
|
||||
// RAT Type
|
||||
//cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN;
|
||||
|
||||
//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));
|
||||
//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
|
||||
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(>pc_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);
|
||||
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -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)
|
||||
{
|
||||
m_mme_gtpc_log->warning("Could not create GTPC session. Not a create session response\n");
|
||||
//TODO Handle err
|
||||
//TODO Handle error
|
||||
return;
|
||||
}
|
||||
if (cs_resp->cause.cause_value != srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED){
|
||||
|
@ -147,41 +175,100 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
|
|||
//TODO Handle error
|
||||
return;
|
||||
}
|
||||
|
||||
//Get MME_UE_S1AP_ID 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);
|
||||
if(id_it == m_teid_to_mme_s1ap_id.end())
|
||||
|
||||
//Get IMSI from the control 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_mme_ctr_teid_to_imsi.end())
|
||||
{
|
||||
//Could not find MME UE S1AP TEID
|
||||
m_mme_gtpc_log->warning("Could not find MME UE S1AP TEID.\n");
|
||||
m_mme_gtpc_log->warning("Could not find IMSI from Ctrl TEID.\n");
|
||||
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
|
||||
srslte::gtpc_f_teid_ie sgw_ctrl_fteid;
|
||||
sgw_ctrl_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
|
||||
srslte::gtp_fteid_t sgw_ctr_fteid;
|
||||
sgw_ctr_fteid.teid = cs_resp_pdu->header.teid;
|
||||
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;
|
||||
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_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
|
||||
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");
|
||||
srslte::gtpc_pdu mb_req_pdu;
|
||||
srslte::gtpc_f_teid_ie *enb_fteid = &erab_ctx->enb_fteid;
|
||||
srslte::gtpc_f_teid_ie *sgw_ctrl_fteid = &erab_ctx->sgw_ctrl_fteid;
|
||||
srslte::gtp_fteid_t *enb_fteid = &erab_ctx->enb_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;
|
||||
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;
|
||||
|
||||
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.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;
|
||||
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) );
|
||||
|
@ -205,54 +292,93 @@ void
|
|||
mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu)
|
||||
{
|
||||
uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid;
|
||||
std::map<uint32_t,uint32_t>::iterator mme_s1ap_id_it = m_teid_to_mme_s1ap_id.find(mme_ctrl_teid);
|
||||
if(mme_s1ap_id_it == m_teid_to_mme_s1ap_id.end())
|
||||
std::map<uint32_t,uint64_t>::iterator imsi_it = m_mme_ctr_teid_to_imsi.find(mme_ctrl_teid);
|
||||
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;
|
||||
}
|
||||
|
||||
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_s1ap->activate_eps_bearer(mme_s1ap_id_it->second,ebi);
|
||||
m_s1ap->activate_eps_bearer(imsi_it->second,ebi);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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_f_teid_ie *sgw_ctrl_fteid = NULL;
|
||||
|
||||
//FIXME the UE control TEID sould be stored in the UE ctxt, not in the E-RAB ctxt
|
||||
//Maybe a mme_s1ap_id to ctrl teid map as well?
|
||||
|
||||
for(int i = 0; i<MAX_ERABS_PER_UE; i++)
|
||||
srslte::gtp_fteid_t sgw_ctr_fteid;
|
||||
srslte::gtp_fteid_t mme_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())
|
||||
{
|
||||
if(ue_ctx->erabs_ctx[i].state != ERAB_DEACTIVATED)
|
||||
{
|
||||
sgw_ctrl_fteid = &ue_ctx->erabs_ctx[i].sgw_ctrl_fteid;
|
||||
break;
|
||||
}
|
||||
m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
|
||||
return;
|
||||
}
|
||||
//FIXME: add proper error handling
|
||||
assert(sgw_ctrl_fteid != NULL);
|
||||
|
||||
sgw_ctr_fteid = it_ctx->second.sgw_ctr_fteid;
|
||||
mme_ctr_fteid = it_ctx->second.mme_ctr_fteid;
|
||||
srslte::gtpc_header *header = &del_req_pdu.header;
|
||||
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;
|
||||
|
||||
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;
|
||||
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;
|
||||
m_spgw->handle_delete_session_request(&del_req_pdu, &del_resp_pdu);
|
||||
|
||||
//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;
|
||||
}
|
||||
} //namespace srsepc
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
namespace srsepc{
|
||||
|
||||
s1ap* s1ap::m_instance = NULL;
|
||||
boost::mutex s1ap_instance_mutex;
|
||||
pthread_mutex_t s1ap_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
s1ap::s1ap():
|
||||
m_s1mme(-1),
|
||||
|
@ -51,21 +51,24 @@ s1ap::~s1ap()
|
|||
s1ap*
|
||||
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();
|
||||
}
|
||||
pthread_mutex_unlock(&s1ap_instance_mutex);
|
||||
return(m_instance);
|
||||
}
|
||||
|
||||
void
|
||||
s1ap::cleanup(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(s1ap_instance_mutex);
|
||||
pthread_mutex_lock(&s1ap_instance_mutex);
|
||||
if(NULL != m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&s1ap_instance_mutex);
|
||||
}
|
||||
|
||||
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;
|
||||
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
|
||||
m_s1ap_log = s1ap_log;
|
||||
|
||||
|
@ -83,17 +86,15 @@ s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, hss_interface_s1
|
|||
m_hss = hss_;
|
||||
|
||||
//Init message handlers
|
||||
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures
|
||||
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures
|
||||
m_s1ap_mngmt_proc->init();
|
||||
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures
|
||||
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures
|
||||
m_s1ap_nas_transport->init(m_hss);
|
||||
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures
|
||||
m_s1ap_ctx_mngmt_proc->init();
|
||||
|
||||
|
||||
//Get pointer to GTP-C class
|
||||
m_mme_gtpc = mme_gtpc::get_instance();
|
||||
|
||||
//Initialize S1-MME
|
||||
m_s1mme = enb_listen();
|
||||
|
||||
|
@ -107,16 +108,23 @@ s1ap::stop()
|
|||
if (m_s1mme != -1){
|
||||
close(m_s1mme);
|
||||
}
|
||||
std::map<uint16_t,enb_ctx_t*>::iterator it = m_active_enbs.begin();
|
||||
while(it!=m_active_enbs.end())
|
||||
std::map<uint16_t,enb_ctx_t*>::iterator enb_it = m_active_enbs.begin();
|
||||
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->console("Deleting eNB context. eNB Id: 0x%x\n", it->second->enb_id);
|
||||
delete_ues_in_enb(it->second->enb_id);
|
||||
delete it->second;
|
||||
m_active_enbs.erase(it++);
|
||||
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", enb_it->second->enb_id);
|
||||
delete enb_it->second;
|
||||
m_active_enbs.erase(enb_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
|
||||
s1ap_mngmt_proc::cleanup();
|
||||
s1ap_nas_transport::cleanup();
|
||||
|
@ -124,56 +132,19 @@ s1ap::stop()
|
|||
return;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
s1ap::delete_ues_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_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;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
s1ap::get_next_mme_ue_s1ap_id()
|
||||
{
|
||||
return m_next_mme_ue_s1ap_id++;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
s1ap::enb_listen()
|
||||
{
|
||||
|
@ -258,7 +229,7 @@ s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb
|
|||
|
||||
}
|
||||
|
||||
bool
|
||||
bool
|
||||
s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri)
|
||||
{
|
||||
bool reply_flag = false;
|
||||
|
@ -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);
|
||||
break;
|
||||
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
|
||||
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);
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
|
@ -306,46 +279,28 @@ s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
|
|||
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE:
|
||||
m_s1ap_log->info("Received Initial Context Setup Response.\n");
|
||||
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:
|
||||
m_s1ap_log->error("Unhandled successful outcome message: %s\n", liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
s1ap::delete_ue_ctx(ue_ctx_t *ue_ctx)
|
||||
//eNB Context Managment
|
||||
void
|
||||
s1ap::add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo *enb_sri)
|
||||
{
|
||||
uint32_t mme_ue_s1ap_id = ue_ctx->mme_ue_s1ap_id;
|
||||
std::map<uint32_t, ue_ctx_t*>::iterator ue_ctx_it = m_active_ues.find(mme_ue_s1ap_id);
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
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));
|
||||
|
||||
//Delete UE within eNB UE set
|
||||
std::map<int32_t,uint16_t>::iterator it = m_sctp_to_enb_id.find(ue_ctx->enb_sri.sinfo_assoc_id);
|
||||
if(it == m_sctp_to_enb_id.end() )
|
||||
{
|
||||
m_s1ap_log->error("Could not find eNB for this 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);
|
||||
|
||||
//Delete UE context
|
||||
delete ue_ctx;
|
||||
m_active_ues.erase(ue_ctx_it);
|
||||
m_s1ap_log->info("Deleted UE Context.\n");
|
||||
|
||||
return true;
|
||||
return;
|
||||
}
|
||||
|
||||
enb_ctx_t*
|
||||
|
@ -363,26 +318,105 @@ 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)
|
||||
s1ap::delete_enb_ctx(int32_t assoc_id)
|
||||
{
|
||||
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));
|
||||
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_ctx_t*
|
||||
s1ap::find_ue_ctx(uint32_t mme_ue_s1ap_id)
|
||||
|
||||
//UE Context Management
|
||||
bool
|
||||
s1ap::add_ue_ctx_to_imsi_map(ue_ctx_t *ue_ctx)
|
||||
{
|
||||
std::map<uint32_t, ue_ctx_t*>::iterator it = m_active_ues.find(mme_ue_s1ap_id);
|
||||
if(it == m_active_ues.end())
|
||||
std::map<uint64_t, ue_ctx_t*>::iterator ctx_it = m_imsi_to_ue_ctx.find(ue_ctx->emm_ctx.imsi);
|
||||
if(ctx_it != m_imsi_to_ue_ctx.end())
|
||||
{
|
||||
m_s1ap_log->error("UE Context already exists. IMSI %015lu",ue_ctx->emm_ctx.imsi);
|
||||
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)
|
||||
{
|
||||
return NULL;
|
||||
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;
|
||||
}
|
||||
|
||||
bool
|
||||
s1ap::add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx_t *ue_ctx)
|
||||
{
|
||||
if(ue_ctx->ecm_ctx.mme_ue_s1ap_id == 0)
|
||||
{
|
||||
m_s1ap_log->error("Could not add UE context to MME UE S1AP map. MME UE S1AP ID 0 is not valid.");
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
if(ctx_it != m_mme_ue_s1ap_id_to_ue_ctx.end())
|
||||
{
|
||||
m_s1ap_log->error("UE Context already exists. MME UE S1AP Id %015lu",ue_ctx->emm_ctx.imsi);
|
||||
return false;
|
||||
}
|
||||
if(ue_ctx->ecm_ctx.imsi != 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 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;
|
||||
}
|
||||
|
||||
ue_ctx_t*
|
||||
s1ap::find_ue_ctx_from_mme_ue_s1ap_id(uint32_t 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())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
|
||||
ue_ctx_t*
|
||||
s1ap::find_ue_ctx_from_imsi(uint64_t imsi)
|
||||
{
|
||||
std::map<uint64_t, ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.find(imsi);
|
||||
if(it == m_imsi_to_ue_ctx.end())
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -391,58 +425,127 @@ s1ap::find_ue_ctx(uint32_t mme_ue_s1ap_id)
|
|||
}
|
||||
|
||||
void
|
||||
s1ap::add_new_ue_ctx(const ue_ctx_t &ue_ctx)
|
||||
s1ap::release_ues_ecm_ctx_in_enb(uint16_t enb_id)
|
||||
{
|
||||
ue_ctx_t *ue_ptr = new ue_ctx_t;
|
||||
memcpy(ue_ptr,&ue_ctx,sizeof(ue_ctx));
|
||||
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())
|
||||
//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() )
|
||||
{
|
||||
m_s1ap_log->error("Could not find eNB's UEs\n");
|
||||
return;
|
||||
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;
|
||||
}
|
||||
it_ue_id->second.insert(ue_ptr->mme_ue_s1ap_id);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
s1ap::get_next_mme_ue_s1ap_id()
|
||||
bool
|
||||
s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
|
||||
{
|
||||
return m_next_mme_ue_s1ap_id++;
|
||||
ue_ctx_t *ue_ctx = find_ue_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
|
||||
if(ue_ctx == NULL)
|
||||
{
|
||||
m_s1ap_log->error("Cannot release UE ECM context, UE not found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
|
||||
return false;
|
||||
}
|
||||
ue_ecm_ctx_t* ecm_ctx = &ue_ctx->ecm_ctx;
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
bool
|
||||
s1ap::delete_ue_ctx(uint64_t imsi)
|
||||
{
|
||||
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
|
||||
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);
|
||||
if(ue_ctx_it == m_active_ues.end())
|
||||
std::map<uint64_t,ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
|
||||
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
|
||||
{
|
||||
m_s1ap_log->error("Could not find UE context\n");
|
||||
return;
|
||||
m_s1ap_log->error("Could not activate EPS bearer: Could not find UE context\n");
|
||||
return;
|
||||
}
|
||||
ue_ctx_t * ue_ctx = ue_ctx_it->second;
|
||||
if (ue_ctx->erabs_ctx[ebi].state != ERAB_CTX_SETUP)
|
||||
//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("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->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->error("Could not activate EPS bearer: ECM context seems to be missing\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ue_ctx->erabs_ctx[ebi].state = ERAB_ACTIVE;
|
||||
m_s1ap_log->info("Activated EPS Bearer\n");
|
||||
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("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("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;
|
||||
}
|
||||
|
||||
ecm_ctx->erabs_ctx[ebi].state = ERAB_ACTIVE;
|
||||
ecm_ctx->state = ECM_STATE_CONNECTED;
|
||||
m_s1ap_log->info("Activated EPS Bearer: Bearer id %d\n",ebi);
|
||||
return;
|
||||
}
|
||||
|
||||
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++;
|
||||
//m_tmsi_to_s1ap_id.insert(std::pair<uint32_t,uint32_t>(m_tmsi,mme_ue_s1ap_id));
|
||||
uint32_t m_tmsi = 0x0123;
|
||||
// uint32_t m_tmsi = m_next_m_tmsi++;
|
||||
uint32_t m_tmsi = m_next_m_tmsi;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -478,3 +581,4 @@ s1ap::print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx)
|
|||
}
|
||||
|
||||
} //namespace srsepc
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
namespace srsepc{
|
||||
|
||||
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()
|
||||
|
@ -48,21 +48,23 @@ s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc()
|
|||
s1ap_ctx_mngmt_proc*
|
||||
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) {
|
||||
m_instance = new s1ap_ctx_mngmt_proc();
|
||||
}
|
||||
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
|
||||
return(m_instance);
|
||||
}
|
||||
|
||||
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) {
|
||||
delete m_instance;
|
||||
m_instance = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -77,8 +79,11 @@ s1ap_ctx_mngmt_proc::init(void)
|
|||
}
|
||||
|
||||
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();
|
||||
|
||||
//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_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();
|
||||
|
||||
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
|
||||
in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_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->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 = ecm_ctx->enb_ue_s1ap_id;
|
||||
|
||||
//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
|
||||
|
||||
//Setup eRAB context
|
||||
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
|
||||
erab_ctxt->e_RABlevelQoSParameters.qCI.QCI = 9;
|
||||
erab_ctxt->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel.PriorityLevel = 15 ;//Lowest
|
||||
erab_ctxt->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.qCI.QCI = 9;
|
||||
erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel.PriorityLevel = 15 ;//Lowest
|
||||
erab_ctx_req->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability = LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION;
|
||||
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
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
erab_ctxt->transportLayerAddress.n_bits = 32; //IPv4
|
||||
uint32_t sgw_s1u_ip = htonl(cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4);
|
||||
//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");
|
||||
// return false;
|
||||
//}
|
||||
erab_ctx_req->transportLayerAddress.n_bits = 32; //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;
|
||||
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
|
||||
|
||||
uint32_t tmp_teid = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.teid;
|
||||
memcpy(erab_ctxt->gTP_TEID.buffer, &tmp_teid, sizeof(uint32_t));
|
||||
uint32_t sgw_s1u_teid = erab_ctx->sgw_s1u_fteid.teid;
|
||||
memcpy(erab_ctx_req->gTP_TEID.buffer, &sgw_s1u_teid, sizeof(uint32_t));
|
||||
|
||||
//Set UE security capabilities and k_enb
|
||||
bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16);
|
||||
bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16);
|
||||
for(int i = 0; i<3; i++)
|
||||
{
|
||||
if(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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -159,35 +156,30 @@ 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[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)
|
||||
{
|
||||
m_s1ap_log->error("IPv6 not supported yet\n");
|
||||
return false;
|
||||
}
|
||||
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);
|
||||
//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)
|
||||
{
|
||||
//Attach procedure initiated from an attach request
|
||||
m_s1ap_log->console("Adding attach accept to Initial Context Setup Request\n");
|
||||
m_s1ap_log->info("Adding attach accept to Initial Context Setup Request\n");
|
||||
m_s1ap_nas_transport->pack_attach_accept(emm_ctx, ecm_ctx, erab_ctx_req, &erab_ctx->pdn_addr_alloc, nas_buffer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer);
|
||||
if(err != LIBLTE_SUCCESS)
|
||||
{
|
||||
m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n");
|
||||
return false;
|
||||
}
|
||||
//Send Reply to eNB
|
||||
ssize_t n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ue_ctx->enb_sri, 0);
|
||||
|
||||
//Send Reply to eNB
|
||||
ssize_t n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ecm_ctx->enb_sri, 0);
|
||||
if(n_sent == -1)
|
||||
{
|
||||
m_s1ap_log->error("Failed to send Initial Context Setup Request\n");
|
||||
|
@ -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
|
||||
ue_ctx->erabs_ctx[erab_ctxt->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;
|
||||
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].state = ERAB_CTX_REQUESTED;
|
||||
//ecm_ctx->erabs_ctx[erab_ctx_req->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.ipv4 = sgw_ctrl_fteid.ipv4;
|
||||
|
||||
struct in_addr addr;
|
||||
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("Initial Context -- S1-U TEID 0x%x. IP %s \n", tmp_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 -- S1-U TEID 0x%x. IP %s \n", tmp_teid,inet_ntoa(addr));
|
||||
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", sgw_s1u_teid,inet_ntoa(addr));
|
||||
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 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(nas_buffer);
|
||||
|
@ -214,23 +208,25 @@ s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id,
|
|||
bool
|
||||
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;
|
||||
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)
|
||||
{
|
||||
m_s1ap_log->error("Could not find UE's context in active UE's map\n");
|
||||
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
|
||||
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;
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
//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);
|
||||
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT ue_rel_req;
|
||||
|
||||
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->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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx;
|
||||
|
||||
//Delete any context at the SPGW
|
||||
bool active = false;
|
||||
for(int i=0;i<MAX_ERABS_PER_UE;i++)
|
||||
//Delete user plane context at the SPGW (but keep GTP-C connection).
|
||||
if (ecm_ctx->state == ECM_STATE_CONNECTED)
|
||||
{
|
||||
if(ue_ctx->erabs_ctx[i].state != ERAB_DEACTIVATED)
|
||||
//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++)
|
||||
{
|
||||
active = true;
|
||||
//ue_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
|
||||
break;
|
||||
ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
|
||||
}
|
||||
}
|
||||
if(active == true)
|
||||
{
|
||||
//There are active E-RABs, send delete session request
|
||||
m_mme_gtpc->send_delete_session_request(ue_ctx);
|
||||
}
|
||||
//m_s1ap->delete_ue_ctx(ue_ctx);
|
||||
for(int i=0;i<MAX_ERABS_PER_UE;i++)
|
||||
{
|
||||
ue_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
|
||||
}
|
||||
|
||||
//Delete UE context
|
||||
m_s1ap_log->info("Deleted UE Context.\n");
|
||||
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)
|
||||
{
|
||||
m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n");
|
||||
return false;
|
||||
}
|
||||
//Send Reply to eNB
|
||||
int n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ecm_ctx->enb_sri, 0);
|
||||
if(n_sent == -1)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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 release access mearers request
|
||||
m_s1ap_log->console("There are active E-RABs, send release access mearers request");
|
||||
m_s1ap_log->info("There are active E-RABs, send release access mearers request");
|
||||
m_mme_gtpc->send_release_access_bearers_request(ecm_ctx->imsi);
|
||||
//The handle_releease_access_bearers_response function will make sure to mark E-RABS DEACTIVATED
|
||||
//It will release the UEs downstream S1-u and keep the upstream S1-U connection active.
|
||||
}
|
||||
else
|
||||
{
|
||||
//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++)
|
||||
{
|
||||
ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
|
||||
}
|
||||
}
|
||||
|
||||
//Delete UE context
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
} //namespace srsepc
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
namespace srsepc{
|
||||
|
||||
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()
|
||||
|
@ -46,21 +46,23 @@ s1ap_mngmt_proc::~s1ap_mngmt_proc()
|
|||
s1ap_mngmt_proc*
|
||||
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) {
|
||||
m_instance = new s1ap_mngmt_proc();
|
||||
}
|
||||
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
|
||||
return(m_instance);
|
||||
}
|
||||
|
||||
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) {
|
||||
delete m_instance;
|
||||
m_instance = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -102,6 +104,7 @@ s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
|
|||
{
|
||||
//eNB already registered
|
||||
//TODO replace enb_ctx
|
||||
m_s1ap_log->warning("eNB Already registered\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -218,11 +221,11 @@ s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buff
|
|||
succ->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP;
|
||||
succ->criticality = LIBLTE_S1AP_CRITICALITY_IGNORE;
|
||||
succ->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE;
|
||||
|
||||
|
||||
LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT* s1_resp=(LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT*)&succ->choice;
|
||||
|
||||
s1_resp->ext=false;
|
||||
|
||||
|
||||
//MME Name
|
||||
s1_resp->MMEname_present=true;
|
||||
s1_resp->MMEname.ext=false;
|
||||
|
@ -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];
|
||||
|
||||
serv_gummei->ext=false;
|
||||
//serv_gummei->iE_Extensions=false;
|
||||
serv_gummei->iE_Extensions_present = false;
|
||||
|
||||
uint32_t plmn=0;
|
||||
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn);
|
||||
|
@ -257,7 +260,9 @@ s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buff
|
|||
|
||||
//Relay Unsupported
|
||||
s1_resp->MMERelaySupportIndicator_present=false;
|
||||
|
||||
|
||||
s1_resp->CriticalityDiagnostics_present = false;
|
||||
|
||||
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
|
||||
|
||||
return true;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -41,7 +41,7 @@
|
|||
namespace srsepc{
|
||||
|
||||
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;
|
||||
|
||||
|
@ -63,21 +63,23 @@ spgw::~spgw()
|
|||
spgw*
|
||||
spgw::get_instance(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(spgw_instance_mutex);
|
||||
pthread_mutex_lock(&spgw_instance_mutex);
|
||||
if(NULL == m_instance) {
|
||||
m_instance = new spgw();
|
||||
}
|
||||
pthread_mutex_unlock(&spgw_instance_mutex);
|
||||
return(m_instance);
|
||||
}
|
||||
|
||||
void
|
||||
spgw::cleanup(void)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(spgw_instance_mutex);
|
||||
pthread_mutex_lock(&spgw_instance_mutex);
|
||||
if(NULL != m_instance) {
|
||||
delete m_instance;
|
||||
m_instance = NULL;
|
||||
}
|
||||
pthread_mutex_unlock(&spgw_instance_mutex);
|
||||
}
|
||||
|
||||
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.
|
||||
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->console("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 GTP-C Tunnel. IMSI: %lu\n", it->second->imsi);
|
||||
delete it->second;
|
||||
m_teid_to_tunnel_ctx.erase(it++);
|
||||
}
|
||||
|
@ -224,6 +226,9 @@ spgw::init_sgi_if(spgw_args_t *args)
|
|||
return srslte::ERROR_CANT_START;
|
||||
}
|
||||
|
||||
//Set initial time of setup
|
||||
gettimeofday(&m_t_last_dl, NULL);
|
||||
|
||||
m_sgi_up = true;
|
||||
return(srslte::ERROR_NONE);
|
||||
}
|
||||
|
@ -297,15 +302,11 @@ spgw::run_thread()
|
|||
if (FD_ISSET(m_s1u, &set))
|
||||
{
|
||||
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);
|
||||
}
|
||||
if (FD_ISSET(m_sgi_if, &set))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -328,6 +329,8 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
|
|||
bool ip_found = false;
|
||||
srslte::gtpc_f_teid_ie enb_fteid;
|
||||
|
||||
struct timeval t_now, t_delta;
|
||||
|
||||
version = msg->msg[0]>>4;
|
||||
((uint8_t*)&dest_ip)[0] = msg->msg[16];
|
||||
((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");
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -405,6 +410,10 @@ spgw::handle_s1u_pdu(srslte::byte_buffer_t *msg)
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper Functions
|
||||
*/
|
||||
uint64_t
|
||||
spgw::get_new_ctrl_teid()
|
||||
{
|
||||
|
@ -424,61 +433,115 @@ spgw::get_new_ue_ipv4()
|
|||
return ntohl(m_h_next_ue_ip);//FIXME Tmp hack
|
||||
}
|
||||
|
||||
void
|
||||
spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu)
|
||||
spgw_tunnel_ctx_t*
|
||||
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();
|
||||
//Setup uplink user TEID
|
||||
uint64_t spgw_uplink_user_teid = get_new_user_teid();
|
||||
//Allocate UE IP
|
||||
in_addr_t ue_ip = get_new_ue_ipv4();
|
||||
|
||||
//in_addr_t ue_ip = inet_addr("172.16.0.2");
|
||||
uint8_t default_bearer_id = 5;
|
||||
|
||||
m_spgw_log->console("SPGW: Allocated Ctrl TEID %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
|
||||
spgw_tunnel_ctx_t *tunnel_ctx = new spgw_tunnel_ctx_t;
|
||||
bzero(tunnel_ctx,sizeof(spgw_tunnel_ctx_t));
|
||||
|
||||
tunnel_ctx->imsi = cs_req->imsi;
|
||||
tunnel_ctx->ebi = default_bearer_id;
|
||||
tunnel_ctx->up_user_fteid.teid = spgw_uplink_user_teid;
|
||||
tunnel_ctx->up_user_fteid.ipv4 = m_s1u_addr.sin_addr.s_addr;
|
||||
tunnel_ctx->dw_ctrl_fteid.teid = cs_req->sender_f_teid.teid;
|
||||
tunnel_ctx->dw_ctrl_fteid.ipv4 = cs_req->sender_f_teid.ipv4;
|
||||
|
||||
|
||||
tunnel_ctx->up_ctrl_fteid.teid = spgw_uplink_ctrl_teid;
|
||||
tunnel_ctx->ue_ipv4 = ue_ip;
|
||||
m_teid_to_tunnel_ctx.insert(std::pair<uint32_t,spgw_tunnel_ctx_t*>(spgw_uplink_ctrl_teid,tunnel_ctx));
|
||||
m_imsi_to_ctr_teid.insert(std::pair<uint64_t,uint32_t>(cs_req->imsi,spgw_uplink_ctrl_teid));
|
||||
return tunnel_ctx;
|
||||
}
|
||||
|
||||
bool
|
||||
spgw::delete_gtp_ctx(uint32_t ctrl_teid)
|
||||
{
|
||||
spgw_tunnel_ctx_t *tunnel_ctx;
|
||||
if(!m_teid_to_tunnel_ctx.count(ctrl_teid)){
|
||||
m_spgw_log->error("Could not find GTP context to delete.\n");
|
||||
return false;
|
||||
}
|
||||
tunnel_ctx = m_teid_to_tunnel_ctx[ctrl_teid];
|
||||
|
||||
//Remove GTP-U connections, if any.
|
||||
if(m_ip_to_teid.count(tunnel_ctx->ue_ipv4))
|
||||
{
|
||||
pthread_mutex_lock(&m_mutex);
|
||||
m_ip_to_teid.erase(tunnel_ctx->ue_ipv4);
|
||||
pthread_mutex_unlock(&m_mutex);
|
||||
}
|
||||
//Remove Ctrl TEID from IMSI to control TEID map
|
||||
m_imsi_to_ctr_teid.erase(tunnel_ctx->imsi);
|
||||
|
||||
//Remove GTP context from control TEID mapping
|
||||
m_teid_to_tunnel_ctx.erase(ctrl_teid);
|
||||
delete tunnel_ctx;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu)
|
||||
{
|
||||
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
|
||||
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
|
||||
header->piggyback = false;
|
||||
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;
|
||||
|
||||
//Initialize to zero
|
||||
bzero(cs_resp,sizeof(struct srslte::gtpc_create_session_response));
|
||||
//Setup Cause
|
||||
cs_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
|
||||
//Setup sender F-TEID (ctrl)
|
||||
cs_resp->sender_f_teid.ipv4_present = true;
|
||||
cs_resp->sender_f_teid.teid = spgw_uplink_ctrl_teid;
|
||||
cs_resp->sender_f_teid.ipv4 = 0;//FIXME This is not relevant, as the GTP-C is not transmitted over sockets yet.
|
||||
cs_resp->sender_f_teid = tunnel_ctx->up_ctrl_fteid;
|
||||
|
||||
//Bearer context created
|
||||
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.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.ipv4 = m_s1u_addr.sin_addr.s_addr;
|
||||
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid = tunnel_ctx->up_user_fteid;
|
||||
//Fill in the PAA
|
||||
cs_resp->paa_present = true;
|
||||
cs_resp->paa.pdn_type = srslte::GTPC_PDN_TYPE_IPV4;
|
||||
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_mme_gtpc->handle_create_session_response(cs_resp_pdu);
|
||||
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));
|
||||
|
||||
//Setup IP to F-TEID map
|
||||
//bool ret = false;
|
||||
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);
|
||||
|
||||
//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
|
||||
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())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
Loading…
Reference in New Issue