diff --git a/lib/include/srslte/asn1/gtpc.h b/lib/include/srslte/asn1/gtpc.h index aca57a4bf..d204cd31d 100644 --- a/lib/include/srslte/asn1/gtpc.h +++ b/lib/include/srslte/asn1/gtpc.h @@ -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 diff --git a/lib/include/srslte/asn1/gtpc_ies.h b/lib/include/srslte/asn1/gtpc_ies.h index 35b5e6498..657fc7c16 100644 --- a/lib/include/srslte/asn1/gtpc_ies.h +++ b/lib/include/srslte/asn1/gtpc_ies.h @@ -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 diff --git a/lib/include/srslte/asn1/gtpc_msg.h b/lib/include/srslte/asn1/gtpc_msg.h index 4271b064d..159be0c80 100644 --- a/lib/include/srslte/asn1/gtpc_msg.h +++ b/lib/include/srslte/asn1/gtpc_msg.h @@ -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 diff --git a/lib/include/srslte/asn1/liblte_mme.h b/lib/include/srslte/asn1/liblte_mme.h index 78e2cae69..85b8b2241 100644 --- a/lib/include/srslte/asn1/liblte_mme.h +++ b/lib/include/srslte/asn1/liblte_mme.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, diff --git a/lib/src/asn1/liblte_mme.cc b/lib/src/asn1/liblte_mme.cc index ea7729519..6d9dedcdc 100644 --- a/lib/src/asn1/liblte_mme.cc +++ b/lib/src/asn1/liblte_mme.cc @@ -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); } diff --git a/srsenb/src/enb.cc b/srsenb/src/enb.cc index e440081d0..564775e5e 100644 --- a/srsenb/src/enb.cc +++ b/srsenb/src/enb.cc @@ -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) { diff --git a/srsepc/epc.conf.example b/srsepc/epc.conf.example index b32a6984a..7fabca584 100644 --- a/srsepc/epc.conf.example +++ b/srsepc/epc.conf.example @@ -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 diff --git a/srsepc/hdr/mme/mme_gtpc.h b/srsepc/hdr/mme/mme_gtpc.h index f2804e22b..23e6acf0a 100644 --- a/srsepc/hdr/mme/mme_gtpc.h +++ b/srsepc/hdr/mme/mme_gtpc.h @@ -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 m_teid_to_mme_s1ap_id; + std::map m_mme_ctr_teid_to_imsi; + std::map m_imsi_to_gtpc_ctx; }; diff --git a/srsepc/hdr/mme/s1ap.h b/srsepc/hdr/mme/s1ap.h index 963e8d51f..31ea68436 100644 --- a/srsepc/hdr/mme/s1ap.h +++ b/srsepc/hdr/mme/s1ap.h @@ -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 m_tmsi_to_s1ap_id; + std::map m_tmsi_to_imsi; private: s1ap(); @@ -107,12 +127,20 @@ private: int m_s1mme; std::map m_active_enbs; std::map m_sctp_to_enb_id; - std::map m_active_ues; std::map > m_enb_id_to_ue_ids; + + + std::map m_imsi_to_ue_ctx; + std::map m_mme_ue_s1ap_id_to_ue_ctx; + + //std::map m_imsi_to_ue_emm_ctx; + //std::map m_mme_ue_s1ap_id_to_ue_ecm_ctx; + //std::map 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; }; diff --git a/srsepc/hdr/mme/s1ap_common.h b/srsepc/hdr/mme/s1ap_common.h index 65c16f8c9..9fea71d3f 100644 --- a/srsepc/hdr/mme/s1ap_common.h +++ b/srsepc/hdr/mme/s1ap_common.h @@ -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 diff --git a/srsepc/hdr/mme/s1ap_ctx_mngmt_proc.h b/srsepc/hdr/mme/s1ap_ctx_mngmt_proc.h index 2eaca64ab..6fc599101 100644 --- a/srsepc/hdr/mme/s1ap_ctx_mngmt_proc.h +++ b/srsepc/hdr/mme/s1ap_ctx_mngmt_proc.h @@ -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(); diff --git a/srsepc/hdr/mme/s1ap_nas_transport.h b/srsepc/hdr/mme/s1ap_nas_transport.h index e958c8dbc..9f5b1b646 100644 --- a/srsepc/hdr/mme/s1ap_nas_transport.h +++ b/srsepc/hdr/mme/s1ap_nas_transport.h @@ -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 diff --git a/srsepc/hdr/spgw/spgw.h b/srsepc/hdr/spgw/spgw.h index 095b4d9b0..e82d3f6ea 100644 --- a/srsepc/hdr/spgw/spgw.h +++ b/srsepc/hdr/spgw/spgw.h @@ -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 m_imsi_to_ctr_teid; //IMSI to control TEID map. Important to check if UE is previously connected std::map m_teid_to_tunnel_ctx; //Map control TEID to tunnel ctx. Usefull to get reply ctrl TEID, UE IP, etc. std::map 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; diff --git a/srsepc/src/hss/hss.cc b/srsepc/src/hss/hss.cc index c9a13f93a..a3bc797b4 100644 --- a/srsepc/src/hss/hss.cc +++ b/srsepc/src/hss/hss.cc @@ -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 diff --git a/srsepc/src/main.cc b/srsepc/src/main.cc index 1736279c4..539b1b245 100644 --- a/srsepc/src/main.cc +++ b/srsepc/src/main.cc @@ -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(&mcc)->default_value("001"), "Mobile Country Code") ("mme.mnc", bpo::value(&mnc)->default_value("01"), "Mobile Network Code") ("mme.mme_bind_addr", bpo::value(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection") + ("mme.dns_addr", bpo::value(&dns_addr)->default_value("8.8.8.8"),"IP address of the DNS server for the UEs") ("mme.apn", bpo::value(&mme_apn)->default_value(""), "Set Access Point Name (APN) for data services") ("hss.db_file", bpo::value(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys") ("hss.auth_algo", bpo::value(&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; diff --git a/srsepc/src/mme/mme.cc b/srsepc/src/mme/mme.cc index eb247164c..4c63b5f6a 100644 --- a/srsepc/src/mme/mme.cc +++ b/srsepc/src/mme/mme.cc @@ -29,13 +29,12 @@ #include #include #include -#include #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 diff --git a/srsepc/src/mme/mme_gtpc.cc b/srsepc/src/mme/mme_gtpc.cc index 4e5d2ad7d..e25ea05d1 100644 --- a/srsepc/src/mme/mme_gtpc.cc +++ b/srsepc/src/mme/mme_gtpc.cc @@ -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(cs_req->sender_f_teid.teid, mme_ue_s1ap_id)); + //Check whether this UE is already registed + std::map::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::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(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(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::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::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::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::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::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::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::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::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::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 diff --git a/srsepc/src/mme/s1ap.cc b/srsepc/src/mme/s1ap.cc index 80d8b6d74..3fe34806c 100644 --- a/srsepc/src/mme/s1ap.cc +++ b/srsepc/src/mme/s1ap.cc @@ -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::iterator it = m_active_enbs.begin(); - while(it!=m_active_enbs.end()) + std::map::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::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::iterator it_assoc = m_sctp_to_enb_id.find(assoc_id); - uint16_t enb_id = it_assoc->second; - - std::map::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 >::iterator ues_in_enb = m_enb_id_to_ue_ids.find(enb_id); - std::set::iterator ue_id = ues_in_enb->second.begin(); - while(ue_id != ues_in_enb->second.end() ) - { - std::map::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::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 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(enb_ptr->enb_id,enb_ptr)); + m_sctp_to_enb_id.insert(std::pair(enb_sri->sinfo_assoc_id, enb_ptr->enb_id)); + m_enb_id_to_ue_ids.insert(std::pair >(enb_ptr->enb_id,ue_set)); - //Delete UE within eNB UE set - std::map::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 >::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 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(enb_ptr->enb_id,enb_ptr)); - m_sctp_to_enb_id.insert(std::pair(enb_sri->sinfo_assoc_id, enb_ptr->enb_id)); - m_enb_id_to_ue_ids.insert(std::pair >(enb_ptr->enb_id,ue_set)); + std::map::iterator it_assoc = m_sctp_to_enb_id.find(assoc_id); + uint16_t enb_id = it_assoc->second; + std::map::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::iterator it = m_active_ues.find(mme_ue_s1ap_id); - if(it == m_active_ues.end()) + std::map::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::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(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::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::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(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::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::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(ue_ptr->mme_ue_s1ap_id,ue_ptr)); - - std::map::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 >::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 >::iterator ues_in_enb = m_enb_id_to_ue_ids.find(enb_id); + std::set::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::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::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 >::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::iterator ue_ctx_it = m_active_ues.find(mme_s1ap_id); - if(ue_ctx_it == m_active_ues.end()) + std::map::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::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(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(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 + diff --git a/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc b/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc index 7dffe3c35..2938b128c 100644 --- a/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc +++ b/srsepc/src/mme/s1ap_ctx_mngmt_proc.cc @@ -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; iE_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;istate == 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;ierabs_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;ierabs_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;ierabs_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 diff --git a/srsepc/src/mme/s1ap_mngmt_proc.cc b/srsepc/src/mme/s1ap_mngmt_proc.cc index 8fa469ec3..4d4b16528 100644 --- a/srsepc/src/mme/s1ap_mngmt_proc.cc +++ b/srsepc/src/mme/s1ap_mngmt_proc.cc @@ -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; diff --git a/srsepc/src/mme/s1ap_nas_transport.cc b/srsepc/src/mme/s1ap_nas_transport.cc index 4cd29703b..2d11384ae 100644 --- a/srsepc/src/mme/s1ap_nas_transport.cc +++ b/srsepc/src/mme/s1ap_nas_transport.cc @@ -28,11 +28,12 @@ #include "mme/s1ap.h" #include "mme/s1ap_nas_transport.h" #include "srslte/common/security.h" +#include "srslte/common/liblte_security.h" namespace srsepc{ s1ap_nas_transport* s1ap_nas_transport::m_instance = NULL; -boost::mutex s1ap_nas_transport_instance_mutex; +pthread_mutex_t s1ap_nas_transport_instance_mutex = PTHREAD_MUTEX_INITIALIZER; s1ap_nas_transport::s1ap_nas_transport() { @@ -47,21 +48,23 @@ s1ap_nas_transport::~s1ap_nas_transport() s1ap_nas_transport* s1ap_nas_transport::get_instance(void) { - boost::mutex::scoped_lock lock(s1ap_nas_transport_instance_mutex); + pthread_mutex_lock(&s1ap_nas_transport_instance_mutex); if(NULL == m_instance) { m_instance = new s1ap_nas_transport(); } + pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex); return(m_instance); } void s1ap_nas_transport::cleanup(void) { - boost::mutex::scoped_lock lock(s1ap_nas_transport_instance_mutex); + pthread_mutex_lock(&s1ap_nas_transport_instance_mutex); if(NULL != m_instance) { delete m_instance; m_instance = NULL; } + pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex); } void @@ -79,12 +82,6 @@ s1ap_nas_transport::init(hss_interface_s1ap * hss_) bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag) { - LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; - LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req; - LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT service_req; - - m_s1ap_log->console("Received Initial UE Message.\n"); - m_s1ap_log->info("Received Initial UE Message.\n"); //Get info from initial UE message uint32_t enb_ue_s1ap_id = init_ue->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID; @@ -93,40 +90,62 @@ s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSA log_unhandled_initial_ue_message_ies(init_ue); /*Check whether NAS Attach Request or Service Request*/ - uint8_t pd, msg_type; + bool mac_valid = false; + uint8_t pd, msg_type, sec_hdr_type; srslte::byte_buffer_t *nas_msg = m_pool->allocate(); memcpy(nas_msg->msg, &init_ue->NAS_PDU.buffer, init_ue->NAS_PDU.n_octets); nas_msg->N_bytes = init_ue->NAS_PDU.n_octets; + liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &pd, &msg_type); if(msg_type == LIBLTE_MME_MSG_TYPE_ATTACH_REQUEST) { - //Get NAS Attach Request and PDN connectivity request messages - LIBLTE_ERROR_ENUM err = liblte_mme_unpack_attach_request_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &attach_req); - if(err != LIBLTE_SUCCESS){ - m_s1ap_log->error("Error unpacking NAS attach request. Error: %s\n", liblte_error_text[err]); - m_pool->deallocate(nas_msg); - return false; - } - /*Get PDN Connectivity Request*/ - err = liblte_mme_unpack_pdn_connectivity_request_msg(&attach_req.esm_msg, &pdn_con_req); - if(err != LIBLTE_SUCCESS){ - m_s1ap_log->error("Error unpacking NAS PDN Connectivity Request. Error: %s\n", liblte_error_text[err]); - m_pool->deallocate(nas_msg); - return false; - } - handle_nas_attach_request(enb_ue_s1ap_id, attach_req, pdn_con_req, reply_buffer, reply_flag, enb_sri); + m_s1ap_log->info("Received Attach Request \n"); + m_s1ap_log->console("Received Attach Request \n"); + handle_nas_attach_request(enb_ue_s1ap_id, nas_msg, reply_buffer,reply_flag, enb_sri); } else if(msg_type == LIBLTE_MME_SECURITY_HDR_TYPE_SERVICE_REQUEST) { - m_s1ap_log->info("Received Service Request\n"); - m_s1ap_log->console("Received Service Request\n"); - liblte_mme_unpack_service_request_msg((LIBLTE_BYTE_MSG_STRUCT*) nas_msg, &service_req); + m_s1ap_log->info("Received Service Request \n"); + m_s1ap_log->console("Received Service Request \n"); + if(!init_ue->S_TMSI_present) + { + m_s1ap_log->error("Service request -- S-TMSI not present\n"); + m_s1ap_log->console("Service request -- S-TMSI not present\n" ); + return false; + } + uint32_t *m_tmsi = (uint32_t*) &init_ue->S_TMSI.m_TMSI.buffer; + uint32_t enb_ue_s1ap_id = init_ue->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID; + m_s1ap_log->info("Service request -- S-TMSI 0x%x\n", ntohl(*m_tmsi)); + m_s1ap_log->console("Service request -- S-TMSI 0x%x\n", ntohl(*m_tmsi) ); + m_s1ap_log->info("Service request -- eNB UE S1AP Id %d\n", enb_ue_s1ap_id); + m_s1ap_log->console("Service request -- eNB UE S1AP Id %d\n", enb_ue_s1ap_id); + handle_nas_service_request(ntohl(*m_tmsi), enb_ue_s1ap_id, nas_msg, reply_buffer,reply_flag, enb_sri); + return true; + } + else if(msg_type == LIBLTE_MME_MSG_TYPE_DETACH_REQUEST) + { + m_s1ap_log->console("Received Initial UE message -- Detach Request\n"); + m_s1ap_log->info("Received Initial UE message -- Detach Request\n"); + if(!init_ue->S_TMSI_present) + { + m_s1ap_log->error("Service request -- S-TMSI not present\n"); + m_s1ap_log->console("Service request -- S-TMSI not present\n" ); + return false; + } + uint32_t *m_tmsi = (uint32_t*) &init_ue->S_TMSI.m_TMSI.buffer; + uint32_t enb_ue_s1ap_id = init_ue->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID; + m_s1ap_log->info("Detach Request -- S-TMSI 0x%x\n", ntohl(*m_tmsi)); + m_s1ap_log->console("Detach Request -- S-TMSI 0x%x\n", ntohl(*m_tmsi) ); + m_s1ap_log->info("Detach Request -- eNB UE S1AP Id %d\n", enb_ue_s1ap_id); + m_s1ap_log->console("Detach Request -- eNB UE S1AP Id %d\n", enb_ue_s1ap_id); - m_s1ap_log->info("Service Request not implemented. Sending Service Reject.\n"); - m_s1ap_log->console("Service Request not implemented. Sending Service Reject.\n"); - /* Force UE to re-attach */ - pack_service_reject(reply_buffer, LIBLTE_MME_EMM_CAUSE_IMPLICITLY_DETACHED, enb_ue_s1ap_id); - *reply_flag = true; + handle_nas_detach_request(ntohl(*m_tmsi), enb_ue_s1ap_id, nas_msg, reply_buffer,reply_flag, enb_sri); + return true; + } + else + { + m_s1ap_log->info("Unhandled Initial UE Message 0x%x\n",msg_type); + m_s1ap_log->console("Unhandled Initial UE Message 0x%x \n", msg_type); } m_pool->deallocate(nas_msg); @@ -136,94 +155,189 @@ s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSA bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag) { - - bool ue_valid = true; + uint8_t pd, msg_type, sec_hdr_type; uint32_t enb_ue_s1ap_id = ul_xport->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID; uint32_t mme_ue_s1ap_id = ul_xport->MME_UE_S1AP_ID.MME_UE_S1AP_ID; + bool mac_valid = false; - ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx(mme_ue_s1ap_id); + //Get UE ECM context + ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id); if(ue_ctx == NULL) { - //TODO UE not registered, send error message. - m_s1ap_log->warning("Received uplink NAS, but could not find UE context. MME-UE S1AP id: %lu\n",mme_ue_s1ap_id); + m_s1ap_log->warning("Received uplink NAS, but could not find UE ECM context. MME-UE S1AP id: %lu\n",mme_ue_s1ap_id); return false; } - m_s1ap_log->debug("Received uplink NAS and found UE. MME-UE S1AP id: %lu\n",mme_ue_s1ap_id); + m_s1ap_log->debug("Received uplink NAS and found UE ECM context. MME-UE S1AP id: %lu\n",mme_ue_s1ap_id); + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; - //Get NAS message type - uint8_t pd, msg_type; + //Parse NAS message header srslte::byte_buffer_t *nas_msg = m_pool->allocate(); - memcpy(nas_msg->msg, &ul_xport->NAS_PDU.buffer, ul_xport->NAS_PDU.n_octets); nas_msg->N_bytes = ul_xport->NAS_PDU.n_octets; liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &pd, &msg_type); - switch (msg_type) { + // Parse the message security header + liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &sec_hdr_type); + + //Find UE EMM context if message is security protected. + if(sec_hdr_type != LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS) + { + //Make sure EMM context is set-up, to do integrity check/de-chiphering + if(emm_ctx->imsi == 0) + { + //No EMM context found. + //Perhaps a temporary context is being created? + //This can happen with integrity protected identity reponse messages + if( !(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY)) + { + m_s1ap_log->warning("Uplink NAS: could not find security context for integrity protected message. MME-UE S1AP id: %lu\n",mme_ue_s1ap_id); + m_pool->deallocate(nas_msg); + return false; + } + } + } + + if( sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS || + (msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) || + (msg_type == LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY)) + { + //Only identity response and authentication response are valid as plain NAS. + //Sometimes authentication response and identity are sent as integrity protected, + //but these messages are sent when the securty context is not setup yet, so we cannot integrity check it. + //FIXME Double-check + switch(msg_type) + { + case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE: + m_s1ap_log->info("Uplink NAS: Received Identity Response\n"); + m_s1ap_log->console("Uplink NAS: Received Identity Response\n"); + handle_identity_response(nas_msg, ue_ctx, reply_buffer, reply_flag); + break; case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE: m_s1ap_log->info("Uplink NAS: Received Authentication Response\n"); m_s1ap_log->console("Uplink NAS: Received Authentication Response\n"); handle_nas_authentication_response(nas_msg, ue_ctx, reply_buffer, reply_flag); break; - case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE: + default: + m_s1ap_log->warning("Unhandled Plain NAS message 0x%x\n", msg_type ); + m_s1ap_log->console("Unhandled Plain NAS message 0x%x\n", msg_type ); + m_pool->deallocate(nas_msg); + return false; + } + //Increment UL NAS count. + emm_ctx->security_ctxt.ul_nas_count++; + } + else if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT || sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT) + { + switch (msg_type) { + case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE: m_s1ap_log->info("Uplink NAS: Received Security Mode Complete\n"); m_s1ap_log->console("Uplink NAS: Received Security Mode Complete\n"); - handle_nas_security_mode_complete(nas_msg, ue_ctx, reply_buffer, reply_flag); + emm_ctx->security_ctxt.ul_nas_count = 0; + emm_ctx->security_ctxt.dl_nas_count = 0; + mac_valid = integrity_check(emm_ctx,nas_msg); + if(mac_valid){ + handle_nas_security_mode_complete(nas_msg, ue_ctx, reply_buffer, reply_flag); + } else { + m_s1ap_log->warning("Invalid MAC in Security Mode Command Complete message.\n" ); + } break; + default: + m_s1ap_log->warning("Unhandled NAS message with new EPS security context 0x%x\n", msg_type ); + m_s1ap_log->warning("Unhandled NAS message with new EPS security context 0x%x\n", msg_type ); + } + } + else if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY || sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED) + { + //Integrity protected NAS message, possibly chiphered. + emm_ctx->security_ctxt.ul_nas_count++; + mac_valid = integrity_check(emm_ctx,nas_msg); + if(!mac_valid){ + m_s1ap_log->warning("Invalid MAC in NAS message type 0x%x.\n", msg_type); + m_pool->deallocate(nas_msg); + return false; + } + switch (msg_type) { case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE: - m_s1ap_log->info("Uplink NAS: Received Attach Complete\n"); - m_s1ap_log->console("Uplink NAS: Received Attach Complete\n"); + m_s1ap_log->info("Integrity Protected UL NAS: Received Attach Complete\n"); + m_s1ap_log->console("Integrity Protected UL NAS: Received Attach Complete\n"); handle_nas_attach_complete(nas_msg, ue_ctx, reply_buffer, reply_flag); - ue_ctx->security_ctxt.ul_nas_count++; break; case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE: - m_s1ap_log->info("Uplink NAS: Received ESM Information Response\n"); - m_s1ap_log->console("Uplink NAS: Received ESM Information Response\n"); + m_s1ap_log->info("Integrity Protected UL NAS: Received ESM Information Response\n"); + m_s1ap_log->console("Integrity Protected UL NAS: Received ESM Information Response\n"); handle_esm_information_response(nas_msg, ue_ctx, reply_buffer, reply_flag); - ue_ctx->security_ctxt.ul_nas_count++; - break; - case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE: - m_s1ap_log->info("Uplink NAS: Received Identity Response\n"); - m_s1ap_log->console("Uplink NAS: Received Identity Response\n"); - handle_identity_response(nas_msg, ue_ctx, reply_buffer, reply_flag); - //ue_ctx->security_ctxt.ul_nas_count++; break; case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST: - m_s1ap_log->info("Uplink NAS: Tracking Area Update Request\n"); + m_s1ap_log->info("Integrity Protected UL NAS: Tracking Area Update Request\n"); + m_s1ap_log->console("Integrity Protected UL NAS: Tracking Area Update Request\n"); handle_tracking_area_update_request(nas_msg, ue_ctx, reply_buffer, reply_flag); break; case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE: - m_s1ap_log->info("Uplink NAS: Authentication Failure\n"); + m_s1ap_log->info("Integrity Protected UL NAS: Authentication Failure\n"); + m_s1ap_log->console("Integrity Protected UL NAS: Authentication Failure\n"); handle_authentication_failure(nas_msg, ue_ctx, reply_buffer, reply_flag); - ue_ctx->security_ctxt.ul_nas_count++; + break; + case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST: + m_s1ap_log->info("Integrity Protected UL NAS: Detach Request\n"); + m_s1ap_log->console("Integrity Protected UL NAS: Detach Request\n"); + handle_nas_detach_request(nas_msg, ue_ctx, reply_buffer, reply_flag); break; default: - m_s1ap_log->warning("Unhandled NAS message 0x%x\n", msg_type ); - m_s1ap_log->console("Unhandled NAS message 0x%x\n", msg_type ); - return false; //FIXME (nas_msg deallocate needs to be called) + m_s1ap_log->warning("Unhandled NAS integrity protected message 0x%x\n", msg_type ); + m_s1ap_log->console("Unhandled NAS integrity protected message 0x%x\n", msg_type ); + m_pool->deallocate(nas_msg); + return false; + } } + else + { + m_s1ap_log->error("Unhandled security header type in Uplink NAS Transport: %d\n", sec_hdr_type); + m_pool->deallocate(nas_msg); + return false; + } + if(*reply_flag == true) { - m_s1ap_log->info("DL NAS: Sent Downlink NAS message\n"); - m_s1ap_log->console("DL NAS: Sent Downlink NAS Message\n"); + m_s1ap_log->console("DL NAS: Sent Downlink NAS Message. DL NAS Count=%d, UL NAS count=%d\n",emm_ctx->security_ctxt.dl_nas_count,emm_ctx->security_ctxt.ul_nas_count ); + m_s1ap_log->info("DL NAS: Sent Downlink NAS message. DL NAS Count=%d, UL NAS count=%d\n",emm_ctx->security_ctxt.dl_nas_count, emm_ctx->security_ctxt.ul_nas_count); + m_s1ap_log->info("DL NAS: MME UE S1AP id %d\n",ecm_ctx->mme_ue_s1ap_id); + m_s1ap_log->console("DL NAS: MME UE S1AP id %d\n",ecm_ctx->mme_ue_s1ap_id); } m_pool->deallocate(nas_msg); - return true; } bool s1ap_nas_transport::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) { + LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT attach_req; + LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT pdn_con_req; + + //Get NAS Attach Request and PDN connectivity request messages + LIBLTE_ERROR_ENUM err = liblte_mme_unpack_attach_request_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &attach_req); + if(err != LIBLTE_SUCCESS){ + m_s1ap_log->error("Error unpacking NAS attach request. Error: %s\n", liblte_error_text[err]); + m_pool->deallocate(nas_msg); + return false; + } + /*Get PDN Connectivity Request*/ + err = liblte_mme_unpack_pdn_connectivity_request_msg(&attach_req.esm_msg, &pdn_con_req); + if(err != LIBLTE_SUCCESS){ + m_s1ap_log->error("Error unpacking NAS PDN Connectivity Request. Error: %s\n", liblte_error_text[err]); + m_pool->deallocate(nas_msg); + return false; + } + //Get attach type from attach request if(attach_req.eps_mobile_id.type_of_id == LIBLTE_MME_EPS_MOBILE_ID_TYPE_IMSI) - { + { m_s1ap_log->console("Attach Request -- IMSI-style attach request\n"); m_s1ap_log->info("Attach Request -- IMSI-style attach request\n"); handle_nas_imsi_attach_request(enb_ue_s1ap_id, attach_req, pdn_con_req, reply_buffer, reply_flag, enb_sri); @@ -232,7 +346,7 @@ s1ap_nas_transport::handle_nas_attach_request(uint32_t enb_ue_s1ap_id, { m_s1ap_log->console("Attach Request -- GUTI-style attach request\n"); m_s1ap_log->info("Attach Request -- GUTI-style attach request\n"); - handle_nas_guti_attach_request(enb_ue_s1ap_id, attach_req, pdn_con_req, reply_buffer, reply_flag, enb_sri); + handle_nas_guti_attach_request(enb_ue_s1ap_id, attach_req, pdn_con_req, nas_msg, reply_buffer, reply_flag, enb_sri); } else { @@ -256,48 +370,73 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id, uint8_t xres[8]; ue_ctx_t ue_ctx; - ue_ctx.imsi = 0; - ue_ctx.enb_ue_s1ap_id = enb_ue_s1ap_id; - ue_ctx.mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); + ue_emm_ctx_t *emm_ctx = &ue_ctx.emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx.ecm_ctx; + //Set UE's EMM context + uint64_t imsi = 0; + for(int i=0;i<=14;i++){ + imsi += attach_req.eps_mobile_id.imsi[i]*std::pow(10,14-i); + } + + //Check if UE is + ue_ctx_t *old_ctx = m_s1ap->find_ue_ctx_from_imsi(imsi); + if(old_ctx!=NULL) + { + m_s1ap_log->console("Attach Request -- UE is already attached."); + m_s1ap_log->info("Attach Request -- UE is already attached."); + //Detaching previoulsy attached UE. + m_mme_gtpc->send_delete_session_request(imsi); + if(old_ctx->ecm_ctx.mme_ue_s1ap_id!=0) + { + m_s1ap->m_s1ap_ctx_mngmt_proc->send_ue_context_release_command(&old_ctx->ecm_ctx, reply_buffer); + } + m_s1ap->delete_ue_ctx(imsi); + } + + emm_ctx->imsi = imsi; + emm_ctx->mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); + emm_ctx->state = EMM_STATE_DEREGISTERED; //Save UE network capabilities - memcpy(&ue_ctx.ue_network_cap, &attach_req.ue_network_cap, sizeof(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT)); - ue_ctx.ms_network_cap_present = attach_req.ms_network_cap_present; + memcpy(&emm_ctx->security_ctxt.ue_network_cap, &attach_req.ue_network_cap, sizeof(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT)); + emm_ctx->security_ctxt.ms_network_cap_present = attach_req.ms_network_cap_present; if(attach_req.ms_network_cap_present) { - memcpy(&ue_ctx.ms_network_cap, &attach_req.ms_network_cap, sizeof(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT)); + memcpy(&emm_ctx->security_ctxt.ms_network_cap, &attach_req.ms_network_cap, sizeof(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT)); } uint8_t eps_bearer_id = pdn_con_req.eps_bearer_id; //TODO: Unused - ue_ctx.procedure_transaction_id = pdn_con_req.proc_transaction_id; + emm_ctx->procedure_transaction_id = pdn_con_req.proc_transaction_id; - //Save whether ESM information transfer is necessary - ue_ctx.eit = pdn_con_req.esm_info_transfer_flag_present; - //m_s1ap_log->console("EPS Bearer id: %d\n", eps_bearer_id); //Initialize NAS count - ue_ctx.security_ctxt.ul_nas_count = 0; - ue_ctx.security_ctxt.dl_nas_count = 0; - //Add eNB info to UE ctxt - memcpy(&ue_ctx.enb_sri, enb_sri, sizeof(struct sctp_sndrcvinfo)); + emm_ctx->security_ctxt.ul_nas_count = 0; + emm_ctx->security_ctxt.dl_nas_count = 0; + + //Set UE ECM context + ecm_ctx->imsi = emm_ctx->imsi; + ecm_ctx->mme_ue_s1ap_id = emm_ctx->mme_ue_s1ap_id; + + //Set eNB information + ecm_ctx->enb_ue_s1ap_id = enb_ue_s1ap_id; + memcpy(&ecm_ctx->enb_sri, enb_sri, sizeof(struct sctp_sndrcvinfo)); + + //Save whether secure ESM information transfer is necessary + ecm_ctx->eit = pdn_con_req.esm_info_transfer_flag_present; + //Initialize E-RABs for(uint i = 0 ; i< MAX_ERABS_PER_UE; i++) { - ue_ctx.erabs_ctx[i].state = ERAB_DEACTIVATED; - ue_ctx.erabs_ctx[i].erab_id = i; + ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED; + ecm_ctx->erabs_ctx[i].erab_id = i; } - //IMSI style attach - ue_ctx.imsi = 0; - for(int i=0;i<=14;i++){ - ue_ctx.imsi += attach_req.eps_mobile_id.imsi[i]*std::pow(10,14-i); - } - - m_s1ap_log->console("Attach request -- IMSI: %015lu\n", ue_ctx.imsi); - m_s1ap_log->info("Attach request -- IMSI: %015lu\n", ue_ctx.imsi); - + //Log Attach Request information + m_s1ap_log->console("Attach request -- IMSI: %015lu\n", emm_ctx->imsi); + m_s1ap_log->info("Attach request -- IMSI: %015lu\n", emm_ctx->imsi); + m_s1ap_log->console("Attach request -- eNB-UE S1AP Id: %d, MME-UE S1AP Id: %d\n", ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); + m_s1ap_log->info("Attach request -- eNB-UE S1AP Id: %d, MME-UE S1AP Id: %d\n", ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); m_s1ap_log->console("Attach request -- Attach type: %d\n", attach_req.eps_attach_type); m_s1ap_log->info("Attach request -- Attach type: %d\n", attach_req.eps_attach_type); - m_s1ap_log->console("Attach request -- eNB-UE S1AP Id: %d, MME-UE S1AP Id: %d\n", ue_ctx.enb_ue_s1ap_id, ue_ctx.mme_ue_s1ap_id); m_s1ap_log->console("Attach Request -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n", attach_req.ue_network_cap.eea[0], attach_req.ue_network_cap.eea[1], @@ -322,20 +461,25 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id, m_s1ap_log->console("PDN Connectivity Request -- ESM Information Transfer requested: %s\n", pdn_con_req.esm_info_transfer_flag_present ? "true" : "false"); //Save attach request type - ue_ctx.attach_type = attach_req.eps_attach_type; + emm_ctx->attach_type = attach_req.eps_attach_type; //Get Authentication Vectors from HSS - if(!m_hss->gen_auth_info_answer(ue_ctx.imsi, ue_ctx.security_ctxt.k_asme, autn, rand, ue_ctx.security_ctxt.xres)) + if(!m_hss->gen_auth_info_answer(emm_ctx->imsi, emm_ctx->security_ctxt.k_asme, autn, rand, emm_ctx->security_ctxt.xres)) { - m_s1ap_log->console("User not found. IMSI %015lu\n",ue_ctx.imsi); - m_s1ap_log->info("User not found. IMSI %015lu\n",ue_ctx.imsi); + m_s1ap_log->console("User not found. IMSI %015lu\n",emm_ctx->imsi); + m_s1ap_log->info("User not found. IMSI %015lu\n",emm_ctx->imsi); return false; } - m_s1ap->add_new_ue_ctx(ue_ctx); + //Save the UE context + ue_ctx_t *new_ctx = new ue_ctx_t; + memcpy(new_ctx,&ue_ctx,sizeof(ue_ctx_t)); + m_s1ap->add_ue_ctx_to_imsi_map(new_ctx); + m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(new_ctx); + //Pack NAS Authentication Request in Downlink NAS Transport msg - pack_authentication_request(reply_buffer, ue_ctx.enb_ue_s1ap_id, ue_ctx.mme_ue_s1ap_id, autn, rand); - + pack_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand); + //Send reply to eNB *reply_flag = true; m_s1ap_log->info("Downlink NAS: Sending Authentication Request\n"); @@ -344,105 +488,440 @@ s1ap_nas_transport::handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id, } bool -s1ap_nas_transport::handle_nas_guti_attach_request(uint32_t enb_ue_s1ap_id, +s1ap_nas_transport::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) { + //Parse the message security header + uint8 pd = 0; + uint8 sec_hdr_type = 0; + liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &sec_hdr_type); + + bool integrity_valid = false; + if(sec_hdr_type != LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) + { + m_s1ap_log->info("Attach request -- GUTI-stlye attach request is not integrity protected\n"); + m_s1ap_log->console("Attach request -- GUTI-stlye attach request is not integrity protected\n"); + } + else{ + m_s1ap_log->info("Attach request -- GUTI-stlye attach request is integrity protected\n"); + m_s1ap_log->console("Attach request -- GUTI-stlye attach request is integrity protected\n"); + } + + //GUTI style attach uint32_t m_tmsi = attach_req.eps_mobile_id.guti.m_tmsi; - std::map::iterator it = m_s1ap->m_tmsi_to_s1ap_id.find(m_tmsi); - if(it == m_s1ap->m_tmsi_to_s1ap_id.end()) + std::map::iterator it = m_s1ap->m_tmsi_to_imsi.find(m_tmsi); + if(it == m_s1ap->m_tmsi_to_imsi.end()) { + + m_s1ap_log->console("Attach Request -- Could not find M-TMSI 0x%x\n", m_tmsi); + m_s1ap_log->info("Attach Request -- Could not find M-TMSI 0x%x\n", m_tmsi); + //Could not find IMSI from M-TMSI, send Id request ue_ctx_t ue_ctx; - ue_ctx.imsi = 0; - ue_ctx.enb_ue_s1ap_id = enb_ue_s1ap_id; - ue_ctx.mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); + ue_emm_ctx_t *emm_ctx = &ue_ctx.emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx.ecm_ctx; + + //We do not know the IMSI of the UE yet + //The IMSI will be set when the identity response is received + //Set EMM ctx + emm_ctx->imsi = 0; + emm_ctx->state = EMM_STATE_DEREGISTERED; + emm_ctx->mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); //Save UE network capabilities - memcpy(&ue_ctx.ue_network_cap, &attach_req.ue_network_cap, sizeof(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT)); - ue_ctx.ms_network_cap_present = attach_req.ms_network_cap_present; + memcpy(&emm_ctx->security_ctxt.ue_network_cap, &attach_req.ue_network_cap, sizeof(LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT)); + emm_ctx->security_ctxt.ms_network_cap_present = attach_req.ms_network_cap_present; if(attach_req.ms_network_cap_present) { - memcpy(&ue_ctx.ms_network_cap, &attach_req.ms_network_cap, sizeof(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT)); + memcpy(&emm_ctx->security_ctxt.ms_network_cap, &attach_req.ms_network_cap, sizeof(LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT)); } + //Initialize NAS count + emm_ctx->security_ctxt.ul_nas_count = 0; + emm_ctx->security_ctxt.dl_nas_count = 0; + emm_ctx->procedure_transaction_id = pdn_con_req.proc_transaction_id; + + //Set ECM context + ecm_ctx->imsi = 0; + ecm_ctx->enb_ue_s1ap_id = enb_ue_s1ap_id; + ecm_ctx->mme_ue_s1ap_id = emm_ctx->mme_ue_s1ap_id; + uint8_t eps_bearer_id = pdn_con_req.eps_bearer_id; //TODO: Unused - ue_ctx.procedure_transaction_id = pdn_con_req.proc_transaction_id; //Save attach request type - ue_ctx.attach_type = attach_req.eps_attach_type; + emm_ctx->attach_type = attach_req.eps_attach_type; //Save whether ESM information transfer is necessary - ue_ctx.eit = pdn_con_req.esm_info_transfer_flag_present; + ecm_ctx->eit = pdn_con_req.esm_info_transfer_flag_present; //m_s1ap_log->console("EPS Bearer id: %d\n", eps_bearer_id); - //Initialize NAS count - ue_ctx.security_ctxt.ul_nas_count = 0; - ue_ctx.security_ctxt.dl_nas_count = 0; //Add eNB info to UE ctxt - memcpy(&ue_ctx.enb_sri, enb_sri, sizeof(struct sctp_sndrcvinfo)); + memcpy(&ecm_ctx->enb_sri, enb_sri, sizeof(struct sctp_sndrcvinfo)); //Initialize E-RABs for(uint i = 0 ; i< MAX_ERABS_PER_UE; i++) { - ue_ctx.erabs_ctx[i].state = ERAB_DEACTIVATED; - ue_ctx.erabs_ctx[i].erab_id = i; + ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED; + ecm_ctx->erabs_ctx[i].erab_id = i; } - m_s1ap_log->console("Attach request -- IMSI: %015lu\n", ue_ctx.imsi); - m_s1ap_log->info("Attach request -- IMSI: %015lu\n", ue_ctx.imsi); - m_s1ap_log->console("Attach request -- eNB-UE S1AP Id: %d, MME-UE S1AP Id: %d\n", ue_ctx.enb_ue_s1ap_id, ue_ctx.mme_ue_s1ap_id); + m_s1ap_log->console("Attach request -- IMSI: %015lu\n", ecm_ctx->imsi); + m_s1ap_log->info("Attach request -- IMSI: %015lu\n", ecm_ctx->imsi); + m_s1ap_log->console("Attach request -- eNB-UE S1AP Id: %d, MME-UE S1AP Id: %d\n", ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); m_s1ap_log->console("Attach Request -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n", - attach_req.ue_network_cap.eea[0], - attach_req.ue_network_cap.eea[1], - attach_req.ue_network_cap.eea[2], - attach_req.ue_network_cap.eea[3], - attach_req.ue_network_cap.eea[4], - attach_req.ue_network_cap.eea[5], - attach_req.ue_network_cap.eea[6], - attach_req.ue_network_cap.eea[7]); + attach_req.ue_network_cap.eea[0], attach_req.ue_network_cap.eea[1], attach_req.ue_network_cap.eea[2], attach_req.ue_network_cap.eea[3], + attach_req.ue_network_cap.eea[4], attach_req.ue_network_cap.eea[5], attach_req.ue_network_cap.eea[6], attach_req.ue_network_cap.eea[7]); m_s1ap_log->console("Attach Request -- UE Network Capabilities EIA: %d%d%d%d%d%d%d%d\n", - attach_req.ue_network_cap.eia[0], - attach_req.ue_network_cap.eia[1], - attach_req.ue_network_cap.eia[2], - attach_req.ue_network_cap.eia[3], - attach_req.ue_network_cap.eia[4], - attach_req.ue_network_cap.eia[5], - attach_req.ue_network_cap.eia[6], - attach_req.ue_network_cap.eia[7]); + attach_req.ue_network_cap.eia[0], attach_req.ue_network_cap.eia[1], attach_req.ue_network_cap.eia[2], attach_req.ue_network_cap.eia[3], + attach_req.ue_network_cap.eia[4], attach_req.ue_network_cap.eia[5], attach_req.ue_network_cap.eia[6], attach_req.ue_network_cap.eia[7]); m_s1ap_log->console("Attach Request -- MS Network Capabilities Present: %s\n", attach_req.ms_network_cap_present ? "true" : "false"); m_s1ap_log->console("PDN Connectivity Request -- EPS Bearer Identity requested: %d\n", pdn_con_req.eps_bearer_id); m_s1ap_log->console("PDN Connectivity Request -- Procedure Transaction Id: %d\n", pdn_con_req.proc_transaction_id); m_s1ap_log->console("PDN Connectivity Request -- ESM Information Transfer requested: %s\n", pdn_con_req.esm_info_transfer_flag_present ? "true" : "false"); m_s1ap_log->console("Could not find M-TMSI=0x%x. Sending ID request\n",m_tmsi); - m_s1ap_log->info("Could not find M-TMSI=0x%d. Sending Id Request\n", m_tmsi); - m_s1ap->add_new_ue_ctx(ue_ctx); - pack_identity_request(reply_buffer, ue_ctx.enb_ue_s1ap_id, ue_ctx.mme_ue_s1ap_id); + m_s1ap_log->info("Could not find M-TMSI=0x%x. Sending Id Request\n", m_tmsi); + //m_s1ap->add_new_ue_ecm_ctx(ue_ecm_ctx); + + //Store temporary ue context + ue_ctx_t *new_ctx = new ue_ctx_t; + memcpy(new_ctx,&ue_ctx,sizeof(ue_ctx_t)); + m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(new_ctx); + + pack_identity_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); *reply_flag = true; return true; } else{ + m_s1ap_log->console("Attach Request -- Found M-TMSI: %d\n",m_tmsi); - ue_ctx_t *ue_ctx_ptr = m_s1ap->find_ue_ctx(it->second); - if(ue_ctx_ptr!=NULL) + m_s1ap_log->console("Attach Request -- IMSI: %015lu\n",it->second); + //Get UE EMM context + ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx_from_imsi(it->second); + if(ue_ctx!=NULL) { - //Save attach request type - ue_ctx_ptr->attach_type = attach_req.eps_attach_type; - m_s1ap_log->console("Found UE context. IMSI: %015lu\n",ue_ctx_ptr->imsi); - m_mme_gtpc->send_create_session_request(ue_ctx_ptr->imsi, ue_ctx_ptr->mme_ue_s1ap_id); - *reply_flag = false; //No reply needed - return true; + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; + m_s1ap_log->console("Found UE context. IMSI: %015lu, old eNB UE S1ap Id %d, old MME UE S1AP Id %d\n",emm_ctx->imsi, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); + //Check NAS integrity + bool msg_valid = false; + emm_ctx->security_ctxt.ul_nas_count++; + msg_valid = integrity_check(emm_ctx,nas_msg); + if(msg_valid == true && emm_ctx->state == EMM_STATE_DEREGISTERED) + { + m_s1ap_log->console("GUTI Attach Integrity valid. UL count %d, DL count %d\n",emm_ctx->security_ctxt.ul_nas_count, emm_ctx->security_ctxt.dl_nas_count); + + //Create new MME UE S1AP Identity + emm_ctx->mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); + ecm_ctx->mme_ue_s1ap_id = emm_ctx->mme_ue_s1ap_id; + ecm_ctx->enb_ue_s1ap_id = enb_ue_s1ap_id; + ecm_ctx->imsi = ecm_ctx->imsi; + + emm_ctx->procedure_transaction_id = pdn_con_req.proc_transaction_id; + //Save Attach type + emm_ctx->attach_type = attach_req.eps_attach_type; + + //Set eNB information + ecm_ctx->enb_ue_s1ap_id = enb_ue_s1ap_id; + memcpy(&ecm_ctx->enb_sri, enb_sri, sizeof(struct sctp_sndrcvinfo)); + //Save whether secure ESM information transfer is necessary + ecm_ctx->eit = pdn_con_req.esm_info_transfer_flag_present; + + //Initialize E-RABs + for(uint i = 0 ; i< MAX_ERABS_PER_UE; i++) + { + ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED; + ecm_ctx->erabs_ctx[i].erab_id = i; + } + + //Store context based on MME UE S1AP id + m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx); + + //Re-generate K_eNB + liblte_security_generate_k_enb(emm_ctx->security_ctxt.k_asme, emm_ctx->security_ctxt.ul_nas_count, emm_ctx->security_ctxt.k_enb); + m_s1ap_log->info("Generating KeNB with UL NAS COUNT: %d\n",emm_ctx->security_ctxt.ul_nas_count); + m_s1ap_log->console("Generating KeNB with UL NAS COUNT: %d\n",emm_ctx->security_ctxt.ul_nas_count); + + m_s1ap_log->console("Attach request -- IMSI: %015lu\n", ecm_ctx->imsi); + m_s1ap_log->info("Attach request -- IMSI: %015lu\n", ecm_ctx->imsi); + m_s1ap_log->console("Attach request -- eNB-UE S1AP Id: %d, MME-UE S1AP Id: %d\n", ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); + m_s1ap_log->console("Attach Request -- UE Network Capabilities EEA: %d%d%d%d%d%d%d%d\n", + attach_req.ue_network_cap.eea[0], attach_req.ue_network_cap.eea[1], attach_req.ue_network_cap.eea[2], attach_req.ue_network_cap.eea[3], + attach_req.ue_network_cap.eea[4], attach_req.ue_network_cap.eea[5], attach_req.ue_network_cap.eea[6], attach_req.ue_network_cap.eea[7]); + m_s1ap_log->console("Attach Request -- UE Network Capabilities EIA: %d%d%d%d%d%d%d%d\n", + attach_req.ue_network_cap.eia[0], attach_req.ue_network_cap.eia[1], attach_req.ue_network_cap.eia[2], attach_req.ue_network_cap.eia[3], + attach_req.ue_network_cap.eia[4], attach_req.ue_network_cap.eia[5], attach_req.ue_network_cap.eia[6], attach_req.ue_network_cap.eia[7]); + m_s1ap_log->console("Attach Request -- MS Network Capabilities Present: %s\n", attach_req.ms_network_cap_present ? "true" : "false"); + m_s1ap_log->console("PDN Connectivity Request -- EPS Bearer Identity requested: %d\n", pdn_con_req.eps_bearer_id); + m_s1ap_log->console("PDN Connectivity Request -- Procedure Transaction Id: %d\n", pdn_con_req.proc_transaction_id); + m_s1ap_log->console("PDN Connectivity Request -- ESM Information Transfer requested: %s\n", pdn_con_req.esm_info_transfer_flag_present ? "true" : "false"); + + //Create session request + m_s1ap_log->console("GUTI Attach -- NAS Integrity OK.\n"); + if(ecm_ctx->eit) + { + m_s1ap_log->console("Secure ESM information transfer requested.\n"); + m_s1ap_log->info("Secure ESM information transfer requested.\n"); + pack_esm_information_request(reply_buffer, emm_ctx, ecm_ctx); + *reply_flag = true; + } + else + { + m_mme_gtpc->send_create_session_request(emm_ctx->imsi); + *reply_flag = false; //No reply needed + } + return true; + } + else + { + if(emm_ctx->state != EMM_STATE_DEREGISTERED) + { + m_s1ap_log->error("Received GUTI-Attach Request from attached user.\n"); + m_s1ap_log->console("Received GUTI-Attach Request from attached user.\n"); + + //Delete previous Ctx, restart authentication + //Detaching previoulsy attached UE. + m_mme_gtpc->send_delete_session_request(emm_ctx->imsi); + if(ecm_ctx->mme_ue_s1ap_id!=0) + { + m_s1ap->m_s1ap_ctx_mngmt_proc->send_ue_context_release_command(ecm_ctx, reply_buffer); + } + } + emm_ctx->security_ctxt.ul_nas_count = 0; + emm_ctx->security_ctxt.dl_nas_count = 0; + + //Create new MME UE S1AP Identity + uint32_t new_mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); + + //Make sure context from previous NAS connections is not present + if(ecm_ctx->mme_ue_s1ap_id!=0) + { + m_s1ap->release_ue_ecm_ctx(ecm_ctx->mme_ue_s1ap_id); + } + emm_ctx->mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); + ecm_ctx->mme_ue_s1ap_id = emm_ctx->mme_ue_s1ap_id; + //Set EMM as de-registered + emm_ctx->state = EMM_STATE_DEREGISTERED; + //Save Attach type + emm_ctx->attach_type = attach_req.eps_attach_type; + + //Set UE ECM context + ecm_ctx->imsi = ecm_ctx->imsi; + ecm_ctx->mme_ue_s1ap_id = ecm_ctx->mme_ue_s1ap_id; + + //Set eNB information + ecm_ctx->enb_ue_s1ap_id = enb_ue_s1ap_id; + memcpy(&ecm_ctx->enb_sri, enb_sri, sizeof(struct sctp_sndrcvinfo)); + //Save whether secure ESM information transfer is necessary + ecm_ctx->eit = pdn_con_req.esm_info_transfer_flag_present; + + //Initialize E-RABs + for(uint i = 0 ; i< MAX_ERABS_PER_UE; i++) + { + ecm_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED; + ecm_ctx->erabs_ctx[i].erab_id = i; + } + //Store context based on MME UE S1AP id + m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx); + + //NAS integrity failed. Re-start authentication process. + m_s1ap_log->console("GUTI Attach request NAS integrity failed.\n"); + m_s1ap_log->console("RE-starting authentication procedure.\n"); + uint8_t autn[16]; + uint8_t rand[16]; + //Get Authentication Vectors from HSS + if(!m_hss->gen_auth_info_answer(emm_ctx->imsi, emm_ctx->security_ctxt.k_asme, autn, rand, emm_ctx->security_ctxt.xres)) + { + m_s1ap_log->console("User not found. IMSI %015lu\n",emm_ctx->imsi); + m_s1ap_log->info("User not found. IMSI %015lu\n",emm_ctx->imsi); + return false; + } + pack_authentication_request(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand); + + //Send reply to eNB + *reply_flag = true; + m_s1ap_log->info("Downlink NAS: Sent Authentication Request\n"); + m_s1ap_log->console("Downlink NAS: Sent Authentication Request\n"); + return true; + } } else { m_s1ap_log->error("Found M-TMSI but could not find UE context\n"); + m_s1ap_log->console("Error: Found M-TMSI but could not find UE context\n"); return false; } } return true; } +bool +s1ap_nas_transport::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 mac_valid = false; + LIBLTE_MME_SERVICE_REQUEST_MSG_STRUCT service_req; + + LIBLTE_ERROR_ENUM err = liblte_mme_unpack_service_request_msg((LIBLTE_BYTE_MSG_STRUCT*) nas_msg, &service_req); + if(err !=LIBLTE_SUCCESS) + { + m_s1ap_log->error("Could not unpack service request\n"); + return false; + } + + std::map::iterator it = m_s1ap->m_tmsi_to_imsi.find(m_tmsi); + if(it == m_s1ap->m_tmsi_to_imsi.end()) + { + m_s1ap_log->console("Could not find IMSI from M-TMSI. M-TMSI 0x%x\n", m_tmsi); + m_s1ap_log->error("Could not find IMSI from M-TMSI. M-TMSI 0x%x\n", m_tmsi); + pack_service_reject(reply_buffer, LIBLTE_MME_EMM_CAUSE_IMPLICITLY_DETACHED, enb_ue_s1ap_id); + *reply_flag = true; + return true; + } + + ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx_from_imsi(it->second); + if(ue_ctx == NULL || ue_ctx->emm_ctx.state != EMM_STATE_REGISTERED) + { + m_s1ap_log->console("UE is not EMM-Registered.\n"); + m_s1ap_log->error("UE is not EMM-Registered.\n"); + pack_service_reject(reply_buffer, LIBLTE_MME_EMM_CAUSE_IMPLICITLY_DETACHED, enb_ue_s1ap_id); + *reply_flag = true; + return true; + } + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; + + emm_ctx->security_ctxt.ul_nas_count++; + mac_valid = short_integrity_check(emm_ctx,nas_msg); + if(mac_valid) + { + m_s1ap_log->console("Service Request -- Short MAC valid\n"); + m_s1ap_log->info("Service Request -- Short MAC valid\n"); + if(ecm_ctx->state == ECM_STATE_CONNECTED) + { + m_s1ap_log->error("Service Request -- User is ECM CONNECTED\n"); + + //Release previous context + m_s1ap_log->info("Service Request -- Releasing previouse ECM context. eNB S1AP Id %d, MME UE S1AP Id %d\n", ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); + m_s1ap->m_s1ap_ctx_mngmt_proc->send_ue_context_release_command(ecm_ctx,reply_buffer); + m_s1ap->release_ue_ecm_ctx(ecm_ctx->mme_ue_s1ap_id); + } + + ecm_ctx->enb_ue_s1ap_id = enb_ue_s1ap_id; + + //UE not connect. Connect normally. + m_s1ap_log->console("Service Request -- User is ECM DISCONNECTED\n"); + m_s1ap_log->info("Service Request -- User is ECM DISCONNECTED\n"); + //Create ECM context + ecm_ctx->imsi = emm_ctx->imsi; + ecm_ctx->mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); + emm_ctx->mme_ue_s1ap_id = ecm_ctx->mme_ue_s1ap_id; + //Set eNB information + ecm_ctx->enb_ue_s1ap_id = enb_ue_s1ap_id; + memcpy(&ecm_ctx->enb_sri, enb_sri, sizeof(struct sctp_sndrcvinfo)); + + //Save whether secure ESM information transfer is necessary + ecm_ctx->eit = false; + + //Get UE IP, and uplink F-TEID + if(emm_ctx->ue_ip.s_addr == 0 ) + { + m_s1ap_log->error("UE has no valid IP assigned upon reception of service request"); + } + + m_s1ap_log->console("UE previously assigned IP: %s",inet_ntoa(emm_ctx->ue_ip)); + + //Re-generate K_eNB + liblte_security_generate_k_enb(emm_ctx->security_ctxt.k_asme, emm_ctx->security_ctxt.ul_nas_count, emm_ctx->security_ctxt.k_enb); + m_s1ap_log->info("Generating KeNB with UL NAS COUNT: %d\n",emm_ctx->security_ctxt.ul_nas_count); + m_s1ap_log->console("UE Ctr TEID %d\n", emm_ctx->sgw_ctrl_fteid.teid); + + //Save UE ctx to MME UE S1AP id + m_s1ap->add_ue_ctx_to_mme_ue_s1ap_id_map(ue_ctx); + m_s1ap->m_s1ap_ctx_mngmt_proc->send_initial_context_setup_request(emm_ctx, ecm_ctx,&ecm_ctx->erabs_ctx[5]); + } + else + { + m_s1ap_log->console("Service Request -- Short MAC invalid. Ignoring service request\n"); + m_s1ap_log->console("Service Request -- Short MAC invalid. Ignoring service request\n"); + } + return true; +} + +bool +s1ap_nas_transport::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 mac_valid = false; + LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT detach_req; + + LIBLTE_ERROR_ENUM err = liblte_mme_unpack_detach_request_msg((LIBLTE_BYTE_MSG_STRUCT*) nas_msg, &detach_req); + if(err !=LIBLTE_SUCCESS) + { + m_s1ap_log->error("Could not unpack detach request\n"); + return false; + } + + std::map::iterator it = m_s1ap->m_tmsi_to_imsi.find(m_tmsi); + if(it == m_s1ap->m_tmsi_to_imsi.end()) + { + m_s1ap_log->console("Could not find IMSI from M-TMSI. M-TMSI 0x%x\n", m_tmsi); + m_s1ap_log->error("Could not find IMSI from M-TMSI. M-TMSI 0x%x\n", m_tmsi); + return true; + } + ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx_from_imsi(it->second); + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; + + m_mme_gtpc->send_delete_session_request(emm_ctx->imsi); + emm_ctx->state = EMM_STATE_DEREGISTERED; + emm_ctx->security_ctxt.ul_nas_count++; + + m_s1ap_log->console("Received. M-TMSI 0x%x\n", m_tmsi); + //Received detach request as an initial UE message + //eNB created new ECM context to send the detach request; this needs to be cleared. + ecm_ctx->mme_ue_s1ap_id = m_s1ap->get_next_mme_ue_s1ap_id(); + ecm_ctx->enb_ue_s1ap_id = enb_ue_s1ap_id; + m_s1ap->m_s1ap_ctx_mngmt_proc->send_ue_context_release_command(ecm_ctx, reply_buffer); + return true; +} + +//FIXME re-factor to reduce code duplication +bool +s1ap_nas_transport::handle_nas_detach_request(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag) +{ + + m_s1ap_log->console("Detach request -- IMSI %015lu", ue_ctx->emm_ctx.imsi); + m_s1ap_log->info("Detach request -- IMSI %015lu", ue_ctx->emm_ctx.imsi); + LIBLTE_MME_DETACH_REQUEST_MSG_STRUCT detach_req; + + LIBLTE_ERROR_ENUM err = liblte_mme_unpack_detach_request_msg((LIBLTE_BYTE_MSG_STRUCT*) nas_msg, &detach_req); + if(err !=LIBLTE_SUCCESS) + { + m_s1ap_log->error("Could not unpack detach request\n"); + return false; + } + + m_mme_gtpc->send_delete_session_request(ue_ctx->emm_ctx.imsi); + ue_ctx->emm_ctx.state = EMM_STATE_DEREGISTERED; + if(ue_ctx->ecm_ctx.mme_ue_s1ap_id!=0) + { + m_s1ap->m_s1ap_ctx_mngmt_proc->send_ue_context_release_command(&ue_ctx->ecm_ctx, reply_msg); + } + return true; +} + bool s1ap_nas_transport::handle_nas_authentication_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool* reply_flag) { @@ -450,7 +929,9 @@ s1ap_nas_transport::handle_nas_authentication_response(srslte::byte_buffer_t *na LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT auth_resp; bool ue_valid=true; - m_s1ap_log->console("Authentication Response -- IMSI %015lu\n", ue_ctx->imsi); + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; + m_s1ap_log->console("Authentication Response -- IMSI %015lu\n", emm_ctx->imsi); //Get NAS authentication response LIBLTE_ERROR_ENUM err = liblte_mme_unpack_authentication_response_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &auth_resp); @@ -467,25 +948,19 @@ s1ap_nas_transport::handle_nas_authentication_response(srslte::byte_buffer_t *na for(int i=0; i<8;i++) { - if(auth_resp.res[i] != ue_ctx->security_ctxt.xres[i]) + if(auth_resp.res[i] != emm_ctx->security_ctxt.xres[i]) { ue_valid = false; } } if(!ue_valid) { - std::cout<security_ctxt.xres[i]; - } - std::cout<info_hex(emm_ctx->security_ctxt.xres,8, "XRES"); m_s1ap_log->console("UE Authentication Rejected.\n"); m_s1ap_log->warning("UE Authentication Rejected.\n"); - //Send back Authentication Reject - pack_authentication_reject(reply_buffer, ue_ctx->enb_ue_s1ap_id, ue_ctx->mme_ue_s1ap_id); + + //Send back Athentication Reject + pack_authentication_reject(reply_buffer, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id); *reply_flag = true; m_s1ap_log->console("Downlink NAS: Sending Authentication Reject.\n"); return false; @@ -495,7 +970,7 @@ s1ap_nas_transport::handle_nas_authentication_response(srslte::byte_buffer_t *na m_s1ap_log->console("UE Authentication Accepted.\n"); m_s1ap_log->info("UE Authentication Accepted.\n"); //Send Security Mode Command - pack_security_mode_command(reply_buffer, ue_ctx); + pack_security_mode_command(reply_buffer, emm_ctx, ecm_ctx); *reply_flag = true; m_s1ap_log->console("Downlink NAS: Sending NAS Security Mode Command.\n"); } @@ -505,6 +980,10 @@ s1ap_nas_transport::handle_nas_authentication_response(srslte::byte_buffer_t *na bool s1ap_nas_transport::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) { + + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; + LIBLTE_MME_SECURITY_MODE_COMPLETE_MSG_STRUCT sm_comp; //Get NAS authentication response @@ -514,19 +993,17 @@ s1ap_nas_transport::handle_nas_security_mode_complete(srslte::byte_buffer_t *nas return false; } - //TODO Check integrity - //TODO Handle imeisv if(sm_comp.imeisv_present) { m_s1ap_log->warning("IMEI-SV present but not handled"); } - m_s1ap_log->info("Security Mode Command Complete -- IMSI: %lu\n", ue_ctx->imsi); - m_s1ap_log->console("Security Mode Command Complete -- IMSI: %lu\n", ue_ctx->imsi); - if(ue_ctx->eit == true) + m_s1ap_log->info("Security Mode Command Complete -- IMSI: %lu\n", emm_ctx->imsi); + m_s1ap_log->console("Security Mode Command Complete -- IMSI: %lu\n", emm_ctx->imsi); + if(ecm_ctx->eit == true) { - pack_esm_information_request(reply_buffer, ue_ctx); + pack_esm_information_request(reply_buffer, emm_ctx, ecm_ctx); m_s1ap_log->console("Sending ESM information request\n"); m_s1ap_log->info("Sending ESM information request\n"); *reply_flag = true; @@ -535,12 +1012,13 @@ s1ap_nas_transport::handle_nas_security_mode_complete(srslte::byte_buffer_t *nas { //FIXME The packging of GTP-C messages is not ready. //This means that GTP-U tunnels are created with function calls, as opposed to GTP-C. - m_mme_gtpc->send_create_session_request(ue_ctx->imsi, ue_ctx->mme_ue_s1ap_id); + m_mme_gtpc->send_create_session_request(emm_ctx->imsi); *reply_flag = false; //No reply needed } return true; } + bool s1ap_nas_transport::handle_nas_attach_complete(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag) { @@ -565,7 +1043,10 @@ s1ap_nas_transport::handle_nas_attach_complete(srslte::byte_buffer_t *nas_msg, u return false; } - m_s1ap_log->console("Unpacked Attached Complete Message\n"); + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; + + m_s1ap_log->console("Unpacked Attached Complete Message. IMSI %d\n", emm_ctx->imsi); m_s1ap_log->console("Unpacked Activate Default EPS Bearer message. EPS Bearer id %d\n",act_bearer.eps_bearer_id); //ue_ctx->erabs_ctx[act_bearer->eps_bearer_id].enb_fteid; if(act_bearer.eps_bearer_id < 5 || act_bearer.eps_bearer_id > 15) @@ -573,7 +1054,17 @@ s1ap_nas_transport::handle_nas_attach_complete(srslte::byte_buffer_t *nas_msg, u m_s1ap_log->error("EPS Bearer ID out of range\n"); return false; } - m_mme_gtpc->send_modify_bearer_request(&ue_ctx->erabs_ctx[act_bearer.eps_bearer_id]); + if(emm_ctx->state == EMM_STATE_DEREGISTERED) + { + //Attach requested from attach request + m_mme_gtpc->send_modify_bearer_request(emm_ctx->imsi, &ecm_ctx->erabs_ctx[act_bearer.eps_bearer_id]); + //Send reply to eNB + m_s1ap_log->console("Packing EMM infromationi\n"); + *reply_flag = pack_emm_information(ue_ctx, reply_msg); + m_s1ap_log->console("Sending EMM infromation, bytes %d\n",reply_msg->N_bytes); + m_s1ap_log->info("Sending EMM infromation\n"); + } + emm_ctx->state = EMM_STATE_REGISTERED; return true; } @@ -602,7 +1093,7 @@ s1ap_nas_transport::handle_esm_information_response(srslte::byte_buffer_t *nas_m //FIXME The packging of GTP-C messages is not ready. //This means that GTP-U tunnels are created with function calls, as opposed to GTP-C. - m_mme_gtpc->send_create_session_request(ue_ctx->imsi, ue_ctx->mme_ue_s1ap_id); + m_mme_gtpc->send_create_session_request(ue_ctx->emm_ctx.imsi); return true; } @@ -624,20 +1115,30 @@ s1ap_nas_transport::handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_ for(int i=0;i<=14;i++){ imsi += id_resp.mobile_id.imsi[i]*std::pow(10,14-i); } + + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; + m_s1ap_log->info("Id Response -- IMSI: %015lu\n", imsi); m_s1ap_log->console("Id Response -- IMSI: %015lu\n", imsi); - ue_ctx->imsi = imsi; + + //Set UE's context IMSI + emm_ctx->imsi=imsi; + ecm_ctx->imsi = imsi; //Get Authentication Vectors from HSS - if(!m_hss->gen_auth_info_answer(imsi, ue_ctx->security_ctxt.k_asme, autn, rand, ue_ctx->security_ctxt.xres)) + if(!m_hss->gen_auth_info_answer(imsi, emm_ctx->security_ctxt.k_asme, autn, rand, emm_ctx->security_ctxt.xres)) { m_s1ap_log->console("User not found. IMSI %015lu\n",imsi); m_s1ap_log->info("User not found. IMSI %015lu\n",imsi); return false; } - + + //Store UE context im IMSI map + m_s1ap->add_ue_ctx_to_imsi_map(ue_ctx); + //Pack NAS Authentication Request in Downlink NAS Transport msg - pack_authentication_request(reply_msg, ue_ctx->enb_ue_s1ap_id, ue_ctx->mme_ue_s1ap_id, autn, rand); + pack_authentication_request(reply_msg, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand); //Send reply to eNB *reply_flag = true; @@ -653,13 +1154,6 @@ bool s1ap_nas_transport::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) { - /* - LIBLTE_ERROR_ENUM err = liblte_mme_unpack_tracking_area_update_msg((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &tau_req); - if(err != LIBLTE_SUCCESS){ - m_s1ap_log->error("Error unpacking NAS authentication response. Error: %s\n", liblte_error_text[err]); - return false; - } - */ m_s1ap_log->console("Warning: Tracking Area Update Request messages not handled yet.\n"); m_s1ap_log->warning("Warning: Tracking Area Update Request messages not handled yet.\n"); //Setup initiating message @@ -676,51 +1170,127 @@ s1ap_nas_transport::handle_tracking_area_update_request(srslte::byte_buffer_t *n //Setup Dw NAS structure LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *dw_nas = &init->choice.DownlinkNASTransport; dw_nas->ext=false; - dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctx->mme_ue_s1ap_id; - dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctx->enb_ue_s1ap_id; + dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctx->ecm_ctx.mme_ue_s1ap_id; + dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctx->ecm_ctx.enb_ue_s1ap_id; dw_nas->HandoverRestrictionList_present=false; dw_nas->SubscriberProfileIDforRFP_present=false; //m_s1ap_log->console("Tracking area accept to MME-UE S1AP Id %d\n", ue_ctx->mme_ue_s1ap_id); - LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT tau_acc; - /*typedef struct{ - LIBLTE_MME_GPRS_TIMER_STRUCT t3412; - LIBLTE_MME_EPS_MOBILE_ID_STRUCT guti; - LIBLTE_MME_TRACKING_AREA_IDENTITY_LIST_STRUCT tai_list; - LIBLTE_MME_EPS_BEARER_CONTEXT_STATUS_STRUCT eps_bearer_context_status; - LIBLTE_MME_LOCATION_AREA_ID_STRUCT lai; - LIBLTE_MME_MOBILE_ID_STRUCT ms_id; - LIBLTE_MME_GPRS_TIMER_STRUCT t3402; - LIBLTE_MME_GPRS_TIMER_STRUCT t3423; - LIBLTE_MME_PLMN_LIST_STRUCT equivalent_plmns; - LIBLTE_MME_EMERGENCY_NUMBER_LIST_STRUCT emerg_num_list; - LIBLTE_MME_EPS_NETWORK_FEATURE_SUPPORT_STRUCT eps_network_feature_support; - LIBLTE_MME_GPRS_TIMER_3_STRUCT t3412_ext; - LIBLTE_MME_ADDITIONAL_UPDATE_RESULT_ENUM additional_update_result; - uint8 eps_update_result; - uint8 emm_cause; - bool t3412_present; - bool guti_present; - bool tai_list_present; - bool eps_bearer_context_status_present; - bool lai_present; - bool ms_id_present; - bool emm_cause_present; - bool t3402_present; - bool t3423_present; - bool equivalent_plmns_present; - bool emerg_num_list_present; - bool eps_network_feature_support_present; - bool additional_update_result_present; - bool t3412_ext_present; -}LIBLTE_MME_TRACKING_AREA_UPDATE_ACCEPT_MSG_STRUCT; -*/ - //Send reply to eNB - //*reply_flag = true; + + //Get decimal MCC and MNC + uint32_t mcc = 0; + mcc += 0x000F & m_s1ap->m_s1ap_args.mcc; + mcc += 10*( (0x00F0 & m_s1ap->m_s1ap_args.mcc) >> 4); + mcc += 100*( (0x0F00 & m_s1ap->m_s1ap_args.mcc) >> 8); + + uint32_t mnc = 0; + if( 0xFF00 == (m_s1ap->m_s1ap_args.mnc & 0xFF00 )) + { + //Two digit MNC + mnc += 0x000F & m_s1ap->m_s1ap_args.mnc; + mnc += 10*((0x00F0 & m_s1ap->m_s1ap_args.mnc) >> 4); + } + else + { + //Three digit MNC + mnc += 0x000F & m_s1ap->m_s1ap_args.mnc; + mnc += 10*((0x00F0 & m_s1ap->m_s1ap_args.mnc) >> 4); + mnc += 100*((0x0F00 & m_s1ap->m_s1ap_args.mnc) >> 8); + } + + //T3412 Timer + tau_acc.t3412_present = true; + tau_acc.t3412.unit = LIBLTE_MME_GPRS_TIMER_UNIT_1_MINUTE; // GPRS 1 minute unit + tau_acc.t3412.value = 30; // 30 minute periodic timer + + //GUTI + tau_acc.guti_present=true; + tau_acc.guti.type_of_id = 6; //110 -> GUTI + tau_acc.guti.guti.mcc = mcc; + tau_acc.guti.guti.mnc = mnc; + tau_acc.guti.guti.mme_group_id = m_s1ap->m_s1ap_args.mme_group; + tau_acc.guti.guti.mme_code = m_s1ap->m_s1ap_args.mme_code; + tau_acc.guti.guti.m_tmsi = 0xF000; + m_s1ap_log->debug("Allocated GUTI: MCC %d, MNC %d, MME Group Id %d, MME Code 0x%x, M-TMSI 0x%x\n", + tau_acc.guti.guti.mcc, + tau_acc.guti.guti.mnc, + tau_acc.guti.guti.mme_group_id, + tau_acc.guti.guti.mme_code, + tau_acc.guti.guti.m_tmsi); + + //Unused Options + tau_acc.t3402_present = false; + tau_acc.t3423_present = false; + tau_acc.equivalent_plmns_present = false; + tau_acc.emerg_num_list_present = false; + tau_acc.eps_network_feature_support_present = false; + tau_acc.additional_update_result_present = false; + tau_acc.t3412_ext_present = false; return true; } +bool +s1ap_nas_transport::short_integrity_check(ue_emm_ctx_t *emm_ctx, srslte::byte_buffer_t *pdu) +{ + uint8_t exp_mac[4]; + uint8_t *mac = &pdu->msg[2]; + int i; + + srslte::security_128_eia1(&emm_ctx->security_ctxt.k_nas_int[16], + emm_ctx->security_ctxt.ul_nas_count, + 0, + SECURITY_DIRECTION_UPLINK, + &pdu->msg[0], + 2, + &exp_mac[0]); + + // Check if expected mac equals the sent mac + for(i=0; i<2; i++){ + if(exp_mac[i+2] != mac[i]){ + m_s1ap_log->warning("Short integrity check failure. Local: count=%d, [%02x %02x %02x %02x], " + "Received: count=%d, [%02x %02x]\n", + emm_ctx->security_ctxt.ul_nas_count, exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], + pdu->msg[1] & 0x1F, mac[0], mac[1]); + return false; + } + } + m_s1ap_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n", + emm_ctx->security_ctxt.ul_nas_count, pdu->msg[1] & 0x1F); + return true; +} + + +bool +s1ap_nas_transport::integrity_check(ue_emm_ctx_t *emm_ctx, srslte::byte_buffer_t *pdu) +{ + uint8_t exp_mac[4]; + uint8_t *mac = &pdu->msg[1]; + int i; + + srslte::security_128_eia1(&emm_ctx->security_ctxt.k_nas_int[16], + emm_ctx->security_ctxt.ul_nas_count, + 0, + SECURITY_DIRECTION_UPLINK, + &pdu->msg[5], + pdu->N_bytes-5, + &exp_mac[0]); + + // Check if expected mac equals the sent mac + for(i=0; i<4; i++){ + if(exp_mac[i] != mac[i]){ + m_s1ap_log->warning("Integrity check failure. UL Local: count=%d, [%02x %02x %02x %02x], " + "Received: UL count=%d, [%02x %02x %02x %02x]\n", + emm_ctx->security_ctxt.ul_nas_count, exp_mac[0], exp_mac[1], exp_mac[2], exp_mac[3], + pdu->msg[5], mac[0], mac[1], mac[2], mac[3]); + return false; + } + } + m_s1ap_log->info("Integrity check ok. Local: count=%d, Received: count=%d\n", + emm_ctx->security_ctxt.ul_nas_count, pdu->msg[5]); + return true; +} + bool s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag) @@ -736,6 +1306,8 @@ s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg return false; } + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; switch(auth_fail.emm_cause){ case 20: @@ -753,22 +1325,21 @@ s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg m_s1ap_log->error("Missing fail parameter\n"); return false; } - if(!m_hss->resync_sqn(ue_ctx->imsi, auth_fail.auth_fail_param)) + if(!m_hss->resync_sqn(emm_ctx->imsi, auth_fail.auth_fail_param)) { - m_s1ap_log->console("Resynchronization failed. IMSI %015lu\n", ue_ctx->imsi); - m_s1ap_log->info("Resynchronization failed. IMSI %015lu\n", ue_ctx->imsi); + m_s1ap_log->console("Resynchronization failed. IMSI %015lu\n", emm_ctx->imsi); + m_s1ap_log->info("Resynchronization failed. IMSI %015lu\n", emm_ctx->imsi); return false; } //Get Authentication Vectors from HSS - if(!m_hss->gen_auth_info_answer(ue_ctx->imsi, ue_ctx->security_ctxt.k_asme, autn, rand, ue_ctx->security_ctxt.xres)) + if(!m_hss->gen_auth_info_answer(emm_ctx->imsi, emm_ctx->security_ctxt.k_asme, autn, rand, emm_ctx->security_ctxt.xres)) { - m_s1ap_log->console("User not found. IMSI %015lu\n", ue_ctx->imsi); - m_s1ap_log->info("User not found. IMSI %015lu\n", ue_ctx->imsi); + m_s1ap_log->console("User not found. IMSI %015lu\n", emm_ctx->imsi); + m_s1ap_log->info("User not found. IMSI %015lu\n", emm_ctx->imsi); return false; } - //Pack NAS Authentication Request in Downlink NAS Transport msg - pack_authentication_request(reply_msg, ue_ctx->enb_ue_s1ap_id, ue_ctx->mme_ue_s1ap_id, autn, rand); + pack_authentication_request(reply_msg, ecm_ctx->enb_ue_s1ap_id, ecm_ctx->mme_ue_s1ap_id, autn, rand); //Send reply to eNB *reply_flag = true; @@ -777,11 +1348,15 @@ s1ap_nas_transport::handle_authentication_failure(srslte::byte_buffer_t *nas_msg //TODO Start T3460 Timer! break; - } - return true; - + } + return true; } - + /* +bool +s1ap_nas_transport::handle_detach_request(nas_msg, ue_ctx, reply_buffer, reply_flag) +{ + return true; + }*/ /*Packing/Unpacking helper functions*/ bool s1ap_nas_transport::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) @@ -919,7 +1494,7 @@ s1ap_nas_transport::unpack_authentication_response(LIBLTE_S1AP_MESSAGE_UPLINKNAS } bool -s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg, ue_ctx_t *ue_ctx) +s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg, ue_emm_ctx_t *ue_emm_ctx, ue_ecm_ctx_t *ue_ecm_ctx) { srslte::byte_buffer_t *nas_buffer = m_pool->allocate(); @@ -937,8 +1512,8 @@ s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg, //Setup Dw NAS structure LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *dw_nas = &init->choice.DownlinkNASTransport; dw_nas->ext=false; - dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctx->mme_ue_s1ap_id; - dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctx->enb_ue_s1ap_id; + dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ecm_ctx->mme_ue_s1ap_id; + dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ecm_ctx->enb_ue_s1ap_id; dw_nas->HandoverRestrictionList_present=false; dw_nas->SubscriberProfileIDforRFP_present=false; @@ -952,14 +1527,14 @@ s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg, sm_cmd.nas_ksi.nas_ksi=0; //Replay UE security cap - memcpy(sm_cmd.ue_security_cap.eea,ue_ctx->ue_network_cap.eea,8*sizeof(bool)); - memcpy(sm_cmd.ue_security_cap.eia,ue_ctx->ue_network_cap.eia,8*sizeof(bool)); - sm_cmd.ue_security_cap.uea_present = ue_ctx->ue_network_cap.uea_present; - memcpy(sm_cmd.ue_security_cap.uea,ue_ctx->ue_network_cap.uea,8*sizeof(bool)); - sm_cmd.ue_security_cap.uia_present = ue_ctx->ue_network_cap.uia_present; - memcpy(sm_cmd.ue_security_cap.uia,ue_ctx->ue_network_cap.uia,8*sizeof(bool)); - sm_cmd.ue_security_cap.gea_present = ue_ctx->ms_network_cap_present; - memcpy(sm_cmd.ue_security_cap.gea,ue_ctx->ms_network_cap.gea,8*sizeof(bool)); + memcpy(sm_cmd.ue_security_cap.eea,ue_emm_ctx->security_ctxt.ue_network_cap.eea,8*sizeof(bool)); + memcpy(sm_cmd.ue_security_cap.eia,ue_emm_ctx->security_ctxt.ue_network_cap.eia,8*sizeof(bool)); + sm_cmd.ue_security_cap.uea_present = ue_emm_ctx->security_ctxt.ue_network_cap.uea_present; + memcpy(sm_cmd.ue_security_cap.uea,ue_emm_ctx->security_ctxt.ue_network_cap.uea,8*sizeof(bool)); + sm_cmd.ue_security_cap.uia_present = ue_emm_ctx->security_ctxt.ue_network_cap.uia_present; + memcpy(sm_cmd.ue_security_cap.uia,ue_emm_ctx->security_ctxt.ue_network_cap.uia,8*sizeof(bool)); + sm_cmd.ue_security_cap.gea_present = ue_emm_ctx->security_ctxt.ms_network_cap_present; + memcpy(sm_cmd.ue_security_cap.gea,ue_emm_ctx->security_ctxt.ms_network_cap.gea,8*sizeof(bool)); sm_cmd.imeisv_req_present=false; sm_cmd.nonce_ue_present=false; @@ -967,28 +1542,35 @@ s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg, uint8_t sec_hdr_type=3; - ue_ctx->security_ctxt.dl_nas_count = 0; - LIBLTE_ERROR_ENUM err = liblte_mme_pack_security_mode_command_msg(&sm_cmd,sec_hdr_type, ue_ctx->security_ctxt.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); + // ue_emm_ctx->security_ctxt.dl_nas_count = 0; + LIBLTE_ERROR_ENUM err = liblte_mme_pack_security_mode_command_msg(&sm_cmd,sec_hdr_type, ue_emm_ctx->security_ctxt.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); if(err != LIBLTE_SUCCESS) { m_s1ap_log->console("Error packing Authentication Request\n"); return false; } - //Generate MAC for integrity protection - //FIXME Write wrapper to support EIA1, EIA2, etc. - //TODO which is the RB ID? Standard says a constant, but which? + //Generate EPS security context uint8_t mac[4]; - - srslte::security_generate_k_nas( ue_ctx->security_ctxt.k_asme, + srslte::security_generate_k_nas( ue_emm_ctx->security_ctxt.k_asme, srslte::CIPHERING_ALGORITHM_ID_EEA0, srslte::INTEGRITY_ALGORITHM_ID_128_EIA1, - ue_ctx->security_ctxt.k_nas_enc, - ue_ctx->security_ctxt.k_nas_int + ue_emm_ctx->security_ctxt.k_nas_enc, + ue_emm_ctx->security_ctxt.k_nas_int ); - - srslte::security_128_eia1 (&ue_ctx->security_ctxt.k_nas_int[16], - ue_ctx->security_ctxt.dl_nas_count, + srslte::security_generate_k_nas( ue_emm_ctx->security_ctxt.k_asme, + srslte::CIPHERING_ALGORITHM_ID_EEA0, + srslte::INTEGRITY_ALGORITHM_ID_128_EIA1, + ue_emm_ctx->security_ctxt.k_nas_enc, + ue_emm_ctx->security_ctxt.k_nas_int + ); + uint8_t key_enb[32]; + liblte_security_generate_k_enb(ue_emm_ctx->security_ctxt.k_asme, ue_emm_ctx->security_ctxt.ul_nas_count, ue_emm_ctx->security_ctxt.k_enb); + m_s1ap_log->info("Generating KeNB with UL NAS COUNT: %d\n",ue_emm_ctx->security_ctxt.ul_nas_count); + //Generate MAC for integrity protection + //FIXME Write wrapper to support EIA1, EIA2, etc. + srslte::security_128_eia1 (&ue_emm_ctx->security_ctxt.k_nas_int[16], + ue_emm_ctx->security_ctxt.dl_nas_count, 0, SECURITY_DIRECTION_DOWNLINK, &nas_buffer->msg[5], @@ -1014,7 +1596,7 @@ s1ap_nas_transport::pack_security_mode_command(srslte::byte_buffer_t *reply_msg, } bool -s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_msg, ue_ctx_t *ue_ctx) +s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_msg, ue_emm_ctx_t *ue_emm_ctx, ue_ecm_ctx_t *ue_ecm_ctx) { srslte::byte_buffer_t *nas_buffer = m_pool->allocate(); @@ -1032,19 +1614,20 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms //Setup Dw NAS structure LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *dw_nas = &init->choice.DownlinkNASTransport; dw_nas->ext=false; - dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctx->mme_ue_s1ap_id;//FIXME Change name - dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctx->enb_ue_s1ap_id; + dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ecm_ctx->mme_ue_s1ap_id;//FIXME Change name + dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ecm_ctx->enb_ue_s1ap_id; dw_nas->HandoverRestrictionList_present=false; dw_nas->SubscriberProfileIDforRFP_present=false; LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT esm_info_req; - esm_info_req.eps_bearer_id = 0; - esm_info_req.proc_transaction_id = ue_ctx->procedure_transaction_id; + esm_info_req.eps_bearer_id=0; + esm_info_req.proc_transaction_id = ue_emm_ctx->procedure_transaction_id; + uint8_t sec_hdr_type=2; - ue_ctx->security_ctxt.dl_nas_count++; + ue_emm_ctx->security_ctxt.dl_nas_count++; - LIBLTE_ERROR_ENUM err = srslte_mme_pack_esm_information_request_msg(&esm_info_req, sec_hdr_type,ue_ctx->security_ctxt.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); + LIBLTE_ERROR_ENUM err = srslte_mme_pack_esm_information_request_msg(&esm_info_req, sec_hdr_type,ue_emm_ctx->security_ctxt.dl_nas_count,(LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); if(err != LIBLTE_SUCCESS) { m_s1ap_log->error("Error packing ESM information request\n"); @@ -1053,8 +1636,8 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms } uint8_t mac[4]; - srslte::security_128_eia1 (&ue_ctx->security_ctxt.k_nas_int[16], - ue_ctx->security_ctxt.dl_nas_count, + srslte::security_128_eia1 (&ue_emm_ctx->security_ctxt.k_nas_int[16], + ue_emm_ctx->security_ctxt.dl_nas_count, 0, SECURITY_DIRECTION_DOWNLINK, &nas_buffer->msg[5], @@ -1081,7 +1664,7 @@ s1ap_nas_transport::pack_esm_information_request(srslte::byte_buffer_t *reply_ms } bool -s1ap_nas_transport::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) { +s1ap_nas_transport::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) { LIBLTE_MME_ATTACH_ACCEPT_MSG_STRUCT attach_accept; LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT act_def_eps_bearer_context_req; //bzero(&act_def_eps_bearer_context_req,sizeof(LIBLTE_MME_ACTIVATE_DEFAULT_EPS_BEARER_CONTEXT_REQUEST_MSG_STRUCT)); @@ -1110,8 +1693,8 @@ s1ap_nas_transport::pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESE } //Attach accept - attach_accept.eps_attach_result = ue_ctx->attach_type; - //Mandatory + attach_accept.eps_attach_result = ue_emm_ctx->attach_type; + //FIXME: Set t3412 from config attach_accept.t3412.unit = LIBLTE_MME_GPRS_TIMER_UNIT_1_MINUTE; // GPRS 1 minute unit attach_accept.t3412.value = 30; // 30 minute periodic timer @@ -1128,7 +1711,7 @@ s1ap_nas_transport::pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESE attach_accept.guti.guti.mnc = mnc; attach_accept.guti.guti.mme_group_id = m_s1ap->m_s1ap_args.mme_group; attach_accept.guti.guti.mme_code = m_s1ap->m_s1ap_args.mme_code; - attach_accept.guti.guti.m_tmsi = m_s1ap->allocate_m_tmsi(ue_ctx->mme_ue_s1ap_id); + attach_accept.guti.guti.m_tmsi = m_s1ap->allocate_m_tmsi(ue_emm_ctx->imsi); m_s1ap_log->debug("Allocated GUTI: MCC %d, MNC %d, MME Group Id %d, MME Code 0x%x, M-TMSI 0x%x\n", attach_accept.guti.guti.mcc, attach_accept.guti.guti.mnc, @@ -1136,10 +1719,23 @@ s1ap_nas_transport::pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESE attach_accept.guti.guti.mme_code, attach_accept.guti.guti.m_tmsi); - //Make sure all unused options are set to false - attach_accept.lai_present=false; - attach_accept.ms_id_present=false; + //Set EMM cause to no CS available attach_accept.emm_cause_present=false; + //attach_accept.emm_cause_present=true; + //attach_accept.emm_cause=18; + + //Set up LAI for combined EPS/IMSI attach + //attach_accept.lai_present=false; + attach_accept.lai_present=true; + attach_accept.lai.mcc = mcc; + attach_accept.lai.mnc = mnc; + attach_accept.lai.lac = 001; + + attach_accept.ms_id_present=true; + attach_accept.ms_id.type_of_id = LIBLTE_MME_MOBILE_ID_TYPE_TMSI; + attach_accept.ms_id.tmsi = attach_accept.guti.guti.m_tmsi; + + //Make sure all unused options are set to false attach_accept.t3402_present=false; attach_accept.t3423_present=false; attach_accept.equivalent_plmns_present=false; @@ -1161,20 +1757,20 @@ s1ap_nas_transport::pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESE act_def_eps_bearer_context_req.eps_qos.mbr_dl = 254; //FIXME act_def_eps_bearer_context_req.eps_qos.mbr_ul_ext = 250; //FIXME act_def_eps_bearer_context_req.eps_qos.mbr_dl_ext = 250; //FIXME check + //set apn - //act_def_eps_bearer_context_req.apn act_def_eps_bearer_context_req.apn.apn = m_s1ap->m_s1ap_args.mme_apn; - act_def_eps_bearer_context_req.proc_transaction_id = ue_ctx->procedure_transaction_id; //FIXME + act_def_eps_bearer_context_req.proc_transaction_id = ue_emm_ctx->procedure_transaction_id; //FIXME //Set DNS server act_def_eps_bearer_context_req.protocol_cnfg_opts_present = true; act_def_eps_bearer_context_req.protocol_cnfg_opts.N_opts = 1; act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[0].id = 0x0d; act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[0].len = 4; - act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[0].contents[0] = 8; - act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[0].contents[1] = 8; - act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[0].contents[2] = 8; - act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[0].contents[3] = 8; + + struct sockaddr_in dns_addr; + inet_pton(AF_INET, m_s1ap->m_s1ap_args.dns_addr.c_str(), &(dns_addr.sin_addr)); + memcpy(act_def_eps_bearer_context_req.protocol_cnfg_opts.opt[0].contents,&dns_addr.sin_addr.s_addr, 4); //Make sure all unused options are set to false act_def_eps_bearer_context_req.negotiated_qos_present = false; @@ -1186,13 +1782,13 @@ s1ap_nas_transport::pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESE act_def_eps_bearer_context_req.connectivity_type_present = false; uint8_t sec_hdr_type =2; - ue_ctx->security_ctxt.dl_nas_count++; + ue_emm_ctx->security_ctxt.dl_nas_count++; liblte_mme_pack_activate_default_eps_bearer_context_request_msg(&act_def_eps_bearer_context_req, &attach_accept.esm_msg); - liblte_mme_pack_attach_accept_msg(&attach_accept, sec_hdr_type, ue_ctx->security_ctxt.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); + liblte_mme_pack_attach_accept_msg(&attach_accept, sec_hdr_type, ue_emm_ctx->security_ctxt.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); //Integrity protect NAS message uint8_t mac[4]; - srslte::security_128_eia1 (&ue_ctx->security_ctxt.k_nas_int[16], - ue_ctx->security_ctxt.dl_nas_count, + srslte::security_128_eia1 (&ue_emm_ctx->security_ctxt.k_nas_int[16], + ue_emm_ctx->security_ctxt.dl_nas_count, 0, SECURITY_DIRECTION_DOWNLINK, &nas_buffer->msg[5], @@ -1263,10 +1859,12 @@ s1ap_nas_transport::pack_identity_request(srslte::byte_buffer_t *reply_msg, uint } bool -s1ap_nas_transport::pack_emm_information(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id) +s1ap_nas_transport::pack_emm_information( ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_msg) { srslte::byte_buffer_t *nas_buffer = m_pool->allocate(); + ue_emm_ctx_t *emm_ctx = &ue_ctx->emm_ctx; + ue_ecm_ctx_t *ecm_ctx = &ue_ctx->ecm_ctx; //Setup initiating message LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; bzero(&tx_pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT)); @@ -1281,14 +1879,14 @@ s1ap_nas_transport::pack_emm_information(srslte::byte_buffer_t *reply_msg, uint3 //Setup Dw NAS structure LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *dw_nas = &init->choice.DownlinkNASTransport; dw_nas->ext=false; - dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = mme_ue_s1ap_id;//FIXME Change name - dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = enb_ue_s1ap_id; + dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ecm_ctx->mme_ue_s1ap_id;//FIXME Change name + dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ecm_ctx->enb_ue_s1ap_id; dw_nas->HandoverRestrictionList_present=false; dw_nas->SubscriberProfileIDforRFP_present=false; LIBLTE_MME_EMM_INFORMATION_MSG_STRUCT emm_info; emm_info.full_net_name_present = true; - emm_info.full_net_name.name = std::string("srsLTE"); + emm_info.full_net_name.name = std::string("Software Radio Systems LTE"); emm_info.full_net_name.add_ci = LIBLTE_MME_ADD_CI_DONT_ADD; emm_info.short_net_name_present = true; emm_info.short_net_name.name = std::string("srsLTE"); @@ -1298,25 +1896,19 @@ s1ap_nas_transport::pack_emm_information(srslte::byte_buffer_t *reply_msg, uint3 emm_info.utc_and_local_time_zone_present = false; emm_info.net_dst_present = false; - //Integrity check - ue_ctx_t * ue_ctx = m_s1ap->find_ue_ctx(mme_ue_s1ap_id); - if(ue_ctx == NULL) - { - return false; - } uint8_t sec_hdr_type =2; - ue_ctx->security_ctxt.dl_nas_count++; - LIBLTE_ERROR_ENUM err = liblte_mme_pack_emm_information_msg(&emm_info, sec_hdr_type, ue_ctx->security_ctxt.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); + emm_ctx->security_ctxt.dl_nas_count++; + LIBLTE_ERROR_ENUM err = liblte_mme_pack_emm_information_msg(&emm_info, sec_hdr_type, emm_ctx->security_ctxt.dl_nas_count, (LIBLTE_BYTE_MSG_STRUCT *) nas_buffer); if(err != LIBLTE_SUCCESS) { - m_s1ap_log->error("Error packing Identity Request\n"); - m_s1ap_log->console("Error packing Identity REquest\n"); + m_s1ap_log->error("Error packing EMM Information\n"); + m_s1ap_log->console("Error packing EMM Information\n"); return false; } uint8_t mac[4]; - srslte::security_128_eia1 (&ue_ctx->security_ctxt.k_nas_int[16], - ue_ctx->security_ctxt.dl_nas_count, + srslte::security_128_eia1 (&emm_ctx->security_ctxt.k_nas_int[16], + emm_ctx->security_ctxt.dl_nas_count, 0, SECURITY_DIRECTION_DOWNLINK, &nas_buffer->msg[5], @@ -1325,9 +1917,20 @@ s1ap_nas_transport::pack_emm_information(srslte::byte_buffer_t *reply_msg, uint3 ); memcpy(&nas_buffer->msg[1],mac,4); + //Copy NAS PDU to Downlink NAS Trasport message buffer + memcpy(dw_nas->NAS_PDU.buffer, nas_buffer->msg, nas_buffer->N_bytes); + dw_nas->NAS_PDU.n_octets = nas_buffer->N_bytes; + //Pack Downlink NAS Transport Message + err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg); + if(err != LIBLTE_SUCCESS) + { + m_s1ap_log->error("Error packing Dw NAS Transport: EMM Info\n"); + m_s1ap_log->console("Error packing Downlink NAS Transport: EMM Info\n"); + return false; + } - m_s1ap_log->info("Packed \n"); + m_s1ap_log->info("Packed UE EMM information\n"); return true; } diff --git a/srsepc/src/spgw/spgw.cc b/srsepc/src/spgw/spgw.cc index add16b2c4..191e131df 100644 --- a/srsepc/src/spgw/spgw.cc +++ b/srsepc/src/spgw/spgw.cc @@ -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::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(spgw_uplink_ctrl_teid,tunnel_ctx)); + m_imsi_to_ctr_teid.insert(std::pair(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(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(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::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4); + std::map::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::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::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