Applied clang-format to the EPC.

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

@ -52,15 +52,14 @@ 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;
typedef struct gtpc_header {
uint8_t version;
bool piggyback;
bool teid_present;
uint8_t type;
uint64_t teid;
uint64_t sequence;
}gtpc_header_t;
} gtpc_header_t;
/****************************************************************************
* GTP-C v2 Payload
@ -68,17 +67,16 @@ typedef struct gtpc_header
*
* 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;
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;
struct gtpc_delete_session_request delete_session_request;
struct gtpc_delete_session_response delete_session_response;
} gtpc_msg_choice_t;
/****************************************************************************
* GTP-C v2 Message
@ -88,10 +86,9 @@ typedef union gtpc_msg_choice
* of one GTP-C header and one union of structures, which can hold
* all the possible GTP-C messages
***************************************************************************/
typedef struct gtpc_pdu
{
struct gtpc_header header;
typedef struct gtpc_pdu {
struct gtpc_header header;
union gtpc_msg_choice choice;
}gtpc_pdu_t;
}//namespace
} gtpc_pdu_t;
} // namespace srslte
#endif // SRSLTE_GTPC_H

@ -26,121 +26,121 @@
#include "srslte/asn1/gtpc_ies.h"
namespace srslte{
namespace srslte {
/****************************************************************
*
* GTP-C Message Types
* Ref: TS 29.274 v10.14.0 Table 6.1-1
* Ref: TS 29.274 v10.14.0 Table 6.1-1
*
****************************************************************/
const uint8_t GTPC_MSG_TYPE_RESERVED = 0;
const uint8_t GTPC_MSG_TYPE_ECHO_REQUEST = 1;
const uint8_t GTPC_MSG_TYPE_ECHO_RESPONSE = 2;
const uint8_t GTPC_MSG_TYPE_RESERVED = 0;
const uint8_t GTPC_MSG_TYPE_ECHO_REQUEST = 1;
const uint8_t GTPC_MSG_TYPE_ECHO_RESPONSE = 2;
const uint8_t GTPC_MSG_TYPE_VERSION_SUPPORT = 3;
//4-24 Reserved for S101
//25-31 Reserved for Sv interface
//SGSN/MME/ePDG to PGW (S4/S11, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_CREATE_SESSION_REQUEST = 32;
// 4-24 Reserved for S101
// 25-31 Reserved for Sv interface
// SGSN/MME/ePDG to PGW (S4/S11, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_CREATE_SESSION_REQUEST = 32;
const uint8_t GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE = 33;
const uint8_t GTPC_MSG_TYPE_DELETE_SESSION_REQUEST = 36;
const uint8_t GTPC_MSG_TYPE_DELETE_SESSION_REQUEST = 36;
const uint8_t GTPC_MSG_TYPE_DELETE_SESSION_RESPONSE = 37;
//SGSN/MME to PGW (S4/S11, S5/S8)
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST = 34;
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE = 35;
const uint8_t GTPC_MSG_TYPE_CHANGE_NOTIFICATION_REQUEST = 38;
// SGSN/MME to PGW (S4/S11, S5/S8)
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST = 34;
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE = 35;
const uint8_t GTPC_MSG_TYPE_CHANGE_NOTIFICATION_REQUEST = 38;
const uint8_t GTPC_MSG_TYPE_CHANGE_NOTIFICATION_RESPONSE = 39;
//40 - 63 for future use
// 40 - 63 for future use
const uint8_t GTPC_MSG_TYPE_RESUME_NOTIFICATION = 164;
const uint8_t GTPC_MSG_TYPE_RESUME_ACKNOWLEDGE = 165;
//Messages without explicit response
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_COMMAND = 64; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_FAILURE_INDICATION = 65; //(PGW to MME/SGSN/ePDG S5/S8, S11/S4, S2b)
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_COMMAND = 66; //(MME/SGSN to PGW S11/S4, S5/S8)
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_FAILURE_INDICATION = 67; //(PGW to MME/SGSN S5/S8, S11/S4))
const uint8_t GTPC_MSG_TYPE_BEARER_RESOURCE_COMMAND = 68; //(MME/SGSN to PGW S11/S4, S5/S8)
const uint8_t GTPC_MSG_TYPE_BEARER_RESOURCE_FAILURE_INDICATION = 69; //(PGW to MME/SGSN S5/S8, S11/S4)
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION_FAILURE_INDICATION = 70; //(SGSN/MME to SGW S4/S11)
const uint8_t GTPC_MSG_TYPE_TRACE_SESSION_ACTIVATION = 71; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_TRACE_SESSION_DEACTIVATION = 72; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_STOP_PAGING_INDICATION = 73; //(SGW to MME/SGSN S11/S4)
//74-94 For future use
//P-GW to SGSN/MME/ePDG
const uint8_t GTPC_MSG_TYPE_CREATE_BEARER_REQUEST = 95;
const uint8_t GTPC_MSG_TYPE_RESUME_ACKNOWLEDGE = 165;
// Messages without explicit response
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_COMMAND = 64; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_FAILURE_INDICATION = 65; //(PGW to MME/SGSN/ePDG S5/S8, S11/S4, S2b)
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_COMMAND = 66; //(MME/SGSN to PGW S11/S4, S5/S8)
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_FAILURE_INDICATION = 67; //(PGW to MME/SGSN S5/S8, S11/S4))
const uint8_t GTPC_MSG_TYPE_BEARER_RESOURCE_COMMAND = 68; //(MME/SGSN to PGW S11/S4, S5/S8)
const uint8_t GTPC_MSG_TYPE_BEARER_RESOURCE_FAILURE_INDICATION = 69; //(PGW to MME/SGSN S5/S8, S11/S4)
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION_FAILURE_INDICATION = 70; //(SGSN/MME to SGW S4/S11)
const uint8_t GTPC_MSG_TYPE_TRACE_SESSION_ACTIVATION = 71; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_TRACE_SESSION_DEACTIVATION = 72; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_STOP_PAGING_INDICATION = 73; //(SGW to MME/SGSN S11/S4)
// 74-94 For future use
// P-GW to SGSN/MME/ePDG
const uint8_t GTPC_MSG_TYPE_CREATE_BEARER_REQUEST = 95;
const uint8_t GTPC_MSG_TYPE_CREATE_BEARER_RESPONSE = 96;
const uint8_t GTPC_MSG_TYPE_UPDATE_BEARER_REQUEST = 97;
const uint8_t GTPC_MSG_TYPE_UPDATE_BEARER_REQUEST = 97;
const uint8_t GTPC_MSG_TYPE_UPDATE_BEARER_RESPONSE = 98;
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_REQUEST = 99;
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_REQUEST = 99;
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_RESPONSE = 100;
//PGW to MME, MME to PGW, SGW to PGW, SGW to MME, PGW to ePDG, ePDG to PGW (S5/S8, S11, S2b)
const uint8_t GTPC_MSG_TYPE_DELETE_PDN_CONNECTION_SET_REQUEST = 101;
// PGW to MME, MME to PGW, SGW to PGW, SGW to MME, PGW to ePDG, ePDG to PGW (S5/S8, S11, S2b)
const uint8_t GTPC_MSG_TYPE_DELETE_PDN_CONNECTION_SET_REQUEST = 101;
const uint8_t GTPC_MSG_TYPE_DELETE_PDN_CONNECTION_SET_RESPONSE = 102;
//103-127 For future use
//MME to MME, SGSN to MME, MME to SGSN, SGSN to SGSN (S3/S10/S16)
const uint8_t GTPC_MSG_TYPE_IDENTIFICATION_REQUEST = 128;
const uint8_t GTPC_MSG_TYPE_IDENTIFICATION_RESPONSE = 129;
const uint8_t GTPC_MSG_TYPE_CONTEXT_REQUEST = 130;
const uint8_t GTPC_MSG_TYPE_CONTEXT_RESPONSE = 131;
const uint8_t GTPC_MSG_TYPE_CONTEXT_ACKNOWLEDGE = 132;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_REQUEST = 133;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_RESPONSE = 134;
// 103-127 For future use
// MME to MME, SGSN to MME, MME to SGSN, SGSN to SGSN (S3/S10/S16)
const uint8_t GTPC_MSG_TYPE_IDENTIFICATION_REQUEST = 128;
const uint8_t GTPC_MSG_TYPE_IDENTIFICATION_RESPONSE = 129;
const uint8_t GTPC_MSG_TYPE_CONTEXT_REQUEST = 130;
const uint8_t GTPC_MSG_TYPE_CONTEXT_RESPONSE = 131;
const uint8_t GTPC_MSG_TYPE_CONTEXT_ACKNOWLEDGE = 132;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_REQUEST = 133;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_RESPONSE = 134;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_COMPLETE_NOTIFICATION = 135;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_COMPLETE_ACKNOWLEDGE = 136;
const uint8_t GTPC_MSG_TYPE_FORWARD_ACCESS_CONTEXT_NOTIFICATION = 137;
const uint8_t GTPC_MSG_TYPE_FORWARD_ACCESS_CONTEXT_ACKNOWLEDGE = 138;
const uint8_t GTPC_MSG_TYPE_RELOCATION_CANCEL_REQUEST = 139;
const uint8_t GTPC_MSG_TYPE_RELOCATION_CANCEL_RESPONSE = 140;
const uint8_t GTPC_MSG_TYPE_CONFIGURATION_TRANSFER_TUNNEL = 141;
//142 - 148 For future use
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_COMPLETE_ACKNOWLEDGE = 136;
const uint8_t GTPC_MSG_TYPE_FORWARD_ACCESS_CONTEXT_NOTIFICATION = 137;
const uint8_t GTPC_MSG_TYPE_FORWARD_ACCESS_CONTEXT_ACKNOWLEDGE = 138;
const uint8_t GTPC_MSG_TYPE_RELOCATION_CANCEL_REQUEST = 139;
const uint8_t GTPC_MSG_TYPE_RELOCATION_CANCEL_RESPONSE = 140;
const uint8_t GTPC_MSG_TYPE_CONFIGURATION_TRANSFER_TUNNEL = 141;
// 142 - 148 For future use
const uint8_t GTPC_MSG_TYPE_RAN_INFORMATION_RELAY = 152;
//SGSN to MME, MME to SGSN (S3)
const uint8_t GTPC_MSG_TYPE_DETACH_NOTIFICATION = 149;
const uint8_t GTPC_MSG_TYPE_DETACH_ACKNOWLEDGE = 150;
const uint8_t GTPC_MSG_TYPE_CS_PAGING_INDICATION = 151;
const uint8_t GTPC_MSG_TYPE_ALERT_MME_NOTIFICATION = 153;
const uint8_t GTPC_MSG_TYPE_ALERT_MME_ACKNOWLEDGE = 154;
// SGSN to MME, MME to SGSN (S3)
const uint8_t GTPC_MSG_TYPE_DETACH_NOTIFICATION = 149;
const uint8_t GTPC_MSG_TYPE_DETACH_ACKNOWLEDGE = 150;
const uint8_t GTPC_MSG_TYPE_CS_PAGING_INDICATION = 151;
const uint8_t GTPC_MSG_TYPE_ALERT_MME_NOTIFICATION = 153;
const uint8_t GTPC_MSG_TYPE_ALERT_MME_ACKNOWLEDGE = 154;
const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_NOTIFICATION = 155;
const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_ACKNOWLEDGE = 156;
//157 - 159 For future use
//GSN/MME to SGW, SGSN to MME (S4/S11/S3) SGSN to SGSN (S16), SGW to PGW (S5/S8)
const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_ACKNOWLEDGE = 156;
// 157 - 159 For future use
// GSN/MME to SGW, SGSN to MME (S4/S11/S3) SGSN to SGSN (S16), SGW to PGW (S5/S8)
const uint8_t GTPC_MSG_TYPE_SUSPEND_NOTIFICATION = 162;
const uint8_t GTPC_MSG_TYPE_SUSPEND_ACKNOWLEDGE = 163;
//SGSN/MME to SGW (S4/S11) const uint8_t GTPC_IE_TYPE_
const uint8_t GTPC_MSG_TYPE_CREATE_FORWARDING_TUNNEL_REQUEST = 160;
const uint8_t GTPC_MSG_TYPE_CREATE_FORWARDING_TUNNEL_RESPONSE = 161;
const uint8_t GTPC_MSG_TYPE_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST = 166;
const uint8_t GTPC_MSG_TYPE_SUSPEND_ACKNOWLEDGE = 163;
// SGSN/MME to SGW (S4/S11) const uint8_t GTPC_IE_TYPE_
const uint8_t GTPC_MSG_TYPE_CREATE_FORWARDING_TUNNEL_REQUEST = 160;
const uint8_t GTPC_MSG_TYPE_CREATE_FORWARDING_TUNNEL_RESPONSE = 161;
const uint8_t GTPC_MSG_TYPE_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST = 166;
const uint8_t GTPC_MSG_TYPE_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE = 167;
const uint8_t GTPC_MSG_TYPE_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST = 168;
const uint8_t GTPC_MSG_TYPE_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST = 168;
const uint8_t GTPC_MSG_TYPE_DELETE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE = 169;
const uint8_t GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_REQUEST = 170;
const uint8_t GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_RESPONSE = 171;
//172 - 175 For future use
//SGW to SGSN/MME (S4/S11)
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION = 176;
const uint8_t GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_REQUEST = 170;
const uint8_t GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_RESPONSE = 171;
// 172 - 175 For future use
// SGW to SGSN/MME (S4/S11)
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION = 176;
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION_ACKNOWLEDGE = 177;
const uint8_t GTPC_MSG_TYPE_PGW_RESTART_NOTIFICATION = 179;
const uint8_t GTPC_MSG_TYPE_PGW_RESTART_NOTIFICATION_ACKNOWLEDGE = 180;
//SGW to SGSN (S4)
//178 Reserved. Allocated in earlier version of the specification.
//181 -189 For future use
//SGW to PGW, PGW to SGW (S5/S8)
const uint8_t GTPC_MSG_TYPE_UPDATE_PDN_CONNECTION_SET_REQUEST = 200;
const uint8_t GTPC_MSG_TYPE_PGW_RESTART_NOTIFICATION = 179;
const uint8_t GTPC_MSG_TYPE_PGW_RESTART_NOTIFICATION_ACKNOWLEDGE = 180;
// SGW to SGSN (S4)
// 178 Reserved. Allocated in earlier version of the specification.
// 181 -189 For future use
// SGW to PGW, PGW to SGW (S5/S8)
const uint8_t GTPC_MSG_TYPE_UPDATE_PDN_CONNECTION_SET_REQUEST = 200;
const uint8_t GTPC_MSG_TYPE_UPDATE_PDN_CONNECTION_SET_RESPONSE = 201;
//For future use
//MME to SGW (S11)
const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_REQUEST = 211;
// For future use
// MME to SGW (S11)
const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_REQUEST = 211;
const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_RESPONSE = 212;
//For future use
//MBMS GW to MME/SGSN (Sm/Sn)
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_START_REQUEST = 231;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_START_RESPONSE = 232;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_UPDATE_REQUEST = 233;
// For future use
// MBMS GW to MME/SGSN (Sm/Sn)
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_START_REQUEST = 231;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_START_RESPONSE = 232;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_UPDATE_REQUEST = 233;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_UPDATE_RESPONSE = 234;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_REQUEST = 235;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_RESPONSE = 236;
//For future use
//Other
//240 - 255 For future use
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_REQUEST = 235;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_RESPONSE = 236;
// For future use
// Other
// 240 - 255 For future use
/****************************************************************************
*
@ -148,91 +148,89 @@ const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_RESPONSE = 236;
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.1-1
*
***************************************************************************/
struct gtpc_create_session_request {
bool imsi_present;
uint64_t imsi; // C
// bool msidn_present;
// uint64_t msisdn; // C
// bool mei_present;
// uint64_t mei; // C/CO
// bool user_location_info_present;
// struct gtpc_user_location_info_ie uli; // C/CO
// bool serving_network_present;
// struct gtpc_serving_network_ie serving_network; // C/CO
struct gtpc_create_session_request
{
bool imsi_present;
uint64_t imsi; // C
//bool msidn_present;
//uint64_t msisdn; // C
//bool mei_present;
//uint64_t mei; // C/CO
//bool user_location_info_present;
//struct gtpc_user_location_info_ie uli; // C/CO
//bool serving_network_present;
//struct gtpc_serving_network_ie serving_network; // C/CO
enum gtpc_rat_type rat_type; // M
// bool indication_flags_present;
// struct indication_flags_ indication_flags; // C
enum gtpc_rat_type rat_type; // M
//bool indication_flags_present;
//struct indication_flags_ indication_flags; // C
struct gtpc_f_teid_ie sender_f_teid; // M
bool pgw_addr_present;
struct gtpc_f_teid_ie pgw_addr; // C
struct gtpc_f_teid_ie sender_f_teid; // M
bool pgw_addr_present;
struct gtpc_f_teid_ie pgw_addr; // C
char apn[MAX_APN_LENGTH]; // M
// bool selection_mode_present;
// enum selection_mode_ selection_mode; // C/CO
// bool pdn_type_present;
// enum gtpc_pdn_type pdn_type; // C
// bool pdn_addr_alloc_present;
// struct pdn_addr_alloc_ pdn_addr_alloc; // C/CO
// bool max_apn_restriction_present;
// enum apn_restriction_ max_apn_restriction; // C
// bool apn_ambr_present;
// struct ambr_ apn_ambr; // C
// bool linked_eps_bearer_id_present;
// uint8_t linked_eps_bearer_id; // C
// bool pco_present;
// uint8_t pco; // C
char apn[MAX_APN_LENGTH]; // M
//bool selection_mode_present;
//enum selection_mode_ selection_mode; // C/CO
//bool pdn_type_present;
//enum gtpc_pdn_type pdn_type; // C
//bool pdn_addr_alloc_present;
//struct pdn_addr_alloc_ pdn_addr_alloc; // C/CO
//bool max_apn_restriction_present;
//enum apn_restriction_ max_apn_restriction; // C
//bool apn_ambr_present;
//struct ambr_ apn_ambr; // C
//bool linked_eps_bearer_id_present;
//uint8_t linked_eps_bearer_id; // C
//bool pco_present;
//uint8_t pco; // C
struct gtpc_bearer_context_created_ie //see TS 29.274 v10.14.0 Table 7.2.1-2
struct gtpc_bearer_context_created_ie // see TS 29.274 v10.14.0 Table 7.2.1-2
{
uint8_t ebi;
bool tft_present;
bool s1_u_enodeb_f_teid_present;
struct gtpc_f_teid_ie s1_u_enodeb_f_teid;
bool s4_u_sgsn_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgsn_f_teid;
bool s5_s8_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_sgw_f_teid;
bool s5_s8_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid;
bool s12_rnc_f_teid_present;
struct gtpc_f_teid_ie s12_rnc_f_teid;
bool s2b_u_epdg_f_teid_present;
struct gtpc_f_teid_ie s2b_u_epdg_f_teid;
struct gtpc_bearer_qos_ie bearer_qos; // M
} eps_bearer_context_created; // M
//bool bearer_context_deleted_present;
//struct bearer_context_ bearer_context_deleted; // C
//bool trace_information_present;
//struct trace_infromation_ trace_information; // C
//bool recovery_present
//uint8_t recovery; // C
//bool mme_fq_csid_present;
//struct fq_csid_ mme_fq_csid; // C
//bool sgw_fq_csid_present;
//struct fq_csid_ sgw_fq_csid; // C
//bool epdg_fq_csid_present;
//struct fq_csid_ epdg_fq_csid; // C
//bool ue_time_zone_present;
//struct ue_time_zone_ ue_time_zone; // CO
//bool uci_present;
//struct uci_ uci; // CO
//bool charging_caracteristics_present;
//enum charging_characteristics_ charging_caracteristics; // O
//bool mme_ldn_present;
//uint8_t mme_ldn[LDN_MAX_SIZE]; // O
//bool sgw_ldn_present;
//uint8_t sgw_ldn[LDN_MAX_SIZE]; // O
//bool epgd_ldn_present;
//uint8_t epdg_ldn[LDN_MAX_SIZE]; // O
//bool signaling_priority_indication;
//enum signalling_priority_indication_ spi; // CO
//bool acpo_present;
//uint8_t apco; // CO
//bool ext; // O
uint8_t ebi;
bool tft_present;
bool s1_u_enodeb_f_teid_present;
struct gtpc_f_teid_ie s1_u_enodeb_f_teid;
bool s4_u_sgsn_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgsn_f_teid;
bool s5_s8_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_sgw_f_teid;
bool s5_s8_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid;
bool s12_rnc_f_teid_present;
struct gtpc_f_teid_ie s12_rnc_f_teid;
bool s2b_u_epdg_f_teid_present;
struct gtpc_f_teid_ie s2b_u_epdg_f_teid;
struct gtpc_bearer_qos_ie bearer_qos;
} eps_bearer_context_created;
// bool bearer_context_deleted_present;
// struct bearer_context_ bearer_context_deleted; // C
// bool trace_information_present;
// struct trace_infromation_ trace_information; // C
// bool recovery_present
// uint8_t recovery; // C
// bool mme_fq_csid_present;
// struct fq_csid_ mme_fq_csid; // C
// bool sgw_fq_csid_present;
// struct fq_csid_ sgw_fq_csid; // C
// bool epdg_fq_csid_present;
// struct fq_csid_ epdg_fq_csid; // C
// bool ue_time_zone_present;
// struct ue_time_zone_ ue_time_zone; // CO
// bool uci_present;
// struct uci_ uci; // CO
// bool charging_caracteristics_present;
// enum charging_characteristics_ charging_caracteristics; // O
// bool mme_ldn_present;
// uint8_t mme_ldn[LDN_MAX_SIZE]; // O
// bool sgw_ldn_present;
// uint8_t sgw_ldn[LDN_MAX_SIZE]; // O
// bool epgd_ldn_present;
// uint8_t epdg_ldn[LDN_MAX_SIZE]; // O
// bool signaling_priority_indication;
// enum signalling_priority_indication_ spi; // CO
// bool acpo_present;
// uint8_t apco; // CO
// bool ext; // O
};
/****************************************************************************
@ -241,58 +239,55 @@ struct gtpc_create_session_request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.2-1
*
***************************************************************************/
struct gtpc_create_session_response
{
struct gtpc_cause_ie cause; //M
//Change Reporting Action //C
//CSG Information Reporting Action //CO
bool sender_f_teid_present;
struct gtpc_f_teid_ie sender_f_teid; //C
//PGW S5/S8/S2b F-TEID //C
bool paa_present;
struct gtpc_pdn_address_allocation_ie paa; //C
//apn_restriction
//apn_ambr
//linked_eps_bearer_id
//pco
struct gtpc_bearer_context_created_ie
{
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s1_u_sgw_f_teid;
bool s4_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgw_f_teid;
bool s5_s8_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid;
bool s12_sgw_f_teid_present;
struct gtpc_f_teid_ie s12_sgw_f_teid;
bool s2b_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s2b_u_pgw_f_teid;
bool bearer_level_qos_present;
struct gtpc_create_session_response {
struct gtpc_cause_ie cause; // M
// Change Reporting Action //C
// CSG Information Reporting Action //CO
bool sender_f_teid_present;
struct gtpc_f_teid_ie sender_f_teid; // C
// PGW S5/S8/S2b F-TEID //C
bool paa_present;
struct gtpc_pdn_address_allocation_ie paa; // C
// apn_restriction
// apn_ambr
// linked_eps_bearer_id
// pco
struct gtpc_bearer_context_created_ie {
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s1_u_sgw_f_teid;
bool s4_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgw_f_teid;
bool s5_s8_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid;
bool s12_sgw_f_teid_present;
struct gtpc_f_teid_ie s12_sgw_f_teid;
bool s2b_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s2b_u_pgw_f_teid;
bool bearer_level_qos_present;
struct gtpc_bearer_qos_ie bearer_level_qos;
//charging_id_present
//charging_id
//bearer_flags_present
//bearer_flags
} eps_bearer_context_created; //M
// charging_id_present
// charging_id
// bearer_flags_present
// bearer_flags
} eps_bearer_context_created; // M
/*
struct gtpc_bearer_context_removed_ie
{
uint8_t ebi;
//
} bearer_context_removed; //C
*/
//recovery; //C
//charging_gateway_name; //C
//charging_gateway_address; //C
//PGW-FQ-CSID //C
//SGW-FQ-CSID //C
//SGW LDN //O
//PGW LDN //O
//PGW Back-Off Time //O
//acpo //CO
// recovery; //C
// charging_gateway_name; //C
// charging_gateway_address; //C
// PGW-FQ-CSID //C
// SGW-FQ-CSID //C
// SGW LDN //O
// PGW LDN //O
// PGW Back-Off Time //O
// acpo //CO
};
/****************************************************************************
@ -301,38 +296,35 @@ struct gtpc_create_session_response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.7-1, 7.2.7-2 and 7.2.7-3
*
***************************************************************************/
struct gtpc_modify_bearer_request
{
//ME Identity (MEI)//C
//User Location Information (ULI)//C
//Serving Network //CO
//RAT Type //C/CO
//Indication Flags
//Sender F-TEID for Control Plane
//APN-AMBR
//Delay Downlink Packet Notification Request
struct gtpc_bearer_context_modified_ie
{
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_enb_f_teid_present;
struct gtpc_modify_bearer_request {
// ME Identity (MEI)//C
// User Location Information (ULI)//C
// Serving Network //CO
// RAT Type //C/CO
// Indication Flags
// Sender F-TEID for Control Plane
// APN-AMBR
// Delay Downlink Packet Notification Request
struct gtpc_bearer_context_modified_ie {
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_enb_f_teid_present;
struct gtpc_f_teid_ie s1_u_enb_f_teid;
bool s5_s8_u_sgw_f_teid_present;
bool s5_s8_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_sgw_f_teid;
bool s12_rnc_f_teid_present;
bool s12_rnc_f_teid_present;
struct gtpc_f_teid_ie s12_rnc_f_teid;
bool s4_u_sgsn_f_teid_present;
bool s4_u_sgsn_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgsn_f_teid;
} eps_bearer_context_to_modify;
//Bearer Contexts to be removed
//Recovery
//UE Time Zone
//MME-FQ-CSID
//SGW-FQ-CSID
//User CSG Information (UCI)
//MME/S4-SGSN LDN
//SGW LDN
// Bearer Contexts to be removed
// Recovery
// UE Time Zone
// MME-FQ-CSID
// SGW-FQ-CSID
// User CSG Information (UCI)
// MME/S4-SGSN LDN
// SGW LDN
};
/****************************************************************************
@ -341,41 +333,38 @@ struct gtpc_modify_bearer_request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.8-1
*
***************************************************************************/
struct gtpc_modify_bearer_response
{
struct gtpc_modify_bearer_response {
struct gtpc_cause_ie cause;
//MSISDN
//Linked EPS Bearer ID
//APN-AMBR
//APN Restriction
//Protocol Configuration Options
// MSISDN
// Linked EPS Bearer ID
// APN-AMBR
// APN Restriction
// Protocol Configuration Options
struct gtpc_bearer_context_modified_ie
{
uint8_t ebi;
struct gtpc_cause_ie cause;
bool s1_u_sgw_f_teid_present;
struct gtpc_bearer_context_modified_ie {
uint8_t ebi;
struct gtpc_cause_ie cause;
bool s1_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s1_u_sgw_f_teid;
bool s12_sgw_f_teid_present;
bool s12_sgw_f_teid_present;
struct gtpc_f_teid_ie s12_sgw_f_teid;
bool s4_u_sgw_f_teid_present;
bool s4_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgw_f_teid;
//charging id
//bearer flags
// charging id
// bearer flags
} eps_bearer_context_modified;
//Bearer Contexts marked for removal
//Change Reporting action
//CSG information reporting action
//Charging gateway name
//charging gateway address
//P-GW FQ-CSID
//S-GW FQ-CSID
//Recovery
//S-GW LDN
//P-GW LDN
//indication Flags
//ext
// Bearer Contexts marked for removal
// Change Reporting action
// CSG information reporting action
// Charging gateway name
// charging gateway address
// P-GW FQ-CSID
// S-GW FQ-CSID
// Recovery
// S-GW LDN
// P-GW LDN
// indication Flags
// ext
};
/****************************************************************************
@ -384,16 +373,14 @@ struct gtpc_modify_bearer_response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.9.1-1
*
***************************************************************************/
struct gtpc_delete_session_request
{
struct gtpc_delete_session_request {
struct gtpc_cause_ie cause;
//Linked EPS Bearer ID
//User Location Information
//Indication Flags
//Protocol Configuration Options
//Originating Node
//Private extension
// Linked EPS Bearer ID
// User Location Information
// Indication Flags
// Protocol Configuration Options
// Originating Node
// Private extension
};
/****************************************************************************
@ -402,13 +389,11 @@ struct gtpc_delete_session_request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.10.1-1
*
***************************************************************************/
struct gtpc_delete_session_response
{
struct gtpc_delete_session_response {
struct gtpc_cause_ie cause;
//Recovery
//Protocol Configuration Options
//Private extension
// Recovery
// Protocol Configuration Options
// Private extension
};
/****************************************************************************
@ -417,30 +402,25 @@ struct gtpc_delete_session_response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.21.1-1
*
***************************************************************************/
struct gtpc_release_access_bearers_request
{
struct gtpc_release_access_bearers_request {
bool list_of_rabs_present;
//Linked EPS Bearer ID
// Linked EPS Bearer ID
bool originating_node_present;
//Indication Flags
//Private Extension
// 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
};
/****************************************************************************
*
* GTP-C v2 Delete Session Response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.22.1-1
*
***************************************************************************/
struct gtpc_release_access_bearers_response {
struct gtpc_cause_ie cause;
// Recovery
// Private extension
};
} //namespace
} // namespace srslte
#endif // SRSLTE_GTPC_MSG_H

@ -27,48 +27,50 @@ namespace srsepc {
class nas;
//NAS -> GTP-C
class gtpc_interface_nas
/******************
* MME Interfaces *
******************/
class gtpc_interface_nas // NAS -> GTP-C
{
public:
virtual bool send_create_session_request(uint64_t imsi) = 0;
virtual bool send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, struct srslte::gtpc_f_teid_ie *enb_fteid) = 0;
virtual bool send_delete_session_request(uint64_t imsi) = 0;
virtual bool send_create_session_request(uint64_t imsi) = 0;
virtual bool send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t* enb_fteid) = 0;
virtual bool send_delete_session_request(uint64_t imsi) = 0;
};
//GTP-C -> S1AP
class s1ap_interface_gtpc
class s1ap_interface_gtpc // GTP-C -> S1AP
{
public:
virtual bool send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup) = 0;
};
//NAS -> S1AP
class s1ap_interface_nas
class s1ap_interface_nas // NAS -> S1AP
{
public:
virtual uint32_t allocate_m_tmsi(uint64_t imsi) = 0;
virtual uint32_t get_next_mme_ue_s1ap_id() = 0;
virtual bool add_nas_ctx_to_imsi_map(nas *nas_ctx) = 0;
virtual bool add_nas_ctx_to_mme_ue_s1ap_id_map(nas *nas_ctx) = 0;
virtual bool add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id) = 0;
virtual bool release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id) = 0;
virtual bool delete_ue_ctx(uint64_t imsi) = 0;
virtual uint64_t find_imsi_from_m_tmsi(uint32_t m_tmsi) = 0;
virtual nas* find_nas_ctx_from_imsi(uint64_t imsi) = 0;
virtual uint32_t allocate_m_tmsi(uint64_t imsi) = 0;
virtual uint32_t get_next_mme_ue_s1ap_id() = 0;
virtual bool add_nas_ctx_to_imsi_map(nas* nas_ctx) = 0;
virtual bool add_nas_ctx_to_mme_ue_s1ap_id_map(nas* nas_ctx) = 0;
virtual bool add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id) = 0;
virtual bool release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id) = 0;
virtual bool delete_ue_ctx(uint64_t imsi) = 0;
virtual uint64_t find_imsi_from_m_tmsi(uint32_t m_tmsi) = 0;
virtual nas* find_nas_ctx_from_imsi(uint64_t imsi) = 0;
virtual bool send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup) = 0;
virtual bool send_ue_context_release_command(uint32_t mme_ue_s1ap_id) = 0;
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri) = 0;
virtual bool send_ue_context_release_command(uint32_t mme_ue_s1ap_id) = 0;
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri) = 0;
};
//NAS -> HSS
class hss_interface_nas
class hss_interface_nas // NAS -> HSS
{
public:
virtual bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres) = 0;
virtual bool gen_update_loc_answer(uint64_t imsi, uint8_t *qci) = 0;
virtual bool resync_sqn(uint64_t imsi, uint8_t *auts) = 0;
virtual bool gen_auth_info_answer(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres) = 0;
virtual bool gen_update_loc_answer(uint64_t imsi, uint8_t* qci) = 0;
virtual bool resync_sqn(uint64_t imsi, uint8_t* auts) = 0;
};
}
} // namespace srsepc
#endif // SRSLTE_EPC_INTERFACES_H

@ -1,5 +1,4 @@
/**
*
/*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
@ -27,14 +26,11 @@
#include "srslte/asn1/gtpc.h"
#include "srslte/common/common.h"
namespace srslte{
namespace srslte {
int
gtpc_pack_create_session_request(struct gtpc_create_session_request *cs_req, srslte::byte_buffer_t)
int gtpc_pack_create_session_request(struct gtpc_create_session_request* cs_req, srslte::byte_buffer_t)
{
//FIXME
// TODO
return 0;
}
};
} // namespace srslte

@ -47,93 +47,86 @@
#define LTE_FDD_ENB_IND_HE_MAX_VALUE 31
#define LTE_FDD_ENB_SEQ_HE_MAX_VALUE 0x07FFFFFFFFFFUL
namespace srsepc{
namespace srsepc {
typedef struct{
typedef struct {
std::string auth_algo;
std::string db_file;
uint16_t mcc;
uint16_t mnc;
}hss_args_t;
typedef struct{
std::string name;
uint64_t imsi;
uint8_t key[16];
bool op_configured;
uint8_t op[16];
uint8_t opc[16];
uint8_t amf[2];
uint8_t sqn[6];
uint16_t qci;
uint8_t last_rand[16];
}hss_ue_ctx_t;
enum hss_auth_algo {
HSS_ALGO_XOR,
HSS_ALGO_MILENAGE
};
uint16_t mcc;
uint16_t mnc;
} hss_args_t;
typedef struct {
std::string name;
uint64_t imsi;
uint8_t key[16];
bool op_configured;
uint8_t op[16];
uint8_t opc[16];
uint8_t amf[2];
uint8_t sqn[6];
uint16_t qci;
uint8_t last_rand[16];
} hss_ue_ctx_t;
enum hss_auth_algo { HSS_ALGO_XOR, HSS_ALGO_MILENAGE };
class hss : public hss_interface_nas
{
public:
static hss* get_instance(void);
static void cleanup(void);
int init(hss_args_t *hss_args, srslte::log_filter* hss_log);
void stop(void);
int init(hss_args_t* hss_args, srslte::log_filter* hss_log);
void stop(void);
virtual bool gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
virtual bool gen_auth_info_answer(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres);
virtual bool gen_update_loc_answer(uint64_t imsi, uint8_t* qci);
virtual bool resync_sqn(uint64_t imsi, uint8_t *auts);
virtual bool resync_sqn(uint64_t imsi, uint8_t* auts);
private:
hss();
virtual ~hss();
static hss *m_instance;
srslte::byte_buffer_pool *m_pool;
std::map<uint64_t,hss_ue_ctx_t*> m_imsi_to_ue_ctx;
static hss* m_instance;
std::map<uint64_t, hss_ue_ctx_t*> m_imsi_to_ue_ctx;
void gen_rand(uint8_t rand_[16]);
bool get_k_amf_opc_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *opc, uint8_t *sqn);
bool get_k_amf_opc_sqn(uint64_t imsi, uint8_t* k, uint8_t* amf, uint8_t* opc, uint8_t* sqn);
bool gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
bool gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres);
bool gen_auth_info_answer_milenage(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres);
bool gen_auth_info_answer_xor(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres);
bool resync_sqn_milenage(uint64_t imsi, uint8_t *auts);
bool resync_sqn_xor(uint64_t imsi, uint8_t *auts);
bool resync_sqn_milenage(uint64_t imsi, uint8_t* auts);
bool resync_sqn_xor(uint64_t imsi, uint8_t* auts);
std::vector<std::string> split_string(const std::string &str, char delimiter);
void get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len);
std::vector<std::string> split_string(const std::string& str, char delimiter);
void get_uint_vec_from_hex_str(const std::string& key_str, uint8_t* key, uint len);
void increment_ue_sqn(uint64_t imsi);
void increment_seq_after_resync(uint64_t imsi);
void increment_sqn(uint8_t *sqn, uint8_t *next_sqn);
void set_sqn(uint64_t imsi, uint8_t *sqn);
void increment_sqn(uint8_t* sqn, uint8_t* next_sqn);
void set_sqn(uint64_t imsi, uint8_t* sqn);
void set_last_rand(uint64_t imsi, uint8_t *rand);
void get_last_rand(uint64_t imsi, uint8_t *rand);
void set_last_rand(uint64_t imsi, uint8_t* rand);
void get_last_rand(uint64_t imsi, uint8_t* rand);
bool set_auth_algo(std::string auth_algo);
bool read_db_file(std::string db_file);
bool write_db_file(std::string db_file);
bool get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx);
std::string hex_string(uint8_t *hex, int size);
bool get_ue_ctx(uint64_t imsi, hss_ue_ctx_t** ue_ctx);
std::string hex_string(uint8_t* hex, int size);
enum hss_auth_algo m_auth_algo;
std::string db_file;
std::string db_file;
/*Logs*/
srslte::log_filter *m_hss_log;
srslte::log_filter* m_hss_log;
uint16_t mcc;
uint16_t mnc;
};
} // namespace srsepc
#endif // SRSEPC_HSS_H

@ -41,44 +41,43 @@
#include "srslte/common/threads.h"
#include "s1ap.h"
namespace srsepc {
namespace srsepc{
typedef struct{
typedef struct {
s1ap_args_t s1ap_args;
//diameter_args_t diameter_args;
//gtpc_args_t gtpc_args;
// diameter_args_t diameter_args;
// gtpc_args_t gtpc_args;
} mme_args_t;
class mme:
public thread
class mme : public thread
{
public:
static mme* get_instance(void);
static void cleanup(void);
int init(mme_args_t* args, srslte::log_filter *nas_log, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log, hss_interface_nas * hss);
int init(mme_args_t* args,
srslte::log_filter* nas_log,
srslte::log_filter* s1ap_log,
srslte::log_filter* mme_gtpc_log);
void stop();
int get_s1_mme();
int get_s1_mme();
void run_thread();
private:
mme();
virtual ~mme();
static mme *m_instance;
s1ap *m_s1ap;
mme_gtpc *m_mme_gtpc;
static mme* m_instance;
s1ap* m_s1ap;
mme_gtpc* m_mme_gtpc;
bool m_running;
srslte::byte_buffer_pool *m_pool;
bool m_running;
srslte::byte_buffer_pool* m_pool;
/*Logs*/
srslte::log_filter *m_nas_log;
srslte::log_filter *m_s1ap_log;
srslte::log_filter *m_mme_gtpc_log;
srslte::log_filter* m_nas_log;
srslte::log_filter* m_s1ap_log;
srslte::log_filter* m_mme_gtpc_log;
};
} // namespace srsepc
#endif // SRSEPC_MME_H

@ -26,58 +26,53 @@
#ifndef SRSEPC_MME_GTPC_H
#define SRSEPC_MME_GTPC_H
#include "nas.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/log.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/asn1/gtpc.h"
#include "nas.h"
namespace srsepc
{
namespace srsepc {
class spgw;
class s1ap;
class mme_gtpc
: public gtpc_interface_nas
class mme_gtpc : public gtpc_interface_nas
{
public:
typedef struct gtpc_ctx{
typedef struct gtpc_ctx {
srslte::gtp_fteid_t mme_ctr_fteid;
srslte::gtp_fteid_t sgw_ctr_fteid;
}gtpc_ctx_t;
} gtpc_ctx_t;
static mme_gtpc* get_instance(void);
static void cleanup(void);
static void cleanup(void);
bool init(srslte::log_filter *mme_gtpc_log);
bool init(srslte::log_filter* mme_gtpc_log);
uint32_t get_new_ctrl_teid();
uint32_t get_new_ctrl_teid();
virtual bool send_create_session_request(uint64_t imsi);
bool handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu);
virtual bool send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t *enb_fteid);
void handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu);
void send_release_access_bearers_request(uint64_t imsi);
bool handle_create_session_response(srslte::gtpc_pdu* cs_resp_pdu);
virtual bool send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t* enb_fteid);
void handle_modify_bearer_response(srslte::gtpc_pdu* mb_resp_pdu);
void send_release_access_bearers_request(uint64_t imsi);
virtual bool send_delete_session_request(uint64_t imsi);
private:
mme_gtpc();
virtual ~mme_gtpc();
static mme_gtpc *m_instance;
static mme_gtpc* m_instance;
srslte::log_filter *m_mme_gtpc_log;
srslte::byte_buffer_pool *m_pool;
srslte::log_filter* m_mme_gtpc_log;
srslte::byte_buffer_pool* m_pool;
s1ap* m_s1ap;
spgw* m_spgw;
s1ap* m_s1ap;
spgw* m_spgw;
in_addr_t m_mme_gtpc_ip;
uint32_t m_next_ctrl_teid;
std::map<uint32_t,uint64_t> m_mme_ctr_teid_to_imsi;
std::map<uint64_t,struct gtpc_ctx> m_imsi_to_gtpc_ctx;
uint32_t m_next_ctrl_teid;
std::map<uint32_t, uint64_t> m_mme_ctr_teid_to_imsi;
std::map<uint64_t, struct gtpc_ctx> m_imsi_to_gtpc_ctx;
};
}
} // namespace srsepc
#endif // SRSEPC_MME_GTPC_H

@ -21,16 +21,15 @@
#ifndef SRSEPC_NAS_H
#define SRSEPC_NAS_H
#include <netinet/sctp.h>
#include "srslte/common/security.h"
#include "srslte/asn1/gtpc_ies.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/asn1/liblte_mme.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/security.h"
#include "srslte/interfaces/epc_interfaces.h"
#include <netinet/sctp.h>
namespace srsepc{
namespace srsepc {
static const uint8_t MAX_ERABS_PER_UE = 16;
@ -42,9 +41,7 @@ typedef enum {
EMM_STATE_DEREGISTERED_INITIATED,
EMM_STATE_N_ITEMS,
} emm_state_t;
static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"DEREGISTERED",
"COMMON PROCEDURE INITIATED",
"REGISTERED",
static const char emm_state_text[EMM_STATE_N_ITEMS][100] = {"DEREGISTERED", "COMMON PROCEDURE INITIATED", "REGISTERED",
"DEREGISTERED INITIATED"};
// MME ECM states (3GPP 23.401 v10.0.0, section 4.6.3)
@ -53,8 +50,8 @@ typedef enum {
ECM_STATE_CONNECTED,
ECM_STATE_N_ITEMS,
} ecm_state_t;
static const char ecm_state_text[ECM_STATE_N_ITEMS][100] = {"IDLE",
"CONNECTED"};
static const char ecm_state_text[ECM_STATE_N_ITEMS][100] = {"IDLE", "CONNECTED"};
/*
// MME ESM states (3GPP 23.401 v10.0.0, section 4.6.3)
typedef enum {
@ -75,73 +72,67 @@ static const char esm_state_text[ESM_STATE_N_ITEMS][100] = {"CONTEXT INACTIVE",
"PROCEDURE_TRANSACTION_INACTIVE"
"PROCEDURE_TRANSACTION_PENDING"};
*/
typedef enum
{
ERAB_DEACTIVATED,
ERAB_CTX_REQUESTED,
ERAB_CTX_SETUP,
ERAB_ACTIVE
} esm_state_t;
typedef enum { ERAB_DEACTIVATED, ERAB_CTX_REQUESTED, ERAB_CTX_SETUP, ERAB_ACTIVE } esm_state_t;
/*
* EMM, ECM, ESM and EPS Security context definitions
*/
typedef struct{
uint64_t imsi;
emm_state_t state;
uint8_t procedure_transaction_id;
uint8_t attach_type;
struct in_addr ue_ip;
srslte::gtpc_f_teid_ie sgw_ctrl_fteid;
typedef struct {
uint64_t imsi;
emm_state_t state;
uint8_t procedure_transaction_id;
uint8_t attach_type;
struct in_addr ue_ip;
srslte::gtpc_f_teid_ie sgw_ctrl_fteid;
} emm_ctx_t;
typedef struct{
ecm_state_t state;
uint32_t enb_ue_s1ap_id;
uint32_t mme_ue_s1ap_id;
struct sctp_sndrcvinfo enb_sri;
bool eit;
typedef struct {
ecm_state_t state;
uint32_t enb_ue_s1ap_id;
uint32_t mme_ue_s1ap_id;
struct sctp_sndrcvinfo enb_sri;
bool eit;
} ecm_ctx_t;
typedef struct{
uint8_t erab_id;
esm_state_t state;
uint8_t qci;
srslte::gtpc_f_teid_ie enb_fteid;
srslte::gtpc_f_teid_ie sgw_s1u_fteid;
typedef struct {
uint8_t erab_id;
esm_state_t state;
uint8_t qci;
srslte::gtpc_f_teid_ie enb_fteid;
srslte::gtpc_f_teid_ie sgw_s1u_fteid;
srslte::gtpc_pdn_address_allocation_ie pdn_addr_alloc;
} esm_ctx_t;
typedef struct{
uint8_t eksi;
uint8_t k_asme[32];
uint8_t autn[16];
uint8_t rand[16];
uint8_t xres[16]; //minimum 6, maximum 16
uint32_t dl_nas_count;
uint32_t ul_nas_count;
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
uint8_t k_nas_enc[32];
uint8_t k_nas_int[32];
uint8_t k_enb[32];
typedef struct {
uint8_t eksi;
uint8_t k_asme[32];
uint8_t autn[16];
uint8_t rand[16];
uint8_t xres[16]; // minimum 6, maximum 16
uint32_t dl_nas_count;
uint32_t ul_nas_count;
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
uint8_t k_nas_enc[32];
uint8_t k_nas_int[32];
uint8_t k_enb[32];
LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT ue_network_cap;
bool ms_network_cap_present;
bool ms_network_cap_present;
LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT ms_network_cap;
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
LIBLTE_MME_EPS_MOBILE_ID_GUTI_STRUCT guti;
} sec_ctx_t;
/*
* NAS Initialization Arguments
*/
typedef struct {
uint16_t mcc;
uint16_t mnc;
uint8_t mme_code;
uint16_t mme_group;
uint16_t tac;
std::string apn;
std::string dns;
uint16_t mcc;
uint16_t mnc;
uint8_t mme_code;
uint16_t mme_group;
uint16_t tac;
std::string apn;
std::string dns;
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
} nas_init_t;
@ -150,101 +141,101 @@ class nas
{
public:
nas();
void init(nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
void init(nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
/***********************
* Initial UE messages *
***********************/
//Attach request messages
static bool handle_attach_request( uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo *enb_sri,
srslte::byte_buffer_t *nas_rx,
nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
// Attach request messages
static bool handle_attach_request(uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* nas_rx,
nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
static bool handle_imsi_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo *enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
static bool handle_imsi_attach_request_unknown_ue(uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT& pdn_con_req,
nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
static bool handle_imsi_attach_request_known_ue( nas *nas_ctx,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo *enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
srslte::byte_buffer_t *nas_rx,
nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
static bool handle_imsi_attach_request_known_ue(nas* nas_ctx,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT& pdn_con_req,
srslte::byte_buffer_t* nas_rx,
nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
static bool handle_guti_attach_request_unknown_ue(uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT& pdn_con_req,
nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
static bool handle_guti_attach_request_unknown_ue( uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo *enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
static bool handle_guti_attach_request_known_ue(nas* nas_ctx,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT& attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT& pdn_con_req,
srslte::byte_buffer_t* nas_rx,
nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
static bool handle_guti_attach_request_known_ue( nas *nas_ctx,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo *enb_sri,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
srslte::byte_buffer_t *nas_rx,
nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
//Service request messages
static bool handle_service_request( uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo *enb_sri,
srslte::byte_buffer_t *nas_rx,
nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
// Service request messages
static bool handle_service_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* nas_rx,
nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
//Dettach request messages
static bool handle_detach_request( uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo *enb_sri,
srslte::byte_buffer_t *nas_rx,
nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
// Dettach request messages
static bool handle_detach_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* nas_rx,
nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
//Tracking area update request messages
static bool handle_tracking_area_update_request( uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo *enb_sri,
srslte::byte_buffer_t *nas_rx,
nas_init_t args,
s1ap_interface_nas *s1ap,
gtpc_interface_nas *gtpc,
hss_interface_nas *hss,
srslte::log *nas_log);
// Tracking area update request messages
static bool handle_tracking_area_update_request(uint32_t m_tmsi,
uint32_t enb_ue_s1ap_id,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* nas_rx,
nas_init_t args,
s1ap_interface_nas* s1ap,
gtpc_interface_nas* gtpc,
hss_interface_nas* hss,
srslte::log* nas_log);
/* Uplink NAS messages handling */
bool handle_authentication_response(srslte::byte_buffer_t* nas_rx);
@ -269,7 +260,7 @@ public:
/* Security functions */
bool integrity_check(srslte::byte_buffer_t* pdu);
bool short_integrity_check(srslte::byte_buffer_t* pdu);
void integrity_generate(srslte::byte_buffer_t* pdu, uint8_t *mac);
void integrity_generate(srslte::byte_buffer_t* pdu, uint8_t* mac);
void cipher_decrypt(srslte::byte_buffer_t* pdu);
void cipher_encrypt(srslte::byte_buffer_t* pdu);
@ -280,20 +271,20 @@ public:
sec_ctx_t m_sec_ctx;
private:
srslte::byte_buffer_pool *m_pool;
srslte::log *m_nas_log;
gtpc_interface_nas *m_gtpc;
s1ap_interface_nas *m_s1ap;
hss_interface_nas *m_hss;
srslte::byte_buffer_pool* m_pool;
srslte::log* m_nas_log;
gtpc_interface_nas* m_gtpc;
s1ap_interface_nas* m_s1ap;
hss_interface_nas* m_hss;
uint16_t m_mcc;
uint16_t m_mnc;
uint16_t m_mme_group;
uint16_t m_mme_code;
uint16_t m_tac;
std::string m_apn;
std::string m_dns;
uint16_t m_mcc;
uint16_t m_mnc;
uint16_t m_mme_group;
uint16_t m_mme_code;
uint16_t m_tac;
std::string m_apn;
std::string m_dns;
};
}//namespace
} // namespace srsepc
#endif // SRSEPC_NAS_H

@ -26,129 +26,126 @@
#ifndef SRSEPC_S1AP_H
#define SRSEPC_S1AP_H
#include "mme_gtpc.h"
#include "nas.h"
#include "s1ap_ctx_mngmt_proc.h"
#include "s1ap_mngmt_proc.h"
#include "s1ap_nas_transport.h"
#include "srsepc/hdr/hss/hss.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/asn1/liblte_mme.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include "srslte/common/s1ap_pcap.h"
#include "srslte/interfaces/epc_interfaces.h"
#include <strings.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/sctp.h>
#include <unistd.h>
#include <map>
#include <netinet/sctp.h>
#include <set>
#include "nas.h"
#include "s1ap_mngmt_proc.h"
#include "s1ap_nas_transport.h"
#include "s1ap_ctx_mngmt_proc.h"
#include "mme_gtpc.h"
#include "srsepc/hdr/hss/hss.h"
#include <strings.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
namespace srsepc{
namespace srsepc {
const uint16_t S1MME_PORT = 36412;
class s1ap:
public s1ap_interface_nas,
public s1ap_interface_gtpc
class s1ap : public s1ap_interface_nas, public s1ap_interface_gtpc
{
public:
static s1ap* get_instance();
static void cleanup();
static void cleanup();
int enb_listen();
int init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log, srslte::log_filter *nas_log, hss_interface_nas * hss_);
int enb_listen();
int init(s1ap_args_t s1ap_args, srslte::log_filter* s1ap_log, srslte::log_filter* nas_log);
void stop();
int get_s1_mme();
void delete_enb_ctx(int32_t assoc_id);
bool s1ap_tx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri);
bool handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri);
bool handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri);
bool handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg);
bool s1ap_tx_pdu(srslte::byte_buffer_t* pdu, struct sctp_sndrcvinfo* enb_sri);
bool handle_s1ap_rx_pdu(srslte::byte_buffer_t* pdu, struct sctp_sndrcvinfo* enb_sri);
bool handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* msg, struct sctp_sndrcvinfo* enb_sri);
bool handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT* msg);
void activate_eps_bearer(uint64_t imsi, uint8_t ebi);
void print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx);
void print_enb_ctx_info(const std::string& prefix, const enb_ctx_t& enb_ctx);
uint32_t get_plmn();
uint32_t get_next_mme_ue_s1ap_id();
uint32_t get_plmn();
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);
void get_enb_ctx(uint16_t sctp_stream);
void add_new_enb_ctx(const enb_ctx_t& enb_ctx, const struct sctp_sndrcvinfo* enb_sri);
void get_enb_ctx(uint16_t sctp_stream);
bool add_nas_ctx_to_imsi_map(nas *nas_ctx);
bool add_nas_ctx_to_mme_ue_s1ap_id_map(nas *nas_ctx);
bool add_nas_ctx_to_imsi_map(nas* nas_ctx);
bool add_nas_ctx_to_mme_ue_s1ap_id_map(nas* nas_ctx);
bool add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id);
virtual nas* find_nas_ctx_from_imsi(uint64_t imsi);
nas* find_nas_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id);
nas* find_nas_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(int32_t enb_assoc);
bool release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id);
void release_ues_ecm_ctx_in_enb(int32_t enb_assoc);
virtual bool delete_ue_ctx(uint64_t imsi);
uint32_t allocate_m_tmsi(uint64_t imsi);
uint32_t allocate_m_tmsi(uint64_t imsi);
virtual uint64_t find_imsi_from_m_tmsi(uint32_t m_tmsi);
s1ap_args_t m_s1ap_args;
srslte::log_filter *m_s1ap_log;
srslte::log_filter *m_nas_log;
s1ap_args_t m_s1ap_args;
srslte::log_filter* m_s1ap_log;
srslte::log_filter* m_nas_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_mngmt_proc* m_s1ap_mngmt_proc;
s1ap_nas_transport* m_s1ap_nas_transport;
s1ap_ctx_mngmt_proc* m_s1ap_ctx_mngmt_proc;
std::map<uint32_t, uint64_t> m_tmsi_to_imsi;
std::map<uint32_t, uint64_t> m_tmsi_to_imsi;
//Interfaces
// Interfaces
virtual bool send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup);
virtual bool send_ue_context_release_command(uint32_t mme_ue_s1ap_id);
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri);
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri);
private:
s1ap();
virtual ~s1ap();
static s1ap *m_instance;
static s1ap* m_instance;
uint32_t m_plmn;
srslte::byte_buffer_pool *m_pool;
uint32_t m_plmn;
srslte::byte_buffer_pool* m_pool;
hss_interface_nas *m_hss;
int m_s1mme;
std::map<uint16_t, enb_ctx_t*> m_active_enbs;
std::map<int32_t, uint16_t> m_sctp_to_enb_id;
std::map<int32_t,std::set<uint32_t> > m_enb_assoc_to_ue_ids;
hss_interface_nas* m_hss;
int m_s1mme;
std::map<uint16_t, enb_ctx_t*> m_active_enbs;
std::map<int32_t, uint16_t> m_sctp_to_enb_id;
std::map<int32_t, std::set<uint32_t> > m_enb_assoc_to_ue_ids;
std::map<uint64_t, nas*> m_imsi_to_nas_ctx;
std::map<uint32_t, nas*> m_mme_ue_s1ap_id_to_nas_ctx;
std::map<uint64_t, nas*> m_imsi_to_nas_ctx;
std::map<uint32_t, nas*> m_mme_ue_s1ap_id_to_nas_ctx;
uint32_t m_next_mme_ue_s1ap_id;
uint32_t m_next_m_tmsi;
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, when the packaging of GTP-C messages is done.
mme_gtpc *m_mme_gtpc;
// FIXME the GTP-C should be moved to the MME class, when the packaging of GTP-C messages is done.
mme_gtpc* m_mme_gtpc;
//PCAP
// PCAP
bool m_pcap_enable;
srslte::s1ap_pcap m_pcap;
};
inline uint32_t
s1ap::get_plmn()
inline uint32_t s1ap::get_plmn()
{
return m_plmn;
}
} //namespace srsepc
} // namespace srsepc
#endif // SRSEPC_S1AP_H

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

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

@ -41,7 +41,7 @@
#include "srslte/common/threads.h"
#include "srslte/asn1/gtpc.h"
namespace srsepc{
namespace srsepc {
class mme_gtpc;
@ -53,64 +53,61 @@ typedef struct {
std::string sgi_if_name;
} spgw_args_t;
typedef struct spgw_tunnel_ctx {
uint64_t imsi;
in_addr_t ue_ipv4;
uint8_t ebi;
struct srslte::gtpc_f_teid_ie up_ctrl_fteid;
struct srslte::gtpc_f_teid_ie up_user_fteid;
struct srslte::gtpc_f_teid_ie dw_ctrl_fteid;
struct srslte::gtpc_f_teid_ie dw_user_fteid;
uint64_t imsi;
in_addr_t ue_ipv4;
uint8_t ebi;
srslte::gtp_fteid_t up_ctrl_fteid;
srslte::gtp_fteid_t up_user_fteid;
srslte::gtp_fteid_t dw_ctrl_fteid;
srslte::gtp_fteid_t dw_user_fteid;
} spgw_tunnel_ctx_t;
class spgw:
public thread
class spgw : public thread
{
public:
static spgw* get_instance(void);
static void cleanup(void);
int init(spgw_args_t* args, srslte::log_filter *spgw_log);
void stop();
void run_thread();
static void cleanup(void);
int init(spgw_args_t* args, srslte::log_filter* spgw_log);
void stop();
void run_thread();
void handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu);
void handle_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_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);
void handle_sgi_pdu(srslte::byte_buffer_t* msg);
void handle_s1u_pdu(srslte::byte_buffer_t* msg);
private:
spgw();
virtual ~spgw();
static spgw *m_instance;
static spgw* m_instance;
srslte::error_t init_sgi_if(spgw_args_t *args);
srslte::error_t init_s1u(spgw_args_t *args);
srslte::error_t init_ue_ip(spgw_args_t *args);
srslte::error_t init_sgi_if(spgw_args_t* args);
srslte::error_t init_s1u(spgw_args_t* args);
srslte::error_t init_ue_ip(spgw_args_t* args);
uint64_t get_new_ctrl_teid();
uint64_t get_new_user_teid();
uint64_t get_new_ctrl_teid();
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;
spgw_tunnel_ctx_t* create_gtp_ctx(struct srslte::gtpc_create_session_request* cs_req);
bool delete_gtp_ctx(uint32_t ctrl_teid);
bool m_running;
srslte::byte_buffer_pool* m_pool;
mme_gtpc* m_mme_gtpc;
bool m_sgi_up;
int m_sgi_if;
int m_sgi_sock;
int m_sgi_if;
int m_sgi_sock;
bool m_s1u_up;
int m_s1u;
int m_s1u;
uint64_t m_next_ctrl_teid;
uint64_t m_next_user_teid;
@ -119,21 +116,19 @@ private:
pthread_mutex_t m_mutex;
std::map<uint64_t,uint32_t> m_imsi_to_ctr_teid; //IMSI to control TEID map. Important to check if UE is previously connected
std::map<uint32_t,spgw_tunnel_ctx*> m_teid_to_tunnel_ctx; //Map control TEID to tunnel ctx. Usefull to get reply ctrl TEID, UE IP, etc.
std::map<in_addr_t,srslte::gtpc_f_teid_ie> m_ip_to_teid; //Map IP to User-plane TEID for downlink traffic
std::map<uint64_t, uint32_t> m_imsi_to_ctr_teid; // IMSI to control TEID map.
// Important to check if UE is previously connected
uint32_t m_h_next_ue_ip;
std::map<uint32_t, spgw_tunnel_ctx*> m_teid_to_tunnel_ctx; // Map control TEID to tunnel ctx.
// Usefull to get reply ctrl TEID, UE IP, etc.
/*Time*/
struct timeval m_t_last_dl;
struct timeval m_t_last_ul;
std::map<in_addr_t, srslte::gtpc_f_teid_ie> m_ip_to_teid; // Map IP to User-plane TEID for downlink traffic
/*Logs*/
srslte::log_filter *m_spgw_log;
uint32_t m_h_next_ue_ip;
/*Logs*/
srslte::log_filter* m_spgw_log;
};
} // namespace srsepc
#endif // SRSEPC_SPGW_H

@ -23,25 +23,22 @@
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <string>
#include <sstream>
#include <iomanip>
#include <inttypes.h> // for printing uint64_t
#include "srsepc/hdr/hss/hss.h"
#include "srslte/common/security.h"
#include <inttypes.h> // for printing uint64_t
#include <iomanip>
#include <sstream>
#include <stdlib.h> /* srand, rand */
#include <string>
#include <time.h>
using namespace srslte;
namespace srsepc{
namespace srsepc {
hss* hss::m_instance = NULL;
hss* hss::m_instance = NULL;
pthread_mutex_t hss_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
hss::hss()
{
m_pool = srslte::byte_buffer_pool::get_instance();
return;
}
@ -50,43 +47,38 @@ hss::~hss()
return;
}
hss*
hss::get_instance(void)
hss* hss::get_instance()
{
pthread_mutex_lock(&hss_instance_mutex);
if(NULL == m_instance) {
if (NULL == m_instance) {
m_instance = new hss();
}
pthread_mutex_unlock(&hss_instance_mutex);
return(m_instance);
return (m_instance);
}
void
hss::cleanup(void)
void hss::cleanup()
{
pthread_mutex_lock(&hss_instance_mutex);
if(NULL != m_instance) {
if (NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&hss_instance_mutex);
}
int
hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
int hss::init(hss_args_t* hss_args, srslte::log_filter* hss_log)
{
srand(time(NULL));
/*Init loggers*/
m_hss_log = hss_log;
/*Set authentication algorithm*/
if(set_auth_algo(hss_args->auth_algo) == false)
{
if (set_auth_algo(hss_args->auth_algo) == false) {
return -1;
}
/*Read user information from DB*/
if(read_db_file(hss_args->db_file) == false)
{
if (read_db_file(hss_args->db_file) == false) {
m_hss_log->console("Error reading user database file %s\n", hss_args->db_file.c_str());
return -1;
}
@ -96,110 +88,92 @@ hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
db_file = hss_args->db_file;
m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s, MCC: %d, MNC: %d\n", hss_args->db_file.c_str(),hss_args->auth_algo.c_str(), mcc, mnc);
m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s, MCC: %d, MNC: %d\n",
hss_args->db_file.c_str(), hss_args->auth_algo.c_str(), mcc, mnc);
m_hss_log->console("HSS Initialized.\n");
return 0;
}
void
hss::stop(void)
void hss::stop()
{
write_db_file(db_file);
std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end())
{
m_hss_log->info("Deleting UE context in HSS. IMSI: %015" PRIu64 "\n", it->second->imsi);
m_hss_log->console("Deleting UE context in HSS. IMSI: %015" PRIu64 "\n", it->second->imsi);
delete it->second;
m_imsi_to_ue_ctx.erase(it++);
}
std::map<uint64_t, hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while (it != m_imsi_to_ue_ctx.end()) {
m_hss_log->info("Deleting UE context in HSS. IMSI: %015" PRIu64 "\n", it->second->imsi);
m_hss_log->console("Deleting UE context in HSS. IMSI: %015" PRIu64 "\n", it->second->imsi);
delete it->second;
m_imsi_to_ue_ctx.erase(it++);
}
return;
}
bool
hss::set_auth_algo(std::string auth_algo)
bool hss::set_auth_algo(std::string auth_algo)
{
if(auth_algo != "xor" && auth_algo != "milenage" )
{
if (auth_algo != "xor" && auth_algo != "milenage") {
m_hss_log->error("Unrecognized authentication algorithm. auth_algo = %s\n", auth_algo.c_str());
return false;
}
if(auth_algo == "xor")
{
if (auth_algo == "xor") {
m_auth_algo = HSS_ALGO_XOR;
}
else
{
} else {
m_auth_algo = HSS_ALGO_MILENAGE;
}
return true;
}
bool
hss::read_db_file(std::string db_filename)
bool hss::read_db_file(std::string db_filename)
{
std::ifstream m_db_file;
m_db_file.open(db_filename.c_str(), std::ifstream::in);
if(!m_db_file.is_open())
{
if (!m_db_file.is_open()) {
return false;
}
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str() );
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str());
std::string line;
while (std::getline(m_db_file, line))
{
if(line[0] != '#')
{
uint column_size = 8;
std::vector<std::string> split = split_string(line,',');
if(split.size() != column_size)
{
while (std::getline(m_db_file, line)) {
if (line[0] != '#') {
uint column_size = 8;
std::vector<std::string> split = split_string(line, ',');
if (split.size() != column_size) {
m_hss_log->error("Error parsing UE database. Wrong number of columns in .csv\n");
m_hss_log->error("Columns: %zd, Expected %d.\n", split.size(), column_size);
return false;
}
hss_ue_ctx_t *ue_ctx = new hss_ue_ctx_t;
ue_ctx->name = split[0];
ue_ctx->imsi = atoll(split[1].c_str());
get_uint_vec_from_hex_str(split[2],ue_ctx->key,16);
if(split[3] == std::string("op"))
{
hss_ue_ctx_t* ue_ctx = new hss_ue_ctx_t;
ue_ctx->name = split[0];
ue_ctx->imsi = atoll(split[1].c_str());
get_uint_vec_from_hex_str(split[2], ue_ctx->key, 16);
if (split[3] == std::string("op")) {
ue_ctx->op_configured = true;
get_uint_vec_from_hex_str(split[4],ue_ctx->op,16);
compute_opc(ue_ctx->key,ue_ctx->op,ue_ctx->opc);
}
else if (split[3] == std::string("opc"))
{
ue_ctx->op_configured =false;
get_uint_vec_from_hex_str(split[4],ue_ctx->opc,16);
}
else
{
get_uint_vec_from_hex_str(split[4], ue_ctx->op, 16);
srslte::compute_opc(ue_ctx->key, ue_ctx->op, ue_ctx->opc);
} else if (split[3] == std::string("opc")) {
ue_ctx->op_configured = false;
get_uint_vec_from_hex_str(split[4], ue_ctx->opc, 16);
} else {
m_hss_log->error("Neither OP nor OPc configured.\n");
return false;
}
get_uint_vec_from_hex_str(split[5],ue_ctx->amf,2);
get_uint_vec_from_hex_str(split[6],ue_ctx->sqn,6);
get_uint_vec_from_hex_str(split[5], ue_ctx->amf, 2);
get_uint_vec_from_hex_str(split[6], ue_ctx->sqn, 6);
m_hss_log->debug("Added user from DB, IMSI: %015" PRIu64 "\n", ue_ctx->imsi);
m_hss_log->debug_hex(ue_ctx->key, 16, "User Key : ");
if(ue_ctx->op_configured){
if (ue_ctx->op_configured) {
m_hss_log->debug_hex(ue_ctx->op, 16, "User OP : ");
}
m_hss_log->debug_hex(ue_ctx->opc, 16, "User OPc : ");
m_hss_log->debug_hex(ue_ctx->amf, 2, "AMF : ");
m_hss_log->debug_hex(ue_ctx->sqn, 6, "SQN : ");
ue_ctx->qci = atoi(split[7].c_str());
m_hss_log->debug("Default Bearer QCI: %d\n",ue_ctx->qci);
m_imsi_to_ue_ctx.insert(std::pair<uint64_t,hss_ue_ctx_t*>(ue_ctx->imsi,ue_ctx));
m_hss_log->debug("Default Bearer QCI: %d\n", ue_ctx->qci);
m_imsi_to_ue_ctx.insert(std::pair<uint64_t, hss_ue_ctx_t*>(ue_ctx->imsi, ue_ctx));
}
}
if(m_db_file.is_open())
{
if (m_db_file.is_open()) {
m_db_file.close();
}
@ -209,19 +183,18 @@ hss::read_db_file(std::string db_filename)
bool hss::write_db_file(std::string db_filename)
{
std::string line;
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t sqn[6];
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t sqn[6];
std::ofstream m_db_file;
m_db_file.open(db_filename.c_str(), std::ofstream::out);
if(!m_db_file.is_open())
{
if (!m_db_file.is_open()) {
return false;
}
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str() );
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str());
//Write comment info
m_db_file << "# " << std::endl
@ -239,86 +212,69 @@ bool hss::write_db_file(std::string db_filename)
<< "# " << std::endl
<< "# Note: Lines starting by '#' are ignored and will be overwritten " << std::endl;
std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end())
{
m_db_file << it->second->name;
m_db_file << ",";
m_db_file << std::setfill('0') << std::setw(15) << it->second->imsi;
m_db_file << ",";
m_db_file << hex_string(it->second->key, 16);
m_db_file << ",";
if(it->second->op_configured){
m_db_file << "op,";
m_db_file << hex_string(it->second->op, 16);
}
else{
m_db_file << "opc,";
m_db_file << hex_string(it->second->opc, 16);
}
m_db_file << ",";
m_db_file << hex_string(it->second->amf, 2);
m_db_file << ",";
m_db_file << hex_string(it->second->sqn, 6);
m_db_file << ",";
m_db_file << it->second->qci;
m_db_file << std::endl;
it++;
}
if(m_db_file.is_open())
{
std::map<uint64_t, hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while (it != m_imsi_to_ue_ctx.end()) {
m_db_file << it->second->name;
m_db_file << ",";
m_db_file << std::setfill('0') << std::setw(15) << it->second->imsi;
m_db_file << ",";
m_db_file << hex_string(it->second->key, 16);
m_db_file << ",";
if (it->second->op_configured) {
m_db_file << "op,";
m_db_file << hex_string(it->second->op, 16);
} else {
m_db_file << "opc,";
m_db_file << hex_string(it->second->opc, 16);
}
m_db_file << ",";
m_db_file << hex_string(it->second->amf, 2);
m_db_file << ",";
m_db_file << hex_string(it->second->sqn, 6);
m_db_file << ",";
m_db_file << it->second->qci;
m_db_file << std::endl;
it++;
}
if (m_db_file.is_open()) {
m_db_file.close();
}
return true;
}
bool
hss::gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
bool hss::gen_auth_info_answer(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres)
{
bool ret = false;
switch (m_auth_algo)
{
case HSS_ALGO_XOR:
ret = gen_auth_info_answer_xor(imsi, k_asme, autn, rand, xres);
break;
case HSS_ALGO_MILENAGE:
ret = gen_auth_info_answer_milenage(imsi, k_asme, autn, rand, xres);
break;
switch (m_auth_algo) {
case HSS_ALGO_XOR:
ret = gen_auth_info_answer_xor(imsi, k_asme, autn, rand, xres);
break;
case HSS_ALGO_MILENAGE:
ret = gen_auth_info_answer_milenage(imsi, k_asme, autn, rand, xres);
break;
}
increment_ue_sqn(imsi);
return ret;
}
bool
hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
bool hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres)
{
uint8_t k[16];
uint8_t amf[2];
uint8_t opc[16];
uint8_t sqn[6];
uint8_t ck[16];
uint8_t ik[16];
uint8_t ak[6];
uint8_t mac[8];
uint8_t ck[16];
uint8_t ik[16];
uint8_t ak[6];
uint8_t mac[8];
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
if (!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn)) {
return false;
}
gen_rand(rand);
security_milenage_f2345( k,
opc,
rand,
xres,
ck,
ik,
ak);
srslte::security_milenage_f2345(k, opc, rand, xres, ck, ik, ak);
m_hss_log->debug_hex(k, 16, "User Key : ");
m_hss_log->debug_hex(opc, 16, "User OPc : ");
@ -328,85 +284,67 @@ hss::gen_auth_info_answer_milenage(uint64_t imsi, uint8_t *k_asme, uint8_t *autn
m_hss_log->debug_hex(ik, 16, "User IK: ");
m_hss_log->debug_hex(ak, 6, "User AK: ");
security_milenage_f1( k,
opc,
rand,
sqn,
amf,
mac);
srslte::security_milenage_f1(k, opc, rand, sqn, amf, mac);
m_hss_log->debug_hex(sqn, 6, "User SQN : ");
m_hss_log->debug_hex(mac, 8, "User MAC : ");
// Generate K_asme
security_generate_k_asme( ck,
ik,
ak,
sqn,
mcc,
mnc,
k_asme);
srslte::security_generate_k_asme(ck, ik, ak, sqn, mcc, mnc, k_asme);
m_hss_log->debug("User MCC : %x MNC : %x \n", mcc, mnc);
m_hss_log->debug_hex(k_asme, 32, "User k_asme : ");
//Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
autn[i] = sqn[i]^ak[i];
// Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for (int i = 0; i < 6; i++) {
autn[i] = sqn[i] ^ ak[i];
}
for(int i=0;i<2;i++)
{
autn[6+i]=amf[i];
for (int i = 0; i < 2; i++) {
autn[6 + i] = amf[i];
}
for(int i=0;i<8;i++)
{
autn[8+i]=mac[i];
for (int i = 0; i < 8; i++) {
autn[8 + i] = mac[i];
}
m_hss_log->debug_hex(autn, 16, "User AUTN: ");
set_last_rand(imsi, rand);
return true;
}
bool
hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
bool hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t* k_asme, uint8_t* autn, uint8_t* rand, uint8_t* xres)
{
uint8_t k[16];
uint8_t amf[2];
uint8_t opc[16];
uint8_t sqn[6];
uint8_t xdout[16];
uint8_t cdout[8];
uint8_t xdout[16];
uint8_t cdout[8];
uint8_t ck[16];
uint8_t ik[16];
uint8_t ak[6];
uint8_t mac[8];
uint8_t ck[16];
uint8_t ik[16];
uint8_t ak[6];
uint8_t mac[8];
int i = 0;
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
if (!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn)) {
return false;
}
gen_rand(rand);
// Use RAND and K to compute RES, CK, IK and AK
for(i=0; i<16; i++) {
xdout[i] = k[i]^rand[i];
for (i = 0; i < 16; i++) {
xdout[i] = k[i] ^ rand[i];
}
for(i=0; i<16; i++) {
xres[i] = xdout[i];
ck[i] = xdout[(i+1)%16];
ik[i] = xdout[(i+2)%16];
for (i = 0; i < 16; i++) {
xres[i] = xdout[i];
ck[i] = xdout[(i + 1) % 16];
ik[i] = xdout[(i + 2) % 16];
}
for(i=0; i<6; i++) {
ak[i] = xdout[i+3];
for (i = 0; i < 6; i++) {
ak[i] = xdout[i + 3];
}
m_hss_log->debug_hex(k, 16, "User Key : ");
@ -418,59 +356,47 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
m_hss_log->debug_hex(ak, 6, "User AK: ");
// Generate cdout
for(i=0; i<6; i++) {
for (i = 0; i < 6; i++) {
cdout[i] = sqn[i];
}
for(i=0; i<2; i++) {
cdout[6+i] = amf[i];
for (i = 0; i < 2; i++) {
cdout[6 + i] = amf[i];
}
// Generate MAC
for(i=0;i<8;i++) {
for (i = 0; i < 8; i++) {
mac[i] = xdout[i] ^ cdout[i];
}
m_hss_log->debug_hex(sqn, 6, "User SQN : ");
m_hss_log->debug_hex(mac, 8, "User MAC : ");
//Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
autn[i] = sqn[i]^ak[i];
// Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for (int i = 0; i < 6; i++) {
autn[i] = sqn[i] ^ ak[i];
}
for(int i=0;i<2;i++)
{
autn[6+i]=amf[i];
for (int i = 0; i < 2; i++) {
autn[6 + i] = amf[i];
}
for(int i=0;i<8;i++)
{
autn[8+i]=mac[i];
for (int i = 0; i < 8; i++) {
autn[8 + i] = mac[i];
}
// Generate K_asme
security_generate_k_asme( ck,
ik,
ak,
sqn,
mcc,
mnc,
k_asme);
srslte::security_generate_k_asme(ck, ik, ak, sqn, mcc, mnc, k_asme);
m_hss_log->debug("User MCC : %x MNC : %x \n", mcc, mnc);
m_hss_log->debug_hex(k_asme, 32, "User k_asme : ");
//Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
autn[i] = sqn[i]^ak[i];
// Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for (int i = 0; i < 6; i++) {
autn[i] = sqn[i] ^ ak[i];
}
for(int i=0;i<2;i++)
{
autn[6+i]=amf[i];
for (int i = 0; i < 2; i++) {
autn[6 + i] = amf[i];
}
for(int i=0;i<8;i++)
{
autn[8+i]=mac[i];
for (int i = 0; i < 8; i++) {
autn[8 + i] = mac[i];
}
m_hss_log->debug_hex(autn, 8, "User AUTN: ");
@ -480,73 +406,60 @@ hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uin
return true;
}
bool
hss::gen_update_loc_answer(uint64_t imsi, uint8_t* qci)
bool hss::gen_update_loc_answer(uint64_t imsi, uint8_t* qci)
{
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n",imsi);
m_hss_log->console("User not found at HSS. IMSI: %015" PRIu64 "\n",imsi);
std::map<uint64_t, hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if (ue_ctx_it == m_imsi_to_ue_ctx.end()) {
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n", imsi);
m_hss_log->console("User not found at HSS. IMSI: %015" PRIu64 "\n", imsi);
return false;
}
hss_ue_ctx_t *ue_ctx = ue_ctx_it->second;
m_hss_log->info("Found User %015" PRIu64 "\n",imsi);
hss_ue_ctx_t* ue_ctx = ue_ctx_it->second;
m_hss_log->info("Found User %015" PRIu64 "\n", imsi);
*qci = ue_ctx->qci;
return true;
}
bool
hss::get_k_amf_opc_sqn(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *opc, uint8_t *sqn)
bool hss::get_k_amf_opc_sqn(uint64_t imsi, uint8_t* k, uint8_t* amf, uint8_t* opc, uint8_t* sqn)
{
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n",imsi);
m_hss_log->console("User not found at HSS. IMSI: %015" PRIu64 "\n",imsi);
std::map<uint64_t, hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if (ue_ctx_it == m_imsi_to_ue_ctx.end()) {
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n", imsi);
m_hss_log->console("User not found at HSS. IMSI: %015" PRIu64 "\n", imsi);
return false;
}
hss_ue_ctx_t *ue_ctx = ue_ctx_it->second;
m_hss_log->info("Found User %015" PRIu64 "\n",imsi);
hss_ue_ctx_t* ue_ctx = ue_ctx_it->second;
m_hss_log->info("Found User %015" PRIu64 "\n", imsi);
memcpy(k, ue_ctx->key, 16);
memcpy(amf, ue_ctx->amf, 2);
memcpy(opc, ue_ctx->opc, 16);
memcpy(sqn, ue_ctx->sqn, 6);
return true;
}
bool
hss::resync_sqn(uint64_t imsi, uint8_t *auts)
bool hss::resync_sqn(uint64_t imsi, uint8_t* auts)
{
bool ret = false;
switch (m_auth_algo)
{
case HSS_ALGO_XOR:
ret = resync_sqn_xor(imsi, auts);
break;
case HSS_ALGO_MILENAGE:
ret = resync_sqn_milenage(imsi, auts);
break;
switch (m_auth_algo) {
case HSS_ALGO_XOR:
ret = resync_sqn_xor(imsi, auts);
break;
case HSS_ALGO_MILENAGE:
ret = resync_sqn_milenage(imsi, auts);
break;
}
increment_seq_after_resync(imsi);
return ret;
}
bool
hss::resync_sqn_xor(uint64_t imsi, uint8_t *auts)
bool hss::resync_sqn_xor(uint64_t imsi, uint8_t* auts)
{
m_hss_log->error("XOR SQN synchronization not supported yet\n");
m_hss_log->console("XOR SQNs synchronization not supported yet\n");
return false;
}
bool
hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
bool hss::resync_sqn_milenage(uint64_t imsi, uint8_t* auts)
{
uint8_t last_rand[16];
uint8_t ak[6];
@ -558,19 +471,18 @@ hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
uint8_t opc[16];
uint8_t sqn[6];
if(!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn))
{
if (!get_k_amf_opc_sqn(imsi, k, amf, opc, sqn)) {
return false;
}
get_last_rand(imsi, last_rand);
for(int i=0; i<6; i++){
for (int i = 0; i < 6; i++) {
sqn_ms_xor_ak[i] = auts[i];
}
for(int i=0; i<8; i++){
mac_s[i] = auts[i+6];
for (int i = 0; i < 8; i++) {
mac_s[i] = auts[i + 6];
}
m_hss_log->debug_hex(k, 16, "User Key : ");
@ -580,62 +492,55 @@ hss::resync_sqn_milenage(uint64_t imsi, uint8_t *auts)
m_hss_log->debug_hex(sqn_ms_xor_ak, 6, "SQN xor AK : ");
m_hss_log->debug_hex(mac_s, 8, "MAC : ");
security_milenage_f5_star(k, opc, last_rand, ak);
srslte::security_milenage_f5_star(k, opc, last_rand, ak);
m_hss_log->debug_hex(ak, 6, "Resynch AK : ");
uint8_t sqn_ms[6];
for(int i=0; i<6; i++){
for (int i = 0; i < 6; i++) {
sqn_ms[i] = sqn_ms_xor_ak[i] ^ ak[i];
}
m_hss_log->debug_hex(sqn_ms, 6, "SQN MS : ");
m_hss_log->debug_hex(sqn , 6, "SQN HE : ");
m_hss_log->debug_hex(sqn, 6, "SQN HE : ");
m_hss_log->debug_hex(amf, 2, "AMF : ");
uint8_t mac_s_tmp[8];
for(int i=0; i<2; i++){
for (int i = 0; i < 2; i++) {
amf[i] = 0;
}
security_milenage_f1_star(k, opc, last_rand, sqn_ms, amf, mac_s_tmp);
srslte::security_milenage_f1_star(k, opc, last_rand, sqn_ms, amf, mac_s_tmp);
m_hss_log->debug_hex(mac_s_tmp, 8, "MAC calc : ");
set_sqn(imsi, sqn_ms);
return true;
}
void
hss::increment_ue_sqn(uint64_t imsi)
void hss::increment_ue_sqn(uint64_t imsi)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if (ret == false) {
return;
}
increment_sqn(ue_ctx->sqn,ue_ctx->sqn);
increment_sqn(ue_ctx->sqn, ue_ctx->sqn);
m_hss_log->debug("Incremented SQN -- IMSI: %015" PRIu64 "\n", imsi);
m_hss_log->debug_hex(ue_ctx->sqn, 6, "SQN: ");
}
void
hss::increment_sqn(uint8_t *sqn, uint8_t *next_sqn)
void hss::increment_sqn(uint8_t* sqn, uint8_t* next_sqn)
{
// The following SQN incrementation function is implemented according to 3GPP TS 33.102 version 11.5.1 Annex C
uint64_t seq;
uint64_t ind;
uint64_t sqn64;
sqn64 =0;
sqn64 = 0;
for(int i=0; i<6; i++)
{
sqn64 |= (uint64_t)sqn[i] << (5-i)*8;
for (int i = 0; i < 6; i++) {
sqn64 |= (uint64_t)sqn[i] << (5 - i) * 8;
}
seq = sqn64 >> LTE_FDD_ENB_IND_HE_N_BITS;
@ -649,40 +554,31 @@ hss::increment_sqn(uint8_t *sqn, uint8_t *next_sqn)
nextind = (ind + 1) % LTE_FDD_ENB_IND_HE_MAX_VALUE;
nextsqn = (nextseq << LTE_FDD_ENB_IND_HE_N_BITS) | nextind;
for(int i=0; i<6; i++)
{
next_sqn[i] = (nextsqn >> (5-i)*8) & 0xFF;
for (int i = 0; i < 6; i++) {
next_sqn[i] = (nextsqn >> (5 - i) * 8) & 0xFF;
}
return;
}
void
hss::increment_seq_after_resync(uint64_t imsi)
void hss::increment_seq_after_resync(uint64_t imsi)
{
// This function only increment the SEQ part of the SQN for resynchronization purpose
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
// This function only increment the SEQ part of the SQN for resynchronization purpose
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if (ret == false) {
return;
}
uint8_t *sqn = ue_ctx->sqn;
uint8_t* sqn = ue_ctx->sqn;
uint64_t seq;
uint64_t ind;
uint64_t sqn64;
sqn64 =0;
sqn64 = 0;
for(int i=0; i<6; i++)
{
sqn64 |= (uint64_t)sqn[i] << (5-i)*8;
for (int i = 0; i < 6; i++) {
sqn64 |= (uint64_t)sqn[i] << (5 - i) * 8;
}
seq = sqn64 >> LTE_FDD_ENB_IND_HE_N_BITS;
@ -694,70 +590,55 @@ hss::increment_seq_after_resync(uint64_t imsi)
nextseq = (seq + 1) % LTE_FDD_ENB_SEQ_HE_MAX_VALUE;
nextsqn = (nextseq << LTE_FDD_ENB_IND_HE_N_BITS) | ind;
for(int i=0; i<6; i++)
{
sqn[i] = (nextsqn >> (5-i)*8) & 0xFF;
for (int i = 0; i < 6; i++) {
sqn[i] = (nextsqn >> (5 - i) * 8) & 0xFF;
}
return;
}
void
hss::set_sqn(uint64_t imsi, uint8_t *sqn)
void hss::set_sqn(uint64_t imsi, uint8_t* sqn)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if (ret == false) {
return;
}
memcpy(ue_ctx->sqn, sqn, 6);
}
void
hss::set_last_rand(uint64_t imsi, uint8_t *rand)
void hss::set_last_rand(uint64_t imsi, uint8_t* rand)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if (ret == false) {
return;
}
memcpy(ue_ctx->last_rand, rand, 16);
}
void
hss::get_last_rand(uint64_t imsi, uint8_t *rand)
void hss::get_last_rand(uint64_t imsi, uint8_t* rand)
{
hss_ue_ctx_t *ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if(ret == false)
{
hss_ue_ctx_t* ue_ctx = NULL;
bool ret = get_ue_ctx(imsi, &ue_ctx);
if (ret == false) {
return;
}
memcpy(rand, ue_ctx->last_rand, 16);
}
void
hss::gen_rand(uint8_t rand_[16])
void hss::gen_rand(uint8_t rand_[16])
{
for(int i=0;i<16;i++)
{
rand_[i]=rand()%256; //Pulls on byte at a time. It's slow, but does not depend on RAND_MAX.
for (int i = 0; i < 16; i++) {
rand_[i] = rand() % 256; // Pulls on byte at a time. It's slow, but does not depend on RAND_MAX.
}
return;
}
bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx)
bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t** ue_ctx)
{
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n",imsi);
std::map<uint64_t, hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if (ue_ctx_it == m_imsi_to_ue_ctx.end()) {
m_hss_log->info("User not found. IMSI: %015" PRIu64 "\n", imsi);
return false;
}
@ -766,43 +647,37 @@ bool hss::get_ue_ctx(uint64_t imsi, hss_ue_ctx_t **ue_ctx)
}
/* Helper functions*/
std::vector<std::string>
hss::split_string(const std::string &str, char delimiter)
std::vector<std::string> hss::split_string(const std::string& str, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(str);
std::string token;
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
while (std::getline(tokenStream, token, delimiter)) {
tokens.push_back(token);
}
return tokens;
}
void
hss::get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len)
void hss::get_uint_vec_from_hex_str(const std::string& key_str, uint8_t* key, uint len)
{
const char *pos = key_str.c_str();
const char* pos = key_str.c_str();
for (uint count = 0; count < len; count++) {
sscanf(pos, "%2hhx", &key[count]);
pos += 2;
}
return;
}
std::string
hss::hex_string(uint8_t *hex, int size)
std::string hss::hex_string(uint8_t* hex, int size)
{
std::stringstream ss;
ss << std::hex << std::setfill('0');
for(int i=0;i<size;i++) {
for (int i = 0; i < size; i++) {
ss << std::setw(2) << static_cast<unsigned>(hex[i]);
}
return ss.str();
}
} //namespace srsepc
} // namespace srsepc

@ -21,20 +21,20 @@
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include <sstream>
#include <fstream>
#include <errno.h>
#include <signal.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "srslte/common/crash_handler.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/config_file.h"
#include "srslte/build_info.h"
#include "srsepc/hdr/mme/mme.h"
#include "srsepc/hdr/hss/hss.h"
#include "srsepc/hdr/mme/mme.h"
#include "srsepc/hdr/spgw/spgw.h"
#include "srslte/build_info.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/config_file.h"
#include "srslte/common/crash_handler.h"
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <errno.h>
#include <fstream>
#include <iostream>
#include <signal.h>
#include <sstream>
using namespace std;
using namespace srsepc;
@ -42,43 +42,41 @@ namespace bpo = boost::program_options;
bool running = true;
void
sig_int_handler(int signo){
void sig_int_handler(int signo)
{
running = false;
}
typedef struct {
std::string nas_level;
int nas_hex_limit;
std::string s1ap_level;
int s1ap_hex_limit;
std::string gtpc_level;
int gtpc_hex_limit;
std::string spgw_level;
int spgw_hex_limit;
std::string hss_level;
int hss_hex_limit;
std::string all_level;
int all_hex_limit;
std::string filename;
}log_args_t;
typedef struct{
mme_args_t mme_args;
hss_args_t hss_args;
spgw_args_t spgw_args;
log_args_t log_args;
}all_args_t;
std::string nas_level;
int nas_hex_limit;
std::string s1ap_level;
int s1ap_hex_limit;
std::string gtpc_level;
int gtpc_hex_limit;
std::string spgw_level;
int spgw_hex_limit;
std::string hss_level;
int hss_hex_limit;
std::string all_level;
int all_hex_limit;
std::string filename;
} log_args_t;
typedef struct {
mme_args_t mme_args;
hss_args_t hss_args;
spgw_args_t spgw_args;
log_args_t log_args;
} all_args_t;
/**********************************************************************
* Program arguments processing
***********************************************************************/
string config_file;
void
parse_args(all_args_t *args, int argc, char* argv[]) {
void parse_args(all_args_t* args, int argc, char* argv[])
{
string mme_name;
string mme_code;
string mme_group;
@ -107,7 +105,6 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
// Command line or config file options
bpo::options_description common("Configuration options");
common.add_options()
("mme.mme_code", bpo::value<string>(&mme_code)->default_value("0x01"), "MME Code")
("mme.name", bpo::value<string>(&mme_name)->default_value("srsmme01"), "MME Name")
("mme.mme_group", bpo::value<string>(&mme_group)->default_value("0x01"), "Cell ID")
@ -136,10 +133,8 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
("log.gtpc_hex_limit", bpo::value<int>(&args->log_args.gtpc_hex_limit), "MME GTPC log hex dump limit")
("log.spgw_level", bpo::value<string>(&args->log_args.spgw_level), "SPGW log level")
("log.spgw_hex_limit", bpo::value<int>(&args->log_args.spgw_hex_limit), "SPGW log hex dump limit")
//("log.gtpu_level", bpo::value<string>(&args->log.gtpu_level), "GTPU log level")
("log.hss_level", bpo::value<string>(&args->log_args.hss_level), "HSS log level")
("log.hss_hex_limit", bpo::value<int>(&args->log_args.hss_hex_limit), "HSS log hex dump limit")
//("log.gtpu_hex_limit",bpo::value<int>(&args->log.gtpu_hex_limit), "GTPU log hex dump limit")
("log.all_level", bpo::value<string>(&args->log_args.all_level)->default_value("info"), "ALL log level")
("log.all_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit")
@ -150,7 +145,7 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
// Positional options - config file location
bpo::options_description position("Positional options");
position.add_options()
("config_file", bpo::value< string >(&config_file), "MME configuration file")
("config_file", bpo::value< string >(&config_file), "MME configuration file")
;
bpo::positional_options_description p;
p.add("config_file", -1);
@ -164,16 +159,16 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
try {
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
bpo::notify(vm);
} catch(bpo::error &e) {
cerr<< e.what() << endl;
} catch (bpo::error& e) {
cerr << e.what() << endl;
exit(1);
}
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
// if no config file given, check users home path
@ -184,10 +179,10 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
}
}
//Parsing Config File
// Parsing Config File
cout << "Reading configuration file " << config_file << "..." << endl;
ifstream conf(config_file.c_str(), ios::in);
if(conf.fail()) {
if (conf.fail()) {
cout << "Failed to read configuration file " << config_file << " - exiting" << endl;
exit(1);
}
@ -212,37 +207,39 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
sstr << std::hex << vm["mme.tac"].as<std::string>();
sstr >> args->mme_args.s1ap_args.tac;
}
// Convert MCC/MNC strings
if(!srslte::string_to_mcc(mcc, &args->mme_args.s1ap_args.mcc)) {
if (!srslte::string_to_mcc(mcc, &args->mme_args.s1ap_args.mcc)) {
cout << "Error parsing mme.mcc:" << mcc << " - must be a 3-digit string." << endl;
}
if(!srslte::string_to_mnc(mnc, &args->mme_args.s1ap_args.mnc)) {
if (!srslte::string_to_mnc(mnc, &args->mme_args.s1ap_args.mnc)) {
cout << "Error parsing mme.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
}
// Convert MCC/MNC strings
if(!srslte::string_to_mcc(mcc, &args->hss_args.mcc)) {
if (!srslte::string_to_mcc(mcc, &args->hss_args.mcc)) {
cout << "Error parsing mme.mcc:" << mcc << " - must be a 3-digit string." << endl;
}
if(!srslte::string_to_mnc(mnc, &args->hss_args.mnc)) {
if (!srslte::string_to_mnc(mnc, &args->hss_args.mnc)) {
cout << "Error parsing mme.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
}
if(boost::iequals(encryption_algo, "eea0")){
if (boost::iequals(encryption_algo, "eea0")) {
args->mme_args.s1ap_args.encryption_algo = srslte::CIPHERING_ALGORITHM_ID_EEA0;
} else if (boost::iequals(encryption_algo, "eea1")){
} else if (boost::iequals(encryption_algo, "eea1")) {
args->mme_args.s1ap_args.encryption_algo = srslte::CIPHERING_ALGORITHM_ID_128_EEA1;
} else if (boost::iequals(encryption_algo, "eea2")){
} else if (boost::iequals(encryption_algo, "eea2")) {
args->mme_args.s1ap_args.encryption_algo = srslte::CIPHERING_ALGORITHM_ID_128_EEA2;
} else{
} else {
args->mme_args.s1ap_args.encryption_algo = srslte::CIPHERING_ALGORITHM_ID_EEA0;
cout << "Error parsing mme.encryption_algo:" << encryption_algo << " - must be EEA0, EEA1, or EEA2." << endl;
cout << "Using default mme.encryption_algo: EEA0" << endl;
}
if (boost::iequals(integrity_algo, "eia0")){
if (boost::iequals(integrity_algo, "eia0")) {
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_EIA0;
cout << "Warning parsing mme.integrity_algo:" << encryption_algo << " - EIA0 will not supported by UEs use EIA1 or EIA2" << endl;
cout << "Warning parsing mme.integrity_algo:" << encryption_algo
<< " - EIA0 will not supported by UEs use EIA1 or EIA2" << endl;
} else if (boost::iequals(integrity_algo, "eia1")) {
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1;
} else if (boost::iequals(integrity_algo, "eia2")) {
@ -254,49 +251,49 @@ 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;
args->spgw_args.sgi_if_name = sgi_if_name;
args->hss_args.db_file = hss_db_file;
args->hss_args.auth_algo = hss_auth_algo;
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;
args->spgw_args.sgi_if_name = sgi_if_name;
args->hss_args.db_file = hss_db_file;
args->hss_args.auth_algo = hss_auth_algo;
// Apply all_level to any unset layers
if (vm.count("log.all_level")) {
if(!vm.count("log.nas_level")) {
if (!vm.count("log.nas_level")) {
args->log_args.nas_level = args->log_args.all_level;
}
if(!vm.count("log.s1ap_level")) {
if (!vm.count("log.s1ap_level")) {
args->log_args.s1ap_level = args->log_args.all_level;
}
if(!vm.count("log.gtpc_level")) {
if (!vm.count("log.gtpc_level")) {
args->log_args.gtpc_level = args->log_args.all_level;
}
if(!vm.count("log.spgw_level")) {
if (!vm.count("log.spgw_level")) {
args->log_args.spgw_level = args->log_args.all_level;
}
if(!vm.count("log.hss_level")) {
if (!vm.count("log.hss_level")) {
args->log_args.hss_level = args->log_args.all_level;
}
}
// Apply all_hex_limit to any unset layers
if (vm.count("log.all_hex_limit")) {
if(!vm.count("log.s1ap_hex_limit")) {
if (!vm.count("log.s1ap_hex_limit")) {
args->log_args.s1ap_hex_limit = args->log_args.all_hex_limit;
}
if(!vm.count("log.gtpc_hex_limit")) {
if (!vm.count("log.gtpc_hex_limit")) {
args->log_args.gtpc_hex_limit = args->log_args.all_hex_limit;
}
if(!vm.count("log.spgw_hex_limit")) {
if (!vm.count("log.spgw_hex_limit")) {
args->log_args.spgw_hex_limit = args->log_args.all_hex_limit;
}
if(!vm.count("log.hss_hex_limit")) {
if (!vm.count("log.hss_hex_limit")) {
args->log_args.hss_hex_limit = args->log_args.all_hex_limit;
}
if(!vm.count("log.nas_hex_limit")) {
if (!vm.count("log.nas_hex_limit")) {
args->log_args.nas_hex_limit = args->log_args.all_hex_limit;
}
}
@ -310,21 +307,20 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
return;
}
srslte::LOG_LEVEL_ENUM
level(std::string l)
srslte::LOG_LEVEL_ENUM level(std::string l)
{
boost::to_upper(l);
if("NONE" == l){
if ("NONE" == l) {
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
} else if ("ERROR" == l) {
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
} else if ("WARNING" == l) {
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
} else if ("INFO" == l) {
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
} else if ("DEBUG" == l) {
return srslte::LOG_LEVEL_DEBUG;
}else{
} else {
return srslte::LOG_LEVEL_NONE;
}
}
@ -349,8 +345,7 @@ std::string get_build_string()
return ss.str();
}
int
main (int argc,char * argv[] )
int main(int argc, char* argv[])
{
signal(SIGINT, sig_int_handler);
signal(SIGTERM, sig_int_handler);
@ -359,15 +354,15 @@ main (int argc,char * argv[] )
// print build info
cout << endl << get_build_string() << endl;
cout << endl <<"--- Software Radio Systems EPC ---" << endl << endl;
cout << endl << "--- Software Radio Systems EPC ---" << endl << endl;
srslte_debug_handle_crash(argc, argv);
all_args_t args;
parse_args(&args, argc, argv);
parse_args(&args, argc, argv);
srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file;
srslte::logger *logger;
srslte::logger* logger;
/*Init logger*/
if (!args.log_args.filename.compare("stdout")) {
@ -381,52 +376,51 @@ main (int argc,char * argv[] )
}
srslte::log_filter nas_log;
nas_log.init("NAS ",logger);
nas_log.init("NAS ", logger);
nas_log.set_level(level(args.log_args.nas_level));
nas_log.set_hex_limit(args.log_args.nas_hex_limit);
srslte::log_filter s1ap_log;
s1ap_log.init("S1AP",logger);
s1ap_log.init("S1AP", logger);
s1ap_log.set_level(level(args.log_args.s1ap_level));
s1ap_log.set_hex_limit(args.log_args.s1ap_hex_limit);
srslte::log_filter mme_gtpc_log;
mme_gtpc_log.init("GTPC",logger);
mme_gtpc_log.init("GTPC", logger);
mme_gtpc_log.set_level(level(args.log_args.gtpc_level));
mme_gtpc_log.set_hex_limit(args.log_args.gtpc_hex_limit);
srslte::log_filter hss_log;
hss_log.init("HSS ",logger);
hss_log.init("HSS ", logger);
hss_log.set_level(level(args.log_args.hss_level));
hss_log.set_hex_limit(args.log_args.hss_hex_limit);
srslte::log_filter spgw_log;
spgw_log.init("SPGW",logger);
spgw_log.init("SPGW", logger);
spgw_log.set_level(level(args.log_args.spgw_level));
spgw_log.set_hex_limit(args.log_args.spgw_hex_limit);
hss *hss = hss::get_instance();
if (hss->init(&args.hss_args,&hss_log)) {
hss* hss = hss::get_instance();
if (hss->init(&args.hss_args, &hss_log)) {
cout << "Error initializing HSS" << endl;
exit(1);
}
mme *mme = mme::get_instance();
if (mme->init(&args.mme_args, &nas_log, &s1ap_log, &mme_gtpc_log, hss)) {
mme* mme = mme::get_instance();
if (mme->init(&args.mme_args, &nas_log, &s1ap_log, &mme_gtpc_log)) {
cout << "Error initializing MME" << endl;
exit(1);
}
spgw *spgw = spgw::get_instance();
if (spgw->init(&args.spgw_args,&spgw_log)) {
spgw* spgw = spgw::get_instance();
if (spgw->init(&args.spgw_args, &spgw_log)) {
cout << "Error initializing SP-GW" << endl;
exit(1);
}
mme->start();
spgw->start();
while(running) {
while (running) {
sleep(1);
}
@ -437,6 +431,6 @@ main (int argc,char * argv[] )
hss->stop();
hss->cleanup();
cout << std::endl <<"--- exiting ---" << endl;
cout << std::endl << "--- exiting ---" << endl;
return 0;
}

@ -24,22 +24,21 @@
*
*/
#include <iostream> //TODO Remove
#include "srsepc/hdr/mme/mme.h"
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <inttypes.h> // for printing uint64_t
#include <netinet/sctp.h>
#include "srsepc/hdr/mme/mme.h"
#include <sys/socket.h>
#include <sys/types.h>
namespace srsepc{
namespace srsepc {
mme* mme::m_instance = NULL;
mme* mme::m_instance = NULL;
pthread_mutex_t mme_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
mme::mme():
m_running(false)
mme::mme() : m_running(false)
{
m_pool = srslte::byte_buffer_pool::get_instance();
m_pool = srslte::byte_buffer_pool::get_instance();
return;
}
@ -48,40 +47,39 @@ mme::~mme()
return;
}
mme*
mme::get_instance(void)
mme* mme::get_instance(void)
{
pthread_mutex_lock(&mme_instance_mutex);
if(NULL == m_instance) {
if (NULL == m_instance) {
m_instance = new mme();
}
pthread_mutex_unlock(&mme_instance_mutex);
return(m_instance);
return (m_instance);
}
void
mme::cleanup(void)
void mme::cleanup(void)
{
pthread_mutex_lock(&mme_instance_mutex);
if(NULL != m_instance) {
if (NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&mme_instance_mutex);
}
int
mme::init(mme_args_t* args, srslte::log_filter *nas_log, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log, hss_interface_nas * hss)
int mme::init(mme_args_t* args,
srslte::log_filter* nas_log,
srslte::log_filter* s1ap_log,
srslte::log_filter* mme_gtpc_log)
{
/*Init logger*/
m_nas_log = nas_log;
m_s1ap_log = s1ap_log;
m_nas_log = nas_log;
m_s1ap_log = s1ap_log;
m_mme_gtpc_log = mme_gtpc_log;
/*Init S1AP*/
m_s1ap = s1ap::get_instance();
if (m_s1ap->init(args->s1ap_args, nas_log, s1ap_log, hss)) {
if (m_s1ap->init(args->s1ap_args, nas_log, s1ap_log)) {
m_s1ap_log->error("Error initializing MME S1APP\n");
exit(-1);
}
@ -99,8 +97,7 @@ mme::init(mme_args_t* args, srslte::log_filter *nas_log, srslte::log_filter *s1a
return 0;
}
void
mme::stop()
void mme::stop()
{
if (m_running) {
m_s1ap->stop();
@ -112,52 +109,49 @@ mme::stop()
return;
}
void
mme::run_thread()
void mme::run_thread()
{
srslte::byte_buffer_t *pdu = m_pool->allocate("mme::run_thread");
uint32_t sz = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET;
srslte::byte_buffer_t* pdu = m_pool->allocate("mme::run_thread");
uint32_t sz = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET;
struct sockaddr_in enb_addr;
struct sockaddr_in enb_addr;
struct sctp_sndrcvinfo sri;
socklen_t fromlen = sizeof(enb_addr);
socklen_t fromlen = sizeof(enb_addr);
bzero(&enb_addr, sizeof(enb_addr));
int rd_sz;
int msg_flags=0;
int msg_flags = 0;
//Mark the thread as running
m_running=true;
// Mark the thread as running
m_running = true;
//Get S1-MME socket
// Get S1-MME socket
int s1mme = m_s1ap->get_s1_mme();
while(m_running)
{
while (m_running) {
m_s1ap_log->debug("Waiting for SCTP Msg\n");
pdu->reset();
rd_sz = sctp_recvmsg(s1mme, pdu->msg, sz,(struct sockaddr*) &enb_addr, &fromlen, &sri, &msg_flags);
if (rd_sz == -1 && errno != EAGAIN){
rd_sz = sctp_recvmsg(s1mme, pdu->msg, sz, (struct sockaddr*)&enb_addr, &fromlen, &sri, &msg_flags);
if (rd_sz == -1 && errno != EAGAIN) {
m_s1ap_log->error("Error reading from SCTP socket: %s", strerror(errno));
}
else if (rd_sz == -1 && errno == EAGAIN){
} else if (rd_sz == -1 && errno == EAGAIN) {
m_s1ap_log->debug("Socket timeout reached");
} else {
if (msg_flags & MSG_NOTIFICATION) {
//Received notification
union sctp_notification *notification = (union sctp_notification*)pdu->msg;
// Received notification
union sctp_notification* notification = (union sctp_notification*)pdu->msg;
m_s1ap_log->debug("SCTP Notification %d\n", notification->sn_header.sn_type);
if (notification->sn_header.sn_type == SCTP_SHUTDOWN_EVENT) {
m_s1ap_log->info("SCTP Association Shutdown. Association: %d\n",sri.sinfo_assoc_id);
m_s1ap_log->console("SCTP Association Shutdown. Association: %d\n",sri.sinfo_assoc_id);
m_s1ap_log->info("SCTP Association Shutdown. Association: %d\n", sri.sinfo_assoc_id);
m_s1ap_log->console("SCTP Association Shutdown. Association: %d\n", sri.sinfo_assoc_id);
m_s1ap->delete_enb_ctx(sri.sinfo_assoc_id);
}
} else {
//Received data
// Received data
pdu->N_bytes = rd_sz;
m_s1ap_log->info("Received S1AP msg. Size: %d\n", pdu->N_bytes);
m_s1ap->handle_s1ap_rx_pdu(pdu,&sri);
m_s1ap->handle_s1ap_rx_pdu(pdu, &sri);
}
}
}
return;
}
} //namespace srsepc
} // namespace srsepc

@ -24,52 +24,48 @@
*
*/
#include <iostream>
#include <inttypes.h> // for printing uint64_t
#include "srslte/asn1/gtpc.h"
#include "srsepc/hdr/mme/mme_gtpc.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/spgw/spgw.h"
#include "srslte/asn1/gtpc.h"
#include <inttypes.h> // for printing uint64_t
namespace srsepc{
namespace srsepc {
mme_gtpc* mme_gtpc::m_instance = NULL;
mme_gtpc* mme_gtpc::m_instance = NULL;
pthread_mutex_t mme_gtpc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
mme_gtpc::mme_gtpc()
{
return;
}
mme_gtpc::~mme_gtpc()
{
return;
}
mme_gtpc*
mme_gtpc::get_instance(void)
mme_gtpc* mme_gtpc::get_instance(void)
{
pthread_mutex_lock(&mme_gtpc_instance_mutex);
if(NULL == m_instance) {
if (NULL == m_instance) {
m_instance = new mme_gtpc();
}
pthread_mutex_unlock(&mme_gtpc_instance_mutex);
return(m_instance);
return (m_instance);
}
void
mme_gtpc::cleanup(void)
void mme_gtpc::cleanup(void)
{
pthread_mutex_lock(&mme_gtpc_instance_mutex);
if(NULL != m_instance) {
if (NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&mme_gtpc_instance_mutex);
}
bool
mme_gtpc::init(srslte::log_filter *mme_gtpc_log)
bool mme_gtpc::init(srslte::log_filter* mme_gtpc_log)
{
/*Init log*/
@ -77,8 +73,7 @@ mme_gtpc::init(srslte::log_filter *mme_gtpc_log)
m_next_ctrl_teid = 1;
m_s1ap = s1ap::get_instance();
m_mme_gtpc_ip = inet_addr("127.0.0.1");//FIXME At the moment, the GTP-C messages are not sent over the wire. So this parameter is not used.
m_s1ap = s1ap::get_instance();
m_spgw = spgw::get_instance();
m_mme_gtpc_log->info("MME GTP-C Initialized\n");
@ -86,32 +81,30 @@ mme_gtpc::init(srslte::log_filter *mme_gtpc_log)
return true;
}
uint32_t
mme_gtpc::get_new_ctrl_teid()
uint32_t mme_gtpc::get_new_ctrl_teid()
{
return m_next_ctrl_teid++; //FIXME Use a Id pool?
return m_next_ctrl_teid++; // FIXME Use a Id pool?
}
bool
mme_gtpc::send_create_session_request(uint64_t imsi)
bool mme_gtpc::send_create_session_request(uint64_t imsi)
{
m_mme_gtpc_log->info("Sending Create Session Request.\n");
m_mme_gtpc_log->console("Sending Create Session Request.\n");
struct srslte::gtpc_pdu cs_req_pdu;
struct srslte::gtpc_create_session_request *cs_req = &cs_req_pdu.choice.create_session_request;
struct srslte::gtpc_pdu cs_req_pdu;
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
// Initialize GTP-C message to zero
bzero(&cs_req_pdu, sizeof(struct srslte::gtpc_pdu));
//Setup GTP-C Header. FIXME: Length, sequence and other fields need to be added.
cs_req_pdu.header.piggyback = false;
// Setup GTP-C Header. FIXME: Length, sequence and other fields need to be added.
cs_req_pdu.header.piggyback = false;
cs_req_pdu.header.teid_present = true;
cs_req_pdu.header.teid = 0; //Send create session request to the butler TEID
cs_req_pdu.header.teid = 0; // Send create session request to the butler TEID
cs_req_pdu.header.type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_REQUEST;
//Setup GTP-C Create Session Request IEs
// Setup GTP-C Create Session Request IEs
cs_req->imsi = imsi;
// Control TEID allocated
cs_req->sender_f_teid.teid = get_new_ctrl_teid();
@ -123,63 +116,63 @@ mme_gtpc::send_create_session_request(uint64_t imsi)
m_mme_gtpc_log->console("Creating Session Response -- MME control TEID: %d\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;
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;
// cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN;
//Bearer QoS
// Bearer QoS
cs_req->eps_bearer_context_created.ebi = 5;
//Check whether this UE is already registed
// Check whether this UE is already registed
std::map<uint64_t, struct gtpc_ctx>::iterator it = m_imsi_to_gtpc_ctx.find(imsi);
if (it != m_imsi_to_gtpc_ctx.end()) {
m_mme_gtpc_log->warning("Create Session Request being called for an UE with an active GTP-C connection.\n");
m_mme_gtpc_log->warning("Deleting previous GTP-C connection.\n");
std::map<uint32_t, uint64_t>::iterator jt = m_mme_ctr_teid_to_imsi.find(it->second.mme_ctr_fteid.teid);
if (jt == m_mme_ctr_teid_to_imsi.end()) {
m_mme_gtpc_log->error("Could not find IMSI from MME Ctrl TEID. MME Ctr TEID: %d\n", it->second.mme_ctr_fteid.teid);
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.
// No need to send delete session request to the SPGW.
// The create session request will be interpreted as a new request and SPGW will delete locally in existing context.
}
//Save RX Control TEID
m_mme_ctr_teid_to_imsi.insert(std::pair<uint32_t,uint64_t>(cs_req->sender_f_teid.teid, imsi));
// Save RX Control TEID
m_mme_ctr_teid_to_imsi.insert(std::pair<uint32_t, uint64_t>(cs_req->sender_f_teid.teid, imsi));
//Save GTP-C context
// Save GTP-C context
gtpc_ctx_t gtpc_ctx;
bzero(&gtpc_ctx,sizeof(gtpc_ctx_t));
bzero(&gtpc_ctx, sizeof(gtpc_ctx_t));
gtpc_ctx.mme_ctr_fteid = cs_req->sender_f_teid;
m_imsi_to_gtpc_ctx.insert(std::pair<uint64_t,gtpc_ctx_t>(imsi,gtpc_ctx));
m_imsi_to_gtpc_ctx.insert(std::pair<uint64_t, gtpc_ctx_t>(imsi, gtpc_ctx));
m_spgw->handle_create_session_request(cs_req, &cs_resp_pdu);
return true;
}
bool
mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
bool mme_gtpc::handle_create_session_response(srslte::gtpc_pdu* cs_resp_pdu)
{
struct srslte::gtpc_create_session_response *cs_resp = & cs_resp_pdu->choice.create_session_response;
struct srslte::gtpc_create_session_response* cs_resp = &cs_resp_pdu->choice.create_session_response;
m_mme_gtpc_log->info("Received Create Session Response\n");
m_mme_gtpc_log->console("Received Create Session Response\n");
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 error
return false;
m_mme_gtpc_log->warning("Could not create GTPC session. Not a create session response\n");
// TODO Handle error
return false;
}
if (cs_resp->cause.cause_value != srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED) {
m_mme_gtpc_log->warning("Could not create GTPC session. Create Session Request not accepted\n");
//TODO Handle error
// TODO Handle error
return false;
}
//Get IMSI from the control TEID
std::map<uint32_t,uint64_t>::iterator id_it = m_mme_ctr_teid_to_imsi.find(cs_resp_pdu->header.teid);
if(id_it == m_mme_ctr_teid_to_imsi.end()) {
// Get IMSI from the control TEID
std::map<uint32_t, uint64_t>::iterator id_it = m_mme_ctr_teid_to_imsi.find(cs_resp_pdu->header.teid);
if (id_it == m_mme_ctr_teid_to_imsi.end()) {
m_mme_gtpc_log->warning("Could not find IMSI from Ctrl TEID.\n");
return false;
}
@ -187,13 +180,13 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
m_mme_gtpc_log->info("MME GTPC Ctrl TEID %" PRIu64 ", IMSI %" PRIu64 "\n", cs_resp_pdu->header.teid, imsi);
//Get S-GW Control F-TEID
// Get S-GW Control F-TEID
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
sgw_ctr_fteid.ipv4 = 0; // FIXME This is not used for now. In the future it will be obtained from the socket addr_info
//Get S-GW S1-u F-TEID
if (cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present == false){
// 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 false;
}
@ -204,7 +197,7 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
m_mme_gtpc_log->console("Create Session Response -- SPGW S1-U Address: %s\n", inet_ntoa(s1u_addr));
m_mme_gtpc_log->info("Create Session Response -- SPGW S1-U Address: %s\n", inet_ntoa(s1u_addr));
//Check UE Ipv4 address was allocated
// Check UE Ipv4 address was allocated
if (cs_resp->paa_present != true) {
m_mme_gtpc_log->error("PDN Adress Allocation not present\n");
return false;
@ -214,79 +207,76 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
return false;
}
//Save create session response info to E-RAB context
nas *nas_ctx = m_s1ap->find_nas_ctx_from_imsi(imsi);
if(nas_ctx == NULL){
// Save create session response info to E-RAB context
nas* nas_ctx = m_s1ap->find_nas_ctx_from_imsi(imsi);
if (nas_ctx == NULL) {
m_mme_gtpc_log->error("Could not find UE context. IMSI %015lu\n", imsi);
return false;
}
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx;
emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
//Save UE IP to nas ctxt
// Save UE IP to nas ctxt
emm_ctx->ue_ip.s_addr = cs_resp->paa.ipv4;
m_mme_gtpc_log->console("SPGW Allocated IP %s to ISMI %015lu\n",inet_ntoa(emm_ctx->ue_ip),emm_ctx->imsi);
//Save SGW ctrl F-TEID in GTP-C context
std::map<uint64_t,struct gtpc_ctx>::iterator it_g = m_imsi_to_gtpc_ctx.find(imsi);
if(it_g == m_imsi_to_gtpc_ctx.end()) {
//Could not find GTP-C Context
m_mme_gtpc_log->console("SPGW Allocated IP %s to ISMI %015lu\n", inet_ntoa(emm_ctx->ue_ip), emm_ctx->imsi);
// Save SGW ctrl F-TEID in GTP-C context
std::map<uint64_t, struct gtpc_ctx>::iterator it_g = m_imsi_to_gtpc_ctx.find(imsi);
if (it_g == m_imsi_to_gtpc_ctx.end()) {
// Could not find GTP-C Context
m_mme_gtpc_log->error("Could not find GTP-C context\n");
return false;
}
gtpc_ctx_t *gtpc_ctx = &it_g->second;
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;
esm_ctx_t *esm_ctx = &nas_ctx->m_esm_ctx[default_bearer];
esm_ctx->pdn_addr_alloc= cs_resp->paa;
esm_ctx->sgw_s1u_fteid = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid;
// Set EPS bearer context
// FIXME default EPS bearer is hard-coded
int default_bearer = 5;
esm_ctx_t* esm_ctx = &nas_ctx->m_esm_ctx[default_bearer];
esm_ctx->pdn_addr_alloc = cs_resp->paa;
esm_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(nas_ctx, default_bearer);
return true;
}
bool
mme_gtpc::send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t *enb_fteid)
bool mme_gtpc::send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t* enb_fteid)
{
m_mme_gtpc_log->info("Sending GTP-C Modify bearer request\n");
srslte::gtpc_pdu mb_req_pdu;
std::map<uint64_t,gtpc_ctx_t>::iterator it = m_imsi_to_gtpc_ctx.find(imsi);
std::map<uint64_t, gtpc_ctx_t>::iterator it = m_imsi_to_gtpc_ctx.find(imsi);
if (it == m_imsi_to_gtpc_ctx.end()) {
m_mme_gtpc_log->error("Modify bearer request for UE without GTP-C connection\n");
return false;
}
srslte::gtp_fteid_t sgw_ctr_fteid = it->second.sgw_ctr_fteid;
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_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST;
srslte::gtpc_header* header = &mb_req_pdu.header;
header->teid_present = true;
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;
mb_req->eps_bearer_context_to_modify.ebi = erab_to_modify;
srslte::gtpc_modify_bearer_request* mb_req = &mb_req_pdu.choice.modify_bearer_request;
mb_req->eps_bearer_context_to_modify.ebi = erab_to_modify;
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_ctr_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) );
m_mme_gtpc_log->info("GTP-C Modify bearer request -- S1-U TEID 0x%x, IP %s\n", enb_fteid->teid, inet_ntoa(addr));
//
srslte::gtpc_pdu mb_resp_pdu;
m_spgw->handle_modify_bearer_request(&mb_req_pdu,&mb_resp_pdu);
m_spgw->handle_modify_bearer_request(&mb_req_pdu, &mb_resp_pdu);
handle_modify_bearer_response(&mb_resp_pdu);
return true;
}
void
mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu)
void mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu* mb_resp_pdu)
{
uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid;
std::map<uint32_t,uint64_t>::iterator imsi_it = m_mme_ctr_teid_to_imsi.find(mme_ctrl_teid);
uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid;
std::map<uint32_t, uint64_t>::iterator imsi_it = m_mme_ctr_teid_to_imsi.find(mme_ctrl_teid);
if (imsi_it == m_mme_ctr_teid_to_imsi.end()) {
m_mme_gtpc_log->error("Could not find IMSI from control TEID\n");
return;
@ -294,44 +284,43 @@ mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu)
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(imsi_it->second,ebi);
m_s1ap->activate_eps_bearer(imsi_it->second, ebi);
return;
}
bool
mme_gtpc::send_delete_session_request(uint64_t imsi)
bool mme_gtpc::send_delete_session_request(uint64_t imsi)
{
m_mme_gtpc_log->info("Sending GTP-C Delete Session Request request. IMSI %" PRIu64 "\n",imsi);
srslte::gtpc_pdu del_req_pdu;
m_mme_gtpc_log->info("Sending GTP-C Delete Session Request request. IMSI %" PRIu64 "\n", imsi);
srslte::gtpc_pdu del_req_pdu;
srslte::gtp_fteid_t sgw_ctr_fteid;
srslte::gtp_fteid_t mme_ctr_fteid;
//Get S-GW Ctr TEID
std::map<uint64_t,gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi);
// Get S-GW Ctr TEID
std::map<uint64_t, gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi);
if (it_ctx == m_imsi_to_gtpc_ctx.end()) {
m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
return false;
m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
return false;
}
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_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_DELETE_SESSION_REQUEST;
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_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_ctr_fteid.teid );
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_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
// TODO Handle delete session response
//Delete GTP-C context
std::map<uint32_t,uint64_t>::iterator it_imsi = m_mme_ctr_teid_to_imsi.find(mme_ctr_fteid.teid);
// Delete GTP-C context
std::map<uint32_t, uint64_t>::iterator it_imsi = m_mme_ctr_teid_to_imsi.find(mme_ctr_fteid.teid);
if (it_imsi == m_mme_ctr_teid_to_imsi.end()) {
m_mme_gtpc_log->error("Could not find IMSI from MME ctr TEID");
} else {
@ -341,35 +330,33 @@ mme_gtpc::send_delete_session_request(uint64_t imsi)
return true;
}
void
mme_gtpc::send_release_access_bearers_request(uint64_t imsi)
void mme_gtpc::send_release_access_bearers_request(uint64_t imsi)
{
m_mme_gtpc_log->info("Sending GTP-C Delete Access Bearers Request\n");
srslte::gtpc_pdu rel_req_pdu;
srslte::gtpc_pdu rel_req_pdu;
srslte::gtp_fteid_t sgw_ctr_fteid;
//Get S-GW Ctr TEID
std::map<uint64_t,gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi);
if(it_ctx == m_imsi_to_gtpc_ctx.end())
{
// Get S-GW Ctr TEID
std::map<uint64_t, gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi);
if (it_ctx == m_imsi_to_gtpc_ctx.end()) {
m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
return;
}
sgw_ctr_fteid = it_ctx->second.sgw_ctr_fteid;
//Set GTP-C header
srslte::gtpc_header *header = &rel_req_pdu.header;
header->teid_present = true;
header->teid = sgw_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_REQUEST;
// 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_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.
// The GTP-C connection will not be torn down, just the user plane bearers.
return;
}
} //namespace srsepc
} // namespace srsepc

File diff suppressed because it is too large Load Diff

@ -24,98 +24,92 @@
*
*/
#include <iostream>
#include <cmath>
#include <inttypes.h> // for printing uint64_t
#include "srslte/common/bcd_helpers.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/liblte_security.h"
#include <cmath>
#include <inttypes.h> // for printing uint64_t
namespace srsepc{
namespace srsepc {
s1ap* s1ap::m_instance = NULL;
s1ap* s1ap::m_instance = NULL;
pthread_mutex_t s1ap_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap::s1ap():
m_s1mme(-1),
m_next_mme_ue_s1ap_id(1),
m_mme_gtpc(NULL),
m_pool(NULL)
s1ap::s1ap() : m_s1mme(-1), m_next_mme_ue_s1ap_id(1), m_mme_gtpc(NULL), m_pool(NULL)
{
return;
}
s1ap::~s1ap()
{
return;
}
s1ap*
s1ap::get_instance(void)
s1ap* s1ap::get_instance(void)
{
pthread_mutex_lock(&s1ap_instance_mutex);
if(m_instance == NULL) {
if (m_instance == NULL) {
m_instance = new s1ap();
}
pthread_mutex_unlock(&s1ap_instance_mutex);
return(m_instance);
return (m_instance);
}
void
s1ap::cleanup(void)
void s1ap::cleanup(void)
{
pthread_mutex_lock(&s1ap_instance_mutex);
if(NULL != m_instance) {
if (NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&s1ap_instance_mutex);
}
int
s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *nas_log, srslte::log_filter *s1ap_log, hss_interface_nas * hss)
int s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter* nas_log, srslte::log_filter* s1ap_log)
{
m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_args = s1ap_args;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &m_plmn);
m_next_m_tmsi = rand();
//Init log
m_nas_log = nas_log;
// Init log
m_nas_log = nas_log;
m_s1ap_log = s1ap_log;
//Get pointer to the HSS
m_hss = hss;
// Get pointer to the HSS
m_hss = hss::get_instance();
//Init message handlers
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures
// Init message handlers
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); // Managment procedures
m_s1ap_mngmt_proc->init();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures
m_s1ap_nas_transport->init(m_hss);
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); // NAS Transport procedures
m_s1ap_nas_transport->init();
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); // Context Management Procedures
m_s1ap_ctx_mngmt_proc->init();
//Get pointer to GTP-C class
// Get pointer to GTP-C class
m_mme_gtpc = mme_gtpc::get_instance();
//Initialize S1-MME
// Initialize S1-MME
m_s1mme = enb_listen();
//Init PCAP
// Init PCAP
m_pcap_enable = s1ap_args.pcap_enable;
if(m_pcap_enable){
if (m_pcap_enable) {
m_pcap.open(s1ap_args.pcap_filename.c_str());
}
m_s1ap_log->info("S1AP Initialized\n");
return 0;
}
void
s1ap::stop()
void s1ap::stop()
{
if (m_s1mme != -1){
if (m_s1mme != -1) {
close(m_s1mme);
}
std::map<uint16_t,enb_ctx_t*>::iterator enb_it = m_active_enbs.begin();
while (enb_it!=m_active_enbs.end()) {
std::map<uint16_t, enb_ctx_t*>::iterator enb_it = m_active_enbs.begin();
while (enb_it != m_active_enbs.end()) {
m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", 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;
@ -123,81 +117,76 @@ s1ap::stop()
}
std::map<uint64_t, nas*>::iterator ue_it = m_imsi_to_nas_ctx.begin();
while (ue_it!=m_imsi_to_nas_ctx.end()) {
while (ue_it != m_imsi_to_nas_ctx.end()) {
m_s1ap_log->info("Deleting UE EMM context. IMSI: %015" PRIu64 "\n", ue_it->first);
m_s1ap_log->console("Deleting UE EMM context. IMSI: %015" PRIu64 "\n", ue_it->first);
delete ue_it->second;
m_imsi_to_nas_ctx.erase(ue_it++);
}
//Cleanup message handlers
// Cleanup message handlers
s1ap_mngmt_proc::cleanup();
s1ap_nas_transport::cleanup();
s1ap_ctx_mngmt_proc::cleanup();
//PCAP
if(m_pcap_enable){
// PCAP
if (m_pcap_enable) {
m_pcap.close();
}
return;
}
int
s1ap::get_s1_mme()
int s1ap::get_s1_mme()
{
return m_s1mme;
}
uint32_t
s1ap::get_next_mme_ue_s1ap_id()
uint32_t s1ap::get_next_mme_ue_s1ap_id()
{
return m_next_mme_ue_s1ap_id++;
return m_next_mme_ue_s1ap_id++;
}
int
s1ap::enb_listen()
int s1ap::enb_listen()
{
/*This function sets up the SCTP socket for eNBs to connect to*/
int sock_fd, err;
struct sockaddr_in s1mme_addr;
int sock_fd, err;
struct sockaddr_in s1mme_addr;
struct sctp_event_subscribe evnts;
m_s1ap_log->info("S1-MME Initializing\n");
sock_fd = socket (AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (sock_fd == -1){
m_s1ap_log->console("Could not create SCTP socket\n");
sock_fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (sock_fd == -1) {
m_s1ap_log->console("Could not create SCTP socket\n");
return -1;
}
//Sets the data_io_event to be able to use sendrecv_info
//Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown
bzero (&evnts, sizeof (evnts)) ;
evnts.sctp_data_io_event = 1;
evnts.sctp_shutdown_event=1;
if(setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof (evnts))){
// Sets the data_io_event to be able to use sendrecv_info
// Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown
bzero(&evnts, sizeof(evnts));
evnts.sctp_data_io_event = 1;
evnts.sctp_shutdown_event = 1;
if (setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts))) {
close(sock_fd);
m_s1ap_log->console("Subscribing to sctp_data_io_events failed\n");
return -1;
}
//S1-MME bind
// S1-MME bind
bzero(&s1mme_addr, sizeof(s1mme_addr));
s1mme_addr.sin_family = AF_INET;
inet_pton(AF_INET, m_s1ap_args.mme_bind_addr.c_str(), &(s1mme_addr.sin_addr) );
inet_pton(AF_INET, m_s1ap_args.mme_bind_addr.c_str(), &(s1mme_addr.sin_addr));
s1mme_addr.sin_port = htons(S1MME_PORT);
err = bind(sock_fd, (struct sockaddr*) &s1mme_addr, sizeof (s1mme_addr));
if (err != 0){
err = bind(sock_fd, (struct sockaddr*)&s1mme_addr, sizeof(s1mme_addr));
if (err != 0) {
close(sock_fd);
m_s1ap_log->error("Error binding SCTP socket\n");
m_s1ap_log->console("Error binding SCTP socket\n");
return -1;
}
//Listen for connections
err = listen(sock_fd,SOMAXCONN);
if (err != 0){
// Listen for connections
err = listen(sock_fd, SOMAXCONN);
if (err != 0) {
close(sock_fd);
m_s1ap_log->error("Error in SCTP socket listen\n");
m_s1ap_log->console("Error in SCTP socket listen\n");
@ -207,88 +196,89 @@ s1ap::enb_listen()
return sock_fd;
}
bool
s1ap::s1ap_tx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri)
bool s1ap::s1ap_tx_pdu(srslte::byte_buffer_t* pdu, struct sctp_sndrcvinfo* enb_sri)
{
ssize_t n_sent = sctp_send(m_s1mme, pdu->msg, pdu->N_bytes, enb_sri, 0);
if(n_sent == -1){
if (n_sent == -1) {
m_s1ap_log->console("Failed to send S1AP PDU.\n");
m_s1ap_log->error("Failed to send S1AP PDU. \n");
return false;
}
if(m_pcap_enable){
m_pcap.write_s1ap(pdu->msg,pdu->N_bytes);
if (m_pcap_enable) {
m_pcap.write_s1ap(pdu->msg, pdu->N_bytes);
}
return true;
}
bool
s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri)
bool s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t* pdu, struct sctp_sndrcvinfo* enb_sri)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT rx_pdu;
if(liblte_s1ap_unpack_s1ap_pdu((LIBLTE_BYTE_MSG_STRUCT*)pdu, &rx_pdu) != LIBLTE_SUCCESS) {
if (liblte_s1ap_unpack_s1ap_pdu((LIBLTE_BYTE_MSG_STRUCT*)pdu, &rx_pdu) != LIBLTE_SUCCESS) {
m_s1ap_log->error("Failed to unpack received PDU\n");
return false;
}
if(m_pcap_enable){
m_pcap.write_s1ap(pdu->msg,pdu->N_bytes);
}
switch(rx_pdu.choice_type) {
case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE:
m_s1ap_log->info("Received initiating PDU\n");
return handle_initiating_message(&rx_pdu.choice.initiatingMessage, enb_sri);
break;
case LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME:
m_s1ap_log->info("Received Succeseful Outcome PDU\n");
return handle_successful_outcome(&rx_pdu.choice.successfulOutcome);
break;
case LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME:
m_s1ap_log->info("Received Unsucceseful Outcome PDU\n");
return true;//TODO handle_unsuccessfuloutcome(&rx_pdu.choice.unsuccessfulOutcome);
break;
default:
m_s1ap_log->error("Unhandled PDU type %d\n", rx_pdu.choice_type);
return false;
if (m_pcap_enable) {
m_pcap.write_s1ap(pdu->msg, pdu->N_bytes);
}
switch (rx_pdu.choice_type) {
case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE:
m_s1ap_log->info("Received initiating PDU\n");
return handle_initiating_message(&rx_pdu.choice.initiatingMessage, enb_sri);
break;
case LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME:
m_s1ap_log->info("Received Succeseful Outcome PDU\n");
return handle_successful_outcome(&rx_pdu.choice.successfulOutcome);
break;
case LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME:
m_s1ap_log->info("Received Unsucceseful Outcome PDU\n");
return true; // TODO handle_unsuccessfuloutcome(&rx_pdu.choice.unsuccessfulOutcome);
break;
default:
m_s1ap_log->error("Unhandled PDU type %d\n", rx_pdu.choice_type);
return false;
}
return true;
}
bool
s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri)
bool s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* msg, struct sctp_sndrcvinfo* enb_sri)
{
bool reply_flag = false;
srslte::byte_buffer_t * reply_buffer = m_pool->allocate();
bool ret = false;
switch(msg->choice_type) {
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST:
m_s1ap_log->info("Received S1 Setup Request.\n");
m_s1ap_mngmt_proc->handle_s1_setup_request(&msg->choice.S1SetupRequest, enb_sri, reply_buffer, &reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE:
m_s1ap_log->info("Received Initial UE Message.\n");
m_s1ap_nas_transport->handle_initial_ue_message(&msg->choice.InitialUEMessage, enb_sri, reply_buffer, &reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT:
m_s1ap_log->info("Received Uplink NAS Transport Message.\n");
m_s1ap_nas_transport->handle_uplink_nas_transport(&msg->choice.UplinkNASTransport, enb_sri, reply_buffer, &reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST:
m_s1ap_log->info("Received UE Context Release Request Message.\n");
m_s1ap_ctx_mngmt_proc->handle_ue_context_release_request(&msg->choice.UEContextReleaseRequest, enb_sri, reply_buffer, &reply_flag);
break;
default:
m_s1ap_log->error("Unhandled S1AP intiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
m_s1ap_log->console("Unhandled S1APintiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
}
//Send Reply to eNB
if(reply_flag == true){
bool reply_flag = false;
srslte::byte_buffer_t* reply_buffer = m_pool->allocate();
bool ret = false;
switch (msg->choice_type) {
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST:
m_s1ap_log->info("Received S1 Setup Request.\n");
m_s1ap_mngmt_proc->handle_s1_setup_request(&msg->choice.S1SetupRequest, enb_sri, reply_buffer, &reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE:
m_s1ap_log->info("Received Initial UE Message.\n");
m_s1ap_nas_transport->handle_initial_ue_message(&msg->choice.InitialUEMessage, enb_sri, reply_buffer,
&reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT:
m_s1ap_log->info("Received Uplink NAS Transport Message.\n");
m_s1ap_nas_transport->handle_uplink_nas_transport(&msg->choice.UplinkNASTransport, enb_sri, reply_buffer,
&reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST:
m_s1ap_log->info("Received UE Context Release Request Message.\n");
m_s1ap_ctx_mngmt_proc->handle_ue_context_release_request(&msg->choice.UEContextReleaseRequest, enb_sri,
reply_buffer, &reply_flag);
break;
default:
m_s1ap_log->error("Unhandled S1AP intiating message: %s\n",
liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
m_s1ap_log->console("Unhandled S1APintiating message: %s\n",
liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
}
// Send Reply to eNB
if (reply_flag == true) {
ret = s1ap_tx_pdu(reply_buffer, enb_sri);
}
@ -296,101 +286,91 @@ s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, stru
return ret;
}
bool
s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
bool s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT* msg)
{
switch(msg->choice_type) {
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE:
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]);
switch (msg->choice_type) {
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;
}
//eNB Context Managment
void
s1ap::add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo *enb_sri)
// eNB Context Managment
void s1ap::add_new_enb_ctx(const enb_ctx_t& enb_ctx, const struct sctp_sndrcvinfo* enb_sri)
{
m_s1ap_log->info("Adding new eNB context. eNB ID %d\n", enb_ctx.enb_id);
std::set<uint32_t> ue_set;
enb_ctx_t *enb_ptr = new enb_ctx_t;
memcpy(enb_ptr,&enb_ctx,sizeof(enb_ctx_t));
m_active_enbs.insert(std::pair<uint16_t,enb_ctx_t*>(enb_ptr->enb_id,enb_ptr));
m_sctp_to_enb_id.insert(std::pair<int32_t,uint16_t>(enb_sri->sinfo_assoc_id, enb_ptr->enb_id));
m_enb_assoc_to_ue_ids.insert(std::pair<int32_t,std::set<uint32_t> >(enb_sri->sinfo_assoc_id,ue_set));
enb_ctx_t* enb_ptr = new enb_ctx_t;
memcpy(enb_ptr, &enb_ctx, sizeof(enb_ctx_t));
m_active_enbs.insert(std::pair<uint16_t, enb_ctx_t*>(enb_ptr->enb_id, enb_ptr));
m_sctp_to_enb_id.insert(std::pair<int32_t, uint16_t>(enb_sri->sinfo_assoc_id, enb_ptr->enb_id));
m_enb_assoc_to_ue_ids.insert(std::pair<int32_t, std::set<uint32_t> >(enb_sri->sinfo_assoc_id, ue_set));
return;
}
enb_ctx_t*
s1ap::find_enb_ctx(uint16_t enb_id)
enb_ctx_t* s1ap::find_enb_ctx(uint16_t enb_id)
{
std::map<uint16_t,enb_ctx_t*>::iterator it = m_active_enbs.find(enb_id);
if(it == m_active_enbs.end())
{
std::map<uint16_t, enb_ctx_t*>::iterator it = m_active_enbs.find(enb_id);
if (it == m_active_enbs.end()) {
return NULL;
}
else
{
} else {
return it->second;
}
}
void
s1ap::delete_enb_ctx(int32_t assoc_id)
void s1ap::delete_enb_ctx(int32_t assoc_id)
{
std::map<int32_t,uint16_t>::iterator it_assoc = m_sctp_to_enb_id.find(assoc_id);
uint16_t enb_id = it_assoc->second;
std::map<int32_t, uint16_t>::iterator it_assoc = m_sctp_to_enb_id.find(assoc_id);
uint16_t enb_id = it_assoc->second;
std::map<uint16_t,enb_ctx_t*>::iterator it_ctx = m_active_enbs.find(enb_id);
if(it_ctx == m_active_enbs.end() || it_assoc == m_sctp_to_enb_id.end())
{
m_s1ap_log->error("Could not find eNB to delete. Association: %d\n",assoc_id);
std::map<uint16_t, enb_ctx_t*>::iterator it_ctx = m_active_enbs.find(enb_id);
if (it_ctx == m_active_enbs.end() || it_assoc == m_sctp_to_enb_id.end()) {
m_s1ap_log->error("Could not find eNB to delete. Association: %d\n", assoc_id);
return;
}
m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
//Delete connected UEs ctx
// Delete connected UEs ctx
release_ues_ecm_ctx_in_enb(assoc_id);
//Delete eNB
// Delete eNB
delete it_ctx->second;
m_active_enbs.erase(it_ctx);
m_sctp_to_enb_id.erase(it_assoc);
return;
}
//UE Context Management
bool
s1ap::add_nas_ctx_to_imsi_map(nas *nas_ctx)
bool s1ap::add_nas_ctx_to_imsi_map(nas* nas_ctx)
{
std::map<uint64_t, nas*>::iterator ctx_it = m_imsi_to_nas_ctx.find(nas_ctx->m_emm_ctx.imsi);
if (ctx_it != m_imsi_to_nas_ctx.end()) {
m_s1ap_log->error("UE Context already exists. IMSI %015" PRIu64 "",nas_ctx->m_emm_ctx.imsi);
m_s1ap_log->error("UE Context already exists. IMSI %015" PRIu64 "", nas_ctx->m_emm_ctx.imsi);
return false;
}
if (nas_ctx->m_ecm_ctx.mme_ue_s1ap_id != 0) {
std::map<uint32_t,nas*>::iterator ctx_it2 = m_mme_ue_s1ap_id_to_nas_ctx.find(nas_ctx->m_ecm_ctx.mme_ue_s1ap_id);
if(ctx_it2 != m_mme_ue_s1ap_id_to_nas_ctx.end() && ctx_it2->second != nas_ctx) {
std::map<uint32_t, nas*>::iterator ctx_it2 = m_mme_ue_s1ap_id_to_nas_ctx.find(nas_ctx->m_ecm_ctx.mme_ue_s1ap_id);
if (ctx_it2 != m_mme_ue_s1ap_id_to_nas_ctx.end() && ctx_it2->second != nas_ctx) {
m_s1ap_log->error("Context identified with IMSI does not match context identified by MME UE S1AP Id.\n");
return false;
}
}
m_imsi_to_nas_ctx.insert(std::pair<uint64_t,nas*>(nas_ctx->m_emm_ctx.imsi, nas_ctx));
m_s1ap_log->debug("Saved UE context corresponding to IMSI %015" PRIu64 "\n",nas_ctx->m_emm_ctx.imsi);
m_imsi_to_nas_ctx.insert(std::pair<uint64_t, nas*>(nas_ctx->m_emm_ctx.imsi, nas_ctx));
m_s1ap_log->debug("Saved UE context corresponding to IMSI %015" PRIu64 "\n", nas_ctx->m_emm_ctx.imsi);
return true;
}
bool
s1ap::add_nas_ctx_to_mme_ue_s1ap_id_map(nas *nas_ctx)
bool s1ap::add_nas_ctx_to_mme_ue_s1ap_id_map(nas* nas_ctx)
{
if (nas_ctx->m_ecm_ctx.mme_ue_s1ap_id == 0) {
m_s1ap_log->error("Could not add UE context to MME UE S1AP map. MME UE S1AP ID 0 is not valid.");
@ -398,33 +378,31 @@ s1ap::add_nas_ctx_to_mme_ue_s1ap_id_map(nas *nas_ctx)
}
std::map<uint32_t, nas*>::iterator ctx_it = m_mme_ue_s1ap_id_to_nas_ctx.find(nas_ctx->m_ecm_ctx.mme_ue_s1ap_id);
if (ctx_it != m_mme_ue_s1ap_id_to_nas_ctx.end()) {
m_s1ap_log->error("UE Context already exists. MME UE S1AP Id %015" PRIu64 "",nas_ctx->m_emm_ctx.imsi);
m_s1ap_log->error("UE Context already exists. MME UE S1AP Id %015" PRIu64 "", nas_ctx->m_emm_ctx.imsi);
return false;
}
if (nas_ctx->m_emm_ctx.imsi != 0) {
std::map<uint32_t,nas*>::iterator ctx_it2 = m_mme_ue_s1ap_id_to_nas_ctx.find(nas_ctx->m_ecm_ctx.mme_ue_s1ap_id);
std::map<uint32_t, nas*>::iterator ctx_it2 = m_mme_ue_s1ap_id_to_nas_ctx.find(nas_ctx->m_ecm_ctx.mme_ue_s1ap_id);
if (ctx_it2 != m_mme_ue_s1ap_id_to_nas_ctx.end() && ctx_it2->second != nas_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_nas_ctx.insert(std::pair<uint32_t, nas*>(nas_ctx->m_ecm_ctx.mme_ue_s1ap_id, nas_ctx));
m_s1ap_log->debug("Saved UE context corresponding to MME UE S1AP Id %d\n",nas_ctx->m_ecm_ctx.mme_ue_s1ap_id);
m_s1ap_log->debug("Saved UE context corresponding to MME UE S1AP Id %d\n", nas_ctx->m_ecm_ctx.mme_ue_s1ap_id);
return true;
}
bool
s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
bool s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
{
std::map<int32_t,std::set<uint32_t> >::iterator ues_in_enb = m_enb_assoc_to_ue_ids.find(enb_assoc);
std::map<int32_t, std::set<uint32_t> >::iterator ues_in_enb = m_enb_assoc_to_ue_ids.find(enb_assoc);
if (ues_in_enb == m_enb_assoc_to_ue_ids.end()) {
m_s1ap_log->error("Could not find eNB from eNB SCTP association %d",enb_assoc);
m_s1ap_log->error("Could not find eNB from eNB SCTP association %d", enb_assoc);
return false;
}
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.find(mme_ue_s1ap_id);
if(ue_id != ues_in_enb->second.end())
{
m_s1ap_log->error("UE with MME UE S1AP Id already exists %d",mme_ue_s1ap_id);
if (ue_id != ues_in_enb->second.end()) {
m_s1ap_log->error("UE with MME UE S1AP Id already exists %d", mme_ue_s1ap_id);
return false;
}
ues_in_enb->second.insert(mme_ue_s1ap_id);
@ -432,8 +410,7 @@ s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
return true;
}
nas*
s1ap::find_nas_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
nas* s1ap::find_nas_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
{
std::map<uint32_t, nas*>::iterator it = m_mme_ue_s1ap_id_to_nas_ctx.find(mme_ue_s1ap_id);
if (it == m_mme_ue_s1ap_id_to_nas_ctx.end()) {
@ -443,8 +420,7 @@ s1ap::find_nas_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
}
}
nas*
s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
nas* s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
{
std::map<uint64_t, nas*>::iterator it = m_imsi_to_nas_ctx.find(imsi);
if (it == m_imsi_to_nas_ctx.end()) {
@ -454,27 +430,27 @@ s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
}
}
void
s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
void s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
{
m_s1ap_log->console("Releasing UEs context\n");
std::map<int32_t,std::set<uint32_t> >::iterator ues_in_enb = m_enb_assoc_to_ue_ids.find(enb_assoc);
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.begin();
std::map<int32_t, std::set<uint32_t> >::iterator ues_in_enb = m_enb_assoc_to_ue_ids.find(enb_assoc);
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.begin();
if (ue_id == ues_in_enb->second.end()) {
m_s1ap_log->console("No UEs to be released\n");
} else {
while (ue_id != ues_in_enb->second.end() ) {
while (ue_id != ues_in_enb->second.end()) {
std::map<uint32_t, nas*>::iterator nas_ctx = m_mme_ue_s1ap_id_to_nas_ctx.find(*ue_id);
emm_ctx_t *emm_ctx = &nas_ctx->second->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->second->m_ecm_ctx;
emm_ctx_t* emm_ctx = &nas_ctx->second->m_emm_ctx;
ecm_ctx_t* ecm_ctx = &nas_ctx->second->m_ecm_ctx;
m_s1ap_log->info("Releasing UE context. IMSI: %015" PRIu64 ", UE-MME S1AP Id: %d\n", emm_ctx->imsi, ecm_ctx->mme_ue_s1ap_id);
if(emm_ctx->state == EMM_STATE_REGISTERED) {
m_s1ap_log->info("Releasing UE context. IMSI: %015" PRIu64 ", UE-MME S1AP Id: %d\n", emm_ctx->imsi,
ecm_ctx->mme_ue_s1ap_id);
if (emm_ctx->state == EMM_STATE_REGISTERED) {
m_mme_gtpc->send_delete_session_request(emm_ctx->imsi);
emm_ctx->state = EMM_STATE_DEREGISTERED;
}
m_s1ap_log->console("Releasing UE ECM context. UE-MME S1AP Id: %d\n", ecm_ctx->mme_ue_s1ap_id);
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->mme_ue_s1ap_id = 0;
ecm_ctx->enb_ue_s1ap_id = 0;
ues_in_enb->second.erase(ue_id++);
@ -482,33 +458,32 @@ s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
}
}
bool
s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
bool s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
{
nas *nas_ctx = find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
nas* nas_ctx = find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_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;
}
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
//Delete UE within eNB UE set
std::map<int32_t,uint16_t>::iterator it = m_sctp_to_enb_id.find(ecm_ctx->enb_sri.sinfo_assoc_id);
if (it == m_sctp_to_enb_id.end() ) {
// Delete UE within eNB UE set
std::map<int32_t, uint16_t>::iterator it = m_sctp_to_enb_id.find(ecm_ctx->enb_sri.sinfo_assoc_id);
if (it == m_sctp_to_enb_id.end()) {
m_s1ap_log->error("Could not find eNB for UE release request.\n");
return false;
}
uint16_t enb_id = it->second;
std::map<int32_t,std::set<uint32_t> >::iterator ue_set = m_enb_assoc_to_ue_ids.find(ecm_ctx->enb_sri.sinfo_assoc_id);
uint16_t enb_id = it->second;
std::map<int32_t, std::set<uint32_t> >::iterator ue_set = m_enb_assoc_to_ue_ids.find(ecm_ctx->enb_sri.sinfo_assoc_id);
if (ue_set == m_enb_assoc_to_ue_ids.end()) {
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
// Release UE ECM context
m_mme_ue_s1ap_id_to_nas_ctx.erase(mme_ue_s1ap_id);
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->mme_ue_s1ap_id = 0;
ecm_ctx->enb_ue_s1ap_id = 0;
@ -516,76 +491,73 @@ s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
return true;
}
bool
s1ap::delete_ue_ctx(uint64_t imsi)
bool s1ap::delete_ue_ctx(uint64_t imsi)
{
nas *nas_ctx = find_nas_ctx_from_imsi(imsi);
nas* nas_ctx = find_nas_ctx_from_imsi(imsi);
if (nas_ctx == NULL) {
m_s1ap_log->info("Cannot delete UE context, UE not found. IMSI: %" PRIu64 "\n", imsi);
return false;
}
//Make sure to release ECM ctx
// Make sure to release ECM ctx
if (nas_ctx->m_ecm_ctx.mme_ue_s1ap_id != 0) {
release_ue_ecm_ctx(nas_ctx->m_ecm_ctx.mme_ue_s1ap_id);
}
//Delete UE context
// Delete UE context
m_imsi_to_nas_ctx.erase(imsi);
delete nas_ctx;
m_s1ap_log->info("Deleted UE Context.\n");
return true;
}
//UE Bearer Managment
void
s1ap::activate_eps_bearer(uint64_t imsi, uint8_t ebi)
void s1ap::activate_eps_bearer(uint64_t imsi, uint8_t ebi)
{
std::map<uint64_t,nas*>::iterator ue_ctx_it = m_imsi_to_nas_ctx.find(imsi);
std::map<uint64_t, nas*>::iterator ue_ctx_it = m_imsi_to_nas_ctx.find(imsi);
if (ue_ctx_it == m_imsi_to_nas_ctx.end()) {
m_s1ap_log->error("Could not activate EPS bearer: Could not find UE context\n");
return;
return;
}
//Make sure NAS is active
uint32_t mme_ue_s1ap_id = ue_ctx_it->second->m_ecm_ctx.mme_ue_s1ap_id;
std::map<uint32_t,nas*>::iterator it = m_mme_ue_s1ap_id_to_nas_ctx.find(mme_ue_s1ap_id);
// Make sure NAS is active
uint32_t mme_ue_s1ap_id = ue_ctx_it->second->m_ecm_ctx.mme_ue_s1ap_id;
std::map<uint32_t, nas*>::iterator it = m_mme_ue_s1ap_id_to_nas_ctx.find(mme_ue_s1ap_id);
if (it == m_mme_ue_s1ap_id_to_nas_ctx.end()) {
m_s1ap_log->error("Could not activate EPS bearer: ECM context seems to be missing\n");
return;
}
ecm_ctx_t * ecm_ctx = &ue_ctx_it->second->m_ecm_ctx;
esm_ctx_t * esm_ctx = &ue_ctx_it->second->m_esm_ctx[ebi];
ecm_ctx_t* ecm_ctx = &ue_ctx_it->second->m_ecm_ctx;
esm_ctx_t* esm_ctx = &ue_ctx_it->second->m_esm_ctx[ebi];
if (esm_ctx->state != ERAB_CTX_SETUP) {
m_s1ap_log->error("Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d, state %d\n", mme_ue_s1ap_id, ebi, esm_ctx->state);
m_s1ap_log->console("Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d, state %d\n", mme_ue_s1ap_id, ebi, esm_ctx->state);
m_s1ap_log->error(
"Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d, state %d\n",
mme_ue_s1ap_id, ebi, esm_ctx->state);
m_s1ap_log->console(
"Could not be activate EPS Bearer, bearer in wrong state: MME S1AP Id %d, EPS Bearer id %d, state %d\n",
mme_ue_s1ap_id, ebi, esm_ctx->state);
return;
}
esm_ctx->state = ERAB_ACTIVE;
ecm_ctx->state = ECM_STATE_CONNECTED;
m_s1ap_log->info("Activated EPS Bearer: Bearer id %d\n",ebi);
m_s1ap_log->info("Activated EPS Bearer: Bearer id %d\n", ebi);
return;
}
uint32_t
s1ap::allocate_m_tmsi(uint64_t imsi)
uint32_t s1ap::allocate_m_tmsi(uint64_t imsi)
{
uint32_t m_tmsi = m_next_m_tmsi;
m_next_m_tmsi = (m_next_m_tmsi + 1) % UINT32_MAX;
m_next_m_tmsi = (m_next_m_tmsi + 1) % UINT32_MAX;
m_tmsi_to_imsi.insert(std::pair<uint32_t,uint64_t>(m_tmsi,imsi));
m_s1ap_log->debug("Allocated M-TMSI 0x%x to IMSI %015" PRIu64 ",\n",m_tmsi,imsi);
m_tmsi_to_imsi.insert(std::pair<uint32_t, uint64_t>(m_tmsi, imsi));
m_s1ap_log->debug("Allocated M-TMSI 0x%x to IMSI %015" PRIu64 ",\n", m_tmsi, imsi);
return m_tmsi;
}
uint64_t
s1ap::find_imsi_from_m_tmsi(uint32_t m_tmsi)
uint64_t s1ap::find_imsi_from_m_tmsi(uint32_t m_tmsi)
{
std::map<uint32_t,uint64_t>::iterator it = m_tmsi_to_imsi.find(m_tmsi);
std::map<uint32_t, uint64_t>::iterator it = m_tmsi_to_imsi.find(m_tmsi);
if (it != m_tmsi_to_imsi.end()) {
m_s1ap_log->debug("Found IMSI %015" PRIu64 " from M-TMSI 0x%x\n", it->second, m_tmsi);
return it->second;
@ -595,38 +567,37 @@ s1ap::find_imsi_from_m_tmsi(uint32_t m_tmsi)
}
}
void
s1ap::print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx)
void s1ap::print_enb_ctx_info(const std::string& prefix, const enb_ctx_t& enb_ctx)
{
std::string mnc_str, mcc_str;
if (enb_ctx.enb_name_present) {
m_s1ap_log->console("%s - eNB Name: %s, eNB id: 0x%x\n",prefix.c_str(), enb_ctx.enb_name, enb_ctx.enb_id);
m_s1ap_log->console("%s - eNB Name: %s, eNB id: 0x%x\n", prefix.c_str(), enb_ctx.enb_name, enb_ctx.enb_id);
m_s1ap_log->info("%s - eNB Name: %s, eNB id: 0x%x\n", prefix.c_str(), enb_ctx.enb_name, enb_ctx.enb_id);
} else {
m_s1ap_log->console("%s - eNB Id 0x%x\n",prefix.c_str(), enb_ctx.enb_id);
m_s1ap_log->console("%s - eNB Id 0x%x\n", prefix.c_str(), enb_ctx.enb_id);
m_s1ap_log->info("%s - eNB Id 0x%x\n", prefix.c_str(), enb_ctx.enb_id);
}
srslte::mcc_to_string(enb_ctx.mcc, &mcc_str);
srslte::mnc_to_string(enb_ctx.mnc, &mnc_str);
m_s1ap_log->info("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(), enb_ctx.plmn);
m_s1ap_log->console("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(), enb_ctx.plmn);
for (int i=0;i<enb_ctx.nof_supported_ta;i++) {
for(int j=0;i<enb_ctx.nof_supported_ta;i++) {
m_s1ap_log->info("%s - TAC %d, B-PLMN %d\n",prefix.c_str(), enb_ctx.tac[i],enb_ctx.bplmns[i][j]);
m_s1ap_log->console("%s - TAC %d, B-PLMN %d\n",prefix.c_str(), enb_ctx.tac[i],enb_ctx.bplmns[i][j]);
m_s1ap_log->console("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(),
enb_ctx.plmn);
for (int i = 0; i < enb_ctx.nof_supported_ta; i++) {
for (int j = 0; i < enb_ctx.nof_supported_ta; i++) {
m_s1ap_log->info("%s - TAC %d, B-PLMN %d\n", prefix.c_str(), enb_ctx.tac[i], enb_ctx.bplmns[i][j]);
m_s1ap_log->console("%s - TAC %d, B-PLMN %d\n", prefix.c_str(), enb_ctx.tac[i], enb_ctx.bplmns[i][j]);
}
}
m_s1ap_log->console("%s - Paging DRX %d\n",prefix.c_str(),enb_ctx.drx);
m_s1ap_log->console("%s - Paging DRX %d\n", prefix.c_str(), enb_ctx.drx);
return;
}
/*
* Interfaces
*/
/*GTP-C||NAS -> S1AP interface*/
bool
s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
/* GTP-C || NAS -> S1AP interface */
bool s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
{
nas* nas_ctx = find_nas_ctx_from_imsi(imsi);
if (nas_ctx == NULL) {
@ -637,9 +608,8 @@ s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
return true;
}
/*NAS -> S1AP interface*/
bool
s1ap::send_ue_context_release_command(uint32_t mme_ue_s1ap_id)
/* NAS -> S1AP interface */
bool s1ap::send_ue_context_release_command(uint32_t mme_ue_s1ap_id)
{
nas* nas_ctx = find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == NULL) {
@ -650,9 +620,11 @@ s1ap::send_ue_context_release_command(uint32_t mme_ue_s1ap_id)
return true;
}
bool
s1ap::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri)
bool s1ap::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri)
{
return m_s1ap_nas_transport->send_downlink_nas_transport(enb_ue_s1ap_id, mme_ue_s1ap_id, nas_msg, enb_sri);
}
} //namespace srsepc
} // namespace srsepc

@ -24,22 +24,28 @@
*
*/
#include "srslte/common/bcd_helpers.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/mme/s1ap_ctx_mngmt_proc.h"
#include "srslte/common/liblte_security.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/int_helpers.h"
#include "srslte/common/liblte_security.h"
namespace srsepc{
namespace srsepc {
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL;
pthread_mutex_t s1ap_ctx_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_ctx_mngmt_proc::s1ap_ctx_mngmt_proc() {}
s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc() {}
s1ap_ctx_mngmt_proc::s1ap_ctx_mngmt_proc()
{
return;
}
s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc()
{
return;
}
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance(void)
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance()
{
pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if (NULL == m_instance) {
@ -49,7 +55,7 @@ s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance(void)
return (m_instance);
}
void s1ap_ctx_mngmt_proc::cleanup(void)
void s1ap_ctx_mngmt_proc::cleanup()
{
pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if (NULL != m_instance) {
@ -59,14 +65,13 @@ void s1ap_ctx_mngmt_proc::cleanup(void)
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex);
}
void s1ap_ctx_mngmt_proc::init(void)
void s1ap_ctx_mngmt_proc::init()
{
m_s1ap = s1ap::get_instance();
m_mme_gtpc = mme_gtpc::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1ap_args = m_s1ap->m_s1ap_args;
m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance();
m_s1ap = s1ap::get_instance();
m_mme_gtpc = mme_gtpc::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1ap_args = m_s1ap->m_s1ap_args;
m_pool = srslte::byte_buffer_pool::get_instance();
}
bool s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas* nas_ctx, uint16_t erab_to_setup)
@ -238,7 +243,8 @@ bool s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(
bool s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT* ue_rel,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer, bool* reply_flag)
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{
LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT ue_rel_req;
@ -246,40 +252,40 @@ bool s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_
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);
nas * nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
nas* nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_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;
}
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx;
emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
//Delete user plane context at the SPGW (but keep GTP-C connection).
// 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
// There are active E-RABs, send release access mearers request
m_s1ap_log->console("There are active E-RABs, send release access bearers request\n");
m_s1ap_log->info("There are active E-RABs, send release access bearers request\n");
//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.
// 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(emm_ctx->imsi);
//Send release context command to enb, so that it can release it's bearers
// Send release context command to enb, so that it can release it's bearers
send_ue_context_release_command(nas_ctx);
} else {
//No ECM Context to release
// No ECM Context to release
m_s1ap_log->info("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("UE is not ECM connected. No need to release S1-U. MME UE S1AP Id %d\n", mme_ue_s1ap_id);
//Make sure E-RABS are merked as DEACTIVATED.
for (int i=0;i<MAX_ERABS_PER_UE;i++) {
// Make sure E-RABS are merked as DEACTIVATED.
for (int i = 0; i < MAX_ERABS_PER_UE; i++) {
nas_ctx->m_esm_ctx[i].state = ERAB_DEACTIVATED;
}
}
//Set UE context to ECM Idle
ecm_ctx->state = ECM_STATE_IDLE;
// Set UE context to ECM Idle
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");
@ -334,14 +340,14 @@ bool s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(
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);
nas * nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
nas* nas_ctx = m_s1ap->find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_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;
}
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_ctx;
emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
// Delete user plane context at the SPGW (but keep GTP-C connection).
if (ecm_ctx->state == ECM_STATE_CONNECTED) {
@ -349,22 +355,22 @@ bool s1ap_ctx_mngmt_proc::handle_ue_context_release_complete(
m_s1ap_log->console("There are active E-RABs, send release access bearers request");
m_s1ap_log->info("There are active E-RABs, send release access bearers request");
m_mme_gtpc->send_release_access_bearers_request(emm_ctx->imsi);
//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.
// 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.
} else {
//No ECM Context to release
// 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 marked as DEACTIVATED.
for (int i=0;i<MAX_ERABS_PER_UE;i++) {
// Make sure E-RABS are marked as DEACTIVATED.
for (int i = 0; i < MAX_ERABS_PER_UE; i++) {
nas_ctx->m_esm_ctx[i].state = ERAB_DEACTIVATED;
}
}
//Delete UE context
// Delete UE context
m_s1ap->release_ue_ecm_ctx(nas_ctx->m_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
} // namespace srsepc

@ -24,92 +24,84 @@
*
*/
//#include "srslte/upper/s1ap_common.h"
#include "srslte/common/bcd_helpers.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/mme/s1ap_mngmt_proc.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/common/bcd_helpers.h"
namespace srsepc{
s1ap_mngmt_proc* s1ap_mngmt_proc::m_instance = NULL;
pthread_mutex_t s1ap_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
namespace srsepc {
s1ap_mngmt_proc* s1ap_mngmt_proc::m_instance = NULL;
pthread_mutex_t s1ap_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_mngmt_proc::s1ap_mngmt_proc()
{
return;
}
s1ap_mngmt_proc::~s1ap_mngmt_proc()
{
return;
}
s1ap_mngmt_proc*
s1ap_mngmt_proc::get_instance(void)
s1ap_mngmt_proc* s1ap_mngmt_proc::get_instance(void)
{
pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex);
if(NULL == m_instance) {
if (NULL == m_instance) {
m_instance = new s1ap_mngmt_proc();
}
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
return(m_instance);
return (m_instance);
}
void
s1ap_mngmt_proc::cleanup(void)
void s1ap_mngmt_proc::cleanup(void)
{
pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex);
if(NULL != m_instance) {
if (NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
}
void
s1ap_mngmt_proc::init(void)
void s1ap_mngmt_proc::init(void)
{
m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1mme = m_s1ap->get_s1_mme();
m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1mme = m_s1ap->get_s1_mme();
m_s1ap_args = m_s1ap->m_s1ap_args;
}
bool
s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag)
bool s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT* msg,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{
enb_ctx_t enb_ctx;
enb_ctx_t enb_ctx;
LIBLTE_S1AP_S1AP_PDU_STRUCT reply_pdu;
if(!unpack_s1_setup_request(msg, &enb_ctx))
{
if (!unpack_s1_setup_request(msg, &enb_ctx)) {
m_s1ap_log->error("Malformed S1 Setup Request\n");
return false;
}
//Log S1 Setup Request Info
// Log S1 Setup Request Info
m_s1ap_log->console("Received S1 Setup Request.\n");
m_s1ap->print_enb_ctx_info(std::string("S1 Setup Request"),enb_ctx);
//Check matching PLMNs
if(enb_ctx.plmn!=m_s1ap->get_plmn()){
m_s1ap->print_enb_ctx_info(std::string("S1 Setup Request"), enb_ctx);
// Check matching PLMNs
if (enb_ctx.plmn != m_s1ap->get_plmn()) {
m_s1ap_log->console("Sending S1 Setup Failure - Unknown PLMN\n");
m_s1ap_log->warning("Sending S1 Setup Failure - Unknown PLMN\n");
pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_UNKNOWN_PLMN,reply_buffer);
}
else{
enb_ctx_t *enb_ptr = m_s1ap->find_enb_ctx(enb_ctx.enb_id);
if(enb_ptr != NULL)
{
//eNB already registered
//TODO replace enb_ctx
pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_UNKNOWN_PLMN, reply_buffer);
} else {
enb_ctx_t* enb_ptr = m_s1ap->find_enb_ctx(enb_ctx.enb_id);
if (enb_ptr != NULL) {
// eNB already registered
// TODO replace enb_ctx
m_s1ap_log->warning("eNB Already registered\n");
}
else
{
//new eNB
m_s1ap->add_new_enb_ctx(enb_ctx,enb_sri);
} else {
// new eNB
m_s1ap->add_new_enb_ctx(enb_ctx, enb_sri);
}
pack_s1_setup_response(m_s1ap_args, reply_buffer);
@ -121,33 +113,31 @@ s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
return true;
}
/*
* Packing/Unpacking helper functions.
*/
bool
s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, enb_ctx_t* enb_ctx)
bool s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT* msg, enb_ctx_t* enb_ctx)
{
uint8_t enb_id_bits[32];
uint32_t plmn = 0;
uint8_t enb_id_bits[32];
uint32_t plmn = 0;
uint16_t tac, bplmn;
uint32_t tmp32=0;
//eNB Name
enb_ctx->enb_name_present=msg->eNBname_present;
if(msg->eNBname_present)
{
bzero(enb_ctx->enb_name,sizeof(enb_ctx->enb_name));
memcpy(enb_ctx->enb_name,&msg->eNBname.buffer,msg->eNBname.n_octets);
uint32_t tmp32 = 0;
// eNB Name
enb_ctx->enb_name_present = msg->eNBname_present;
if (msg->eNBname_present) {
bzero(enb_ctx->enb_name, sizeof(enb_ctx->enb_name));
memcpy(enb_ctx->enb_name, &msg->eNBname.buffer, msg->eNBname.n_octets);
}
//eNB Id
bzero(enb_id_bits,sizeof(enb_id_bits));
memcpy(&enb_id_bits[32-LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], msg->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer, LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
liblte_pack(enb_id_bits, 32, (uint8_t*) &tmp32);
enb_ctx->enb_id=ntohl(tmp32);
//PLMN Id
// eNB Id
bzero(enb_id_bits, sizeof(enb_id_bits));
memcpy(&enb_id_bits[32 - LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], msg->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer,
LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
liblte_pack(enb_id_bits, 32, (uint8_t*)&tmp32);
enb_ctx->enb_id = ntohl(tmp32);
// PLMN Id
((uint8_t*)&plmn)[1] = msg->Global_ENB_ID.pLMNidentity.buffer[0];
((uint8_t*)&plmn)[2] = msg->Global_ENB_ID.pLMNidentity.buffer[1];
((uint8_t*)&plmn)[3] = msg->Global_ENB_ID.pLMNidentity.buffer[2];
@ -155,18 +145,16 @@ s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
enb_ctx->plmn = ntohl(plmn);
srslte::s1ap_plmn_to_mccmnc(enb_ctx->plmn, &enb_ctx->mcc, &enb_ctx->mnc);
//SupportedTAs
enb_ctx->nof_supported_ta=msg->SupportedTAs.len;
for(uint16_t i=0; i<msg->SupportedTAs.len; i++)
{
//TAC
((uint8_t*)&enb_ctx->tac[i])[0] = msg->SupportedTAs.buffer[i].tAC.buffer[0];
((uint8_t*)&enb_ctx->tac[i])[1] = msg->SupportedTAs.buffer[i].tAC.buffer[1];
enb_ctx->tac[i]=ntohs(enb_ctx->tac[i]);
enb_ctx->nof_supported_bplmns[i]=msg->SupportedTAs.buffer[i].broadcastPLMNs.len;
for (uint16_t j=0; j<msg->SupportedTAs.buffer[i].broadcastPLMNs.len; j++)
{
//BPLMNs
// SupportedTAs
enb_ctx->nof_supported_ta = msg->SupportedTAs.len;
for (uint16_t i = 0; i < msg->SupportedTAs.len; i++) {
// TAC
((uint8_t*)&enb_ctx->tac[i])[0] = msg->SupportedTAs.buffer[i].tAC.buffer[0];
((uint8_t*)&enb_ctx->tac[i])[1] = msg->SupportedTAs.buffer[i].tAC.buffer[1];
enb_ctx->tac[i] = ntohs(enb_ctx->tac[i]);
enb_ctx->nof_supported_bplmns[i] = msg->SupportedTAs.buffer[i].broadcastPLMNs.len;
for (uint16_t j = 0; j < msg->SupportedTAs.buffer[i].broadcastPLMNs.len; j++) {
// BPLMNs
((uint8_t*)&enb_ctx->bplmns[i][j])[1] = msg->SupportedTAs.buffer[i].broadcastPLMNs.buffer[j].buffer[0];
((uint8_t*)&enb_ctx->bplmns[i][j])[2] = msg->SupportedTAs.buffer[i].broadcastPLMNs.buffer[j].buffer[1];
((uint8_t*)&enb_ctx->bplmns[i][j])[3] = msg->SupportedTAs.buffer[i].broadcastPLMNs.buffer[j].buffer[2];
@ -175,41 +163,38 @@ s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRU
}
}
//Default Paging DRX
// Default Paging DRX
enb_ctx->drx = msg->DefaultPagingDRX.e;
return true;
}
bool
s1ap_mngmt_proc::pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte::byte_buffer_t *msg)
bool s1ap_mngmt_proc::pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte::byte_buffer_t* msg)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME;
LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *unsucc = &pdu.choice.unsuccessfulOutcome;
unsucc->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP;
unsucc->criticality = LIBLTE_S1AP_CRITICALITY_REJECT;
unsucc->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE;
LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT* s1_fail=(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT*)&unsucc->choice;
s1_fail->TimeToWait_present=false;
s1_fail->CriticalityDiagnostics_present=false;
s1_fail->Cause.ext=false;
s1_fail->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_MISC;
s1_fail->Cause.choice.misc.ext=false;
s1_fail->Cause.choice.misc.e=cause;
LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT* unsucc = &pdu.choice.unsuccessfulOutcome;
unsucc->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP;
unsucc->criticality = LIBLTE_S1AP_CRITICALITY_REJECT;
unsucc->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE;
LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT* s1_fail = (LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT*)&unsucc->choice;
s1_fail->TimeToWait_present = false;
s1_fail->CriticalityDiagnostics_present = false;
s1_fail->Cause.ext = false;
s1_fail->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_MISC;
s1_fail->Cause.choice.misc.ext = false;
s1_fail->Cause.choice.misc.e = cause;
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
return true;
}
}
bool
s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buffer_t *msg)
bool s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buffer_t* msg)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
@ -217,55 +202,50 @@ s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buff
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME;
LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *succ = &pdu.choice.successfulOutcome;
succ->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP;
succ->criticality = LIBLTE_S1AP_CRITICALITY_IGNORE;
succ->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE;
LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT* succ = &pdu.choice.successfulOutcome;
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;
LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT* s1_resp = (LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT*)&succ->choice;
s1_resp->ext=false;
s1_resp->ext = false;
//MME Name
s1_resp->MMEname_present=true;
s1_resp->MMEname.ext=false;
s1_resp->MMEname.n_octets=s1ap_args.mme_name.length();
memcpy(s1_resp->MMEname.buffer,s1ap_args.mme_name.c_str(),s1ap_args.mme_name.length());
// MME Name
s1_resp->MMEname_present = true;
s1_resp->MMEname.ext = false;
s1_resp->MMEname.n_octets = s1ap_args.mme_name.length();
memcpy(s1_resp->MMEname.buffer, s1ap_args.mme_name.c_str(), s1ap_args.mme_name.length());
//Served GUMEIs
s1_resp->ServedGUMMEIs.len=1;//TODO Only one served GUMMEI supported
LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *serv_gummei = &s1_resp->ServedGUMMEIs.buffer[0];
// Served GUMEIs
s1_resp->ServedGUMMEIs.len = 1; // TODO Only one served GUMMEI supported
LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT* serv_gummei = &s1_resp->ServedGUMMEIs.buffer[0];
serv_gummei->ext=false;
serv_gummei->ext = false;
serv_gummei->iE_Extensions_present = false;
uint32_t plmn=0;
uint32_t plmn = 0;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn);
plmn=htonl(plmn);
serv_gummei->servedPLMNs.len = 1; //Only one PLMN supported
serv_gummei->servedPLMNs.buffer[0].buffer[0]=((uint8_t*)&plmn)[1];
serv_gummei->servedPLMNs.buffer[0].buffer[1]=((uint8_t*)&plmn)[2];
serv_gummei->servedPLMNs.buffer[0].buffer[2]=((uint8_t*)&plmn)[3];
serv_gummei->servedGroupIDs.len=1; //LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT
uint16_t tmp=htons(s1ap_args.mme_group);
serv_gummei->servedGroupIDs.buffer[0].buffer[0]=((uint8_t*)&tmp)[0];
serv_gummei->servedGroupIDs.buffer[0].buffer[1]=((uint8_t*)&tmp)[1];
serv_gummei->servedMMECs.len=1; //Only one MMEC served
serv_gummei->servedMMECs.buffer[0].buffer[0]=s1ap_args.mme_code;
//Relative MME Capacity
s1_resp->RelativeMMECapacity.RelativeMMECapacity=255;
//Relay Unsupported
s1_resp->MMERelaySupportIndicator_present=false;
plmn = htonl(plmn);
serv_gummei->servedPLMNs.len = 1; // Only one PLMN supported
serv_gummei->servedPLMNs.buffer[0].buffer[0] = ((uint8_t*)&plmn)[1];
serv_gummei->servedPLMNs.buffer[0].buffer[1] = ((uint8_t*)&plmn)[2];
serv_gummei->servedPLMNs.buffer[0].buffer[2] = ((uint8_t*)&plmn)[3];
serv_gummei->servedGroupIDs.len = 1; // LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT
uint16_t tmp = htons(s1ap_args.mme_group);
serv_gummei->servedGroupIDs.buffer[0].buffer[0] = ((uint8_t*)&tmp)[0];
serv_gummei->servedGroupIDs.buffer[0].buffer[1] = ((uint8_t*)&tmp)[1];
serv_gummei->servedMMECs.len = 1; // Only one MMEC served
serv_gummei->servedMMECs.buffer[0].buffer[0] = s1ap_args.mme_code;
s1_resp->RelativeMMECapacity.RelativeMMECapacity = 255;
s1_resp->MMERelaySupportIndicator_present = false;
s1_resp->CriticalityDiagnostics_present = false;
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
return true;
return true;
}
} //namespace srsepc
} // namespace srsepc

@ -24,22 +24,28 @@
*
*/
#include <iostream>
#include <cmath>
#include <inttypes.h> // for printing uint64_t
#include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/mme/s1ap_nas_transport.h"
#include "srslte/common/security.h"
#include "srslte/common/liblte_security.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/common/int_helpers.h"
#include "srslte/common/liblte_security.h"
#include "srslte/common/security.h"
#include <cmath>
#include <inttypes.h> // for printing uint64_t
namespace srsepc{
namespace srsepc {
s1ap_nas_transport* s1ap_nas_transport::m_instance = NULL;
pthread_mutex_t s1ap_nas_transport_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_nas_transport::s1ap_nas_transport() {}
s1ap_nas_transport::~s1ap_nas_transport() {}
s1ap_nas_transport::s1ap_nas_transport()
{
return;
}
s1ap_nas_transport::~s1ap_nas_transport()
{
return;
}
s1ap_nas_transport* s1ap_nas_transport::get_instance(void)
{
@ -61,46 +67,47 @@ void s1ap_nas_transport::cleanup(void)
pthread_mutex_unlock(&s1ap_nas_transport_instance_mutex);
}
void s1ap_nas_transport::init(hss_interface_nas* hss_)
void s1ap_nas_transport::init()
{
m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_pool = srslte::byte_buffer_pool::get_instance();
m_hss = hss_;
m_hss = hss::get_instance();
m_mme_gtpc = mme_gtpc::get_instance();
}
bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT* init_ue,
struct sctp_sndrcvinfo* enb_sri, srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{
bool err, mac_valid;
uint8_t pd, msg_type, sec_hdr_type;
srslte::byte_buffer_t *nas_msg = m_pool->allocate();
bool err, mac_valid;
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;
uint64_t imsi = 0;
uint32_t m_tmsi = 0;
uint64_t imsi = 0;
uint32_t m_tmsi = 0;
uint32_t enb_ue_s1ap_id = init_ue->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID;
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &pd, &msg_type);
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &msg_type);
m_s1ap_log->console("Initial UE message: %s\n", liblte_nas_msg_type_to_string(msg_type));
m_s1ap_log->info ("Initial UE message: %s\n", liblte_nas_msg_type_to_string(msg_type));
m_s1ap_log->info("Initial UE message: %s\n", liblte_nas_msg_type_to_string(msg_type));
nas_init_t nas_init;
nas_init.mcc = m_s1ap->m_s1ap_args.mcc;
nas_init.mnc = m_s1ap->m_s1ap_args.mnc;
nas_init.mme_code = m_s1ap->m_s1ap_args.mme_code;
nas_init.mme_group = m_s1ap->m_s1ap_args.mme_group;
nas_init.tac = m_s1ap->m_s1ap_args.tac;
nas_init.apn = m_s1ap->m_s1ap_args.mme_apn;
nas_init.dns = m_s1ap->m_s1ap_args.dns_addr;
nas_init.mcc = m_s1ap->m_s1ap_args.mcc;
nas_init.mnc = m_s1ap->m_s1ap_args.mnc;
nas_init.mme_code = m_s1ap->m_s1ap_args.mme_code;
nas_init.mme_group = m_s1ap->m_s1ap_args.mme_group;
nas_init.tac = m_s1ap->m_s1ap_args.tac;
nas_init.apn = m_s1ap->m_s1ap_args.mme_apn;
nas_init.dns = m_s1ap->m_s1ap_args.dns_addr;
nas_init.integ_algo = m_s1ap->m_s1ap_args.integrity_algo;
nas_init.cipher_algo = m_s1ap->m_s1ap_args.encryption_algo;
if(init_ue->S_TMSI_present){
if (init_ue->S_TMSI_present) {
srslte::uint8_to_uint32(init_ue->S_TMSI.m_TMSI.buffer, &m_tmsi);
}
@ -140,7 +147,8 @@ bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUE
bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT* ul_xport,
struct sctp_sndrcvinfo* enb_sri,
srslte::byte_buffer_t* reply_buffer, bool* reply_flag)
srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{
uint8_t pd, msg_type, sec_hdr_type;
uint32_t enb_ue_s1ap_id = ul_xport->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID;
@ -168,36 +176,34 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
// Parse the message security header
liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &sec_hdr_type);
// Invalid Security Header Type simply return function
if (!(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT ||
sec_hdr_type ==LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT))
{
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT)) {
m_s1ap_log->error("Unhandled security header type in Uplink NAS Transport: %d\n", sec_hdr_type);
m_pool->deallocate(nas_msg);
return false;
}
// Todo: Check on count mismatch of uplink count and do resync nas counter...
// Check MAC if message is integrity protected
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_WITH_NEW_EPS_SECURITY_CONTEXT ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT)
{
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT) {
mac_valid = nas_ctx->integrity_check(nas_msg);
if (mac_valid == false){
m_s1ap_log->warning("Invalid MAC message. Even if security header indicates integrity protection (Maybe: Identity Response or Authenticatio Response)\n" );
if (mac_valid == false) {
m_s1ap_log->warning("Invalid MAC message. Even if security header indicates integrity protection (Maybe: "
"Identity Response or Authenticatio Response)\n");
}
}
// Decrypt message if indicated
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT)
{
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT) {
m_s1ap_log->debug_hex(nas_msg->msg, nas_msg->N_bytes, "Encrypted");
nas_ctx->cipher_decrypt(nas_msg);
msg_encrypted = true;
@ -205,17 +211,19 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
}
// Now parse message header and handle message
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT *) nas_msg, &pd, &msg_type);
liblte_mme_parse_msg_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &msg_type);
//Find UE EMM context if message is security protected.
// 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
// Make sure EMM context is set-up, to do integrity check/de-chiphering
if (emm_ctx->imsi == 0) {
//No EMM context found. Perhaps a temporary context is being created?
//This can happen with integrity protected identity reponse messages
if ( !(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE && sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY) ) {
m_s1ap_log->warning("Uplink NAS: could not find security context for integrity protected message. MME-UE S1AP id: %d\n",mme_ue_s1ap_id);
// No EMM context found. Perhaps a temporary context is being created?
// This can happen with integrity protected identity reponse messages
if (!(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE &&
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY)) {
m_s1ap_log->warning(
"Uplink NAS: could not find security context for integrity protected message. MME-UE S1AP id: %d\n",
mme_ue_s1ap_id);
m_pool->deallocate(nas_msg);
return false;
}
@ -237,85 +245,90 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
liblte_nas_sec_hdr_type_to_string(sec_hdr_type), mac_valid == true ? "yes" : "no",
msg_encrypted == true ? "yes" : "no");
switch (msg_type)
{
case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE:
m_s1ap_log->info("UL NAS: Received Identity Response\n");
m_s1ap_log->console("UL NAS: Received Identity Response\n");
nas_ctx->handle_identity_response(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE:
m_s1ap_log->info("UL NAS: Received Authentication Response\n");
m_s1ap_log->console("UL NAS: Received Authentication Response\n");
nas_ctx->handle_authentication_response(nas_msg);
// In case of a successful authentication response, security mode command follows.
// Reset counter for incoming security mode complete
sec_ctx->ul_nas_count = 0;
sec_ctx->dl_nas_count = 0;
increase_ul_nas_cnt = false;
break;
// Authentication failure with the option sync failure can be sent not integrity protected
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
m_s1ap_log->info("UL NAS: Authentication Failure\n");
m_s1ap_log->console("UL NAS: Authentication Failure\n");
nas_ctx->handle_authentication_failure(nas_msg);
break;
// Detach request can be sent not integrity protected when "power off" option is used
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
m_s1ap_log->info("UL NAS: Detach Request\n");
m_s1ap_log->console("UL NAS: Detach Request\n");
// FIXME: check integrity protection in detach request
nas_ctx->handle_detach_request(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE:
m_s1ap_log->info("UL NAS: Received Security Mode Complete\n");
m_s1ap_log->console("UL NAS: Received Security Mode Complete\n");
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT && mac_valid == true){
nas_ctx->handle_security_mode_complete(nas_msg);
} else {
// Security Mode Complete was not integrity protected
m_s1ap_log->console("Security Mode Complete %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
m_s1ap_log->warning("Security Mode Complete %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
increase_ul_nas_cnt = false;
}
break;
case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE:
m_s1ap_log->info("UL NAS: Received Attach Complete\n");
m_s1ap_log->console("UL NAS: Received Attach Complete\n");
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true){
nas_ctx->handle_attach_complete(nas_msg);
} else {
// Attach Complete was not integrity protected
m_s1ap_log->console("Attach Complete not integrity protected. Discard message.\n");
m_s1ap_log->warning("Attach Complete not integrity protected. Discard message.\n");
increase_ul_nas_cnt = false;
}
break;
case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE:
m_s1ap_log->info("UL NAS: Received ESM Information Response\n");
m_s1ap_log->console("UL NAS: Received ESM Information Response\n");
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true){
nas_ctx->handle_esm_information_response(nas_msg);
} else {
// Attach Complete was not integrity protected
m_s1ap_log->console("ESM Information Response %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
m_s1ap_log->warning("ESM Information Response %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity"));
increase_ul_nas_cnt = false;
}
break;
case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST:
m_s1ap_log->info("UL NAS: Tracking Area Update Request\n");
m_s1ap_log->console("UL NAS: Tracking Area Update Request\n");
nas_ctx->handle_tracking_area_update_request(nas_msg);
break;
default:
m_s1ap_log->warning("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type));
m_s1ap_log->console("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type));
m_pool->deallocate(nas_msg);
return false;
switch (msg_type) {
case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE:
m_s1ap_log->info("UL NAS: Received Identity Response\n");
m_s1ap_log->console("UL NAS: Received Identity Response\n");
nas_ctx->handle_identity_response(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE:
m_s1ap_log->info("UL NAS: Received Authentication Response\n");
m_s1ap_log->console("UL NAS: Received Authentication Response\n");
nas_ctx->handle_authentication_response(nas_msg);
// In case of a successful authentication response, security mode command follows.
// Reset counter for incoming security mode complete
sec_ctx->ul_nas_count = 0;
sec_ctx->dl_nas_count = 0;
increase_ul_nas_cnt = false;
break;
// Authentication failure with the option sync failure can be sent not integrity protected
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
m_s1ap_log->info("UL NAS: Authentication Failure\n");
m_s1ap_log->console("UL NAS: Authentication Failure\n");
nas_ctx->handle_authentication_failure(nas_msg);
break;
// Detach request can be sent not integrity protected when "power off" option is used
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
m_s1ap_log->info("UL NAS: Detach Request\n");
m_s1ap_log->console("UL NAS: Detach Request\n");
// FIXME: check integrity protection in detach request
nas_ctx->handle_detach_request(nas_msg);
break;
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE:
m_s1ap_log->info("UL NAS: Received Security Mode Complete\n");
m_s1ap_log->console("UL NAS: Received Security Mode Complete\n");
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT &&
mac_valid == true) {
nas_ctx->handle_security_mode_complete(nas_msg);
} else {
// Security Mode Complete was not integrity protected
m_s1ap_log->console("Security Mode Complete %s. Discard message.\n",
(mac_valid ? "not integrity protected" : "invalid integrity"));
m_s1ap_log->warning("Security Mode Complete %s. Discard message.\n",
(mac_valid ? "not integrity protected" : "invalid integrity"));
increase_ul_nas_cnt = false;
}
break;
case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE:
m_s1ap_log->info("UL NAS: Received Attach Complete\n");
m_s1ap_log->console("UL NAS: Received Attach Complete\n");
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true) {
nas_ctx->handle_attach_complete(nas_msg);
} else {
// Attach Complete was not integrity protected
m_s1ap_log->console("Attach Complete not integrity protected. Discard message.\n");
m_s1ap_log->warning("Attach Complete not integrity protected. Discard message.\n");
increase_ul_nas_cnt = false;
}
break;
case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE:
m_s1ap_log->info("UL NAS: Received ESM Information Response\n");
m_s1ap_log->console("UL NAS: Received ESM Information Response\n");
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true) {
nas_ctx->handle_esm_information_response(nas_msg);
} else {
// Attach Complete was not integrity protected
m_s1ap_log->console("ESM Information Response %s. Discard message.\n",
(mac_valid ? "not integrity protected" : "invalid integrity"));
m_s1ap_log->warning("ESM Information Response %s. Discard message.\n",
(mac_valid ? "not integrity protected" : "invalid integrity"));
increase_ul_nas_cnt = false;
}
break;
case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST:
m_s1ap_log->info("UL NAS: Tracking Area Update Request\n");
m_s1ap_log->console("UL NAS: Tracking Area Update Request\n");
nas_ctx->handle_tracking_area_update_request(nas_msg);
break;
default:
m_s1ap_log->warning("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type));
m_s1ap_log->console("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type));
m_pool->deallocate(nas_msg);
return false;
}
//Increment UL NAS count. if counter not resetted in function, e.g., DL Security mode command after Authentication response
// Increment UL NAS count. if counter not resetted in function, e.g., DL Security mode command after Authentication
// response
if (increase_ul_nas_cnt == true) {
sec_ctx->ul_nas_count++;
}
@ -323,37 +336,39 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
return true;
}
bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg, struct sctp_sndrcvinfo enb_sri)
bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri)
{
//Allocate Reply buffer
srslte::byte_buffer_t *reply_msg = m_pool->allocate();
// Allocate Reply buffer
srslte::byte_buffer_t* reply_msg = m_pool->allocate();
//Setup initiating message
// Setup initiating message
LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
bzero(&tx_pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
tx_pdu.ext = false;
tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
tx_pdu.ext = false;
tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_DOWNLINKNASTRANSPORT;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* init = &tx_pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_DOWNLINKNASTRANSPORT;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT;
//Setup Dw NAS structure
LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *dw_nas = &init->choice.DownlinkNASTransport;
dw_nas->ext=false;
dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = enb_ue_s1ap_id;
dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = mme_ue_s1ap_id;
dw_nas->HandoverRestrictionList_present=false;
dw_nas->SubscriberProfileIDforRFP_present=false;
// Setup Dw NAS structure
LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT* dw_nas = &init->choice.DownlinkNASTransport;
dw_nas->ext = false;
dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = enb_ue_s1ap_id;
dw_nas->MME_UE_S1AP_ID.MME_UE_S1AP_ID = mme_ue_s1ap_id;
dw_nas->HandoverRestrictionList_present = false;
dw_nas->SubscriberProfileIDforRFP_present = false;
//Copy NAS PDU to Downlink NAS Trasport message buffer
// Copy NAS PDU to Downlink NAS Trasport message buffer
memcpy(dw_nas->NAS_PDU.buffer, nas_msg->msg, nas_msg->N_bytes);
dw_nas->NAS_PDU.n_octets = nas_msg->N_bytes;
//Pack Downlink NAS Transport Message
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg);
// Pack Downlink NAS Transport Message
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_msg);
if (err != LIBLTE_SUCCESS) {
m_s1ap_log->error("Error packing Downlink NAS Transport.\n");
m_s1ap_log->console("Error packing Downlink NAS Transport.\n");
@ -365,5 +380,4 @@ bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, ui
return true;
}
} //namespace srsepc
} // namespace srsepc

@ -24,33 +24,27 @@
*
*/
#include <iostream>
#include "srsepc/hdr/spgw/spgw.h"
#include "srsepc/hdr/mme/mme_gtpc.h"
#include "srslte/upper/gtpu.h"
#include <algorithm>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <inttypes.h> // for printing uint64_t
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include <inttypes.h> // for printing uint64_t
#include "srsepc/hdr/spgw/spgw.h"
#include "srsepc/hdr/mme/mme_gtpc.h"
#include "srslte/upper/gtpu.h"
#include <netinet/in.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
namespace srsepc{
namespace srsepc {
spgw* spgw::m_instance = NULL;
spgw* spgw::m_instance = NULL;
pthread_mutex_t spgw_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
const uint16_t SPGW_BUFFER_SIZE = 2500;
spgw::spgw():
m_running(false),
m_sgi_up(false),
m_s1u_up(false),
m_next_ctrl_teid(1),
m_next_user_teid(1)
spgw::spgw() : m_running(false), m_sgi_up(false), m_s1u_up(false), m_next_ctrl_teid(1), m_next_user_teid(1)
{
return;
}
@ -60,92 +54,83 @@ spgw::~spgw()
return;
}
spgw*
spgw::get_instance(void)
spgw* spgw::get_instance()
{
pthread_mutex_lock(&spgw_instance_mutex);
if(NULL == m_instance) {
if (NULL == m_instance) {
m_instance = new spgw();
}
pthread_mutex_unlock(&spgw_instance_mutex);
return(m_instance);
return (m_instance);
}
void
spgw::cleanup(void)
void spgw::cleanup()
{
pthread_mutex_lock(&spgw_instance_mutex);
if(NULL != m_instance) {
if (NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
pthread_mutex_unlock(&spgw_instance_mutex);
}
int
spgw::init(spgw_args_t* args, srslte::log_filter *spgw_log)
int spgw::init(spgw_args_t* args, srslte::log_filter* spgw_log)
{
srslte::error_t err;
m_pool = srslte::byte_buffer_pool::get_instance();
//Init log
// Init log
m_spgw_log = spgw_log;
m_mme_gtpc = mme_gtpc::get_instance();
//Init SGi interface
// Init SGi interface
err = init_sgi_if(args);
if (err != srslte::ERROR_NONE)
{
if (err != srslte::ERROR_NONE) {
m_spgw_log->console("Could not initialize the SGi interface.\n");
return -1;
}
//Init S1-U
// Init S1-U
err = init_s1u(args);
if (err != srslte::ERROR_NONE)
{
if (err != srslte::ERROR_NONE) {
m_spgw_log->console("Could not initialize the S1-U interface.\n");
return -1;
}
//Initialize UE ip pool
// Initialize UE ip pool
err = init_ue_ip(args);
if (err != srslte::ERROR_NONE)
{
if (err != srslte::ERROR_NONE) {
m_spgw_log->console("Could not initialize the S1-U interface.\n");
return -1;
}
//Init mutex
pthread_mutex_init(&m_mutex,NULL);
// Init mutex
pthread_mutex_init(&m_mutex, NULL);
m_spgw_log->info("SP-GW Initialized.\n");
m_spgw_log->console("SP-GW Initialized.\n");
return 0;
}
void
spgw::stop()
void spgw::stop()
{
if(m_running)
{
if (m_running) {
m_running = false;
thread_cancel();
wait_thread_finish();
//Clean up SGi interface
if(m_sgi_up)
{
// Clean up SGi interface
if (m_sgi_up) {
close(m_sgi_if);
close(m_sgi_sock);
}
//Clean up S1-U socket
if(m_s1u_up)
{
// Clean up S1-U socket
if (m_s1u_up) {
close(m_s1u);
}
}
std::map<uint32_t,spgw_tunnel_ctx*>::iterator it = m_teid_to_tunnel_ctx.begin(); //Map control TEID to tunnel ctx. Usefull to get reply ctrl TEID, UE IP, etc.
while(it!=m_teid_to_tunnel_ctx.end())
{
//Delete GTP-C tunnel
std::map<uint32_t, spgw_tunnel_ctx*>::iterator it = m_teid_to_tunnel_ctx.begin();
while (it != m_teid_to_tunnel_ctx.end()) {
m_spgw_log->info("Deleting SP-GW GTP-C Tunnel. IMSI: %lu\n", it->second->imsi);
m_spgw_log->console("Deleting SP-GW GTP-C Tunnel. IMSI: %lu\n", it->second->imsi);
delete it->second;
@ -154,33 +139,31 @@ spgw::stop()
return;
}
srslte::error_t
spgw::init_sgi_if(spgw_args_t *args)
srslte::error_t spgw::init_sgi_if(spgw_args_t* args)
{
struct ifreq ifr;
if (m_sgi_up) {
return(srslte::ERROR_ALREADY_STARTED);
return (srslte::ERROR_ALREADY_STARTED);
}
// Construct the TUN device
m_sgi_if = open("/dev/net/tun", O_RDWR);
m_spgw_log->info("TUN file descriptor = %d\n", m_sgi_if);
if (m_sgi_if < 0) {
m_spgw_log->error("Failed to open TUN device: %s\n", strerror(errno));
return(srslte::ERROR_CANT_START);
return (srslte::ERROR_CANT_START);
}
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, args->sgi_if_name.c_str(), std::min(args->sgi_if_name.length(), (size_t)(IFNAMSIZ-1)));
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0';
strncpy(ifr.ifr_ifrn.ifrn_name, args->sgi_if_name.c_str(),
std::min(args->sgi_if_name.length(), (size_t)(IFNAMSIZ - 1)));
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ - 1] = '\0';
if (ioctl(m_sgi_if, TUNSETIFF, &ifr) < 0) {
m_spgw_log->error("Failed to set TUN device name: %s\n", strerror(errno));
close(m_sgi_if);
return(srslte::ERROR_CANT_START);
return (srslte::ERROR_CANT_START);
}
// Bring up the interface
@ -189,31 +172,32 @@ spgw::init_sgi_if(spgw_args_t *args)
if (ioctl(m_sgi_sock, SIOCGIFFLAGS, &ifr) < 0) {
m_spgw_log->error("Failed to bring up socket: %s\n", strerror(errno));
close(m_sgi_if);
return(srslte::ERROR_CANT_START);
return (srslte::ERROR_CANT_START);
}
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if (ioctl(m_sgi_sock, SIOCSIFFLAGS, &ifr) < 0) {
m_spgw_log->error("Failed to set socket flags: %s\n", strerror(errno));
close(m_sgi_if);
return(srslte::ERROR_CANT_START);
return (srslte::ERROR_CANT_START);
}
//Set IP of the interface
struct sockaddr_in *addr = (struct sockaddr_in*)&ifr.ifr_addr;
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(args->sgi_if_addr.c_str());
addr->sin_port = 0;
// Set IP of the interface
struct sockaddr_in* addr = (struct sockaddr_in*)&ifr.ifr_addr;
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(args->sgi_if_addr.c_str());
addr->sin_port = 0;
if (ioctl(m_sgi_sock, SIOCSIFADDR, &ifr) < 0) {
m_spgw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_if_addr.c_str(), strerror(errno));
m_spgw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_if_addr.c_str(),
strerror(errno));
close(m_sgi_if);
close(m_sgi_sock);
return srslte::ERROR_CANT_START;
}
ifr.ifr_netmask.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
ifr.ifr_netmask.sa_family = AF_INET;
((struct sockaddr_in*)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
if (ioctl(m_sgi_sock, SIOCSIFNETMASK, &ifr) < 0) {
m_spgw_log->error("Failed to set TUN interface Netmask. Error: %s\n", strerror(errno));
close(m_sgi_if);
@ -221,75 +205,69 @@ 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);
return (srslte::ERROR_NONE);
}
srslte::error_t
spgw::init_s1u(spgw_args_t *args)
srslte::error_t spgw::init_s1u(spgw_args_t* args)
{
//Open S1-U socket
m_s1u = socket(AF_INET,SOCK_DGRAM,0);
// Open S1-U socket
m_s1u = socket(AF_INET, SOCK_DGRAM, 0);
if (m_s1u == -1) {
m_spgw_log->error("Failed to open socket: %s\n", strerror(errno));
return srslte::ERROR_CANT_START;
}
m_s1u_up = true;
//Bind the socket
m_s1u_addr.sin_family = AF_INET;
m_s1u_addr.sin_addr.s_addr=inet_addr(args->gtpu_bind_addr.c_str());
m_s1u_addr.sin_port=htons(GTPU_RX_PORT);
// Bind the socket
m_s1u_addr.sin_family = AF_INET;
m_s1u_addr.sin_addr.s_addr = inet_addr(args->gtpu_bind_addr.c_str());
m_s1u_addr.sin_port = htons(GTPU_RX_PORT);
if (bind(m_s1u,(struct sockaddr *)&m_s1u_addr,sizeof(struct sockaddr_in))) {
if (bind(m_s1u, (struct sockaddr*)&m_s1u_addr, sizeof(struct sockaddr_in))) {
m_spgw_log->error("Failed to bind socket: %s\n", strerror(errno));
return srslte::ERROR_CANT_START;
}
m_spgw_log->info("S1-U socket = %d\n", m_s1u);
m_spgw_log->info("S1-U IP = %s, Port = %d \n", inet_ntoa(m_s1u_addr.sin_addr),ntohs(m_s1u_addr.sin_port));
m_spgw_log->info("S1-U IP = %s, Port = %d \n", inet_ntoa(m_s1u_addr.sin_addr), ntohs(m_s1u_addr.sin_port));
return srslte::ERROR_NONE;
}
srslte::error_t
spgw::init_ue_ip(spgw_args_t *args)
srslte::error_t spgw::init_ue_ip(spgw_args_t* args)
{
m_h_next_ue_ip = ntohl(inet_addr(args->sgi_if_addr.c_str()));
return srslte::ERROR_NONE;
}
void
spgw::run_thread()
void spgw::run_thread()
{
//Mark the thread as running
m_running=true;
srslte::byte_buffer_t *msg;
// Mark the thread as running
m_running = true;
srslte::byte_buffer_t* msg;
msg = m_pool->allocate();
struct sockaddr src_addr;
socklen_t addrlen;
struct iphdr *ip_pkt;
int sgi = m_sgi_if;
socklen_t addrlen;
struct iphdr* ip_pkt;
int sgi = m_sgi_if;
fd_set set;
//struct timeval to;
int max_fd = std::max(m_s1u,sgi);
// struct timeval to;
int max_fd = std::max(m_s1u, sgi);
while (m_running) {
msg->reset();
FD_ZERO(&set);
FD_SET(m_s1u, &set);
FD_SET(sgi, &set);
//m_spgw_log->info("Waiting for S1-U or SGi packets.\n");
int n = select(max_fd+1, &set, NULL, NULL, NULL);
// m_spgw_log->info("Waiting for S1-U or SGi packets.\n");
int n = select(max_fd + 1, &set, NULL, NULL, NULL);
if (n == -1) {
m_spgw_log->error("Error from select\n");
} else if (n) {
if (FD_ISSET(m_s1u, &set)) {
msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen );
msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen);
handle_s1u_pdu(msg);
}
if (FD_ISSET(m_sgi_if, &set)) {
@ -304,17 +282,16 @@ spgw::run_thread()
return;
}
void
spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
void spgw::handle_sgi_pdu(srslte::byte_buffer_t* msg)
{
uint8_t version=0;
uint32_t dest_ip;
struct in_addr dest_addr;
std::map<uint32_t,srslte::gtpc_f_teid_ie>::iterator gtp_fteid_it;
bool ip_found = false;
srslte::gtpc_f_teid_ie enb_fteid;
struct iphdr *iph = (struct iphdr *) msg->msg;
uint8_t version = 0;
uint32_t dest_ip;
struct in_addr dest_addr;
std::map<uint32_t, srslte::gtpc_f_teid_ie>::iterator gtp_fteid_it;
bool ip_found = false;
srslte::gtpc_f_teid_ie enb_fteid;
struct iphdr* iph = (struct iphdr*)msg->msg;
if (iph->version != 4) {
m_spgw_log->warning("IPv6 not supported yet.\n");
return;
@ -327,7 +304,7 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
pthread_mutex_lock(&m_mutex);
gtp_fteid_it = m_ip_to_teid.find(iph->daddr);
if (gtp_fteid_it != m_ip_to_teid.end()) {
ip_found = true;
ip_found = true;
enb_fteid = gtp_fteid_it->second;
}
pthread_mutex_unlock(&m_mutex);
@ -337,145 +314,61 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
}
struct sockaddr_in enb_addr;
enb_addr.sin_family = AF_INET;
enb_addr.sin_port = htons(GTPU_RX_PORT);
enb_addr.sin_family = AF_INET;
enb_addr.sin_port = htons(GTPU_RX_PORT);
enb_addr.sin_addr.s_addr = enb_fteid.ipv4;
//Setup GTP-U header
// Setup GTP-U header
srslte::gtpu_header_t header;
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL;
header.message_type = GTPU_MSG_DATA_PDU;
header.length = msg->N_bytes;
header.teid = enb_fteid.teid;
//Write header into packet
// Write header into packet
if (!srslte::gtpu_write_header(&header, msg, m_spgw_log)) {
m_spgw_log->console("Error writing GTP-U header on PDU\n");
}
//Send packet to destination
int n = sendto(m_s1u,msg->msg,msg->N_bytes,0,(struct sockaddr*) &enb_addr,sizeof(enb_addr));
if (n<0) {
// Send packet to destination
int n = sendto(m_s1u, msg->msg, msg->N_bytes, 0, (struct sockaddr*)&enb_addr, sizeof(enb_addr));
if (n < 0) {
m_spgw_log->error("Error sending packet to eNB\n");
return;
} 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);
} 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;
}
void
spgw::handle_s1u_pdu(srslte::byte_buffer_t *msg)
void spgw::handle_s1u_pdu(srslte::byte_buffer_t* msg)
{
//m_spgw_log->console("Received PDU from S1-U. Bytes=%d\n",msg->N_bytes);
// m_spgw_log->console("Received PDU from S1-U. Bytes=%d\n",msg->N_bytes);
srslte::gtpu_header_t header;
srslte::gtpu_read_header(msg, &header, m_spgw_log);
//m_spgw_log->console("TEID 0x%x. Bytes=%d\n", header.teid, msg->N_bytes);
// m_spgw_log->console("TEID 0x%x. Bytes=%d\n", header.teid, msg->N_bytes);
int n = write(m_sgi_if, msg->msg, msg->N_bytes);
if (n<0) {
if (n < 0) {
m_spgw_log->error("Could not write to TUN interface.\n");
} else {
//m_spgw_log->console("Forwarded packet to TUN interface. Bytes= %d/%d\n", n, msg->N_bytes);
// m_spgw_log->console("Forwarded packet to TUN interface. Bytes= %d/%d\n", n, msg->N_bytes);
}
return;
}
/*
* Helper Functions
* GTP-C Handler Functions
*/
uint64_t
spgw::get_new_ctrl_teid()
{
return m_next_ctrl_teid++;
}
uint64_t
spgw::get_new_user_teid()
{
return m_next_user_teid++;
}
in_addr_t
spgw::get_new_ue_ipv4()
{
m_h_next_ue_ip++;
return ntohl(m_h_next_ue_ip);//FIXME Tmp hack
}
spgw_tunnel_ctx_t*
spgw::create_gtp_ctx(struct srslte::gtpc_create_session_request *cs_req)
{
//Setup uplink control TEID
uint64_t spgw_uplink_ctrl_teid = get_new_ctrl_teid();
//Setup uplink user TEID
uint64_t spgw_uplink_user_teid = get_new_user_teid();
//Allocate UE IP
in_addr_t ue_ip = get_new_ue_ipv4();
//in_addr_t ue_ip = inet_addr("172.16.0.2");
uint8_t default_bearer_id = 5;
m_spgw_log->console("SPGW: Allocated Ctrl TEID %" PRIu64 "\n", spgw_uplink_ctrl_teid);
m_spgw_log->console("SPGW: Allocated User TEID %" PRIu64 "\n", spgw_uplink_user_teid);
struct in_addr ue_ip_;
ue_ip_.s_addr=ue_ip;
m_spgw_log->console("SPGW: Allocate UE IP %s\n", inet_ntoa(ue_ip_));
//Save the UE IP to User TEID map
spgw_tunnel_ctx_t *tunnel_ctx = new spgw_tunnel_ctx_t;
bzero(tunnel_ctx,sizeof(spgw_tunnel_ctx_t));
tunnel_ctx->imsi = cs_req->imsi;
tunnel_ctx->ebi = default_bearer_id;
tunnel_ctx->up_user_fteid.teid = spgw_uplink_user_teid;
tunnel_ctx->up_user_fteid.ipv4 = m_s1u_addr.sin_addr.s_addr;
tunnel_ctx->dw_ctrl_fteid.teid = cs_req->sender_f_teid.teid;
tunnel_ctx->dw_ctrl_fteid.ipv4 = cs_req->sender_f_teid.ipv4;
tunnel_ctx->up_ctrl_fteid.teid = spgw_uplink_ctrl_teid;
tunnel_ctx->ue_ipv4 = ue_ip;
m_teid_to_tunnel_ctx.insert(std::pair<uint32_t,spgw_tunnel_ctx_t*>(spgw_uplink_ctrl_teid,tunnel_ctx));
m_imsi_to_ctr_teid.insert(std::pair<uint64_t,uint32_t>(cs_req->imsi,spgw_uplink_ctrl_teid));
return tunnel_ctx;
}
bool
spgw::delete_gtp_ctx(uint32_t ctrl_teid)
{
spgw_tunnel_ctx_t *tunnel_ctx;
if (!m_teid_to_tunnel_ctx.count(ctrl_teid)) {
m_spgw_log->error("Could not find GTP context to delete.\n");
return false;
}
tunnel_ctx = m_teid_to_tunnel_ctx[ctrl_teid];
//Remove GTP-U connections, if any.
if (m_ip_to_teid.count(tunnel_ctx->ue_ipv4)) {
pthread_mutex_lock(&m_mutex);
m_ip_to_teid.erase(tunnel_ctx->ue_ipv4);
pthread_mutex_unlock(&m_mutex);
}
//Remove Ctrl TEID from IMSI to control TEID map
m_imsi_to_ctr_teid.erase(tunnel_ctx->imsi);
//Remove GTP context from control TEID mapping
m_teid_to_tunnel_ctx.erase(ctrl_teid);
delete tunnel_ctx;
return true;
}
void
spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu)
void spgw::handle_create_session_request(struct srslte::gtpc_create_session_request* cs_req,
struct srslte::gtpc_pdu* cs_resp_pdu)
{
m_spgw_log->info("Received Create Session Request\n");
spgw_tunnel_ctx_t *tunnel_ctx;
int default_bearer_id = 5;
//Check if IMSI has active GTP-C and/or GTP-U
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 %015" PRIu64 " already exists.\n", cs_req->imsi);
@ -486,64 +379,64 @@ spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *
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;
// 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;
// Setup GTP-C header
header->piggyback = false;
header->teid_present = true;
header->teid = tunnel_ctx->dw_ctrl_fteid.teid; //Send create session requesponse to the UE's MME Ctrl TEID
header->type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE;
header->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
// 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)
// Setup sender F-TEID (ctrl)
cs_resp->sender_f_teid.ipv4_present = true;
cs_resp->sender_f_teid = tunnel_ctx->up_ctrl_fteid;
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 = tunnel_ctx->up_user_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 = tunnel_ctx->up_user_fteid;
//Fill in the PAA
cs_resp->paa_present = true;
cs_resp->paa.pdn_type = srslte::GTPC_PDN_TYPE_IPV4;
// 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 = tunnel_ctx->ue_ipv4;
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;
}
void
spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct srslte::gtpc_pdu *mb_resp_pdu)
void spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu* mb_req_pdu, struct srslte::gtpc_pdu* mb_resp_pdu)
{
m_spgw_log->info("Received Modified Bearer Request\n");
//Get control tunnel info from mb_req PDU
uint32_t ctrl_teid = mb_req_pdu->header.teid;
std::map<uint32_t,spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
// Get control tunnel info from mb_req PDU
uint32_t ctrl_teid = mb_req_pdu->header.teid;
std::map<uint32_t, spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
if (tunnel_it == m_teid_to_tunnel_ctx.end()) {
m_spgw_log->warning("Could not find TEID %d to modify\n",ctrl_teid);
m_spgw_log->warning("Could not find TEID %d to modify\n", ctrl_teid);
return;
}
spgw_tunnel_ctx_t *tunnel_ctx = tunnel_it->second;
spgw_tunnel_ctx_t* tunnel_ctx = tunnel_it->second;
//Store user DW link TEID
srslte::gtpc_modify_bearer_request *mb_req = &mb_req_pdu->choice.modify_bearer_request;
tunnel_ctx->dw_user_fteid.teid = mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid;
tunnel_ctx->dw_user_fteid.ipv4 = mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.ipv4;
//Set up actual tunnel
// Store user DW link TEID
srslte::gtpc_modify_bearer_request* mb_req = &mb_req_pdu->choice.modify_bearer_request;
tunnel_ctx->dw_user_fteid.teid = mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid;
tunnel_ctx->dw_user_fteid.ipv4 = mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.ipv4;
// Set up actual tunnel
m_spgw_log->info("Setting Up GTP-U tunnel. Tunnel info: \n");
struct in_addr addr;
addr.s_addr = tunnel_ctx->ue_ipv4;
m_spgw_log->info("IMSI: %lu, UE IP, %s \n",tunnel_ctx->imsi, inet_ntoa(addr));
m_spgw_log->info("S-GW Rx Ctrl TEID 0x%x, MME Rx Ctrl TEID 0x%x\n", tunnel_ctx->up_ctrl_fteid.teid, tunnel_ctx->dw_ctrl_fteid.teid);
m_spgw_log->info("IMSI: %lu, UE IP, %s \n", tunnel_ctx->imsi, inet_ntoa(addr));
m_spgw_log->info("S-GW Rx Ctrl TEID 0x%x, MME Rx Ctrl TEID 0x%x\n", tunnel_ctx->up_ctrl_fteid.teid,
tunnel_ctx->dw_ctrl_fteid.teid);
m_spgw_log->info("S-GW Rx Ctrl IP (NA), MME Rx Ctrl IP (NA)\n");
struct in_addr addr2;
@ -554,79 +447,158 @@ spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct s
addr3.s_addr = tunnel_ctx->dw_user_fteid.ipv4;
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;
// Setup IP to F-TEID map
// bool ret = false;
pthread_mutex_lock(&m_mutex);
m_ip_to_teid[tunnel_ctx->ue_ipv4]=tunnel_ctx->dw_user_fteid;
//ret = m_ip_to_teid.insert(std::pair<uint32_t,srslte::gtpc_f_teid_ie>(tunnel_ctx->ue_ipv4, tunnel_ctx->dw_user_fteid));
m_ip_to_teid[tunnel_ctx->ue_ipv4] = tunnel_ctx->dw_user_fteid;
// ret = m_ip_to_teid.insert(std::pair<uint32_t,srslte::gtpc_f_teid_ie>(tunnel_ctx->ue_ipv4,
// tunnel_ctx->dw_user_fteid));
pthread_mutex_unlock(&m_mutex);
//Setting up Modify bearer response PDU
//Header
srslte::gtpc_header *header = &mb_resp_pdu->header;
header->piggyback = false;
header->teid_present = true;
header->teid = tunnel_ctx->dw_ctrl_fteid.teid; //
header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE;
//PDU
srslte::gtpc_modify_bearer_response *mb_resp = &mb_resp_pdu->choice.modify_bearer_response;
mb_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
mb_resp->eps_bearer_context_modified.ebi = tunnel_ctx->ebi;
// Setting up Modify bearer response PDU
// Header
srslte::gtpc_header* header = &mb_resp_pdu->header;
header->piggyback = false;
header->teid_present = true;
header->teid = tunnel_ctx->dw_ctrl_fteid.teid; //
header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE;
// PDU
srslte::gtpc_modify_bearer_response* mb_resp = &mb_resp_pdu->choice.modify_bearer_response;
mb_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
mb_resp->eps_bearer_context_modified.ebi = tunnel_ctx->ebi;
mb_resp->eps_bearer_context_modified.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
return;
}
void
spgw::handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct srslte::gtpc_pdu *del_resp_pdu)
void spgw::handle_delete_session_request(struct srslte::gtpc_pdu* del_req_pdu, struct srslte::gtpc_pdu* del_resp_pdu)
{
//Find tunel ctxt
uint32_t ctrl_teid = del_req_pdu->header.teid;
std::map<uint32_t,spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
// Find tunel ctxt
uint32_t ctrl_teid = del_req_pdu->header.teid;
std::map<uint32_t, spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
if (tunnel_it == m_teid_to_tunnel_ctx.end()) {
m_spgw_log->warning("Could not find TEID %d to delete\n",ctrl_teid);
m_spgw_log->warning("Could not find TEID %d to delete\n", ctrl_teid);
return;
}
spgw_tunnel_ctx_t *tunnel_ctx = tunnel_it->second;
in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4;
spgw_tunnel_ctx_t* tunnel_ctx = tunnel_it->second;
in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4;
//Delete data tunnel
// Delete data tunnel
pthread_mutex_lock(&m_mutex);
std::map<in_addr_t,srslte::gtp_fteid_t>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4);
std::map<in_addr_t, srslte::gtp_fteid_t>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4);
if (data_it != m_ip_to_teid.end()) {
m_ip_to_teid.erase(data_it);
}
pthread_mutex_unlock(&m_mutex);
m_teid_to_tunnel_ctx.erase(tunnel_it);
delete tunnel_ctx;
delete tunnel_ctx;
return;
}
void
spgw::handle_release_access_bearers_request(struct srslte::gtpc_pdu *rel_req_pdu, struct srslte::gtpc_pdu *rel_resp_pdu)
void spgw::handle_release_access_bearers_request(struct srslte::gtpc_pdu* rel_req_pdu,
struct srslte::gtpc_pdu* rel_resp_pdu)
{
//Find tunel ctxt
uint32_t ctrl_teid = rel_req_pdu->header.teid;
std::map<uint32_t,spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
// Find tunel ctxt
uint32_t ctrl_teid = rel_req_pdu->header.teid;
std::map<uint32_t, spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
if (tunnel_it == m_teid_to_tunnel_ctx.end()) {
m_spgw_log->warning("Could not find TEID %d to release bearers from\n",ctrl_teid);
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;
spgw_tunnel_ctx_t* tunnel_ctx = tunnel_it->second;
in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4;
//Delete data tunnel
// Delete data tunnel
pthread_mutex_lock(&m_mutex);
std::map<in_addr_t,srslte::gtpc_f_teid_ie>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4);
std::map<in_addr_t, srslte::gtpc_f_teid_ie>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4);
if (data_it != m_ip_to_teid.end()) {
m_ip_to_teid.erase(data_it);
}
pthread_mutex_unlock(&m_mutex);
//Do NOT delete control tunnel
// Do NOT delete control tunnel
return;
}
} //namespace srsepc
/*
* Helper Functions
*/
uint64_t spgw::get_new_ctrl_teid()
{
return m_next_ctrl_teid++;
}
uint64_t spgw::get_new_user_teid()
{
return m_next_user_teid++;
}
in_addr_t spgw::get_new_ue_ipv4()
{
m_h_next_ue_ip++;
return ntohl(m_h_next_ue_ip); // FIXME Tmp hack
}
spgw_tunnel_ctx_t* spgw::create_gtp_ctx(struct srslte::gtpc_create_session_request* cs_req)
{
// Setup uplink control TEID
uint64_t spgw_uplink_ctrl_teid = get_new_ctrl_teid();
// Setup uplink user TEID
uint64_t spgw_uplink_user_teid = get_new_user_teid();
// Allocate UE IP
in_addr_t ue_ip = get_new_ue_ipv4();
// in_addr_t ue_ip = inet_addr("172.16.0.2");
uint8_t default_bearer_id = 5;
m_spgw_log->console("SPGW: Allocated Ctrl TEID %" PRIu64 "\n", spgw_uplink_ctrl_teid);
m_spgw_log->console("SPGW: Allocated User TEID %" PRIu64 "\n", spgw_uplink_user_teid);
struct in_addr ue_ip_;
ue_ip_.s_addr = ue_ip;
m_spgw_log->console("SPGW: Allocate UE IP %s\n", inet_ntoa(ue_ip_));
// Save the UE IP to User TEID map
spgw_tunnel_ctx_t* tunnel_ctx = new spgw_tunnel_ctx_t;
bzero(tunnel_ctx, sizeof(spgw_tunnel_ctx_t));
tunnel_ctx->imsi = cs_req->imsi;
tunnel_ctx->ebi = default_bearer_id;
tunnel_ctx->up_user_fteid.teid = spgw_uplink_user_teid;
tunnel_ctx->up_user_fteid.ipv4 = m_s1u_addr.sin_addr.s_addr;
tunnel_ctx->dw_ctrl_fteid.teid = cs_req->sender_f_teid.teid;
tunnel_ctx->dw_ctrl_fteid.ipv4 = cs_req->sender_f_teid.ipv4;
tunnel_ctx->up_ctrl_fteid.teid = spgw_uplink_ctrl_teid;
tunnel_ctx->ue_ipv4 = ue_ip;
m_teid_to_tunnel_ctx.insert(std::pair<uint32_t, spgw_tunnel_ctx_t*>(spgw_uplink_ctrl_teid, tunnel_ctx));
m_imsi_to_ctr_teid.insert(std::pair<uint64_t, uint32_t>(cs_req->imsi, spgw_uplink_ctrl_teid));
return tunnel_ctx;
}
bool spgw::delete_gtp_ctx(uint32_t ctrl_teid)
{
spgw_tunnel_ctx_t* tunnel_ctx;
if (!m_teid_to_tunnel_ctx.count(ctrl_teid)) {
m_spgw_log->error("Could not find GTP context to delete.\n");
return false;
}
tunnel_ctx = m_teid_to_tunnel_ctx[ctrl_teid];
// Remove GTP-U connections, if any.
if (m_ip_to_teid.count(tunnel_ctx->ue_ipv4)) {
pthread_mutex_lock(&m_mutex);
m_ip_to_teid.erase(tunnel_ctx->ue_ipv4);
pthread_mutex_unlock(&m_mutex);
}
// Remove Ctrl TEID from IMSI to control TEID map
m_imsi_to_ctr_teid.erase(tunnel_ctx->imsi);
// Remove GTP context from control TEID mapping
m_teid_to_tunnel_ctx.erase(ctrl_teid);
delete tunnel_ctx;
return true;
}
} // namespace srsepc

Loading…
Cancel
Save