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

@ -26,121 +26,121 @@
#include "srslte/asn1/gtpc_ies.h" #include "srslte/asn1/gtpc_ies.h"
namespace srslte{ namespace srslte {
/**************************************************************** /****************************************************************
* *
* GTP-C Message Types * 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_RESERVED = 0;
const uint8_t GTPC_MSG_TYPE_ECHO_REQUEST = 1; const uint8_t GTPC_MSG_TYPE_ECHO_REQUEST = 1;
const uint8_t GTPC_MSG_TYPE_ECHO_RESPONSE = 2; const uint8_t GTPC_MSG_TYPE_ECHO_RESPONSE = 2;
const uint8_t GTPC_MSG_TYPE_VERSION_SUPPORT = 3; const uint8_t GTPC_MSG_TYPE_VERSION_SUPPORT = 3;
//4-24 Reserved for S101 // 4-24 Reserved for S101
//25-31 Reserved for Sv interface // 25-31 Reserved for Sv interface
//SGSN/MME/ePDG to PGW (S4/S11, S5/S8, S2b) // 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_REQUEST = 32;
const uint8_t GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE = 33; 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; const uint8_t GTPC_MSG_TYPE_DELETE_SESSION_RESPONSE = 37;
//SGSN/MME to PGW (S4/S11, S5/S8) // 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_REQUEST = 34;
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE = 35; 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_REQUEST = 38;
const uint8_t GTPC_MSG_TYPE_CHANGE_NOTIFICATION_RESPONSE = 39; 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_NOTIFICATION = 164;
const uint8_t GTPC_MSG_TYPE_RESUME_ACKNOWLEDGE = 165; const uint8_t GTPC_MSG_TYPE_RESUME_ACKNOWLEDGE = 165;
//Messages without explicit response // 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_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_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_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_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_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_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_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_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_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) const uint8_t GTPC_MSG_TYPE_STOP_PAGING_INDICATION = 73; //(SGW to MME/SGSN S11/S4)
//74-94 For future use // 74-94 For future use
//P-GW to SGSN/MME/ePDG // P-GW to SGSN/MME/ePDG
const uint8_t GTPC_MSG_TYPE_CREATE_BEARER_REQUEST = 95; 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_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_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; 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) // 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_REQUEST = 101;
const uint8_t GTPC_MSG_TYPE_DELETE_PDN_CONNECTION_SET_RESPONSE = 102; const uint8_t GTPC_MSG_TYPE_DELETE_PDN_CONNECTION_SET_RESPONSE = 102;
//103-127 For future use // 103-127 For future use
//MME to MME, SGSN to MME, MME to SGSN, SGSN to SGSN (S3/S10/S16) // 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_REQUEST = 128;
const uint8_t GTPC_MSG_TYPE_IDENTIFICATION_RESPONSE = 129; 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_REQUEST = 130;
const uint8_t GTPC_MSG_TYPE_CONTEXT_RESPONSE = 131; const uint8_t GTPC_MSG_TYPE_CONTEXT_RESPONSE = 131;
const uint8_t GTPC_MSG_TYPE_CONTEXT_ACKNOWLEDGE = 132; 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_REQUEST = 133;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_RESPONSE = 134; 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_NOTIFICATION = 135;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_COMPLETE_ACKNOWLEDGE = 136; 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_NOTIFICATION = 137;
const uint8_t GTPC_MSG_TYPE_FORWARD_ACCESS_CONTEXT_ACKNOWLEDGE = 138; 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_REQUEST = 139;
const uint8_t GTPC_MSG_TYPE_RELOCATION_CANCEL_RESPONSE = 140; const uint8_t GTPC_MSG_TYPE_RELOCATION_CANCEL_RESPONSE = 140;
const uint8_t GTPC_MSG_TYPE_CONFIGURATION_TRANSFER_TUNNEL = 141; const uint8_t GTPC_MSG_TYPE_CONFIGURATION_TRANSFER_TUNNEL = 141;
//142 - 148 For future use // 142 - 148 For future use
const uint8_t GTPC_MSG_TYPE_RAN_INFORMATION_RELAY = 152; const uint8_t GTPC_MSG_TYPE_RAN_INFORMATION_RELAY = 152;
//SGSN to MME, MME to SGSN (S3) // SGSN to MME, MME to SGSN (S3)
const uint8_t GTPC_MSG_TYPE_DETACH_NOTIFICATION = 149; const uint8_t GTPC_MSG_TYPE_DETACH_NOTIFICATION = 149;
const uint8_t GTPC_MSG_TYPE_DETACH_ACKNOWLEDGE = 150; 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_CS_PAGING_INDICATION = 151;
const uint8_t GTPC_MSG_TYPE_ALERT_MME_NOTIFICATION = 153; 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_ALERT_MME_ACKNOWLEDGE = 154;
const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_NOTIFICATION = 155; const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_NOTIFICATION = 155;
const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_ACKNOWLEDGE = 156; const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_ACKNOWLEDGE = 156;
//157 - 159 For future use // 157 - 159 For future use
//GSN/MME to SGW, SGSN to MME (S4/S11/S3) SGSN to SGSN (S16), SGW to PGW (S5/S8) // 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_NOTIFICATION = 162;
const uint8_t GTPC_MSG_TYPE_SUSPEND_ACKNOWLEDGE = 163; const uint8_t GTPC_MSG_TYPE_SUSPEND_ACKNOWLEDGE = 163;
//SGSN/MME to SGW (S4/S11) const uint8_t GTPC_IE_TYPE_ // 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_REQUEST = 160;
const uint8_t GTPC_MSG_TYPE_CREATE_FORWARDING_TUNNEL_RESPONSE = 161; 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_REQUEST = 166;
const uint8_t GTPC_MSG_TYPE_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_RESPONSE = 167; 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_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_REQUEST = 170;
const uint8_t GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_RESPONSE = 171; const uint8_t GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_RESPONSE = 171;
//172 - 175 For future use // 172 - 175 For future use
//SGW to SGSN/MME (S4/S11) // 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 = 176;
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION_ACKNOWLEDGE = 177; 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 = 179;
const uint8_t GTPC_MSG_TYPE_PGW_RESTART_NOTIFICATION_ACKNOWLEDGE = 180; const uint8_t GTPC_MSG_TYPE_PGW_RESTART_NOTIFICATION_ACKNOWLEDGE = 180;
//SGW to SGSN (S4) // SGW to SGSN (S4)
//178 Reserved. Allocated in earlier version of the specification. // 178 Reserved. Allocated in earlier version of the specification.
//181 -189 For future use // 181 -189 For future use
//SGW to PGW, PGW to SGW (S5/S8) // 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_REQUEST = 200;
const uint8_t GTPC_MSG_TYPE_UPDATE_PDN_CONNECTION_SET_RESPONSE = 201; const uint8_t GTPC_MSG_TYPE_UPDATE_PDN_CONNECTION_SET_RESPONSE = 201;
//For future use // For future use
//MME to SGW (S11) // MME to SGW (S11)
const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_REQUEST = 211; const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_REQUEST = 211;
const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_RESPONSE = 212; const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_RESPONSE = 212;
//For future use // For future use
//MBMS GW to MME/SGSN (Sm/Sn) // 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_REQUEST = 231;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_START_RESPONSE = 232; 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_REQUEST = 233;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_UPDATE_RESPONSE = 234; 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_REQUEST = 235;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_RESPONSE = 236; const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_RESPONSE = 236;
//For future use // For future use
//Other // Other
//240 - 255 For future use // 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 * 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 enum gtpc_rat_type rat_type; // M
{ // bool indication_flags_present;
bool imsi_present; // struct indication_flags_ indication_flags; // C
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 struct gtpc_f_teid_ie sender_f_teid; // M
//bool indication_flags_present; bool pgw_addr_present;
//struct indication_flags_ indication_flags; // C struct gtpc_f_teid_ie pgw_addr; // C
struct gtpc_f_teid_ie sender_f_teid; // M char apn[MAX_APN_LENGTH]; // M
bool pgw_addr_present; // bool selection_mode_present;
struct gtpc_f_teid_ie pgw_addr; // C // 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 struct gtpc_bearer_context_created_ie // see TS 29.274 v10.14.0 Table 7.2.1-2
//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
{ {
uint8_t ebi; uint8_t ebi;
bool tft_present; bool tft_present;
bool s1_u_enodeb_f_teid_present; bool s1_u_enodeb_f_teid_present;
struct gtpc_f_teid_ie s1_u_enodeb_f_teid; struct gtpc_f_teid_ie s1_u_enodeb_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; struct gtpc_f_teid_ie s4_u_sgsn_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; struct gtpc_f_teid_ie s5_s8_u_sgw_f_teid;
bool s5_s8_u_pgw_f_teid_present; bool s5_s8_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid; struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid;
bool s12_rnc_f_teid_present; bool s12_rnc_f_teid_present;
struct gtpc_f_teid_ie s12_rnc_f_teid; struct gtpc_f_teid_ie s12_rnc_f_teid;
bool s2b_u_epdg_f_teid_present; bool s2b_u_epdg_f_teid_present;
struct gtpc_f_teid_ie s2b_u_epdg_f_teid; struct gtpc_f_teid_ie s2b_u_epdg_f_teid;
struct gtpc_bearer_qos_ie bearer_qos; // M struct gtpc_bearer_qos_ie bearer_qos;
} eps_bearer_context_created; // M } eps_bearer_context_created;
//bool bearer_context_deleted_present; // bool bearer_context_deleted_present;
//struct bearer_context_ bearer_context_deleted; // C // struct bearer_context_ bearer_context_deleted; // C
//bool trace_information_present; // bool trace_information_present;
//struct trace_infromation_ trace_information; // C // struct trace_infromation_ trace_information; // C
//bool recovery_present // bool recovery_present
//uint8_t recovery; // C // uint8_t recovery; // C
//bool mme_fq_csid_present; // bool mme_fq_csid_present;
//struct fq_csid_ mme_fq_csid; // C // struct fq_csid_ mme_fq_csid; // C
//bool sgw_fq_csid_present; // bool sgw_fq_csid_present;
//struct fq_csid_ sgw_fq_csid; // C // struct fq_csid_ sgw_fq_csid; // C
//bool epdg_fq_csid_present; // bool epdg_fq_csid_present;
//struct fq_csid_ epdg_fq_csid; // C // struct fq_csid_ epdg_fq_csid; // C
//bool ue_time_zone_present; // bool ue_time_zone_present;
//struct ue_time_zone_ ue_time_zone; // CO // struct ue_time_zone_ ue_time_zone; // CO
//bool uci_present; // bool uci_present;
//struct uci_ uci; // CO // struct uci_ uci; // CO
//bool charging_caracteristics_present; // bool charging_caracteristics_present;
//enum charging_characteristics_ charging_caracteristics; // O // enum charging_characteristics_ charging_caracteristics; // O
//bool mme_ldn_present; // bool mme_ldn_present;
//uint8_t mme_ldn[LDN_MAX_SIZE]; // O // uint8_t mme_ldn[LDN_MAX_SIZE]; // O
//bool sgw_ldn_present; // bool sgw_ldn_present;
//uint8_t sgw_ldn[LDN_MAX_SIZE]; // O // uint8_t sgw_ldn[LDN_MAX_SIZE]; // O
//bool epgd_ldn_present; // bool epgd_ldn_present;
//uint8_t epdg_ldn[LDN_MAX_SIZE]; // O // uint8_t epdg_ldn[LDN_MAX_SIZE]; // O
//bool signaling_priority_indication; // bool signaling_priority_indication;
//enum signalling_priority_indication_ spi; // CO // enum signalling_priority_indication_ spi; // CO
//bool acpo_present; // bool acpo_present;
//uint8_t apco; // CO // uint8_t apco; // CO
//bool ext; // O // 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 * Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.2-1
* *
***************************************************************************/ ***************************************************************************/
struct gtpc_create_session_response struct gtpc_create_session_response {
{ struct gtpc_cause_ie cause; // M
struct gtpc_cause_ie cause; //M // Change Reporting Action //C
//Change Reporting Action //C // CSG Information Reporting Action //CO
//CSG Information Reporting Action //CO bool sender_f_teid_present;
bool sender_f_teid_present; struct gtpc_f_teid_ie sender_f_teid; // C
struct gtpc_f_teid_ie sender_f_teid; //C // PGW S5/S8/S2b F-TEID //C
//PGW S5/S8/S2b F-TEID //C bool paa_present;
bool paa_present; struct gtpc_pdn_address_allocation_ie paa; // C
struct gtpc_pdn_address_allocation_ie paa; //C // apn_restriction
//apn_restriction // apn_ambr
//apn_ambr // linked_eps_bearer_id
//linked_eps_bearer_id // pco
//pco struct gtpc_bearer_context_created_ie {
struct gtpc_bearer_context_created_ie uint8_t ebi;
{ gtpc_cause_ie cause;
uint8_t ebi; bool s1_u_sgw_f_teid_present;
gtpc_cause_ie cause; struct gtpc_f_teid_ie s1_u_sgw_f_teid;
bool s1_u_sgw_f_teid_present; bool s4_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s1_u_sgw_f_teid; struct gtpc_f_teid_ie s4_u_sgw_f_teid;
bool s4_u_sgw_f_teid_present; bool s5_s8_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgw_f_teid; struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid;
bool s5_s8_u_pgw_f_teid_present; bool s12_sgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid; struct gtpc_f_teid_ie s12_sgw_f_teid;
bool s12_sgw_f_teid_present; bool s2b_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s12_sgw_f_teid; struct gtpc_f_teid_ie s2b_u_pgw_f_teid;
bool s2b_u_pgw_f_teid_present; bool bearer_level_qos_present;
struct gtpc_f_teid_ie s2b_u_pgw_f_teid;
bool bearer_level_qos_present;
struct gtpc_bearer_qos_ie bearer_level_qos; struct gtpc_bearer_qos_ie bearer_level_qos;
//charging_id_present // charging_id_present
//charging_id // charging_id
//bearer_flags_present // bearer_flags_present
//bearer_flags // bearer_flags
} eps_bearer_context_created; //M } eps_bearer_context_created; // M
/* /*
struct gtpc_bearer_context_removed_ie struct gtpc_bearer_context_removed_ie
{ {
uint8_t ebi; uint8_t ebi;
//
} bearer_context_removed; //C } bearer_context_removed; //C
*/ */
//recovery; //C // recovery; //C
//charging_gateway_name; //C // charging_gateway_name; //C
//charging_gateway_address; //C // charging_gateway_address; //C
//PGW-FQ-CSID //C // PGW-FQ-CSID //C
//SGW-FQ-CSID //C // SGW-FQ-CSID //C
//SGW LDN //O // SGW LDN //O
//PGW LDN //O // PGW LDN //O
//PGW Back-Off Time //O // PGW Back-Off Time //O
//acpo //CO // 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 * Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.7-1, 7.2.7-2 and 7.2.7-3
* *
***************************************************************************/ ***************************************************************************/
struct gtpc_modify_bearer_request {
struct gtpc_modify_bearer_request // ME Identity (MEI)//C
{ // User Location Information (ULI)//C
//ME Identity (MEI)//C // Serving Network //CO
//User Location Information (ULI)//C // RAT Type //C/CO
//Serving Network //CO // Indication Flags
//RAT Type //C/CO // Sender F-TEID for Control Plane
//Indication Flags // APN-AMBR
//Sender F-TEID for Control Plane // Delay Downlink Packet Notification Request
//APN-AMBR struct gtpc_bearer_context_modified_ie {
//Delay Downlink Packet Notification Request uint8_t ebi;
struct gtpc_bearer_context_modified_ie gtpc_cause_ie cause;
{ bool s1_u_enb_f_teid_present;
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_enb_f_teid_present;
struct gtpc_f_teid_ie s1_u_enb_f_teid; 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; 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; 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; struct gtpc_f_teid_ie s4_u_sgsn_f_teid;
} eps_bearer_context_to_modify; } eps_bearer_context_to_modify;
//Bearer Contexts to be removed // Bearer Contexts to be removed
//Recovery // Recovery
//UE Time Zone // UE Time Zone
//MME-FQ-CSID // MME-FQ-CSID
//SGW-FQ-CSID // SGW-FQ-CSID
//User CSG Information (UCI) // User CSG Information (UCI)
//MME/S4-SGSN LDN // MME/S4-SGSN LDN
//SGW 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 * 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; struct gtpc_cause_ie cause;
//MSISDN // MSISDN
//Linked EPS Bearer ID // Linked EPS Bearer ID
//APN-AMBR // APN-AMBR
//APN Restriction // APN Restriction
//Protocol Configuration Options // Protocol Configuration Options
struct gtpc_bearer_context_modified_ie struct gtpc_bearer_context_modified_ie {
{ uint8_t ebi;
uint8_t ebi; struct gtpc_cause_ie cause;
struct gtpc_cause_ie cause; bool s1_u_sgw_f_teid_present;
bool s1_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s1_u_sgw_f_teid; 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; 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; struct gtpc_f_teid_ie s4_u_sgw_f_teid;
//charging id // charging id
//bearer flags // bearer flags
} eps_bearer_context_modified; } eps_bearer_context_modified;
//Bearer Contexts marked for removal // Bearer Contexts marked for removal
//Change Reporting action // Change Reporting action
//CSG information reporting action // CSG information reporting action
//Charging gateway name // Charging gateway name
//charging gateway address // charging gateway address
//P-GW FQ-CSID // P-GW FQ-CSID
//S-GW FQ-CSID // S-GW FQ-CSID
//Recovery // Recovery
//S-GW LDN // S-GW LDN
//P-GW LDN // P-GW LDN
//indication Flags // indication Flags
//ext // ext
}; };
/**************************************************************************** /****************************************************************************
@ -384,16 +373,14 @@ struct gtpc_modify_bearer_response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.9.1-1 * 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; struct gtpc_cause_ie cause;
//Linked EPS Bearer ID // Linked EPS Bearer ID
//User Location Information // User Location Information
//Indication Flags // Indication Flags
//Protocol Configuration Options // Protocol Configuration Options
//Originating Node // Originating Node
//Private extension // 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 * 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; struct gtpc_cause_ie cause;
//Recovery // Recovery
//Protocol Configuration Options // Protocol Configuration Options
//Private extension // 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 * 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; bool list_of_rabs_present;
//Linked EPS Bearer ID // Linked EPS Bearer ID
bool originating_node_present; bool originating_node_present;
//Indication Flags // Indication Flags
//Private Extension // Private Extension
}; };
/**************************************************************************** /****************************************************************************
* *
* GTP-C v2 Delete Session Response * GTP-C v2 Delete Session Response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.22.1-1 * Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.22.1-1
* *
***************************************************************************/ ***************************************************************************/
struct gtpc_release_access_bearers_response {
struct gtpc_release_access_bearers_response struct gtpc_cause_ie cause;
{ // Recovery
struct gtpc_cause_ie cause; // Private extension
//Recovery };
//Private extension
};
} //namespace } // namespace srslte
#endif // SRSLTE_GTPC_MSG_H #endif // SRSLTE_GTPC_MSG_H

@ -27,48 +27,50 @@ namespace srsepc {
class nas; class nas;
//NAS -> GTP-C /******************
class gtpc_interface_nas * MME Interfaces *
******************/
class gtpc_interface_nas // NAS -> GTP-C
{ {
public: public:
virtual bool send_create_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, struct srslte::gtpc_f_teid_ie *enb_fteid) = 0; virtual bool send_modify_bearer_request(uint64_t imsi, uint16_t erab_to_modify, srslte::gtp_fteid_t* enb_fteid) = 0;
virtual bool send_delete_session_request(uint64_t imsi) = 0; virtual bool send_delete_session_request(uint64_t imsi) = 0;
}; };
//GTP-C -> S1AP class s1ap_interface_gtpc // GTP-C -> S1AP
class s1ap_interface_gtpc
{ {
public: public:
virtual bool send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup) = 0; virtual bool send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup) = 0;
}; };
//NAS -> S1AP class s1ap_interface_nas // NAS -> S1AP
class s1ap_interface_nas
{ {
public: public:
virtual uint32_t allocate_m_tmsi(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 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_imsi_map(nas* nas_ctx) = 0;
virtual bool add_nas_ctx_to_mme_ue_s1ap_id_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 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 release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id) = 0;
virtual bool delete_ue_ctx(uint64_t imsi) = 0; virtual bool delete_ue_ctx(uint64_t imsi) = 0;
virtual uint64_t find_imsi_from_m_tmsi(uint32_t m_tmsi) = 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 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_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_ue_context_release_command(uint32_t mme_ue_s1ap_id) = 0;
virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, srslte::byte_buffer_t *nas_msg, struct sctp_sndrcvinfo enb_sri) = 0; virtual bool send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri) = 0;
}; };
//NAS -> HSS class hss_interface_nas // NAS -> HSS
class hss_interface_nas
{ {
public: 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_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 gen_update_loc_answer(uint64_t imsi, uint8_t* qci) = 0;
virtual bool resync_sqn(uint64_t imsi, uint8_t *auts) = 0; virtual bool resync_sqn(uint64_t imsi, uint8_t* auts) = 0;
}; };
} } // namespace srsepc
#endif // SRSLTE_EPC_INTERFACES_H #endif // SRSLTE_EPC_INTERFACES_H

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

@ -47,93 +47,86 @@
#define LTE_FDD_ENB_IND_HE_MAX_VALUE 31 #define LTE_FDD_ENB_IND_HE_MAX_VALUE 31
#define LTE_FDD_ENB_SEQ_HE_MAX_VALUE 0x07FFFFFFFFFFUL #define LTE_FDD_ENB_SEQ_HE_MAX_VALUE 0x07FFFFFFFFFFUL
namespace srsepc{ namespace srsepc {
typedef struct{ typedef struct {
std::string auth_algo; std::string auth_algo;
std::string db_file; std::string db_file;
uint16_t mcc; uint16_t mcc;
uint16_t mnc; uint16_t mnc;
}hss_args_t; } hss_args_t;
typedef struct{ typedef struct {
std::string name; std::string name;
uint64_t imsi; uint64_t imsi;
uint8_t key[16]; uint8_t key[16];
bool op_configured; bool op_configured;
uint8_t op[16]; uint8_t op[16];
uint8_t opc[16]; uint8_t opc[16];
uint8_t amf[2]; uint8_t amf[2];
uint8_t sqn[6]; uint8_t sqn[6];
uint16_t qci; uint16_t qci;
uint8_t last_rand[16]; uint8_t last_rand[16];
}hss_ue_ctx_t; } hss_ue_ctx_t;
enum hss_auth_algo { enum hss_auth_algo { HSS_ALGO_XOR, HSS_ALGO_MILENAGE };
HSS_ALGO_XOR,
HSS_ALGO_MILENAGE
};
class hss : public hss_interface_nas class hss : public hss_interface_nas
{ {
public: public:
static hss* get_instance(void); static hss* get_instance(void);
static void cleanup(void); static void cleanup(void);
int init(hss_args_t *hss_args, srslte::log_filter* hss_log); int init(hss_args_t* hss_args, srslte::log_filter* hss_log);
void stop(void); 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 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: private:
hss(); hss();
virtual ~hss(); virtual ~hss();
static hss *m_instance; static hss* m_instance;
srslte::byte_buffer_pool *m_pool;
std::map<uint64_t,hss_ue_ctx_t*> m_imsi_to_ue_ctx;
std::map<uint64_t, hss_ue_ctx_t*> m_imsi_to_ue_ctx;
void gen_rand(uint8_t rand_[16]); 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_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_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_milenage(uint64_t imsi, uint8_t* auts);
bool resync_sqn_xor(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); 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 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_ue_sqn(uint64_t imsi);
void increment_seq_after_resync(uint64_t imsi); void increment_seq_after_resync(uint64_t imsi);
void increment_sqn(uint8_t *sqn, uint8_t *next_sqn); void increment_sqn(uint8_t* sqn, uint8_t* next_sqn);
void set_sqn(uint64_t imsi, uint8_t *sqn); void set_sqn(uint64_t imsi, uint8_t* sqn);
void set_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); void get_last_rand(uint64_t imsi, uint8_t* rand);
bool set_auth_algo(std::string auth_algo); bool set_auth_algo(std::string auth_algo);
bool read_db_file(std::string db_file); bool read_db_file(std::string db_file);
bool write_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); bool get_ue_ctx(uint64_t imsi, hss_ue_ctx_t** ue_ctx);
std::string hex_string(uint8_t *hex, int size); std::string hex_string(uint8_t* hex, int size);
enum hss_auth_algo m_auth_algo; enum hss_auth_algo m_auth_algo;
std::string db_file; std::string db_file;
/*Logs*/ /*Logs*/
srslte::log_filter *m_hss_log; srslte::log_filter* m_hss_log;
uint16_t mcc; uint16_t mcc;
uint16_t mnc; uint16_t mnc;
}; };
} // namespace srsepc } // namespace srsepc
#endif // SRSEPC_HSS_H #endif // SRSEPC_HSS_H

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

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

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

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

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

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

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

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

@ -21,20 +21,20 @@
* and at http://www.gnu.org/licenses/. * 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/hss/hss.h"
#include "srsepc/hdr/mme/mme.h"
#include "srsepc/hdr/spgw/spgw.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 std;
using namespace srsepc; using namespace srsepc;
@ -42,43 +42,41 @@ namespace bpo = boost::program_options;
bool running = true; bool running = true;
void void sig_int_handler(int signo)
sig_int_handler(int signo){ {
running = false; running = false;
} }
typedef struct { typedef struct {
std::string nas_level; std::string nas_level;
int nas_hex_limit; int nas_hex_limit;
std::string s1ap_level; std::string s1ap_level;
int s1ap_hex_limit; int s1ap_hex_limit;
std::string gtpc_level; std::string gtpc_level;
int gtpc_hex_limit; int gtpc_hex_limit;
std::string spgw_level; std::string spgw_level;
int spgw_hex_limit; int spgw_hex_limit;
std::string hss_level; std::string hss_level;
int hss_hex_limit; int hss_hex_limit;
std::string all_level; std::string all_level;
int all_hex_limit; int all_hex_limit;
std::string filename; std::string filename;
}log_args_t; } log_args_t;
typedef struct {
typedef struct{ mme_args_t mme_args;
mme_args_t mme_args; hss_args_t hss_args;
hss_args_t hss_args; spgw_args_t spgw_args;
spgw_args_t spgw_args; log_args_t log_args;
log_args_t log_args; } all_args_t;
}all_args_t;
/********************************************************************** /**********************************************************************
* Program arguments processing * Program arguments processing
***********************************************************************/ ***********************************************************************/
string config_file; string config_file;
void void parse_args(all_args_t* args, int argc, char* argv[])
parse_args(all_args_t *args, int argc, char* argv[]) { {
string mme_name; string mme_name;
string mme_code; string mme_code;
string mme_group; string mme_group;
@ -107,7 +105,6 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
// Command line or config file options // Command line or config file options
bpo::options_description common("Configuration options"); bpo::options_description common("Configuration options");
common.add_options() common.add_options()
("mme.mme_code", bpo::value<string>(&mme_code)->default_value("0x01"), "MME Code") ("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.name", bpo::value<string>(&mme_name)->default_value("srsmme01"), "MME Name")
("mme.mme_group", bpo::value<string>(&mme_group)->default_value("0x01"), "Cell ID") ("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.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_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.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_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.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_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") ("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 // Positional options - config file location
bpo::options_description position("Positional options"); bpo::options_description position("Positional options");
position.add_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; bpo::positional_options_description p;
p.add("config_file", -1); p.add("config_file", -1);
@ -164,16 +159,16 @@ parse_args(all_args_t *args, int argc, char* argv[]) {
try { try {
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm); bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
bpo::notify(vm); bpo::notify(vm);
} catch(bpo::error &e) { } catch (bpo::error& e) {
cerr<< e.what() << endl; cerr << e.what() << endl;
exit(1); exit(1);
} }
// help option was given - print usage and exit // help option was given - print usage and exit
if (vm.count("help")) { if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl; cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl; cout << common << endl << general << endl;
exit(0); exit(0);
} }
// if no config file given, check users home path // 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; cout << "Reading configuration file " << config_file << "..." << endl;
ifstream conf(config_file.c_str(), ios::in); ifstream conf(config_file.c_str(), ios::in);
if(conf.fail()) { if (conf.fail()) {
cout << "Failed to read configuration file " << config_file << " - exiting" << endl; cout << "Failed to read configuration file " << config_file << " - exiting" << endl;
exit(1); 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 << std::hex << vm["mme.tac"].as<std::string>();
sstr >> args->mme_args.s1ap_args.tac; sstr >> args->mme_args.s1ap_args.tac;
} }
// Convert MCC/MNC strings // 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; 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; cout << "Error parsing mme.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
} }
// Convert MCC/MNC strings // 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; 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; 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; 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; 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; 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; 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 << "Error parsing mme.encryption_algo:" << encryption_algo << " - must be EEA0, EEA1, or EEA2." << endl;
cout << "Using default mme.encryption_algo: EEA0" << 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; 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")) { } else if (boost::iequals(integrity_algo, "eia1")) {
args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1; args->mme_args.s1ap_args.integrity_algo = srslte::INTEGRITY_ALGORITHM_ID_128_EIA1;
} else if (boost::iequals(integrity_algo, "eia2")) { } 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_bind_addr = mme_bind_addr;
args->mme_args.s1ap_args.mme_name = mme_name; args->mme_args.s1ap_args.mme_name = mme_name;
args->mme_args.s1ap_args.dns_addr = dns_addr; args->mme_args.s1ap_args.dns_addr = dns_addr;
args->mme_args.s1ap_args.mme_apn = mme_apn; args->mme_args.s1ap_args.mme_apn = mme_apn;
args->spgw_args.gtpu_bind_addr = spgw_bind_addr; args->spgw_args.gtpu_bind_addr = spgw_bind_addr;
args->spgw_args.sgi_if_addr = sgi_if_addr; args->spgw_args.sgi_if_addr = sgi_if_addr;
args->spgw_args.sgi_if_name = sgi_if_name; args->spgw_args.sgi_if_name = sgi_if_name;
args->hss_args.db_file = hss_db_file; args->hss_args.db_file = hss_db_file;
args->hss_args.auth_algo = hss_auth_algo; args->hss_args.auth_algo = hss_auth_algo;
// Apply all_level to any unset layers // Apply all_level to any unset layers
if (vm.count("log.all_level")) { 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; 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; 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; 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; 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; args->log_args.hss_level = args->log_args.all_level;
} }
} }
// Apply all_hex_limit to any unset layers // Apply all_hex_limit to any unset layers
if (vm.count("log.all_hex_limit")) { 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; 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; 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; 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; 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; 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; return;
} }
srslte::LOG_LEVEL_ENUM srslte::LOG_LEVEL_ENUM level(std::string l)
level(std::string l)
{ {
boost::to_upper(l); boost::to_upper(l);
if("NONE" == l){ if ("NONE" == l) {
return srslte::LOG_LEVEL_NONE; return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){ } else if ("ERROR" == l) {
return srslte::LOG_LEVEL_ERROR; return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){ } else if ("WARNING" == l) {
return srslte::LOG_LEVEL_WARNING; return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){ } else if ("INFO" == l) {
return srslte::LOG_LEVEL_INFO; return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){ } else if ("DEBUG" == l) {
return srslte::LOG_LEVEL_DEBUG; return srslte::LOG_LEVEL_DEBUG;
}else{ } else {
return srslte::LOG_LEVEL_NONE; return srslte::LOG_LEVEL_NONE;
} }
} }
@ -349,8 +345,7 @@ std::string get_build_string()
return ss.str(); return ss.str();
} }
int int main(int argc, char* argv[])
main (int argc,char * argv[] )
{ {
signal(SIGINT, sig_int_handler); signal(SIGINT, sig_int_handler);
signal(SIGTERM, sig_int_handler); signal(SIGTERM, sig_int_handler);
@ -359,15 +354,15 @@ main (int argc,char * argv[] )
// print build info // print build info
cout << endl << get_build_string() << endl; 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); srslte_debug_handle_crash(argc, argv);
all_args_t args; all_args_t args;
parse_args(&args, argc, argv); parse_args(&args, argc, argv);
srslte::logger_stdout logger_stdout; srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file; srslte::logger_file logger_file;
srslte::logger *logger; srslte::logger* logger;
/*Init logger*/ /*Init logger*/
if (!args.log_args.filename.compare("stdout")) { if (!args.log_args.filename.compare("stdout")) {
@ -381,52 +376,51 @@ main (int argc,char * argv[] )
} }
srslte::log_filter nas_log; 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_level(level(args.log_args.nas_level));
nas_log.set_hex_limit(args.log_args.nas_hex_limit); nas_log.set_hex_limit(args.log_args.nas_hex_limit);
srslte::log_filter s1ap_log; 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_level(level(args.log_args.s1ap_level));
s1ap_log.set_hex_limit(args.log_args.s1ap_hex_limit); s1ap_log.set_hex_limit(args.log_args.s1ap_hex_limit);
srslte::log_filter mme_gtpc_log; 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_level(level(args.log_args.gtpc_level));
mme_gtpc_log.set_hex_limit(args.log_args.gtpc_hex_limit); mme_gtpc_log.set_hex_limit(args.log_args.gtpc_hex_limit);
srslte::log_filter hss_log; 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_level(level(args.log_args.hss_level));
hss_log.set_hex_limit(args.log_args.hss_hex_limit); hss_log.set_hex_limit(args.log_args.hss_hex_limit);
srslte::log_filter spgw_log; 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_level(level(args.log_args.spgw_level));
spgw_log.set_hex_limit(args.log_args.spgw_hex_limit); spgw_log.set_hex_limit(args.log_args.spgw_hex_limit);
hss* hss = hss::get_instance();
hss *hss = hss::get_instance(); if (hss->init(&args.hss_args, &hss_log)) {
if (hss->init(&args.hss_args,&hss_log)) {
cout << "Error initializing HSS" << endl; cout << "Error initializing HSS" << endl;
exit(1); exit(1);
} }
mme *mme = mme::get_instance(); mme* mme = mme::get_instance();
if (mme->init(&args.mme_args, &nas_log, &s1ap_log, &mme_gtpc_log, hss)) { if (mme->init(&args.mme_args, &nas_log, &s1ap_log, &mme_gtpc_log)) {
cout << "Error initializing MME" << endl; cout << "Error initializing MME" << endl;
exit(1); exit(1);
} }
spgw *spgw = spgw::get_instance(); spgw* spgw = spgw::get_instance();
if (spgw->init(&args.spgw_args,&spgw_log)) { if (spgw->init(&args.spgw_args, &spgw_log)) {
cout << "Error initializing SP-GW" << endl; cout << "Error initializing SP-GW" << endl;
exit(1); exit(1);
} }
mme->start(); mme->start();
spgw->start(); spgw->start();
while(running) { while (running) {
sleep(1); sleep(1);
} }
@ -437,6 +431,6 @@ main (int argc,char * argv[] )
hss->stop(); hss->stop();
hss->cleanup(); hss->cleanup();
cout << std::endl <<"--- exiting ---" << endl; cout << std::endl << "--- exiting ---" << endl;
return 0; return 0;
} }

@ -24,22 +24,21 @@
* *
*/ */
#include <iostream> //TODO Remove #include "srsepc/hdr/mme/mme.h"
#include <arpa/inet.h> #include <arpa/inet.h>
#include <sys/types.h> #include <inttypes.h> // for printing uint64_t
#include <sys/socket.h>
#include <netinet/sctp.h> #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; pthread_mutex_t mme_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
mme::mme(): mme::mme() : m_running(false)
m_running(false)
{ {
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
return; return;
} }
@ -48,40 +47,39 @@ mme::~mme()
return; return;
} }
mme* mme* mme::get_instance(void)
mme::get_instance(void)
{ {
pthread_mutex_lock(&mme_instance_mutex); pthread_mutex_lock(&mme_instance_mutex);
if(NULL == m_instance) { if (NULL == m_instance) {
m_instance = new mme(); m_instance = new mme();
} }
pthread_mutex_unlock(&mme_instance_mutex); pthread_mutex_unlock(&mme_instance_mutex);
return(m_instance); return (m_instance);
} }
void void mme::cleanup(void)
mme::cleanup(void)
{ {
pthread_mutex_lock(&mme_instance_mutex); pthread_mutex_lock(&mme_instance_mutex);
if(NULL != m_instance) { if (NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&mme_instance_mutex); pthread_mutex_unlock(&mme_instance_mutex);
} }
int int mme::init(mme_args_t* args,
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) srslte::log_filter* nas_log,
srslte::log_filter* s1ap_log,
srslte::log_filter* mme_gtpc_log)
{ {
/*Init logger*/ /*Init logger*/
m_nas_log = nas_log; m_nas_log = nas_log;
m_s1ap_log = s1ap_log; m_s1ap_log = s1ap_log;
m_mme_gtpc_log = mme_gtpc_log; m_mme_gtpc_log = mme_gtpc_log;
/*Init S1AP*/ /*Init S1AP*/
m_s1ap = s1ap::get_instance(); 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"); m_s1ap_log->error("Error initializing MME S1APP\n");
exit(-1); exit(-1);
} }
@ -99,8 +97,7 @@ mme::init(mme_args_t* args, srslte::log_filter *nas_log, srslte::log_filter *s1a
return 0; return 0;
} }
void void mme::stop()
mme::stop()
{ {
if (m_running) { if (m_running) {
m_s1ap->stop(); m_s1ap->stop();
@ -112,52 +109,49 @@ mme::stop()
return; return;
} }
void void mme::run_thread()
mme::run_thread()
{ {
srslte::byte_buffer_t *pdu = m_pool->allocate("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; 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; struct sctp_sndrcvinfo sri;
socklen_t fromlen = sizeof(enb_addr); socklen_t fromlen = sizeof(enb_addr);
bzero(&enb_addr, sizeof(enb_addr)); bzero(&enb_addr, sizeof(enb_addr));
int rd_sz; int rd_sz;
int msg_flags=0; int msg_flags = 0;
//Mark the thread as running // Mark the thread as running
m_running=true; m_running = true;
//Get S1-MME socket // Get S1-MME socket
int s1mme = m_s1ap->get_s1_mme(); int s1mme = m_s1ap->get_s1_mme();
while(m_running) while (m_running) {
{
m_s1ap_log->debug("Waiting for SCTP Msg\n"); m_s1ap_log->debug("Waiting for SCTP Msg\n");
pdu->reset(); pdu->reset();
rd_sz = sctp_recvmsg(s1mme, pdu->msg, sz,(struct sockaddr*) &enb_addr, &fromlen, &sri, &msg_flags); rd_sz = sctp_recvmsg(s1mme, pdu->msg, sz, (struct sockaddr*)&enb_addr, &fromlen, &sri, &msg_flags);
if (rd_sz == -1 && errno != EAGAIN){ if (rd_sz == -1 && errno != EAGAIN) {
m_s1ap_log->error("Error reading from SCTP socket: %s", strerror(errno)); 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"); m_s1ap_log->debug("Socket timeout reached");
} else { } else {
if (msg_flags & MSG_NOTIFICATION) { if (msg_flags & MSG_NOTIFICATION) {
//Received notification // Received notification
union sctp_notification *notification = (union sctp_notification*)pdu->msg; union sctp_notification* notification = (union sctp_notification*)pdu->msg;
m_s1ap_log->debug("SCTP Notification %d\n", notification->sn_header.sn_type); m_s1ap_log->debug("SCTP Notification %d\n", notification->sn_header.sn_type);
if (notification->sn_header.sn_type == SCTP_SHUTDOWN_EVENT) { 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->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->console("SCTP Association Shutdown. Association: %d\n", sri.sinfo_assoc_id);
m_s1ap->delete_enb_ctx(sri.sinfo_assoc_id); m_s1ap->delete_enb_ctx(sri.sinfo_assoc_id);
} }
} else { } else {
//Received data // Received data
pdu->N_bytes = rd_sz; pdu->N_bytes = rd_sz;
m_s1ap_log->info("Received S1AP msg. Size: %d\n", pdu->N_bytes); 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; 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/mme_gtpc.h"
#include "srsepc/hdr/mme/s1ap.h" #include "srsepc/hdr/mme/s1ap.h"
#include "srsepc/hdr/spgw/spgw.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; pthread_mutex_t mme_gtpc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
mme_gtpc::mme_gtpc() mme_gtpc::mme_gtpc()
{ {
return;
} }
mme_gtpc::~mme_gtpc() mme_gtpc::~mme_gtpc()
{ {
return;
} }
mme_gtpc* mme_gtpc* mme_gtpc::get_instance(void)
mme_gtpc::get_instance(void)
{ {
pthread_mutex_lock(&mme_gtpc_instance_mutex); pthread_mutex_lock(&mme_gtpc_instance_mutex);
if(NULL == m_instance) { if (NULL == m_instance) {
m_instance = new mme_gtpc(); m_instance = new mme_gtpc();
} }
pthread_mutex_unlock(&mme_gtpc_instance_mutex); pthread_mutex_unlock(&mme_gtpc_instance_mutex);
return(m_instance); return (m_instance);
} }
void void mme_gtpc::cleanup(void)
mme_gtpc::cleanup(void)
{ {
pthread_mutex_lock(&mme_gtpc_instance_mutex); pthread_mutex_lock(&mme_gtpc_instance_mutex);
if(NULL != m_instance) { if (NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&mme_gtpc_instance_mutex); 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*/ /*Init log*/
@ -77,8 +73,7 @@ mme_gtpc::init(srslte::log_filter *mme_gtpc_log)
m_next_ctrl_teid = 1; m_next_ctrl_teid = 1;
m_s1ap = s1ap::get_instance(); m_s1ap = s1ap::get_instance();
m_mme_gtpc_ip = inet_addr("127.0.0.1");//FIXME At the moment, the GTP-C messages are not sent over the wire. So this parameter is not used.
m_spgw = spgw::get_instance(); m_spgw = spgw::get_instance();
m_mme_gtpc_log->info("MME GTP-C Initialized\n"); 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; return true;
} }
uint32_t uint32_t mme_gtpc::get_new_ctrl_teid()
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 bool mme_gtpc::send_create_session_request(uint64_t imsi)
mme_gtpc::send_create_session_request(uint64_t imsi)
{ {
m_mme_gtpc_log->info("Sending Create Session Request.\n"); m_mme_gtpc_log->info("Sending Create Session Request.\n");
m_mme_gtpc_log->console("Sending Create Session Request.\n"); m_mme_gtpc_log->console("Sending Create Session Request.\n");
struct srslte::gtpc_pdu cs_req_pdu; 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_create_session_request* cs_req = &cs_req_pdu.choice.create_session_request;
struct srslte::gtpc_pdu cs_resp_pdu; struct srslte::gtpc_pdu cs_resp_pdu;
//Initialize GTP-C message to zero // Initialize GTP-C message to zero
bzero(&cs_req_pdu, sizeof(struct srslte::gtpc_pdu)); bzero(&cs_req_pdu, sizeof(struct srslte::gtpc_pdu));
//Setup GTP-C Header. FIXME: Length, sequence and other fields need to be added. // Setup GTP-C Header. FIXME: Length, sequence and other fields need to be added.
cs_req_pdu.header.piggyback = false; cs_req_pdu.header.piggyback = false;
cs_req_pdu.header.teid_present = true; 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; 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; cs_req->imsi = imsi;
// Control TEID allocated // Control TEID allocated
cs_req->sender_f_teid.teid = get_new_ctrl_teid(); 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); m_mme_gtpc_log->console("Creating Session Response -- MME control TEID: %d\n", cs_req->sender_f_teid.teid);
// APN // APN
strncpy(cs_req->apn, m_s1ap->m_s1ap_args.mme_apn.c_str(), sizeof(cs_req->apn)-1); strncpy(cs_req->apn, m_s1ap->m_s1ap_args.mme_apn.c_str(), sizeof(cs_req->apn) - 1);
cs_req->apn[sizeof(cs_req->apn)-1] = 0; cs_req->apn[sizeof(cs_req->apn) - 1] = 0;
// RAT Type // RAT Type
//cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN; // cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN;
//Bearer QoS // Bearer QoS
cs_req->eps_bearer_context_created.ebi = 5; 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); std::map<uint64_t, struct gtpc_ctx>::iterator it = m_imsi_to_gtpc_ctx.find(imsi);
if (it != m_imsi_to_gtpc_ctx.end()) { 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("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"); 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); 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()) { 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 { } else {
m_mme_ctr_teid_to_imsi.erase(jt); m_mme_ctr_teid_to_imsi.erase(jt);
} }
m_imsi_to_gtpc_ctx.erase(it); m_imsi_to_gtpc_ctx.erase(it);
//No need to send delete session request to the SPGW. // 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. // The create session request will be interpreted as a new request and SPGW will delete locally in existing context.
} }
//Save RX Control TEID // Save RX Control TEID
m_mme_ctr_teid_to_imsi.insert(std::pair<uint32_t,uint64_t>(cs_req->sender_f_teid.teid, imsi)); 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; 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; 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); m_spgw->handle_create_session_request(cs_req, &cs_resp_pdu);
return true; return true;
} }
bool bool mme_gtpc::handle_create_session_response(srslte::gtpc_pdu* cs_resp_pdu)
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->info("Received Create Session Response\n");
m_mme_gtpc_log->console("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) { if (cs_resp_pdu->header.type != srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE) {
m_mme_gtpc_log->warning("Could not create GTPC session. Not a create session response\n"); m_mme_gtpc_log->warning("Could not create GTPC session. Not a create session response\n");
//TODO Handle error // TODO Handle error
return false; return false;
} }
if (cs_resp->cause.cause_value != srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED) { 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"); m_mme_gtpc_log->warning("Could not create GTPC session. Create Session Request not accepted\n");
//TODO Handle error // TODO Handle error
return false; return false;
} }
//Get IMSI from the control TEID // 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); 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()) { if (id_it == m_mme_ctr_teid_to_imsi.end()) {
m_mme_gtpc_log->warning("Could not find IMSI from Ctrl TEID.\n"); m_mme_gtpc_log->warning("Could not find IMSI from Ctrl TEID.\n");
return false; 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); 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; srslte::gtp_fteid_t sgw_ctr_fteid;
sgw_ctr_fteid.teid = cs_resp_pdu->header.teid; 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 // Get S-GW S1-u F-TEID
if (cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present == false){ if (cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present == false) {
m_mme_gtpc_log->error("Did not receive SGW S1-U F-TEID in create session response\n"); m_mme_gtpc_log->error("Did not receive SGW S1-U F-TEID in create session response\n");
return false; 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->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)); 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) { if (cs_resp->paa_present != true) {
m_mme_gtpc_log->error("PDN Adress Allocation not present\n"); m_mme_gtpc_log->error("PDN Adress Allocation not present\n");
return false; return false;
@ -214,79 +207,76 @@ mme_gtpc::handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu)
return false; return false;
} }
//Save create session response info to E-RAB context // Save create session response info to E-RAB context
nas *nas_ctx = m_s1ap->find_nas_ctx_from_imsi(imsi); nas* nas_ctx = m_s1ap->find_nas_ctx_from_imsi(imsi);
if(nas_ctx == NULL){ if (nas_ctx == NULL) {
m_mme_gtpc_log->error("Could not find UE context. IMSI %015lu\n", imsi); m_mme_gtpc_log->error("Could not find UE context. IMSI %015lu\n", imsi);
return false; return false;
} }
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx; emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_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; 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); 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); // Save SGW ctrl F-TEID in GTP-C context
if(it_g == m_imsi_to_gtpc_ctx.end()) { std::map<uint64_t, struct gtpc_ctx>::iterator it_g = m_imsi_to_gtpc_ctx.find(imsi);
//Could not find GTP-C Context 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"); m_mme_gtpc_log->error("Could not find GTP-C context\n");
return false; 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; gtpc_ctx->sgw_ctr_fteid = sgw_ctr_fteid;
//Set EPS bearer context // Set EPS bearer context
//FIXME default EPS bearer is hard-coded // FIXME default EPS bearer is hard-coded
int default_bearer=5; int default_bearer = 5;
esm_ctx_t *esm_ctx = &nas_ctx->m_esm_ctx[default_bearer]; esm_ctx_t* esm_ctx = &nas_ctx->m_esm_ctx[default_bearer];
esm_ctx->pdn_addr_alloc= cs_resp->paa; esm_ctx->pdn_addr_alloc = cs_resp->paa;
esm_ctx->sgw_s1u_fteid = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid; 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); m_s1ap->m_s1ap_ctx_mngmt_proc->send_initial_context_setup_request(nas_ctx, default_bearer);
return true; 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"); m_mme_gtpc_log->info("Sending GTP-C Modify bearer request\n");
srslte::gtpc_pdu mb_req_pdu; 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()) { if (it == m_imsi_to_gtpc_ctx.end()) {
m_mme_gtpc_log->error("Modify bearer request for UE without GTP-C connection\n"); m_mme_gtpc_log->error("Modify bearer request for UE without GTP-C connection\n");
return false; 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; srslte::gtpc_header* header = &mb_req_pdu.header;
header->teid_present = true; header->teid_present = true;
header->teid = sgw_ctr_fteid.teid; header->teid = sgw_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST; header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST;
srslte::gtpc_modify_bearer_request *mb_req = &mb_req_pdu.choice.modify_bearer_request; srslte::gtpc_modify_bearer_request* mb_req = &mb_req_pdu.choice.modify_bearer_request;
mb_req->eps_bearer_context_to_modify.ebi = erab_to_modify; 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.ipv4 = enb_fteid->ipv4;
mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid = enb_fteid->teid; mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid = enb_fteid->teid;
m_mme_gtpc_log->info("GTP-C Modify bearer request -- S-GW Control TEID %d\n", sgw_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; struct in_addr addr;
addr.s_addr = enb_fteid->ipv4; addr.s_addr = enb_fteid->ipv4;
m_mme_gtpc_log->info("GTP-C Modify bearer request -- S1-U TEID 0x%x, IP %s\n", enb_fteid->teid, inet_ntoa(addr) ); m_mme_gtpc_log->info("GTP-C Modify bearer request -- S1-U TEID 0x%x, IP %s\n", enb_fteid->teid, inet_ntoa(addr));
//
srslte::gtpc_pdu mb_resp_pdu; 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); handle_modify_bearer_response(&mb_resp_pdu);
return true; return true;
} }
void void mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu* mb_resp_pdu)
mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu)
{ {
uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid; uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid;
std::map<uint32_t,uint64_t>::iterator imsi_it = m_mme_ctr_teid_to_imsi.find(mme_ctrl_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()) { if (imsi_it == m_mme_ctr_teid_to_imsi.end()) {
m_mme_gtpc_log->error("Could not find IMSI from control TEID\n"); m_mme_gtpc_log->error("Could not find IMSI from control TEID\n");
return; 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; uint8_t ebi = mb_resp_pdu->choice.modify_bearer_response.eps_bearer_context_modified.ebi;
m_mme_gtpc_log->debug("Activating EPS bearer with id %d\n", ebi); m_mme_gtpc_log->debug("Activating EPS bearer with id %d\n", ebi);
m_s1ap->activate_eps_bearer(imsi_it->second,ebi); m_s1ap->activate_eps_bearer(imsi_it->second, ebi);
return; return;
} }
bool bool mme_gtpc::send_delete_session_request(uint64_t imsi)
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); m_mme_gtpc_log->info("Sending GTP-C Delete Session Request request. IMSI %" PRIu64 "\n", imsi);
srslte::gtpc_pdu del_req_pdu; srslte::gtpc_pdu del_req_pdu;
srslte::gtp_fteid_t sgw_ctr_fteid; srslte::gtp_fteid_t sgw_ctr_fteid;
srslte::gtp_fteid_t mme_ctr_fteid; srslte::gtp_fteid_t mme_ctr_fteid;
//Get S-GW Ctr TEID // Get S-GW Ctr TEID
std::map<uint64_t,gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi); std::map<uint64_t, gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi);
if (it_ctx == m_imsi_to_gtpc_ctx.end()) { if (it_ctx == m_imsi_to_gtpc_ctx.end()) {
m_mme_gtpc_log->error("Could not find GTP-C context to remove\n"); m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
return false; return false;
} }
sgw_ctr_fteid = it_ctx->second.sgw_ctr_fteid; sgw_ctr_fteid = it_ctx->second.sgw_ctr_fteid;
mme_ctr_fteid = it_ctx->second.mme_ctr_fteid; mme_ctr_fteid = it_ctx->second.mme_ctr_fteid;
srslte::gtpc_header *header = &del_req_pdu.header; srslte::gtpc_header* header = &del_req_pdu.header;
header->teid_present = true; header->teid_present = true;
header->teid = sgw_ctr_fteid.teid; header->teid = sgw_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_DELETE_SESSION_REQUEST; header->type = srslte::GTPC_MSG_TYPE_DELETE_SESSION_REQUEST;
srslte::gtpc_delete_session_request *del_req = &del_req_pdu.choice.delete_session_request; srslte::gtpc_delete_session_request* del_req = &del_req_pdu.choice.delete_session_request;
del_req->cause.cause_value = srslte::GTPC_CAUSE_VALUE_ISR_DEACTIVATION; del_req->cause.cause_value = srslte::GTPC_CAUSE_VALUE_ISR_DEACTIVATION;
m_mme_gtpc_log->info("GTP-C Delete Session Request -- S-GW Control TEID %d\n", sgw_ctr_fteid.teid ); m_mme_gtpc_log->info("GTP-C Delete Session Request -- S-GW Control TEID %d\n", sgw_ctr_fteid.teid);
srslte::gtpc_pdu del_resp_pdu; srslte::gtpc_pdu del_resp_pdu;
m_spgw->handle_delete_session_request(&del_req_pdu, &del_resp_pdu); m_spgw->handle_delete_session_request(&del_req_pdu, &del_resp_pdu);
//TODO Handle delete session response // TODO Handle delete session response
//Delete GTP-C context // Delete GTP-C context
std::map<uint32_t,uint64_t>::iterator it_imsi = m_mme_ctr_teid_to_imsi.find(mme_ctr_fteid.teid); 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()) { if (it_imsi == m_mme_ctr_teid_to_imsi.end()) {
m_mme_gtpc_log->error("Could not find IMSI from MME ctr TEID"); m_mme_gtpc_log->error("Could not find IMSI from MME ctr TEID");
} else { } else {
@ -341,35 +330,33 @@ mme_gtpc::send_delete_session_request(uint64_t imsi)
return true; return true;
} }
void void mme_gtpc::send_release_access_bearers_request(uint64_t imsi)
mme_gtpc::send_release_access_bearers_request(uint64_t imsi)
{ {
m_mme_gtpc_log->info("Sending GTP-C Delete Access Bearers Request\n"); 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; srslte::gtp_fteid_t sgw_ctr_fteid;
//Get S-GW Ctr TEID // Get S-GW Ctr TEID
std::map<uint64_t,gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi); std::map<uint64_t, gtpc_ctx_t>::iterator it_ctx = m_imsi_to_gtpc_ctx.find(imsi);
if(it_ctx == m_imsi_to_gtpc_ctx.end()) if (it_ctx == m_imsi_to_gtpc_ctx.end()) {
{
m_mme_gtpc_log->error("Could not find GTP-C context to remove\n"); m_mme_gtpc_log->error("Could not find GTP-C context to remove\n");
return; return;
} }
sgw_ctr_fteid = it_ctx->second.sgw_ctr_fteid; sgw_ctr_fteid = it_ctx->second.sgw_ctr_fteid;
//Set GTP-C header // Set GTP-C header
srslte::gtpc_header *header = &rel_req_pdu.header; srslte::gtpc_header* header = &rel_req_pdu.header;
header->teid_present = true; header->teid_present = true;
header->teid = sgw_ctr_fteid.teid; header->teid = sgw_ctr_fteid.teid;
header->type = srslte::GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_REQUEST; 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; 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 ); 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; srslte::gtpc_pdu rel_resp_pdu;
m_spgw->handle_release_access_bearers_request(&rel_req_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; 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 "srsepc/hdr/mme/s1ap.h"
#include "srslte/asn1/gtpc.h" #include "srslte/asn1/gtpc.h"
#include "srslte/common/bcd_helpers.h"
#include "srslte/common/liblte_security.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; pthread_mutex_t s1ap_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap::s1ap(): s1ap::s1ap() : m_s1mme(-1), m_next_mme_ue_s1ap_id(1), m_mme_gtpc(NULL), m_pool(NULL)
m_s1mme(-1),
m_next_mme_ue_s1ap_id(1),
m_mme_gtpc(NULL),
m_pool(NULL)
{ {
return;
} }
s1ap::~s1ap() s1ap::~s1ap()
{ {
return;
} }
s1ap* s1ap* s1ap::get_instance(void)
s1ap::get_instance(void)
{ {
pthread_mutex_lock(&s1ap_instance_mutex); pthread_mutex_lock(&s1ap_instance_mutex);
if(m_instance == NULL) { if (m_instance == NULL) {
m_instance = new s1ap(); m_instance = new s1ap();
} }
pthread_mutex_unlock(&s1ap_instance_mutex); pthread_mutex_unlock(&s1ap_instance_mutex);
return(m_instance); return (m_instance);
} }
void void s1ap::cleanup(void)
s1ap::cleanup(void)
{ {
pthread_mutex_lock(&s1ap_instance_mutex); pthread_mutex_lock(&s1ap_instance_mutex);
if(NULL != m_instance) { if (NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&s1ap_instance_mutex); pthread_mutex_unlock(&s1ap_instance_mutex);
} }
int int s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter* nas_log, srslte::log_filter* s1ap_log)
s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *nas_log, srslte::log_filter *s1ap_log, hss_interface_nas * hss)
{ {
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_args = s1ap_args; m_s1ap_args = s1ap_args;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &m_plmn); srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &m_plmn);
m_next_m_tmsi = rand(); m_next_m_tmsi = rand();
//Init log
m_nas_log = nas_log; // Init log
m_nas_log = nas_log;
m_s1ap_log = s1ap_log; m_s1ap_log = s1ap_log;
//Get pointer to the HSS // Get pointer to the HSS
m_hss = hss; m_hss = hss::get_instance();
//Init message handlers // Init message handlers
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); // Managment procedures
m_s1ap_mngmt_proc->init(); m_s1ap_mngmt_proc->init();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); // NAS Transport procedures
m_s1ap_nas_transport->init(m_hss); m_s1ap_nas_transport->init();
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); // Context Management Procedures
m_s1ap_ctx_mngmt_proc->init(); m_s1ap_ctx_mngmt_proc->init();
//Get pointer to GTP-C class // Get pointer to GTP-C class
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
//Initialize S1-MME // Initialize S1-MME
m_s1mme = enb_listen(); m_s1mme = enb_listen();
//Init PCAP // Init PCAP
m_pcap_enable = s1ap_args.pcap_enable; 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_pcap.open(s1ap_args.pcap_filename.c_str());
} }
m_s1ap_log->info("S1AP Initialized\n"); m_s1ap_log->info("S1AP Initialized\n");
return 0; return 0;
} }
void void s1ap::stop()
s1ap::stop()
{ {
if (m_s1mme != -1){ if (m_s1mme != -1) {
close(m_s1mme); close(m_s1mme);
} }
std::map<uint16_t,enb_ctx_t*>::iterator enb_it = m_active_enbs.begin(); std::map<uint16_t, enb_ctx_t*>::iterator enb_it = m_active_enbs.begin();
while (enb_it!=m_active_enbs.end()) { 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->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); m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", enb_it->second->enb_id);
delete enb_it->second; delete enb_it->second;
@ -123,81 +117,76 @@ s1ap::stop()
} }
std::map<uint64_t, nas*>::iterator ue_it = m_imsi_to_nas_ctx.begin(); 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->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); m_s1ap_log->console("Deleting UE EMM context. IMSI: %015" PRIu64 "\n", ue_it->first);
delete ue_it->second; delete ue_it->second;
m_imsi_to_nas_ctx.erase(ue_it++); m_imsi_to_nas_ctx.erase(ue_it++);
} }
//Cleanup message handlers // Cleanup message handlers
s1ap_mngmt_proc::cleanup(); s1ap_mngmt_proc::cleanup();
s1ap_nas_transport::cleanup(); s1ap_nas_transport::cleanup();
s1ap_ctx_mngmt_proc::cleanup(); s1ap_ctx_mngmt_proc::cleanup();
//PCAP // PCAP
if(m_pcap_enable){ if (m_pcap_enable) {
m_pcap.close(); m_pcap.close();
} }
return; return;
} }
int int s1ap::get_s1_mme()
s1ap::get_s1_mme()
{ {
return m_s1mme; return m_s1mme;
} }
uint32_t uint32_t s1ap::get_next_mme_ue_s1ap_id()
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*/ /*This function sets up the SCTP socket for eNBs to connect to*/
int sock_fd, err; int sock_fd, err;
struct sockaddr_in s1mme_addr; struct sockaddr_in s1mme_addr;
struct sctp_event_subscribe evnts; struct sctp_event_subscribe evnts;
m_s1ap_log->info("S1-MME Initializing\n"); m_s1ap_log->info("S1-MME Initializing\n");
sock_fd = socket (AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP); sock_fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (sock_fd == -1){ if (sock_fd == -1) {
m_s1ap_log->console("Could not create SCTP socket\n"); m_s1ap_log->console("Could not create SCTP socket\n");
return -1; return -1;
} }
//Sets the data_io_event to be able to use sendrecv_info // Sets the data_io_event to be able to use sendrecv_info
//Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown // Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown
bzero (&evnts, sizeof (evnts)) ; bzero(&evnts, sizeof(evnts));
evnts.sctp_data_io_event = 1; evnts.sctp_data_io_event = 1;
evnts.sctp_shutdown_event=1; evnts.sctp_shutdown_event = 1;
if(setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof (evnts))){ if (setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof(evnts))) {
close(sock_fd); close(sock_fd);
m_s1ap_log->console("Subscribing to sctp_data_io_events failed\n"); m_s1ap_log->console("Subscribing to sctp_data_io_events failed\n");
return -1; return -1;
} }
//S1-MME bind // S1-MME bind
bzero(&s1mme_addr, sizeof(s1mme_addr)); bzero(&s1mme_addr, sizeof(s1mme_addr));
s1mme_addr.sin_family = AF_INET; 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); s1mme_addr.sin_port = htons(S1MME_PORT);
err = bind(sock_fd, (struct sockaddr*) &s1mme_addr, sizeof (s1mme_addr)); err = bind(sock_fd, (struct sockaddr*)&s1mme_addr, sizeof(s1mme_addr));
if (err != 0){ if (err != 0) {
close(sock_fd); close(sock_fd);
m_s1ap_log->error("Error binding SCTP socket\n"); m_s1ap_log->error("Error binding SCTP socket\n");
m_s1ap_log->console("Error binding SCTP socket\n"); m_s1ap_log->console("Error binding SCTP socket\n");
return -1; return -1;
} }
//Listen for connections // Listen for connections
err = listen(sock_fd,SOMAXCONN); err = listen(sock_fd, SOMAXCONN);
if (err != 0){ if (err != 0) {
close(sock_fd); close(sock_fd);
m_s1ap_log->error("Error in SCTP socket listen\n"); m_s1ap_log->error("Error in SCTP socket listen\n");
m_s1ap_log->console("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; return sock_fd;
} }
bool bool s1ap::s1ap_tx_pdu(srslte::byte_buffer_t* pdu, struct sctp_sndrcvinfo* enb_sri)
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); 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->console("Failed to send S1AP PDU.\n");
m_s1ap_log->error("Failed to send S1AP PDU. \n"); m_s1ap_log->error("Failed to send S1AP PDU. \n");
return false; return false;
} }
if(m_pcap_enable){ if (m_pcap_enable) {
m_pcap.write_s1ap(pdu->msg,pdu->N_bytes); m_pcap.write_s1ap(pdu->msg, pdu->N_bytes);
} }
return true; return true;
} }
bool bool s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t* pdu, struct sctp_sndrcvinfo* enb_sri)
s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri)
{ {
LIBLTE_S1AP_S1AP_PDU_STRUCT rx_pdu; 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"); m_s1ap_log->error("Failed to unpack received PDU\n");
return false; return false;
} }
if(m_pcap_enable){ if (m_pcap_enable) {
m_pcap.write_s1ap(pdu->msg,pdu->N_bytes); m_pcap.write_s1ap(pdu->msg, pdu->N_bytes);
} }
switch(rx_pdu.choice_type) { switch (rx_pdu.choice_type) {
case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE: case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE:
m_s1ap_log->info("Received initiating PDU\n"); m_s1ap_log->info("Received initiating PDU\n");
return handle_initiating_message(&rx_pdu.choice.initiatingMessage, enb_sri); return handle_initiating_message(&rx_pdu.choice.initiatingMessage, enb_sri);
break; break;
case LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME: case LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME:
m_s1ap_log->info("Received Succeseful Outcome PDU\n"); m_s1ap_log->info("Received Succeseful Outcome PDU\n");
return handle_successful_outcome(&rx_pdu.choice.successfulOutcome); return handle_successful_outcome(&rx_pdu.choice.successfulOutcome);
break; break;
case LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME: case LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME:
m_s1ap_log->info("Received Unsucceseful Outcome PDU\n"); m_s1ap_log->info("Received Unsucceseful Outcome PDU\n");
return true;//TODO handle_unsuccessfuloutcome(&rx_pdu.choice.unsuccessfulOutcome); return true; // TODO handle_unsuccessfuloutcome(&rx_pdu.choice.unsuccessfulOutcome);
break; break;
default: default:
m_s1ap_log->error("Unhandled PDU type %d\n", rx_pdu.choice_type); m_s1ap_log->error("Unhandled PDU type %d\n", rx_pdu.choice_type);
return false; return false;
} }
return true; return true;
} }
bool bool s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* msg, struct sctp_sndrcvinfo* enb_sri)
s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri)
{ {
bool reply_flag = false; bool reply_flag = false;
srslte::byte_buffer_t * reply_buffer = m_pool->allocate(); srslte::byte_buffer_t* reply_buffer = m_pool->allocate();
bool ret = false; bool ret = false;
switch(msg->choice_type) { switch (msg->choice_type) {
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST: case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST:
m_s1ap_log->info("Received S1 Setup Request.\n"); 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); m_s1ap_mngmt_proc->handle_s1_setup_request(&msg->choice.S1SetupRequest, enb_sri, reply_buffer, &reply_flag);
break; break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE: case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE:
m_s1ap_log->info("Received Initial UE Message.\n"); m_s1ap_log->info("Received Initial UE Message.\n");
m_s1ap_nas_transport->handle_initial_ue_message(&msg->choice.InitialUEMessage, enb_sri, reply_buffer, &reply_flag); m_s1ap_nas_transport->handle_initial_ue_message(&msg->choice.InitialUEMessage, enb_sri, reply_buffer,
break; &reply_flag);
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT: break;
m_s1ap_log->info("Received Uplink NAS Transport Message.\n"); case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT:
m_s1ap_nas_transport->handle_uplink_nas_transport(&msg->choice.UplinkNASTransport, enb_sri, reply_buffer, &reply_flag); m_s1ap_log->info("Received Uplink NAS Transport Message.\n");
break; m_s1ap_nas_transport->handle_uplink_nas_transport(&msg->choice.UplinkNASTransport, enb_sri, reply_buffer,
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST: &reply_flag);
m_s1ap_log->info("Received UE Context Release Request Message.\n"); break;
m_s1ap_ctx_mngmt_proc->handle_ue_context_release_request(&msg->choice.UEContextReleaseRequest, enb_sri, reply_buffer, &reply_flag); case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST:
break; m_s1ap_log->info("Received UE Context Release Request Message.\n");
default: m_s1ap_ctx_mngmt_proc->handle_ue_context_release_request(&msg->choice.UEContextReleaseRequest, enb_sri,
m_s1ap_log->error("Unhandled S1AP intiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]); reply_buffer, &reply_flag);
m_s1ap_log->console("Unhandled S1APintiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]); break;
} default:
m_s1ap_log->error("Unhandled S1AP intiating message: %s\n",
//Send Reply to eNB liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
if(reply_flag == true){ 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); ret = s1ap_tx_pdu(reply_buffer, enb_sri);
} }
@ -296,101 +286,91 @@ s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, stru
return ret; return ret;
} }
bool bool s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT* msg)
s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
{ {
switch(msg->choice_type) { switch (msg->choice_type) {
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE: case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE:
m_s1ap_log->info("Received Initial Context Setup Response.\n"); m_s1ap_log->info("Received Initial Context Setup Response.\n");
return m_s1ap_ctx_mngmt_proc->handle_initial_context_setup_response(&msg->choice.InitialContextSetupResponse); return m_s1ap_ctx_mngmt_proc->handle_initial_context_setup_response(&msg->choice.InitialContextSetupResponse);
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTRELEASECOMPLETE: case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_UECONTEXTRELEASECOMPLETE:
m_s1ap_log->info("Received UE Context Release Complete\n"); m_s1ap_log->info("Received UE Context Release Complete\n");
return m_s1ap_ctx_mngmt_proc->handle_ue_context_release_complete(&msg->choice.UEContextReleaseComplete); return m_s1ap_ctx_mngmt_proc->handle_ue_context_release_complete(&msg->choice.UEContextReleaseComplete);
default: default:
m_s1ap_log->error("Unhandled successful outcome message: %s\n", liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]); m_s1ap_log->error("Unhandled successful outcome message: %s\n",
liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]);
} }
return true; return true;
} }
//eNB Context Managment // eNB Context Managment
void void s1ap::add_new_enb_ctx(const enb_ctx_t& enb_ctx, const struct sctp_sndrcvinfo* enb_sri)
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); m_s1ap_log->info("Adding new eNB context. eNB ID %d\n", enb_ctx.enb_id);
std::set<uint32_t> ue_set; std::set<uint32_t> ue_set;
enb_ctx_t *enb_ptr = new enb_ctx_t; enb_ctx_t* enb_ptr = new enb_ctx_t;
memcpy(enb_ptr,&enb_ctx,sizeof(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_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_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)); m_enb_assoc_to_ue_ids.insert(std::pair<int32_t, std::set<uint32_t> >(enb_sri->sinfo_assoc_id, ue_set));
return; return;
} }
enb_ctx_t* enb_ctx_t* s1ap::find_enb_ctx(uint16_t enb_id)
s1ap::find_enb_ctx(uint16_t enb_id)
{ {
std::map<uint16_t,enb_ctx_t*>::iterator it = m_active_enbs.find(enb_id); std::map<uint16_t, enb_ctx_t*>::iterator it = m_active_enbs.find(enb_id);
if(it == m_active_enbs.end()) if (it == m_active_enbs.end()) {
{
return NULL; return NULL;
} } else {
else
{
return it->second; return it->second;
} }
} }
void void s1ap::delete_enb_ctx(int32_t assoc_id)
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); std::map<int32_t, uint16_t>::iterator it_assoc = m_sctp_to_enb_id.find(assoc_id);
uint16_t enb_id = it_assoc->second; uint16_t enb_id = it_assoc->second;
std::map<uint16_t,enb_ctx_t*>::iterator it_ctx = m_active_enbs.find(enb_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()) 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);
m_s1ap_log->error("Could not find eNB to delete. Association: %d\n",assoc_id);
return; return;
} }
m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", enb_id); 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); 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); release_ues_ecm_ctx_in_enb(assoc_id);
//Delete eNB // Delete eNB
delete it_ctx->second; delete it_ctx->second;
m_active_enbs.erase(it_ctx); m_active_enbs.erase(it_ctx);
m_sctp_to_enb_id.erase(it_assoc); m_sctp_to_enb_id.erase(it_assoc);
return; return;
} }
//UE Context Management //UE Context Management
bool bool s1ap::add_nas_ctx_to_imsi_map(nas* nas_ctx)
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); 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()) { 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; return false;
} }
if (nas_ctx->m_ecm_ctx.mme_ue_s1ap_id != 0) { 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); 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) { 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"); m_s1ap_log->error("Context identified with IMSI does not match context identified by MME UE S1AP Id.\n");
return false; return false;
} }
} }
m_imsi_to_nas_ctx.insert(std::pair<uint64_t,nas*>(nas_ctx->m_emm_ctx.imsi, nas_ctx)); 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_s1ap_log->debug("Saved UE context corresponding to IMSI %015" PRIu64 "\n", nas_ctx->m_emm_ctx.imsi);
return true; return true;
} }
bool bool s1ap::add_nas_ctx_to_mme_ue_s1ap_id_map(nas* nas_ctx)
s1ap::add_nas_ctx_to_mme_ue_s1ap_id_map(nas *nas_ctx)
{ {
if (nas_ctx->m_ecm_ctx.mme_ue_s1ap_id == 0) { 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."); 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); 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()) { 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; return false;
} }
if (nas_ctx->m_emm_ctx.imsi != 0) { 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) { 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"); m_s1ap_log->error("Context identified with MME UE S1AP Id does not match context identified by IMSI.\n");
return false; 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_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; return true;
} }
bool bool s1ap::add_ue_to_enb_set(int32_t enb_assoc, uint32_t mme_ue_s1ap_id)
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()) { 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; return false;
} }
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.find(mme_ue_s1ap_id); std::set<uint32_t>::iterator ue_id = ues_in_enb->second.find(mme_ue_s1ap_id);
if(ue_id != ues_in_enb->second.end()) if (ue_id != ues_in_enb->second.end()) {
{ m_s1ap_log->error("UE with MME UE S1AP Id already exists %d", mme_ue_s1ap_id);
m_s1ap_log->error("UE with MME UE S1AP Id already exists %d",mme_ue_s1ap_id);
return false; return false;
} }
ues_in_enb->second.insert(mme_ue_s1ap_id); 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; return true;
} }
nas* nas* s1ap::find_nas_ctx_from_mme_ue_s1ap_id(uint32_t mme_ue_s1ap_id)
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); 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()) { 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* nas* s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
{ {
std::map<uint64_t, nas*>::iterator it = m_imsi_to_nas_ctx.find(imsi); std::map<uint64_t, nas*>::iterator it = m_imsi_to_nas_ctx.find(imsi);
if (it == m_imsi_to_nas_ctx.end()) { if (it == m_imsi_to_nas_ctx.end()) {
@ -454,27 +430,27 @@ s1ap::find_nas_ctx_from_imsi(uint64_t imsi)
} }
} }
void void s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
{ {
m_s1ap_log->console("Releasing UEs context\n"); 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::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::set<uint32_t>::iterator ue_id = ues_in_enb->second.begin();
if (ue_id == ues_in_enb->second.end()) { if (ue_id == ues_in_enb->second.end()) {
m_s1ap_log->console("No UEs to be released\n"); m_s1ap_log->console("No UEs to be released\n");
} else { } 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); 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; emm_ctx_t* emm_ctx = &nas_ctx->second->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->second->m_ecm_ctx; ecm_ctx_t* ecm_ctx = &nas_ctx->second->m_ecm_ctx;
m_s1ap_log->info("Releasing UE context. IMSI: %015" PRIu64 ", UE-MME S1AP Id: %d\n", emm_ctx->imsi, ecm_ctx->mme_ue_s1ap_id); m_s1ap_log->info("Releasing UE context. IMSI: %015" PRIu64 ", UE-MME S1AP Id: %d\n", emm_ctx->imsi,
if(emm_ctx->state == EMM_STATE_REGISTERED) { ecm_ctx->mme_ue_s1ap_id);
if (emm_ctx->state == EMM_STATE_REGISTERED) {
m_mme_gtpc->send_delete_session_request(emm_ctx->imsi); m_mme_gtpc->send_delete_session_request(emm_ctx->imsi);
emm_ctx->state = EMM_STATE_DEREGISTERED; 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); 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->mme_ue_s1ap_id = 0;
ecm_ctx->enb_ue_s1ap_id = 0; ecm_ctx->enb_ue_s1ap_id = 0;
ues_in_enb->second.erase(ue_id++); ues_in_enb->second.erase(ue_id++);
@ -482,33 +458,32 @@ s1ap::release_ues_ecm_ctx_in_enb(int32_t enb_assoc)
} }
} }
bool bool s1ap::release_ue_ecm_ctx(uint32_t mme_ue_s1ap_id)
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) { 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); m_s1ap_log->error("Cannot release UE ECM context, UE not found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
return false; return false;
} }
ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx; ecm_ctx_t* ecm_ctx = &nas_ctx->m_ecm_ctx;
//Delete UE within eNB UE set // 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); 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() ) { if (it == m_sctp_to_enb_id.end()) {
m_s1ap_log->error("Could not find eNB for UE release request.\n"); m_s1ap_log->error("Could not find eNB for UE release request.\n");
return false; return false;
} }
uint16_t enb_id = it->second; 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); 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()) { if (ue_set == m_enb_assoc_to_ue_ids.end()) {
m_s1ap_log->error("Could not find the eNB's UEs.\n"); m_s1ap_log->error("Could not find the eNB's UEs.\n");
return false; return false;
} }
ue_set->second.erase(mme_ue_s1ap_id); 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); 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->mme_ue_s1ap_id = 0;
ecm_ctx->enb_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; return true;
} }
bool bool s1ap::delete_ue_ctx(uint64_t imsi)
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) { if (nas_ctx == NULL) {
m_s1ap_log->info("Cannot delete UE context, UE not found. IMSI: %" PRIu64 "\n", imsi); m_s1ap_log->info("Cannot delete UE context, UE not found. IMSI: %" PRIu64 "\n", imsi);
return false; 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) { if (nas_ctx->m_ecm_ctx.mme_ue_s1ap_id != 0) {
release_ue_ecm_ctx(nas_ctx->m_ecm_ctx.mme_ue_s1ap_id); 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); m_imsi_to_nas_ctx.erase(imsi);
delete nas_ctx; delete nas_ctx;
m_s1ap_log->info("Deleted UE Context.\n"); m_s1ap_log->info("Deleted UE Context.\n");
return true; return true;
} }
//UE Bearer Managment //UE Bearer Managment
void void s1ap::activate_eps_bearer(uint64_t imsi, uint8_t ebi)
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()) { 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"); m_s1ap_log->error("Could not activate EPS bearer: Could not find UE context\n");
return; return;
} }
//Make sure NAS is active // Make sure NAS is active
uint32_t mme_ue_s1ap_id = ue_ctx_it->second->m_ecm_ctx.mme_ue_s1ap_id; 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); 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()) { 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"); m_s1ap_log->error("Could not activate EPS bearer: ECM context seems to be missing\n");
return; return;
} }
ecm_ctx_t * ecm_ctx = &ue_ctx_it->second->m_ecm_ctx; 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]; esm_ctx_t* esm_ctx = &ue_ctx_it->second->m_esm_ctx[ebi];
if (esm_ctx->state != ERAB_CTX_SETUP) { 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->error(
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); "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; return;
} }
esm_ctx->state = ERAB_ACTIVE; esm_ctx->state = ERAB_ACTIVE;
ecm_ctx->state = ECM_STATE_CONNECTED; 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; return;
} }
uint32_t uint32_t s1ap::allocate_m_tmsi(uint64_t imsi)
s1ap::allocate_m_tmsi(uint64_t imsi)
{ {
uint32_t m_tmsi = m_next_m_tmsi; 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_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_s1ap_log->debug("Allocated M-TMSI 0x%x to IMSI %015" PRIu64 ",\n", m_tmsi, imsi);
return m_tmsi; return m_tmsi;
} }
uint64_t uint64_t s1ap::find_imsi_from_m_tmsi(uint32_t m_tmsi)
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()) { 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); m_s1ap_log->debug("Found IMSI %015" PRIu64 " from M-TMSI 0x%x\n", it->second, m_tmsi);
return it->second; return it->second;
@ -595,38 +567,37 @@ s1ap::find_imsi_from_m_tmsi(uint32_t m_tmsi)
} }
} }
void void s1ap::print_enb_ctx_info(const std::string& prefix, const enb_ctx_t& enb_ctx)
s1ap::print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx)
{ {
std::string mnc_str, mcc_str; std::string mnc_str, mcc_str;
if (enb_ctx.enb_name_present) { 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); 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 { } 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); 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::mcc_to_string(enb_ctx.mcc, &mcc_str);
srslte::mnc_to_string(enb_ctx.mnc, &mnc_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->info("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(), enb_ctx.plmn);
m_s1ap_log->console("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(), enb_ctx.plmn); m_s1ap_log->console("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(),
for (int i=0;i<enb_ctx.nof_supported_ta;i++) { enb_ctx.plmn);
for(int j=0;i<enb_ctx.nof_supported_ta;i++) { for (int i = 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]); for (int j = 0; i < enb_ctx.nof_supported_ta; i++) {
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->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; return;
} }
/* /*
* Interfaces * Interfaces
*/ */
/*GTP-C||NAS -> S1AP interface*/ /* GTP-C || NAS -> S1AP interface */
bool bool s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
{ {
nas* nas_ctx = find_nas_ctx_from_imsi(imsi); nas* nas_ctx = find_nas_ctx_from_imsi(imsi);
if (nas_ctx == NULL) { if (nas_ctx == NULL) {
@ -637,9 +608,8 @@ s1ap::send_initial_context_setup_request(uint64_t imsi, uint16_t erab_to_setup)
return true; return true;
} }
/*NAS -> S1AP interface*/ /* NAS -> S1AP interface */
bool bool s1ap::send_ue_context_release_command(uint32_t mme_ue_s1ap_id)
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); nas* nas_ctx = find_nas_ctx_from_mme_ue_s1ap_id(mme_ue_s1ap_id);
if (nas_ctx == NULL) { if (nas_ctx == NULL) {
@ -650,9 +620,11 @@ s1ap::send_ue_context_release_command(uint32_t mme_ue_s1ap_id)
return true; return true;
} }
bool bool s1ap::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
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) 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); 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 "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/int_helpers.h"
#include "srslte/common/liblte_security.h"
namespace srsepc {
namespace srsepc{
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL; s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL;
pthread_mutex_t s1ap_ctx_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER; 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); pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if (NULL == m_instance) { if (NULL == m_instance) {
@ -49,7 +55,7 @@ s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::get_instance(void)
return (m_instance); 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); pthread_mutex_lock(&s1ap_ctx_mngmt_proc_instance_mutex);
if (NULL != m_instance) { if (NULL != m_instance) {
@ -59,14 +65,13 @@ void s1ap_ctx_mngmt_proc::cleanup(void)
pthread_mutex_unlock(&s1ap_ctx_mngmt_proc_instance_mutex); 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_s1ap = s1ap::get_instance();
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log; m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1ap_args = m_s1ap->m_s1ap_args; m_s1ap_args = m_s1ap->m_s1ap_args;
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance();
} }
bool s1ap_ctx_mngmt_proc::send_initial_context_setup_request(nas* nas_ctx, uint16_t erab_to_setup) 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, bool s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT* ue_rel,
struct sctp_sndrcvinfo* enb_sri, 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; 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->info("Received UE Context Release Request. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("Received UE Context Release Request. MME-UE S1AP Id %d\n", mme_ue_s1ap_id); m_s1ap_log->console("Received UE Context Release Request. MME-UE S1AP Id %d\n", mme_ue_s1ap_id);
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) { 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->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); m_s1ap_log->console("No UE context to release found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
return false; return false;
} }
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx; emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_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) { 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->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"); 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 // 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. // 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); 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); send_ue_context_release_command(nas_ctx);
} else { } 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->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); 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. // Make sure E-RABS are merked as DEACTIVATED.
for (int i=0;i<MAX_ERABS_PER_UE;i++) { for (int i = 0; i < MAX_ERABS_PER_UE; i++) {
nas_ctx->m_esm_ctx[i].state = ERAB_DEACTIVATED; nas_ctx->m_esm_ctx[i].state = ERAB_DEACTIVATED;
} }
} }
//Set UE context to ECM Idle // Set UE context to ECM Idle
ecm_ctx->state = ECM_STATE_IDLE; ecm_ctx->state = ECM_STATE_IDLE;
ecm_ctx->enb_ue_s1ap_id = 0; ecm_ctx->enb_ue_s1ap_id = 0;
ecm_ctx->mme_ue_s1ap_id = 0; ecm_ctx->mme_ue_s1ap_id = 0;
m_s1ap_log->info("UE is ECM IDLE.\n"); 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->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); 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) { 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->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); m_s1ap_log->console("No UE context to release found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
return false; return false;
} }
emm_ctx_t *emm_ctx = &nas_ctx->m_emm_ctx; emm_ctx_t* emm_ctx = &nas_ctx->m_emm_ctx;
ecm_ctx_t *ecm_ctx = &nas_ctx->m_ecm_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) { 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->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_s1ap_log->info("There are active E-RABs, send release access bearers request");
m_mme_gtpc->send_release_access_bearers_request(emm_ctx->imsi); 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 // 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. // It will release the UEs downstream S1-U and keep the upstream S1-U connection active.
} else { } 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->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); 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. // Make sure E-RABS are marked as DEACTIVATED.
for (int i=0;i<MAX_ERABS_PER_UE;i++) { for (int i = 0; i < MAX_ERABS_PER_UE; i++) {
nas_ctx->m_esm_ctx[i].state = ERAB_DEACTIVATED; 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->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->info("UE Context Release Completed.\n");
m_s1ap_log->console("UE Context Release Completed.\n"); m_s1ap_log->console("UE Context Release Completed.\n");
return true; 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_mngmt_proc.h"
#include "srsepc/hdr/mme/s1ap.h"
#include "srslte/common/bcd_helpers.h"
namespace srsepc{ 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::m_instance = NULL;
pthread_mutex_t s1ap_mngmt_proc_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
s1ap_mngmt_proc::s1ap_mngmt_proc() s1ap_mngmt_proc::s1ap_mngmt_proc()
{ {
return;
} }
s1ap_mngmt_proc::~s1ap_mngmt_proc() s1ap_mngmt_proc::~s1ap_mngmt_proc()
{ {
return;
} }
s1ap_mngmt_proc* s1ap_mngmt_proc* s1ap_mngmt_proc::get_instance(void)
s1ap_mngmt_proc::get_instance(void)
{ {
pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex); pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex);
if(NULL == m_instance) { if (NULL == m_instance) {
m_instance = new s1ap_mngmt_proc(); m_instance = new s1ap_mngmt_proc();
} }
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex); pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
return(m_instance); return (m_instance);
} }
void void s1ap_mngmt_proc::cleanup(void)
s1ap_mngmt_proc::cleanup(void)
{ {
pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex); pthread_mutex_lock(&s1ap_mngmt_proc_instance_mutex);
if(NULL != m_instance) { if (NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex); pthread_mutex_unlock(&s1ap_mngmt_proc_instance_mutex);
} }
void void s1ap_mngmt_proc::init(void)
s1ap_mngmt_proc::init(void)
{ {
m_s1ap = s1ap::get_instance(); m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log; m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1mme = m_s1ap->get_s1_mme(); m_s1mme = m_s1ap->get_s1_mme();
m_s1ap_args = m_s1ap->m_s1ap_args; m_s1ap_args = m_s1ap->m_s1ap_args;
} }
bool bool s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT* msg,
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) 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; 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"); m_s1ap_log->error("Malformed S1 Setup Request\n");
return false; return false;
} }
//Log S1 Setup Request Info // Log S1 Setup Request Info
m_s1ap_log->console("Received S1 Setup Request.\n"); m_s1ap_log->console("Received S1 Setup Request.\n");
m_s1ap->print_enb_ctx_info(std::string("S1 Setup Request"),enb_ctx); m_s1ap->print_enb_ctx_info(std::string("S1 Setup Request"), enb_ctx);
//Check matching PLMNs
if(enb_ctx.plmn!=m_s1ap->get_plmn()){
// 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->console("Sending S1 Setup Failure - Unknown PLMN\n");
m_s1ap_log->warning("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); pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_UNKNOWN_PLMN, reply_buffer);
} } else {
else{ enb_ctx_t* enb_ptr = m_s1ap->find_enb_ctx(enb_ctx.enb_id);
enb_ctx_t *enb_ptr = m_s1ap->find_enb_ctx(enb_ctx.enb_id); if (enb_ptr != NULL) {
if(enb_ptr != NULL) // eNB already registered
{ // TODO replace enb_ctx
//eNB already registered
//TODO replace enb_ctx
m_s1ap_log->warning("eNB Already registered\n"); m_s1ap_log->warning("eNB Already registered\n");
} } else {
else // new eNB
{ m_s1ap->add_new_enb_ctx(enb_ctx, enb_sri);
//new eNB
m_s1ap->add_new_enb_ctx(enb_ctx,enb_sri);
} }
pack_s1_setup_response(m_s1ap_args, reply_buffer); 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; return true;
} }
/* /*
* Packing/Unpacking helper functions. * Packing/Unpacking helper functions.
*/ */
bool bool s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT* msg, enb_ctx_t* enb_ctx)
s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, enb_ctx_t* enb_ctx)
{ {
uint8_t enb_id_bits[32]; uint8_t enb_id_bits[32];
uint32_t plmn = 0; uint32_t plmn = 0;
uint16_t tac, bplmn; uint16_t tac, bplmn;
uint32_t tmp32=0; uint32_t tmp32 = 0;
//eNB Name // eNB Name
enb_ctx->enb_name_present=msg->eNBname_present; enb_ctx->enb_name_present = msg->eNBname_present;
if(msg->eNBname_present) if (msg->eNBname_present) {
{ bzero(enb_ctx->enb_name, sizeof(enb_ctx->enb_name));
bzero(enb_ctx->enb_name,sizeof(enb_ctx->enb_name)); memcpy(enb_ctx->enb_name, &msg->eNBname.buffer, msg->eNBname.n_octets);
memcpy(enb_ctx->enb_name,&msg->eNBname.buffer,msg->eNBname.n_octets);
} }
//eNB Id // eNB Id
bzero(enb_id_bits,sizeof(enb_id_bits)); bzero(enb_id_bits, sizeof(enb_id_bits));
memcpy(&enb_id_bits[32-LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], msg->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer, LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN); memcpy(&enb_id_bits[32 - LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], msg->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer,
liblte_pack(enb_id_bits, 32, (uint8_t*) &tmp32); LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
enb_ctx->enb_id=ntohl(tmp32); liblte_pack(enb_id_bits, 32, (uint8_t*)&tmp32);
enb_ctx->enb_id = ntohl(tmp32);
//PLMN Id
// PLMN Id
((uint8_t*)&plmn)[1] = msg->Global_ENB_ID.pLMNidentity.buffer[0]; ((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)[2] = msg->Global_ENB_ID.pLMNidentity.buffer[1];
((uint8_t*)&plmn)[3] = msg->Global_ENB_ID.pLMNidentity.buffer[2]; ((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); enb_ctx->plmn = ntohl(plmn);
srslte::s1ap_plmn_to_mccmnc(enb_ctx->plmn, &enb_ctx->mcc, &enb_ctx->mnc); srslte::s1ap_plmn_to_mccmnc(enb_ctx->plmn, &enb_ctx->mcc, &enb_ctx->mnc);
//SupportedTAs // SupportedTAs
enb_ctx->nof_supported_ta=msg->SupportedTAs.len; enb_ctx->nof_supported_ta = msg->SupportedTAs.len;
for(uint16_t i=0; i<msg->SupportedTAs.len; i++) for (uint16_t i = 0; i < msg->SupportedTAs.len; i++) {
{ // TAC
//TAC ((uint8_t*)&enb_ctx->tac[i])[0] = msg->SupportedTAs.buffer[i].tAC.buffer[0];
((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];
((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->tac[i]=ntohs(enb_ctx->tac[i]); enb_ctx->nof_supported_bplmns[i] = msg->SupportedTAs.buffer[i].broadcastPLMNs.len;
enb_ctx->nof_supported_bplmns[i]=msg->SupportedTAs.buffer[i].broadcastPLMNs.len; for (uint16_t j = 0; j < msg->SupportedTAs.buffer[i].broadcastPLMNs.len; j++) {
for (uint16_t j=0; j<msg->SupportedTAs.buffer[i].broadcastPLMNs.len; j++) // BPLMNs
{
//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])[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])[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]; ((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; enb_ctx->drx = msg->DefaultPagingDRX.e;
return true; return true;
} }
bool bool s1ap_mngmt_proc::pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte::byte_buffer_t* msg)
s1ap_mngmt_proc::pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte::byte_buffer_t *msg)
{ {
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu; LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT)); bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME; pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME;
LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *unsucc = &pdu.choice.unsuccessfulOutcome; LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT* unsucc = &pdu.choice.unsuccessfulOutcome;
unsucc->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP; unsucc->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP;
unsucc->criticality = LIBLTE_S1AP_CRITICALITY_REJECT; unsucc->criticality = LIBLTE_S1AP_CRITICALITY_REJECT;
unsucc->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE; unsucc->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE;
LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT* s1_fail=(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT*)&unsucc->choice; LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT* s1_fail = (LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT*)&unsucc->choice;
s1_fail->TimeToWait_present=false; s1_fail->TimeToWait_present = false;
s1_fail->CriticalityDiagnostics_present=false; s1_fail->CriticalityDiagnostics_present = false;
s1_fail->Cause.ext=false; s1_fail->Cause.ext = false;
s1_fail->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_MISC; s1_fail->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_MISC;
s1_fail->Cause.choice.misc.ext=false; s1_fail->Cause.choice.misc.ext = false;
s1_fail->Cause.choice.misc.e=cause; s1_fail->Cause.choice.misc.e = cause;
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg); liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
return true; return true;
} }
bool bool s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buffer_t* msg)
s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buffer_t *msg)
{ {
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu; 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; pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME;
LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *succ = &pdu.choice.successfulOutcome; LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT* succ = &pdu.choice.successfulOutcome;
succ->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP; succ->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP;
succ->criticality = LIBLTE_S1AP_CRITICALITY_IGNORE; succ->criticality = LIBLTE_S1AP_CRITICALITY_IGNORE;
succ->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE; 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 // MME Name
s1_resp->MMEname_present=true; s1_resp->MMEname_present = true;
s1_resp->MMEname.ext=false; s1_resp->MMEname.ext = false;
s1_resp->MMEname.n_octets=s1ap_args.mme_name.length(); 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()); memcpy(s1_resp->MMEname.buffer, s1ap_args.mme_name.c_str(), s1ap_args.mme_name.length());
//Served GUMEIs // Served GUMEIs
s1_resp->ServedGUMMEIs.len=1;//TODO Only one served GUMMEI supported s1_resp->ServedGUMMEIs.len = 1; // TODO Only one served GUMMEI supported
LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *serv_gummei = &s1_resp->ServedGUMMEIs.buffer[0]; LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT* serv_gummei = &s1_resp->ServedGUMMEIs.buffer[0];
serv_gummei->ext=false; serv_gummei->ext = false;
serv_gummei->iE_Extensions_present = false; serv_gummei->iE_Extensions_present = false;
uint32_t plmn=0; uint32_t plmn = 0;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn); srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn);
plmn=htonl(plmn); plmn = htonl(plmn);
serv_gummei->servedPLMNs.len = 1; //Only one PLMN supported 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[0] = ((uint8_t*)&plmn)[1];
serv_gummei->servedPLMNs.buffer[0].buffer[1]=((uint8_t*)&plmn)[2]; serv_gummei->servedPLMNs.buffer[0].buffer[1] = ((uint8_t*)&plmn)[2];
serv_gummei->servedPLMNs.buffer[0].buffer[2]=((uint8_t*)&plmn)[3]; serv_gummei->servedPLMNs.buffer[0].buffer[2] = ((uint8_t*)&plmn)[3];
serv_gummei->servedGroupIDs.len=1; //LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT serv_gummei->servedGroupIDs.len = 1; // LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT
uint16_t tmp=htons(s1ap_args.mme_group); 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[0] = ((uint8_t*)&tmp)[0];
serv_gummei->servedGroupIDs.buffer[0].buffer[1]=((uint8_t*)&tmp)[1]; serv_gummei->servedGroupIDs.buffer[0].buffer[1] = ((uint8_t*)&tmp)[1];
serv_gummei->servedMMECs.len=1; //Only one MMEC served serv_gummei->servedMMECs.len = 1; // Only one MMEC served
serv_gummei->servedMMECs.buffer[0].buffer[0]=s1ap_args.mme_code; serv_gummei->servedMMECs.buffer[0].buffer[0] = s1ap_args.mme_code;
//Relative MME Capacity s1_resp->RelativeMMECapacity.RelativeMMECapacity = 255;
s1_resp->RelativeMMECapacity.RelativeMMECapacity=255; s1_resp->MMERelaySupportIndicator_present = false;
//Relay Unsupported
s1_resp->MMERelaySupportIndicator_present=false;
s1_resp->CriticalityDiagnostics_present = false; s1_resp->CriticalityDiagnostics_present = false;
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg); liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
return true;
return true;
} }
} //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 "srsepc/hdr/mme/s1ap_nas_transport.h"
#include "srslte/common/security.h" #include "srsepc/hdr/mme/s1ap.h"
#include "srslte/common/liblte_security.h"
#include "srslte/common/int_helpers.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; s1ap_nas_transport* s1ap_nas_transport::m_instance = NULL;
pthread_mutex_t s1ap_nas_transport_instance_mutex = PTHREAD_MUTEX_INITIALIZER; 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) 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); 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 = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log; m_s1ap_log = m_s1ap->m_s1ap_log;
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
m_hss = hss_; m_hss = hss::get_instance();
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
} }
bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT* init_ue, bool s1ap_nas_transport::handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT* init_ue,
struct sctp_sndrcvinfo* enb_sri, srslte::byte_buffer_t* reply_buffer, struct sctp_sndrcvinfo* enb_sri,
bool* reply_flag) srslte::byte_buffer_t* reply_buffer,
bool* reply_flag)
{ {
bool err, mac_valid; bool err, mac_valid;
uint8_t pd, msg_type, sec_hdr_type; uint8_t pd, msg_type, sec_hdr_type;
srslte::byte_buffer_t *nas_msg = m_pool->allocate(); srslte::byte_buffer_t* nas_msg = m_pool->allocate();
memcpy(nas_msg->msg, &init_ue->NAS_PDU.buffer, init_ue->NAS_PDU.n_octets); 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; nas_msg->N_bytes = init_ue->NAS_PDU.n_octets;
uint64_t imsi = 0; uint64_t imsi = 0;
uint32_t m_tmsi = 0; uint32_t m_tmsi = 0;
uint32_t enb_ue_s1ap_id = init_ue->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID; 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->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_t nas_init;
nas_init.mcc = m_s1ap->m_s1ap_args.mcc; nas_init.mcc = m_s1ap->m_s1ap_args.mcc;
nas_init.mnc = m_s1ap->m_s1ap_args.mnc; nas_init.mnc = m_s1ap->m_s1ap_args.mnc;
nas_init.mme_code = m_s1ap->m_s1ap_args.mme_code; nas_init.mme_code = m_s1ap->m_s1ap_args.mme_code;
nas_init.mme_group = m_s1ap->m_s1ap_args.mme_group; nas_init.mme_group = m_s1ap->m_s1ap_args.mme_group;
nas_init.tac = m_s1ap->m_s1ap_args.tac; nas_init.tac = m_s1ap->m_s1ap_args.tac;
nas_init.apn = m_s1ap->m_s1ap_args.mme_apn; nas_init.apn = m_s1ap->m_s1ap_args.mme_apn;
nas_init.dns = m_s1ap->m_s1ap_args.dns_addr; nas_init.dns = m_s1ap->m_s1ap_args.dns_addr;
nas_init.integ_algo = m_s1ap->m_s1ap_args.integrity_algo; nas_init.integ_algo = m_s1ap->m_s1ap_args.integrity_algo;
nas_init.cipher_algo = m_s1ap->m_s1ap_args.encryption_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); 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, bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT* ul_xport,
struct sctp_sndrcvinfo* enb_sri, 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; uint8_t pd, msg_type, sec_hdr_type;
uint32_t enb_ue_s1ap_id = ul_xport->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID; uint32_t 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 // Parse the message security header
liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &sec_hdr_type); liblte_mme_parse_msg_sec_header((LIBLTE_BYTE_MSG_STRUCT*)nas_msg, &pd, &sec_hdr_type);
// Invalid Security Header Type simply return function // Invalid Security Header Type simply return function
if (!(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS || 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 ||
sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED || 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_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_s1ap_log->error("Unhandled security header type in Uplink NAS Transport: %d\n", sec_hdr_type);
m_pool->deallocate(nas_msg); m_pool->deallocate(nas_msg);
return false; return false;
} }
// Todo: Check on count mismatch of uplink count and do resync nas counter... // Todo: Check on count mismatch of uplink count and do resync nas counter...
// Check MAC if message is integrity protected // Check MAC if message is integrity protected
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY || 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_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_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); mac_valid = nas_ctx->integrity_check(nas_msg);
if (mac_valid == false){ if (mac_valid == false) {
m_s1ap_log->warning("Invalid MAC message. Even if security header indicates integrity protection (Maybe: Identity Response or Authenticatio Response)\n" ); m_s1ap_log->warning("Invalid MAC message. Even if security header indicates integrity protection (Maybe: "
"Identity Response or Authenticatio Response)\n");
} }
} }
// Decrypt message if indicated // Decrypt message if indicated
if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED || 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"); m_s1ap_log->debug_hex(nas_msg->msg, nas_msg->N_bytes, "Encrypted");
nas_ctx->cipher_decrypt(nas_msg); nas_ctx->cipher_decrypt(nas_msg);
msg_encrypted = true; 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 // 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) { 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) { if (emm_ctx->imsi == 0) {
//No EMM context found. Perhaps a temporary context is being created? // No EMM context found. Perhaps a temporary context is being created?
//This can happen with integrity protected identity reponse messages // 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) ) { if (!(msg_type == LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE &&
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); 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); m_pool->deallocate(nas_msg);
return false; 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", liblte_nas_sec_hdr_type_to_string(sec_hdr_type), mac_valid == true ? "yes" : "no",
msg_encrypted == true ? "yes" : "no"); msg_encrypted == true ? "yes" : "no");
switch (msg_type) switch (msg_type) {
{ case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE:
case LIBLTE_MME_MSG_TYPE_IDENTITY_RESPONSE: m_s1ap_log->info("UL NAS: Received Identity Response\n");
m_s1ap_log->info("UL NAS: Received Identity Response\n"); m_s1ap_log->console("UL NAS: Received Identity Response\n");
m_s1ap_log->console("UL NAS: Received Identity Response\n"); nas_ctx->handle_identity_response(nas_msg);
nas_ctx->handle_identity_response(nas_msg); break;
break; case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE:
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_RESPONSE: m_s1ap_log->info("UL NAS: Received Authentication Response\n");
m_s1ap_log->info("UL NAS: Received Authentication Response\n"); m_s1ap_log->console("UL NAS: Received Authentication Response\n");
m_s1ap_log->console("UL NAS: Received Authentication Response\n"); nas_ctx->handle_authentication_response(nas_msg);
nas_ctx->handle_authentication_response(nas_msg); // In case of a successful authentication response, security mode command follows.
// In case of a successful authentication response, security mode command follows. // Reset counter for incoming security mode complete
// Reset counter for incoming security mode complete sec_ctx->ul_nas_count = 0;
sec_ctx->ul_nas_count = 0; sec_ctx->dl_nas_count = 0;
sec_ctx->dl_nas_count = 0; increase_ul_nas_cnt = false;
increase_ul_nas_cnt = false; break;
break; // Authentication failure with the option sync failure can be sent not integrity protected
// Authentication failure with the option sync failure can be sent not integrity protected case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE:
case LIBLTE_MME_MSG_TYPE_AUTHENTICATION_FAILURE: m_s1ap_log->info("UL NAS: Authentication Failure\n");
m_s1ap_log->info("UL NAS: Authentication Failure\n"); m_s1ap_log->console("UL NAS: Authentication Failure\n");
m_s1ap_log->console("UL NAS: Authentication Failure\n"); nas_ctx->handle_authentication_failure(nas_msg);
nas_ctx->handle_authentication_failure(nas_msg); break;
break; // Detach request can be sent not integrity protected when "power off" option is used
// Detach request can be sent not integrity protected when "power off" option is used case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST:
case LIBLTE_MME_MSG_TYPE_DETACH_REQUEST: m_s1ap_log->info("UL NAS: Detach Request\n");
m_s1ap_log->info("UL NAS: Detach Request\n"); m_s1ap_log->console("UL NAS: Detach Request\n");
m_s1ap_log->console("UL NAS: Detach Request\n"); // FIXME: check integrity protection in detach request
// FIXME: check integrity protection in detach request nas_ctx->handle_detach_request(nas_msg);
nas_ctx->handle_detach_request(nas_msg); break;
break; case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE:
case LIBLTE_MME_MSG_TYPE_SECURITY_MODE_COMPLETE: m_s1ap_log->info("UL NAS: Received Security Mode Complete\n");
m_s1ap_log->info("UL NAS: Received Security Mode Complete\n"); m_s1ap_log->console("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 &&
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED_WITH_NEW_EPS_SECURITY_CONTEXT && mac_valid == true){ mac_valid == true) {
nas_ctx->handle_security_mode_complete(nas_msg); nas_ctx->handle_security_mode_complete(nas_msg);
} else { } else {
// Security Mode Complete was not integrity protected // 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->console("Security Mode Complete %s. Discard message.\n",
m_s1ap_log->warning("Security Mode Complete %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity")); (mac_valid ? "not integrity protected" : "invalid integrity"));
increase_ul_nas_cnt = false; m_s1ap_log->warning("Security Mode Complete %s. Discard message.\n",
} (mac_valid ? "not integrity protected" : "invalid integrity"));
break; increase_ul_nas_cnt = false;
case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE: }
m_s1ap_log->info("UL NAS: Received Attach Complete\n"); break;
m_s1ap_log->console("UL NAS: Received Attach Complete\n"); case LIBLTE_MME_MSG_TYPE_ATTACH_COMPLETE:
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true){ m_s1ap_log->info("UL NAS: Received Attach Complete\n");
nas_ctx->handle_attach_complete(nas_msg); m_s1ap_log->console("UL NAS: Received Attach Complete\n");
} else { if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true) {
// Attach Complete was not integrity protected nas_ctx->handle_attach_complete(nas_msg);
m_s1ap_log->console("Attach Complete not integrity protected. Discard message.\n"); } else {
m_s1ap_log->warning("Attach Complete not integrity protected. Discard message.\n"); // Attach Complete was not integrity protected
increase_ul_nas_cnt = false; m_s1ap_log->console("Attach Complete not integrity protected. Discard message.\n");
} m_s1ap_log->warning("Attach Complete not integrity protected. Discard message.\n");
break; increase_ul_nas_cnt = false;
case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE: }
m_s1ap_log->info("UL NAS: Received ESM Information Response\n"); break;
m_s1ap_log->console("UL NAS: Received ESM Information Response\n"); case LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_RESPONSE:
if(sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true){ m_s1ap_log->info("UL NAS: Received ESM Information Response\n");
nas_ctx->handle_esm_information_response(nas_msg); m_s1ap_log->console("UL NAS: Received ESM Information Response\n");
} else { if (sec_hdr_type == LIBLTE_MME_SECURITY_HDR_TYPE_INTEGRITY_AND_CIPHERED && mac_valid == true) {
// Attach Complete was not integrity protected nas_ctx->handle_esm_information_response(nas_msg);
m_s1ap_log->console("ESM Information Response %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity")); } else {
m_s1ap_log->warning("ESM Information Response %s. Discard message.\n", (mac_valid ? "not integrity protected": "invalid integrity")); // Attach Complete was not integrity protected
increase_ul_nas_cnt = false; m_s1ap_log->console("ESM Information Response %s. Discard message.\n",
} (mac_valid ? "not integrity protected" : "invalid integrity"));
break; m_s1ap_log->warning("ESM Information Response %s. Discard message.\n",
case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST: (mac_valid ? "not integrity protected" : "invalid integrity"));
m_s1ap_log->info("UL NAS: Tracking Area Update Request\n"); increase_ul_nas_cnt = false;
m_s1ap_log->console("UL NAS: Tracking Area Update Request\n"); }
nas_ctx->handle_tracking_area_update_request(nas_msg); break;
break; case LIBLTE_MME_MSG_TYPE_TRACKING_AREA_UPDATE_REQUEST:
default: m_s1ap_log->info("UL NAS: Tracking Area Update Request\n");
m_s1ap_log->warning("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type)); m_s1ap_log->console("UL NAS: Tracking Area Update Request\n");
m_s1ap_log->console("Unhandled NAS integrity protected message %s\n", liblte_nas_msg_type_to_string(msg_type)); nas_ctx->handle_tracking_area_update_request(nas_msg);
m_pool->deallocate(nas_msg); break;
return false; 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) { if (increase_ul_nas_cnt == true) {
sec_ctx->ul_nas_count++; sec_ctx->ul_nas_count++;
} }
@ -323,37 +336,39 @@ bool s1ap_nas_transport::handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKN
return true; return true;
} }
bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id, bool s1ap_nas_transport::send_downlink_nas_transport(uint32_t enb_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg, struct sctp_sndrcvinfo enb_sri) uint32_t mme_ue_s1ap_id,
srslte::byte_buffer_t* nas_msg,
struct sctp_sndrcvinfo enb_sri)
{ {
//Allocate Reply buffer // Allocate Reply buffer
srslte::byte_buffer_t *reply_msg = m_pool->allocate(); srslte::byte_buffer_t* reply_msg = m_pool->allocate();
//Setup initiating message // Setup initiating message
LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu; LIBLTE_S1AP_S1AP_PDU_STRUCT tx_pdu;
bzero(&tx_pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT)); bzero(&tx_pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
tx_pdu.ext = false; tx_pdu.ext = false;
tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE; tx_pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &tx_pdu.choice.initiatingMessage; LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT* init = &tx_pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_DOWNLINKNASTRANSPORT; init->procedureCode = LIBLTE_S1AP_PROC_ID_DOWNLINKNASTRANSPORT;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT; init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_DOWNLINKNASTRANSPORT;
//Setup Dw NAS structure // Setup Dw NAS structure
LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT *dw_nas = &init->choice.DownlinkNASTransport; LIBLTE_S1AP_MESSAGE_DOWNLINKNASTRANSPORT_STRUCT* dw_nas = &init->choice.DownlinkNASTransport;
dw_nas->ext=false; dw_nas->ext = false;
dw_nas->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = enb_ue_s1ap_id; 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->MME_UE_S1AP_ID.MME_UE_S1AP_ID = mme_ue_s1ap_id;
dw_nas->HandoverRestrictionList_present=false; dw_nas->HandoverRestrictionList_present = false;
dw_nas->SubscriberProfileIDforRFP_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); memcpy(dw_nas->NAS_PDU.buffer, nas_msg->msg, nas_msg->N_bytes);
dw_nas->NAS_PDU.n_octets = nas_msg->N_bytes; dw_nas->NAS_PDU.n_octets = nas_msg->N_bytes;
//Pack Downlink NAS Transport Message // Pack Downlink NAS Transport Message
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT *) reply_msg); LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&tx_pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_msg);
if (err != LIBLTE_SUCCESS) { if (err != LIBLTE_SUCCESS) {
m_s1ap_log->error("Error packing Downlink NAS Transport.\n"); m_s1ap_log->error("Error packing Downlink NAS Transport.\n");
m_s1ap_log->console("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; 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 <algorithm>
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <inttypes.h> // for printing uint64_t
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_tun.h> #include <linux/if_tun.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <inttypes.h> // for printing uint64_t #include <netinet/in.h>
#include "srsepc/hdr/spgw/spgw.h" #include <sys/ioctl.h>
#include "srsepc/hdr/mme/mme_gtpc.h" #include <sys/socket.h>
#include "srslte/upper/gtpu.h"
namespace srsepc{ namespace srsepc {
spgw* spgw::m_instance = NULL; spgw* spgw::m_instance = NULL;
pthread_mutex_t spgw_instance_mutex = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t spgw_instance_mutex = PTHREAD_MUTEX_INITIALIZER;
const uint16_t SPGW_BUFFER_SIZE = 2500; const uint16_t SPGW_BUFFER_SIZE = 2500;
spgw::spgw(): spgw::spgw() : m_running(false), m_sgi_up(false), m_s1u_up(false), m_next_ctrl_teid(1), m_next_user_teid(1)
m_running(false),
m_sgi_up(false),
m_s1u_up(false),
m_next_ctrl_teid(1),
m_next_user_teid(1)
{ {
return; return;
} }
@ -60,92 +54,83 @@ spgw::~spgw()
return; return;
} }
spgw* spgw* spgw::get_instance()
spgw::get_instance(void)
{ {
pthread_mutex_lock(&spgw_instance_mutex); pthread_mutex_lock(&spgw_instance_mutex);
if(NULL == m_instance) { if (NULL == m_instance) {
m_instance = new spgw(); m_instance = new spgw();
} }
pthread_mutex_unlock(&spgw_instance_mutex); pthread_mutex_unlock(&spgw_instance_mutex);
return(m_instance); return (m_instance);
} }
void void spgw::cleanup()
spgw::cleanup(void)
{ {
pthread_mutex_lock(&spgw_instance_mutex); pthread_mutex_lock(&spgw_instance_mutex);
if(NULL != m_instance) { if (NULL != m_instance) {
delete m_instance; delete m_instance;
m_instance = NULL; m_instance = NULL;
} }
pthread_mutex_unlock(&spgw_instance_mutex); pthread_mutex_unlock(&spgw_instance_mutex);
} }
int int spgw::init(spgw_args_t* args, srslte::log_filter* spgw_log)
spgw::init(spgw_args_t* args, srslte::log_filter *spgw_log)
{ {
srslte::error_t err; srslte::error_t err;
m_pool = srslte::byte_buffer_pool::get_instance(); m_pool = srslte::byte_buffer_pool::get_instance();
//Init log // Init log
m_spgw_log = spgw_log; m_spgw_log = spgw_log;
m_mme_gtpc = mme_gtpc::get_instance(); m_mme_gtpc = mme_gtpc::get_instance();
//Init SGi interface // Init SGi interface
err = init_sgi_if(args); 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"); m_spgw_log->console("Could not initialize the SGi interface.\n");
return -1; return -1;
} }
//Init S1-U // Init S1-U
err = init_s1u(args); 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"); m_spgw_log->console("Could not initialize the S1-U interface.\n");
return -1; return -1;
} }
//Initialize UE ip pool // Initialize UE ip pool
err = init_ue_ip(args); 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"); m_spgw_log->console("Could not initialize the S1-U interface.\n");
return -1; return -1;
} }
//Init mutex // Init mutex
pthread_mutex_init(&m_mutex,NULL); pthread_mutex_init(&m_mutex, NULL);
m_spgw_log->info("SP-GW Initialized.\n"); m_spgw_log->info("SP-GW Initialized.\n");
m_spgw_log->console("SP-GW Initialized.\n"); m_spgw_log->console("SP-GW Initialized.\n");
return 0; return 0;
} }
void void spgw::stop()
spgw::stop()
{ {
if(m_running) if (m_running) {
{
m_running = false; m_running = false;
thread_cancel(); thread_cancel();
wait_thread_finish(); wait_thread_finish();
//Clean up SGi interface // Clean up SGi interface
if(m_sgi_up) if (m_sgi_up) {
{
close(m_sgi_if); close(m_sgi_if);
close(m_sgi_sock); close(m_sgi_sock);
} }
//Clean up S1-U socket // Clean up S1-U socket
if(m_s1u_up) if (m_s1u_up) {
{
close(m_s1u); 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->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); m_spgw_log->console("Deleting SP-GW GTP-C Tunnel. IMSI: %lu\n", it->second->imsi);
delete it->second; delete it->second;
@ -154,33 +139,31 @@ spgw::stop()
return; return;
} }
srslte::error_t srslte::error_t spgw::init_sgi_if(spgw_args_t* args)
spgw::init_sgi_if(spgw_args_t *args)
{ {
struct ifreq ifr;
if (m_sgi_up) { if (m_sgi_up) {
return(srslte::ERROR_ALREADY_STARTED); return (srslte::ERROR_ALREADY_STARTED);
} }
// Construct the TUN device // Construct the TUN device
m_sgi_if = open("/dev/net/tun", O_RDWR); m_sgi_if = open("/dev/net/tun", O_RDWR);
m_spgw_log->info("TUN file descriptor = %d\n", m_sgi_if); m_spgw_log->info("TUN file descriptor = %d\n", m_sgi_if);
if (m_sgi_if < 0) { if (m_sgi_if < 0) {
m_spgw_log->error("Failed to open TUN device: %s\n", strerror(errno)); 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)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI; ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, args->sgi_if_name.c_str(), std::min(args->sgi_if_name.length(), (size_t)(IFNAMSIZ-1))); strncpy(ifr.ifr_ifrn.ifrn_name, args->sgi_if_name.c_str(),
ifr.ifr_ifrn.ifrn_name[IFNAMSIZ-1]='\0'; 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) { if (ioctl(m_sgi_if, TUNSETIFF, &ifr) < 0) {
m_spgw_log->error("Failed to set TUN device name: %s\n", strerror(errno)); m_spgw_log->error("Failed to set TUN device name: %s\n", strerror(errno));
close(m_sgi_if); close(m_sgi_if);
return(srslte::ERROR_CANT_START); return (srslte::ERROR_CANT_START);
} }
// Bring up the interface // Bring up the interface
@ -189,31 +172,32 @@ spgw::init_sgi_if(spgw_args_t *args)
if (ioctl(m_sgi_sock, SIOCGIFFLAGS, &ifr) < 0) { if (ioctl(m_sgi_sock, SIOCGIFFLAGS, &ifr) < 0) {
m_spgw_log->error("Failed to bring up socket: %s\n", strerror(errno)); m_spgw_log->error("Failed to bring up socket: %s\n", strerror(errno));
close(m_sgi_if); close(m_sgi_if);
return(srslte::ERROR_CANT_START); return (srslte::ERROR_CANT_START);
} }
ifr.ifr_flags |= IFF_UP | IFF_RUNNING; ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if (ioctl(m_sgi_sock, SIOCSIFFLAGS, &ifr) < 0) { if (ioctl(m_sgi_sock, SIOCSIFFLAGS, &ifr) < 0) {
m_spgw_log->error("Failed to set socket flags: %s\n", strerror(errno)); m_spgw_log->error("Failed to set socket flags: %s\n", strerror(errno));
close(m_sgi_if); close(m_sgi_if);
return(srslte::ERROR_CANT_START); return (srslte::ERROR_CANT_START);
} }
//Set IP of the interface // Set IP of the interface
struct sockaddr_in *addr = (struct sockaddr_in*)&ifr.ifr_addr; struct sockaddr_in* addr = (struct sockaddr_in*)&ifr.ifr_addr;
addr->sin_family = AF_INET; addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(args->sgi_if_addr.c_str()); addr->sin_addr.s_addr = inet_addr(args->sgi_if_addr.c_str());
addr->sin_port = 0; addr->sin_port = 0;
if (ioctl(m_sgi_sock, SIOCSIFADDR, &ifr) < 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_if);
close(m_sgi_sock); close(m_sgi_sock);
return srslte::ERROR_CANT_START; return srslte::ERROR_CANT_START;
} }
ifr.ifr_netmask.sa_family = AF_INET; ifr.ifr_netmask.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0"); ((struct sockaddr_in*)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
if (ioctl(m_sgi_sock, SIOCSIFNETMASK, &ifr) < 0) { if (ioctl(m_sgi_sock, SIOCSIFNETMASK, &ifr) < 0) {
m_spgw_log->error("Failed to set TUN interface Netmask. Error: %s\n", strerror(errno)); m_spgw_log->error("Failed to set TUN interface Netmask. Error: %s\n", strerror(errno));
close(m_sgi_if); close(m_sgi_if);
@ -221,75 +205,69 @@ spgw::init_sgi_if(spgw_args_t *args)
return srslte::ERROR_CANT_START; return srslte::ERROR_CANT_START;
} }
//Set initial time of setup
gettimeofday(&m_t_last_dl, NULL);
m_sgi_up = true; m_sgi_up = true;
return(srslte::ERROR_NONE); return (srslte::ERROR_NONE);
} }
srslte::error_t srslte::error_t spgw::init_s1u(spgw_args_t* args)
spgw::init_s1u(spgw_args_t *args)
{ {
//Open S1-U socket // Open S1-U socket
m_s1u = socket(AF_INET,SOCK_DGRAM,0); m_s1u = socket(AF_INET, SOCK_DGRAM, 0);
if (m_s1u == -1) { if (m_s1u == -1) {
m_spgw_log->error("Failed to open socket: %s\n", strerror(errno)); m_spgw_log->error("Failed to open socket: %s\n", strerror(errno));
return srslte::ERROR_CANT_START; return srslte::ERROR_CANT_START;
} }
m_s1u_up = true; m_s1u_up = true;
//Bind the socket // Bind the socket
m_s1u_addr.sin_family = AF_INET; 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_addr.s_addr = inet_addr(args->gtpu_bind_addr.c_str());
m_s1u_addr.sin_port=htons(GTPU_RX_PORT); 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)); m_spgw_log->error("Failed to bind socket: %s\n", strerror(errno));
return srslte::ERROR_CANT_START; return srslte::ERROR_CANT_START;
} }
m_spgw_log->info("S1-U socket = %d\n", m_s1u); 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; return srslte::ERROR_NONE;
} }
srslte::error_t srslte::error_t spgw::init_ue_ip(spgw_args_t* args)
spgw::init_ue_ip(spgw_args_t *args)
{ {
m_h_next_ue_ip = ntohl(inet_addr(args->sgi_if_addr.c_str())); m_h_next_ue_ip = ntohl(inet_addr(args->sgi_if_addr.c_str()));
return srslte::ERROR_NONE; return srslte::ERROR_NONE;
} }
void void spgw::run_thread()
spgw::run_thread()
{ {
//Mark the thread as running // Mark the thread as running
m_running=true; m_running = true;
srslte::byte_buffer_t *msg; srslte::byte_buffer_t* msg;
msg = m_pool->allocate(); msg = m_pool->allocate();
struct sockaddr src_addr; struct sockaddr src_addr;
socklen_t addrlen; socklen_t addrlen;
struct iphdr *ip_pkt; struct iphdr* ip_pkt;
int sgi = m_sgi_if; int sgi = m_sgi_if;
fd_set set; fd_set set;
//struct timeval to; // struct timeval to;
int max_fd = std::max(m_s1u,sgi); int max_fd = std::max(m_s1u, sgi);
while (m_running) { while (m_running) {
msg->reset(); msg->reset();
FD_ZERO(&set); FD_ZERO(&set);
FD_SET(m_s1u, &set); FD_SET(m_s1u, &set);
FD_SET(sgi, &set); FD_SET(sgi, &set);
//m_spgw_log->info("Waiting for S1-U or SGi packets.\n"); // m_spgw_log->info("Waiting for S1-U or SGi packets.\n");
int n = select(max_fd+1, &set, NULL, NULL, NULL); int n = select(max_fd + 1, &set, NULL, NULL, NULL);
if (n == -1) { if (n == -1) {
m_spgw_log->error("Error from select\n"); m_spgw_log->error("Error from select\n");
} else if (n) { } else if (n) {
if (FD_ISSET(m_s1u, &set)) { if (FD_ISSET(m_s1u, &set)) {
msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen ); msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen);
handle_s1u_pdu(msg); handle_s1u_pdu(msg);
} }
if (FD_ISSET(m_sgi_if, &set)) { if (FD_ISSET(m_sgi_if, &set)) {
@ -304,17 +282,16 @@ spgw::run_thread()
return; return;
} }
void void spgw::handle_sgi_pdu(srslte::byte_buffer_t* msg)
spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
{ {
uint8_t version=0; uint8_t version = 0;
uint32_t dest_ip; uint32_t dest_ip;
struct in_addr dest_addr; struct in_addr dest_addr;
std::map<uint32_t,srslte::gtpc_f_teid_ie>::iterator gtp_fteid_it; std::map<uint32_t, srslte::gtpc_f_teid_ie>::iterator gtp_fteid_it;
bool ip_found = false; bool ip_found = false;
srslte::gtpc_f_teid_ie enb_fteid; srslte::gtpc_f_teid_ie enb_fteid;
struct iphdr *iph = (struct iphdr *) msg->msg; struct iphdr* iph = (struct iphdr*)msg->msg;
if (iph->version != 4) { if (iph->version != 4) {
m_spgw_log->warning("IPv6 not supported yet.\n"); m_spgw_log->warning("IPv6 not supported yet.\n");
return; return;
@ -327,7 +304,7 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
gtp_fteid_it = m_ip_to_teid.find(iph->daddr); gtp_fteid_it = m_ip_to_teid.find(iph->daddr);
if (gtp_fteid_it != m_ip_to_teid.end()) { if (gtp_fteid_it != m_ip_to_teid.end()) {
ip_found = true; ip_found = true;
enb_fteid = gtp_fteid_it->second; enb_fteid = gtp_fteid_it->second;
} }
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
@ -337,145 +314,61 @@ spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
} }
struct sockaddr_in enb_addr; struct sockaddr_in enb_addr;
enb_addr.sin_family = AF_INET; enb_addr.sin_family = AF_INET;
enb_addr.sin_port = htons(GTPU_RX_PORT); enb_addr.sin_port = htons(GTPU_RX_PORT);
enb_addr.sin_addr.s_addr = enb_fteid.ipv4; enb_addr.sin_addr.s_addr = enb_fteid.ipv4;
//Setup GTP-U header // Setup GTP-U header
srslte::gtpu_header_t header; srslte::gtpu_header_t header;
header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL; header.flags = GTPU_FLAGS_VERSION_V1 | GTPU_FLAGS_GTP_PROTOCOL;
header.message_type = GTPU_MSG_DATA_PDU; header.message_type = GTPU_MSG_DATA_PDU;
header.length = msg->N_bytes; header.length = msg->N_bytes;
header.teid = enb_fteid.teid; header.teid = enb_fteid.teid;
//Write header into packet // Write header into packet
if (!srslte::gtpu_write_header(&header, msg, m_spgw_log)) { if (!srslte::gtpu_write_header(&header, msg, m_spgw_log)) {
m_spgw_log->console("Error writing GTP-U header on PDU\n"); m_spgw_log->console("Error writing GTP-U header on PDU\n");
} }
// Send packet to destination
//Send packet to destination int n = sendto(m_s1u, msg->msg, msg->N_bytes, 0, (struct sockaddr*)&enb_addr, sizeof(enb_addr));
int n = sendto(m_s1u,msg->msg,msg->N_bytes,0,(struct sockaddr*) &enb_addr,sizeof(enb_addr)); if (n < 0) {
if (n<0) {
m_spgw_log->error("Error sending packet to eNB\n"); m_spgw_log->error("Error sending packet to eNB\n");
return; return;
} else if((unsigned int) 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); m_spgw_log->error("Mis-match between packet bytes and sent bytes: Sent: %d, Packet: %d \n", n, msg->N_bytes);
} }
return; 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_header_t header;
srslte::gtpu_read_header(msg, &header, m_spgw_log); 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); 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"); m_spgw_log->error("Could not write to TUN interface.\n");
} else { } 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; return;
} }
/* /*
* Helper Functions * GTP-C Handler Functions
*/ */
uint64_t void spgw::handle_create_session_request(struct srslte::gtpc_create_session_request* cs_req,
spgw::get_new_ctrl_teid() struct srslte::gtpc_pdu* cs_resp_pdu)
{
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)
{ {
m_spgw_log->info("Received Create Session Request\n"); m_spgw_log->info("Received Create Session Request\n");
spgw_tunnel_ctx_t *tunnel_ctx; spgw_tunnel_ctx_t* tunnel_ctx;
int default_bearer_id = 5; int default_bearer_id = 5;
//Check if IMSI has active GTP-C and/or GTP-U // Check if IMSI has active GTP-C and/or GTP-U
bool gtpc_present = m_imsi_to_ctr_teid.count(cs_req->imsi); bool gtpc_present = m_imsi_to_ctr_teid.count(cs_req->imsi);
if (gtpc_present) { if (gtpc_present) {
m_spgw_log->console("SPGW: GTP-C context for IMSI %015" PRIu64 " already exists.\n", cs_req->imsi); 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"); m_spgw_log->info("Creating new GTP-C context\n");
tunnel_ctx = create_gtp_ctx(cs_req); tunnel_ctx = create_gtp_ctx(cs_req);
//Create session response message // Create session response message
srslte::gtpc_header *header = &cs_resp_pdu->header; srslte::gtpc_header* header = &cs_resp_pdu->header;
srslte::gtpc_create_session_response *cs_resp = &cs_resp_pdu->choice.create_session_response; srslte::gtpc_create_session_response* cs_resp = &cs_resp_pdu->choice.create_session_response;
//Setup GTP-C header // Setup GTP-C header
header->piggyback = false; header->piggyback = false;
header->teid_present = true; header->teid_present = true;
header->teid = tunnel_ctx->dw_ctrl_fteid.teid; //Send create session requesponse to the UE's MME Ctrl TEID header->teid = tunnel_ctx->dw_ctrl_fteid.teid; // Send create session requesponse to the UE's MME Ctrl TEID
header->type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE; header->type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE;
//Initialize to zero // Initialize to zero
bzero(cs_resp,sizeof(struct srslte::gtpc_create_session_response)); bzero(cs_resp, sizeof(struct srslte::gtpc_create_session_response));
//Setup Cause // Setup Cause
cs_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED; cs_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
//Setup sender F-TEID (ctrl) // Setup sender F-TEID (ctrl)
cs_resp->sender_f_teid.ipv4_present = true; cs_resp->sender_f_teid.ipv4_present = true;
cs_resp->sender_f_teid = tunnel_ctx->up_ctrl_fteid; cs_resp->sender_f_teid = tunnel_ctx->up_ctrl_fteid;
//Bearer context created // Bearer context created
cs_resp->eps_bearer_context_created.ebi = default_bearer_id; cs_resp->eps_bearer_context_created.ebi = default_bearer_id;
cs_resp->eps_bearer_context_created.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED; cs_resp->eps_bearer_context_created.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present=true; cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present = true;
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid = tunnel_ctx->up_user_fteid; cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid = tunnel_ctx->up_user_fteid;
//Fill in the PAA // Fill in the PAA
cs_resp->paa_present = true; cs_resp->paa_present = true;
cs_resp->paa.pdn_type = srslte::GTPC_PDN_TYPE_IPV4; cs_resp->paa.pdn_type = srslte::GTPC_PDN_TYPE_IPV4;
cs_resp->paa.ipv4_present = true; cs_resp->paa.ipv4_present = true;
cs_resp->paa.ipv4 = tunnel_ctx->ue_ipv4; cs_resp->paa.ipv4 = tunnel_ctx->ue_ipv4;
m_spgw_log->info("Sending Create Session Response\n"); m_spgw_log->info("Sending Create Session Response\n");
m_mme_gtpc->handle_create_session_response(cs_resp_pdu); m_mme_gtpc->handle_create_session_response(cs_resp_pdu);
return; return;
} }
void void spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu* mb_req_pdu, struct srslte::gtpc_pdu* mb_resp_pdu)
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"); m_spgw_log->info("Received Modified Bearer Request\n");
//Get control tunnel info from mb_req PDU // Get control tunnel info from mb_req PDU
uint32_t ctrl_teid = mb_req_pdu->header.teid; 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); 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()) { 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; return;
} }
spgw_tunnel_ctx_t *tunnel_ctx = tunnel_it->second; spgw_tunnel_ctx_t* tunnel_ctx = tunnel_it->second;
//Store user DW link TEID // Store user DW link TEID
srslte::gtpc_modify_bearer_request *mb_req = &mb_req_pdu->choice.modify_bearer_request; srslte::gtpc_modify_bearer_request* mb_req = &mb_req_pdu->choice.modify_bearer_request;
tunnel_ctx->dw_user_fteid.teid = mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid; 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; tunnel_ctx->dw_user_fteid.ipv4 = mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.ipv4;
//Set up actual tunnel // Set up actual tunnel
m_spgw_log->info("Setting Up GTP-U tunnel. Tunnel info: \n"); m_spgw_log->info("Setting Up GTP-U tunnel. Tunnel info: \n");
struct in_addr addr; struct in_addr addr;
addr.s_addr = tunnel_ctx->ue_ipv4; 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("IMSI: %lu, UE IP, %s \n", tunnel_ctx->imsi, inet_ntoa(addr));
m_spgw_log->info("S-GW Rx Ctrl TEID 0x%x, MME Rx Ctrl TEID 0x%x\n", tunnel_ctx->up_ctrl_fteid.teid, tunnel_ctx->dw_ctrl_fteid.teid); m_spgw_log->info("S-GW Rx Ctrl TEID 0x%x, MME Rx Ctrl TEID 0x%x\n", tunnel_ctx->up_ctrl_fteid.teid,
tunnel_ctx->dw_ctrl_fteid.teid);
m_spgw_log->info("S-GW Rx Ctrl IP (NA), MME Rx Ctrl IP (NA)\n"); m_spgw_log->info("S-GW Rx Ctrl IP (NA), MME Rx Ctrl IP (NA)\n");
struct in_addr addr2; 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; 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)); m_spgw_log->info("eNB Rx User TEID 0x%x, eNB Rx User IP %s\n", tunnel_ctx->dw_user_fteid.teid, inet_ntoa(addr3));
//Setup IP to F-TEID map // Setup IP to F-TEID map
//bool ret = false; // bool ret = false;
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
m_ip_to_teid[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)); // ret = m_ip_to_teid.insert(std::pair<uint32_t,srslte::gtpc_f_teid_ie>(tunnel_ctx->ue_ipv4,
// tunnel_ctx->dw_user_fteid));
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
//Setting up Modify bearer response PDU // Setting up Modify bearer response PDU
//Header // Header
srslte::gtpc_header *header = &mb_resp_pdu->header; srslte::gtpc_header* header = &mb_resp_pdu->header;
header->piggyback = false; header->piggyback = false;
header->teid_present = true; header->teid_present = true;
header->teid = tunnel_ctx->dw_ctrl_fteid.teid; // header->teid = tunnel_ctx->dw_ctrl_fteid.teid; //
header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE; header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE;
//PDU // PDU
srslte::gtpc_modify_bearer_response *mb_resp = &mb_resp_pdu->choice.modify_bearer_response; 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->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.ebi = tunnel_ctx->ebi;
mb_resp->eps_bearer_context_modified.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED; mb_resp->eps_bearer_context_modified.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
return; return;
} }
void void spgw::handle_delete_session_request(struct srslte::gtpc_pdu* del_req_pdu, struct srslte::gtpc_pdu* del_resp_pdu)
spgw::handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct srslte::gtpc_pdu *del_resp_pdu)
{ {
//Find tunel ctxt // Find tunel ctxt
uint32_t ctrl_teid = del_req_pdu->header.teid; 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); 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()) { 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; return;
} }
spgw_tunnel_ctx_t *tunnel_ctx = tunnel_it->second; spgw_tunnel_ctx_t* tunnel_ctx = tunnel_it->second;
in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4; in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4;
//Delete data tunnel // Delete data tunnel
pthread_mutex_lock(&m_mutex); 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()) { if (data_it != m_ip_to_teid.end()) {
m_ip_to_teid.erase(data_it); m_ip_to_teid.erase(data_it);
} }
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
m_teid_to_tunnel_ctx.erase(tunnel_it); m_teid_to_tunnel_ctx.erase(tunnel_it);
delete tunnel_ctx; delete tunnel_ctx;
return; return;
} }
void void spgw::handle_release_access_bearers_request(struct srslte::gtpc_pdu* rel_req_pdu,
spgw::handle_release_access_bearers_request(struct srslte::gtpc_pdu *rel_req_pdu, struct srslte::gtpc_pdu *rel_resp_pdu) struct srslte::gtpc_pdu* rel_resp_pdu)
{ {
//Find tunel ctxt // Find tunel ctxt
uint32_t ctrl_teid = rel_req_pdu->header.teid; 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); 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()) { 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; return;
} }
spgw_tunnel_ctx_t *tunnel_ctx = tunnel_it->second; spgw_tunnel_ctx_t* tunnel_ctx = tunnel_it->second;
in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4; in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4;
//Delete data tunnel // Delete data tunnel
pthread_mutex_lock(&m_mutex); pthread_mutex_lock(&m_mutex);
std::map<in_addr_t,srslte::gtpc_f_teid_ie>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4); std::map<in_addr_t, srslte::gtpc_f_teid_ie>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4);
if (data_it != m_ip_to_teid.end()) { if (data_it != m_ip_to_teid.end()) {
m_ip_to_teid.erase(data_it); m_ip_to_teid.erase(data_it);
} }
pthread_mutex_unlock(&m_mutex); pthread_mutex_unlock(&m_mutex);
//Do NOT delete control tunnel // Do NOT delete control tunnel
return; 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