Merge pull request #138 from softwareradiosystems/epc

Epc
master
Ismael Gomez 7 years ago committed by GitHub
commit f25e34aad7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -66,6 +66,7 @@ configure_file(
########################################################################
option(ENABLE_SRSUE "Build srsUE application" ON)
option(ENABLE_SRSENB "Build srsENB application" ON)
option(ENABLE_SRSEPC "Build srsEPC application" ON)
option(DISABLE_SIMD "disable simd instructions" OFF)
option(ENABLE_GUI "Enable GUI (using srsGUI)" ON)
@ -161,7 +162,7 @@ else(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND)
endif(BLADERF_FOUND OR UHD_FOUND OR SOAPYSDR_FOUND)
# Boost
if(ENABLE_SRSUE OR ENABLE_SRSENB)
if(ENABLE_SRSUE OR ENABLE_SRSENB OR ENABLE_SRSEPC)
if(BUILD_STATIC)
set(Boost_USE_STATIC_LIBS ON)
endif(BUILD_STATIC)
@ -183,7 +184,7 @@ if(ENABLE_SRSUE OR ENABLE_SRSENB)
"1.65.0" "1.65" "1.66.0" "1.66" "1.67.0" "1.67" "1.68.0" "1.68" "1.69.0" "1.69"
)
find_package(Boost "1.35" COMPONENTS ${BOOST_REQUIRED_COMPONENTS})
endif(ENABLE_SRSUE OR ENABLE_SRSENB)
endif(ENABLE_SRSUE OR ENABLE_SRSENB OR ENABLE_SRSEPC)
# srsGUI
if(ENABLE_GUI)
@ -374,3 +375,10 @@ if(RF_FOUND)
else(RF_FOUND)
message(STATUS "srsUE and srsENB builds disabled due to missing RF driver")
endif(RF_FOUND)
if(ENABLE_SRSEPC)
message(STATUS "Building with srsEPC")
add_subdirectory(srsepc)
else(ENABLE_SRSEPC)
message(STATUS "srsEPC build disabled")
endif(ENABLE_SRSEPC)

@ -0,0 +1,102 @@
/* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef GTPC_V2_H
#define GTPC_V2_H
#include <stdint.h>
#include "srslte/asn1/gtpc_msg.h"
namespace srslte{
/*GTP-C Version*/
const uint8_t GTPC_V2 = 2;
/****************************************************************************
* GTP-C v2 Header
* Ref: 3GPP TS 29.274 v10.14.0 Section 5
*
* | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
*
* 1 | Version | P | T | S | S | S |
* 2 | Message Type |
* 3 | Length (1st Octet) |
* 4 | Length (2nd Octet) |
* m | If T=1, TEID (1st Octet) |
* m+1 | If T=1, TEID (2nd Octet) |
* m+2 | If T=1, TEID (3st Octet) |
* m+3 | If T=1, TEID (4st Octet) |
* n | Sequence |
* n+1 | Sequence |
* n+2 | Sequence |
* n+3 | Spare |
***************************************************************************/
typedef struct gtpc_header
{
uint8_t version;
bool piggyback;
bool teid_present;
uint8_t type;
uint64_t teid;
uint64_t sequence;
} gtpc_header_t;
/****************************************************************************
* GTP-C v2 Payload
* Ref: 3GPP TS 29.274 v10.14.0 Section 5
*
* Union that hold the different structures for the possible message types.
***************************************************************************/
typedef union gtpc_msg_choice
{
struct gtpc_create_session_request create_session_request;
struct gtpc_create_session_response create_session_response;
struct gtpc_modify_bearer_request modify_bearer_request;
struct gtpc_modify_bearer_response modify_bearer_response;
struct gtpc_delete_session_request delete_session_request;
struct gtpc_delete_session_response delete_session_response;
} gtpc_msg_choice_t;
/****************************************************************************
* GTP-C v2 Message
* Ref: 3GPP TS 29.274 v10.14.0
*
* This is the main structure to represent a GTP-C message. It is composed
* of one GTP-C header and one union of structures, which can hold
* all the possible GTP-C messages
***************************************************************************/
typedef struct gtpc_pdu
{
struct gtpc_header header;
union gtpc_msg_choice choice;
} gtpc_pdu_t;
};
#endif

@ -0,0 +1,428 @@
/* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef GTPC_IES_H
#define GTPC_IES_H
#include "srslte/phy/io/netsource.h"
namespace srslte
{
/****************************************************************
*
* GTP-C IE Types
* Ref: TS 29.274 v10.14.0 Table 8.1-1
*
****************************************************************/
enum gtpc_ie_type
{
//const uint8_t GTPC_IE_TYPE_RESERVED = 0;
GTPC_IE_TYPE_IMSI = 1,
GTPC_IE_TYPE_CAUSE = 2,
GTPC_IE_TYPE_RECOVERY = 3,
//4 to 50 RESERVED_FOR_S101_INTERFACE
GTPC_IE_TYPE_STN_SR = 51,
//52 to 70 RESERVED_FOR_SV_INTERFACE
GTPC_IE_TYPE_APN = 71,
GTPC_IE_TYPE_AMBR = 72,
GTPC_IE_TYPE_EBI = 73,
GTPC_IE_TYPE_IP_ADDRESS = 74,
GTPC_IE_TYPE_MEI = 75,
GTPC_IE_TYPE_MSISDN = 76,
GTPC_IE_TYPE_INDICATION = 77,
GTPC_IE_TYPE_PCO = 78,
GTPC_IE_TYPE_PDN_ADDRESS_ALLOCATION = 79,
GTPC_IE_TYPE_BEARER_QOS = 80,
GTPC_IE_TYPE_FLOW_QOS = 81,
GTPC_IE_TYPE_RAT_TYPE = 82,
GTPC_IE_TYPE_SERVING_NETWORK = 83,
GTPC_IE_TYPE_BEARER_TFT = 84,
GTPC_IE_TYPE_TAD = 85,
GTPC_IE_TYPE_ULI = 86,
GTPC_IE_TYPE_F_TEID = 87,
GTPC_IE_TYPE_TMSI = 88,
GTPC_IE_TYPE_GLOBAL_CN_ID = 89,
GTPC_IE_TYPE_S103_PDN_DATA_FORWARDING_INFO = 90,
GTPC_IE_TYPE_S1_U_DATA_FORWARDING_INFO = 91,
GTPC_IE_TYPE_DELAY_VALUE = 92,
GTPC_IE_TYPE_BEARER_CONTEXT = 93,
GTPC_IE_TYPE_CHARGING_ID = 94,
GTPC_IE_TYPE_CHARGING_CHARACTERISTICS = 95,
GTPC_IE_TYPE_TRACE_INFORMATION = 96,
GTPC_IE_TYPE_BEARER_FLAGS = 97,
//98 Reserved
GTPC_IE_TYPE_PDN_TYPE = 99,
GTPC_IE_TYPE_PROCEDURE_TRANSACTION_ID = 100,
GTPC_IE_TYPE_DRX_PARAMETER = 101,
//102 Reserved
GTPC_IE_TYPE_MM_CONTEXT_GSM_KEY_AND_TRIPLETS = 103,
GTPC_IE_TYPE_MM_CONTEXT_UMTS_KEY_USED_CIPHER_AND_QUINTUPLETS = 104,
GTPC_IE_TYPE_MM_CONTEXT_GSM_KEY_USED_CIPHER_AND_QUINTUPLETS = 105,
GTPC_IE_TYPE_MM_CONTEXT_UMTS_KEY_AND_QUINTUPLETS = 106,
GTPC_IE_TYPE_MM_CONTEXT_EPS_SECURITY_CONTEXT_QUADRUPLETS_AND_QUINTUPLETS = 107,
GTPC_IE_TYPE_MM_CONTEXT_UMTS_KEY_QUADRUPLETS_AND_QUINTUPLETS = 108,
GTPC_IE_TYPE_PDN_CONNECTION = 109,
GTPC_IE_TYPE_PDU_NUMBERS = 110,
GTPC_IE_TYPE_P_TMSI = 111,
GTPC_IE_TYPE_P_TMSI_SIGNATURE = 112,
GTPC_IE_TYPE_HOP_COUNTER = 113,
GTPC_IE_TYPE_UE_TIME_ZONE = 114,
GTPC_IE_TYPE_TRACE_REFERENCE = 115,
GTPC_IE_TYPE_COMPLETE_REQUEST_MESSAGE = 116,
GTPC_IE_TYPE_GUTI = 117,
GTPC_IE_TYPE_F_CONTAINER = 118,
GTPC_IE_TYPE_F_CAUSE = 119,
GTPC_IE_TYPE_SELECTED_PLMN_ID = 120,
GTPC_IE_TYPE_TARGET_IDENTIFICATION = 121,
//122 Reserved
GTPC_IE_TYPE_PACKET_FLOW_ID = 123,
GTPC_IE_TYPE_RAB_CONTEXT = 124,
GTPC_IE_TYPE_SOURCE_RNC_PDCP_CONTEXT_INFO = 125,
GTPC_IE_TYPE_UDP_SOURCE_PORT_NUMBER = 126,
GTPC_IE_TYPE_APN_RESTRICTION = 127,
GTPC_IE_TYPE_SELECTION_MODE = 128,
GTPC_IE_TYPE_SOURCE_IDENTIFICATION = 129,
//130 RESERVED
GTPC_IE_TYPE_CHANGE_REPORTING_ACTION = 131,
GTPC_IE_TYPE_FQ_CSID = 132,
GTPC_IE_TYPE_CHANNEL_NEEDED = 133,
GTPC_IE_TYPE_EMLPP_PRIORITY = 134,
GTPC_IE_TYPE_NODE_TYPE = 135,
GTPC_IE_TYPE_FQDN = 136,
GTPC_IE_TYPE_TI = 137,
GTPC_IE_TYPE_MBMS_SESSION_DURATION = 138,
GTPC_IE_TYPE_MBMS_SERVICE_AREA = 139,
GTPC_IE_TYPE_MBMS_SESSION_IDENTIFIER = 140,
GTPC_IE_TYPE_MBMS_FLOW_IDENTIFIER = 141,
GTPC_IE_TYPE_MBMS_IP_MULTICAST_DISTRIBUTION = 142,
GTPC_IE_TYPE_MBMS_DISTRIBUTION_ACKNOWLEDGE = 143,
GTPC_IE_TYPE_RFSP_INDEX = 144,
GTPC_IE_TYPE_UCI = 145,
GTPC_IE_TYPE_CSG_INFORMATION_REPORTING_ACTION = 146,
GTPC_IE_TYPE_CSG_ID = 147,
GTPC_IE_TYPE_CMI = 148,
GTPC_IE_TYPE_SERVICE_INDICATOR = 149,
GTPC_IE_TYPE_DETACH_TYPE = 150,
GTPC_IE_TYPE_LDN = 151,
GTPC_IE_TYPE_NODE_FEATURES = 152,
GTPC_IE_TYPE_MBMS_TIME_TO_DATA_TRANSFER = 153,
GTPC_IE_TYPE_THROTTLING =154,
GTPC_IE_TYPE_ARP = 155,
GTPC_IE_TYPE_EPC_TIMER = 156,
GTPC_IE_TYPE_SIGNALLING_PRIORITY_INDICATION = 157,
GTPC_IE_TYPE_TMGI = 158,
GTPC_IE_TYPE_ADDITIONAL_MM_CONTEXT_FOR_SRVCC = 159,
GTPC_IE_TYPE_ADDITIONAL_FLAGS_FOR_SRVCC = 160,
//161 RESERVED
GTPC_IE_TYPE_MDT_CONFIGURATION = 162,
GTPC_IE_TYPE_APCO = 163,
//164 RESERVED
GTPC_IE_TYPE_CHANGE_TO_REPORT_FLAGS = 165,
//168 TO 254 SPARE. FOR FUTURE USE.
GTPC_IE_TYPE_PRIVATE_EXTENSION = 255
};
/****************************************************************
*
* GTP-C IMSI IE
* Ref: TS 29.274 v10.14.0 Figure 8.3-1
*
****************************************************************/
/*
* The IMSI should be kept as an uint64_t.
* The responsibility to convert from uint64_t to BCD coded is on
* the pack_imsi_ie function
*/
/****************************************************************************
*
* GTP-C Cause IE
* Ref: 3GPP TS 29.274 v10.14.0 Figure 8.4-1 and Table 8.4-1
*
***************************************************************************/
enum gtpc_cause_value
{
//Reserved
GTPC_CAUSE_VALUE_LOCAL_DETACH = 2,
GTPC_CAUSE_VALUE_COMPLETE_DETACH = 3,
GTPC_CAUSE_VALUE_RAT_CHANGED_FROM_3GPP_TO_NON_3GPP = 4,
GTPC_CAUSE_VALUE_ISR_DEACTIVATION = 5,
GTPC_CAUSE_VALUE_ERROR_INDICATION_RECEIVED_FROM_RNC_ENODEB_S4_SGSN = 6,
GTPC_CAUSE_VALUE_IMSI_DETACH_ONLY = 7,
GTPC_CAUSE_VALUE_REACTIVATION_REQUESTED = 8,
GTPC_CAUSE_VALUE_PDN_RECONNECTION_TO_THIS_APN_DISALLOWED = 9,
GTPC_CAUSE_VALUE_ACCESS_CHANGED_FROM_NON_3GPP_TO_3GPP = 10,
GTPC_CAUSE_VALUE_PDN_CONNECTION_INACTIVITY_TIMER_EXPIRES = 11,
//Spare. This value range shall be used by Cause values in an initial/request message.
GTPC_CAUSE_VALUE_REQUEST_ACCEPTED = 16,
GTPC_CAUSE_VALUE_REQUEST_ACCEPTED_PARTIALLY = 17,
GTPC_CAUSE_VALUE_NEW_PDN_TYPE_DUE_TO_NETWORK_PREFERENCE = 18,
GTPC_CAUSE_VALUE_NEW_PDN_TYPE_DUE_TO_SINGLE_ADDRESS_BEARER_ONLY = 19,
//20-63 Spare.
GTPC_CAUSE_VALUE_CONTEXT_NOT_FOUND = 64,
GTPC_CAUSE_VALUE_INVALID_MESSAGE_FORMAT = 65,
GTPC_CAUSE_VALUE_VERSION_NOT_SUPPORTED_BY_NEXT_PEER = 66,
GTPC_CAUSE_VALUE_INVALID_LENGTH = 67,
GTPC_CAUSE_VALUE_SERVICE_NOT_SUPPORTED = 68,
GTPC_CAUSE_VALUE_MANDATORY_IE_INCORRECT = 69,
GTPC_CAUSE_VALUE_MANDATORY_IE_MISSING = 70,
//71 Shall not be used.
GTPC_CAUSE_VALUE_SYSTEM_FAILURE = 72,
GTPC_CAUSE_VALUE_NO_RESOURCES_AVAILABLE = 73,
GTPC_CAUSE_VALUE_SEMANTIC_ERROR_IN_THE_TFT_OPERATION = 74,
GTPC_CAUSE_VALUE_SYNTACTIC_ERROR_IN_THE_TFT_OPERATION = 75,
GTPC_CAUSE_VALUE_SEMANTIC_ERRORS_IN_PACKET_FILTER = 76,
GTPC_CAUSE_VALUE_SYNTACTIC_ERRORS_IN_PACKET_FILTER = 77,
GTPC_CAUSE_VALUE_MISSING_OR_UNKNOWN_APN = 78,
//79 Shall not be used.
GTPC_CAUSE_VALUE_GRE_KEY_NOT_FOUND = 80,
GTPC_CAUSE_VALUE_RELOCATION_FAILURE = 81,
GTPC_CAUSE_VALUE_DENIED_IN_RAT = 82,
GTPC_CAUSE_VALUE_PREFERRED_PDN_TYPE_NOT_SUPPORTED = 83,
GTPC_CAUSE_VALUE_ALL_DYNAMIC_ADDRESSES_ARE_OCCUPIED = 84,
GTPC_CAUSE_VALUE_UE_CONTEXT_WITHOUT_TFT_ALREADY_ACTIVATED = 85,
GTPC_CAUSE_VALUE_PROTOCOL_TYPE_NOT_SUPPORTED = 86,
GTPC_CAUSE_VALUE_UE_NOT_RESPONDING = 87,
GTPC_CAUSE_VALUE_UE_REFUSES = 88,
GTPC_CAUSE_VALUE_SERVICE_DENIED = 89,
GTPC_CAUSE_VALUE_UNABLE_TO_PAGE_UE = 90,
GTPC_CAUSE_VALUE_NO_MEMORY_AVAILABLE = 91,
GTPC_CAUSE_VALUE_USER_AUTHENTICATION_FAILED = 92,
GTPC_CAUSE_VALUE_APN_ACCESS_DENIED_NO_SUBSCRIPTION = 93,
GTPC_CAUSE_VALUE_REQUEST_REJECTED = 94,
GTPC_CAUSE_VALUE_P_TMSI_SIGNATURE_MISMATCH = 95,
GTPC_CAUSE_VALUE_IMSI_IMEI_NOT_KNOWN = 96,
GTPC_CAUSE_VALUE_SEMANTIC_ERROR_IN_THE_TAD_OPERATION = 97,
GTPC_CAUSE_VALUE_SYNTACTIC_ERROR_IN_THE_TAD_OPERATION = 98,
//99 Shall not be used.
GTPC_CAUSE_VALUE_REMOTE_PEER_NOT_RESPONDING = 100,
GTPC_CAUSE_VALUE_COLLISION_WITH_NETWORK_INITIATED_REQUEST = 101,
GTPC_CAUSE_VALUE_UNABLE_TO_PAGE_UE_DUE_TO_SUSPENSION = 102,
GTPC_CAUSE_VALUE_CONDITIONAL_IE_MISSING = 103,
GTPC_CAUSE_VALUE_APN_RESTRICTION_TYPE_INCOMPATIBLE_WITH_CURRENTLY_ACTIVE_PDN_CONNECTION = 104,
GTPC_CAUSE_VALUE_INVALID_OVERALL_LENGTH_OF_THE_TRIGGERED_RESPONSE_MSG_AND_A_PIGGYBACKED_INITIAL_MSG = 105,
GTPC_CAUSE_VALUE_DATA_FORWARDING_NOT_SUPPORTED = 106,
GTPC_CAUSE_VALUE_INVALID_REPLY_FROM_REMOTE_PEER = 107,
GTPC_CAUSE_VALUE_FALLBACK_TO_GTPV1 = 108,
GTPC_CAUSE_VALUE_INVALID_PEER = 109,
GTPC_CAUSE_VALUE_TEMPORARILY_REJECTED_DUE_TO_HANDOVER_PROCEDURE_IN_PROGRESS = 110,
GTPC_CAUSE_VALUE_MODIFICATIONS_NOT_LIMITED_TO_S1_U_BEARERS = 111,
GTPC_CAUSE_VALUE_REQUEST_REJECTED_FOR_A_PMIPV6_REASON = 112,
GTPC_CAUSE_VALUE_APN_CONGESTION = 113,
GTPC_CAUSE_VALUE_BEARER_HANDLING_NOT_SUPPORTED = 114,
GTPC_CAUSE_VALUE_UE_ALREADY_RE_ATTACHED = 115,
GTPC_CAUSE_VALUE_MULTIPLE_PDN_CONNECTIONS_FOR_A_GIVEN_APN_NOT_ALLOWED = 116
//117-239 Spare. For future use in a triggered/response message.
//240-255 Spare. For future use in an initial/request message.
};
struct gtpc_cause_ie
{
enum gtpc_cause_value cause_value;
bool pce;
bool bce;
bool cs;
enum gtpc_ie_type offending_ie_type;
uint16_t length_of_offending_ie;
uint8_t offending_ie_instance;
};
/****************************************************************************
*
* GTP-C Recovery IE
* Ref: 3GPP TS 29.274 v10.14.0 Figure 8.5-1
*
***************************************************************************/
/*
* The Recovery (Restart Counter) IE should be kept as an uint8_t.
*/
/****************************************************************************
*
* GTP-C Access Point Name IE
* Ref: 3GPP TS 29.274 v10.14.0 Figure 8.6-1
*
***************************************************************************/
/*
* APN IE should be kept as an null terminated string.
* This string will be kept in a char[MAX_APN_LENGTH] buffer.
*/
#define MAX_APN_LENGTH 1024
/****************************************************************************
*
* GTP-C Aggregate Maximum bit-rate IE
* Ref: 3GPP TS 29.274 v10.14.0 Table 8.7-1
*
***************************************************************************/
struct gtpc_ambr_ie
{
uint32_t apn_ambr_uplink;
uint32_t apn_ambr_downlink;
};
/****************************************************************************
*
* GTP-C EPS Bearer ID address IE
* Ref: 3GPP TS 29.274 v10.14.0 Figure 8.8-1
*
***************************************************************************/
/*
* The EPS Bearer ID (EBI) IE should be kept as an uint8_t.
*/
/****************************************************************************
*
* GTP-C IP address IE
* Ref: 3GPP TS 29.274 v10.14.0 Figure 8.9-1
*
***************************************************************************/
/*
* IP addresse IEs should the sockaddr_storage struct, which can hold IPv4
* and IPv6 addresses.
*/
//TODO
//TODO IEs between 8.10 and 8.13 missing
//TODO
/****************************************************************************
*
* GTP-C PDN Type IE
* Ref: 3GPP TS 29.274 v10.14.0 Figure 8.14-1
*
***************************************************************************/
enum gtpc_pdn_type
{
GTPC_PDN_TYPE_IPV4 = 1,
GTPC_PDN_TYPE_IPV6 = 2,
GTPC_PDN_TYPE_IPV4V6 = 3
};
struct gtpc_pdn_address_allocation_ie
{
enum gtpc_pdn_type pdn_type;
bool ipv4_present;
bool ipv6_present;
in_addr_t ipv4;
struct in6_addr ipv6;
};
//TODO
//TODO IEs between 8.15 and 8.17 missing
//TODO
/****************************************************************************
*
* GTP-C RAT Type IE
* Ref: 3GPP TS 29.274 v10.14.0 Figure 8.17-1
*
***************************************************************************/
enum gtpc_rat_type
{
UTRAN = 1,
GERAN,
WLAN,
GAN,
HSPA_EVOLUTION,
EUTRAN,
Virtual
};
//TODO
//TODO IEs between 8.17 and 8.22 missing
//TODO
/****************************************************************************
*
* GTP-C Fully Qualified Tunnel End-point Identifier (F-TEID) IE
* Ref: 3GPP TS 29.274 v10.14.0 Figure 8.22-1
*
***************************************************************************/
enum gtpc_interface_type
{
S1_U_ENODEB_GTP_U_INTERFACE,
S1_U_SGW_GTP_U_INTERFACE,
S12_RNC_GTP_U_INTERFACE,
S12_SGW_GTP_U_INTERFACE,
S5_S8_SGW_GTP_U_INTERFACE,
S5_S8_PGW_GTP_U_INTERFACE,
S5_S8_SGW_GTP_C_INTERFACE,
S5_S8_PGW_GTP_C_INTERFACE,
S5_S8_SGW_PMIPV6_INTERFACE, //(the 32 bit GRE key is encoded in 32 bit TEID field and since alternate CoA is not used the control plane and user plane addresses are the same for PMIPv6)
S5_S8_PGW_PMIPV6_INTERFACE, //(the 32 bit GRE key is encoded in 32 bit TEID field and the control plane and user plane addresses are the same for PMIPv6)
S11_MME_GTP_C_INTERFACE,
S11_S4_SGW_GTP_C_INTERFACE,
S10_MME_GTP_C_INTERFACE,
S3_MME_GTP_C_INTERFACE,
S3_SGSN_GTP_C_INTERFACE,
S4_SGSN_GTP_U_INTERFACE,
S4_SGW_GTP_U_INTERFACE,
S4_SGSN_GTP_C_INTERFACE,
S16_SGSN_GTP_C_INTERFACE,
ENODEB_GTP_U_INTERFACE_FOR_DL_DATA_FORWARDING,
ENODEB_GTP_U_INTERFACE_FOR_UL_DATA_FORWARDING,
RNC_GTP_U_INTERFACE_FOR_DATA_FORWARDING,
SGSN_GTP_U_INTERFACE_FOR_DATA_FORWARDING,
SGW_GTP_U_INTERFACE_FOR_DL_DATA_FORWARDING,
SM_MBMS_GW_GTP_C_INTERFACE,
SN_MBMS_GW_GTP_C_INTERFACE,
SM_MME_GTP_C_INTERFACE,
SN_SGSN_GTP_C_INTERFACE,
SGW_GTP_U_INTERFACE_FOR_UL_DATA_FORWARDING,
SN_SGSN_GTP_U_INTERFACE,
S2B_EPDG_GTP_C_INTERFACE,
S2B_U_EPDG_GTP_U_INTERFACE,
S2B_PGW_GTP_C_INTERFACE,
S2B_U_PGW_GTP_U_INTERFACE
};
struct gtpc_f_teid_ie
{
bool ipv4_present;
bool ipv6_present;
enum gtpc_interface_type interface_type;
uint32_t teid;
in_addr_t ipv4;
struct in6_addr ipv6; //FIXME
};
//TODO
//TODO IEs between 8.22 and 8.28 missing
//TODO
/****************************************************************************
*
* GTP-C Bearer Context IE
* Ref: 3GPP TS 29.274 v10.14.0 Table 8.28-1
*
***************************************************************************/
//The usage of this grouped IE is specific to the GTP-C message being sent.
//As such, each GTP-C message will define it's bearer context structures
//locally, according to the rules of TS 29.274 v10.14.0 Section 7.
} //namespace
#endif //GTPC_IES_H

@ -0,0 +1,414 @@
/* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef GTPC_V2_MSG_H
#define GTPC_V2_MSG_H
#include "srslte/asn1/gtpc_ies.h"
namespace srslte{
/****************************************************************
*
* GTP-C Message Types
* Ref: TS 29.274 v10.14.0 Table 6.1-1
*
****************************************************************/
const uint8_t GTPC_MSG_TYPE_RESERVED = 0;
const uint8_t GTPC_MSG_TYPE_ECHO_REQUEST = 1;
const uint8_t GTPC_MSG_TYPE_ECHO_RESPONSE = 2;
const uint8_t GTPC_MSG_TYPE_VERSION_SUPPORT = 3;
//4-24 Reserved for S101
//25-31 Reserved for Sv interface
//SGSN/MME/ePDG to PGW (S4/S11, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_CREATE_SESSION_REQUEST = 32;
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_RESPONSE = 37;
//SGSN/MME to PGW (S4/S11, S5/S8)
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST = 34;
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE = 35;
const uint8_t GTPC_MSG_TYPE_CHANGE_NOTIFICATION_REQUEST = 38;
const uint8_t GTPC_MSG_TYPE_CHANGE_NOTIFICATION_RESPONSE = 39;
//40 - 63 for future use
const uint8_t GTPC_MSG_TYPE_RESUME_NOTIFICATION = 164;
const uint8_t GTPC_MSG_TYPE_RESUME_ACKNOWLEDGE = 165;
//Messages without explicit response
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_COMMAND = 64; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_MODIFY_BEARER_FAILURE_INDICATION = 65; //(PGW to MME/SGSN/ePDG S5/S8, S11/S4, S2b)
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_COMMAND = 66; //(MME/SGSN to PGW S11/S4, S5/S8)
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_FAILURE_INDICATION = 67; //(PGW to MME/SGSN S5/S8, S11/S4))
const uint8_t GTPC_MSG_TYPE_BEARER_RESOURCE_COMMAND = 68; //(MME/SGSN to PGW S11/S4, S5/S8)
const uint8_t GTPC_MSG_TYPE_BEARER_RESOURCE_FAILURE_INDICATION = 69; //(PGW to MME/SGSN S5/S8, S11/S4)
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION_FAILURE_INDICATION = 70; //(SGSN/MME to SGW S4/S11)
const uint8_t GTPC_MSG_TYPE_TRACE_SESSION_ACTIVATION = 71; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_TRACE_SESSION_DEACTIVATION = 72; //(MME/SGSN/ePDG to PGW S11/S4, S5/S8, S2b)
const uint8_t GTPC_MSG_TYPE_STOP_PAGING_INDICATION = 73; //(SGW to MME/SGSN S11/S4)
//74-94 For future use
//P-GW to SGSN/MME/ePDG
const uint8_t GTPC_MSG_TYPE_CREATE_BEARER_REQUEST = 95;
const uint8_t GTPC_MSG_TYPE_CREATE_BEARER_RESPONSE = 96;
const uint8_t GTPC_MSG_TYPE_UPDATE_BEARER_REQUEST = 97;
const uint8_t GTPC_MSG_TYPE_UPDATE_BEARER_RESPONSE = 98;
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_REQUEST = 99;
const uint8_t GTPC_MSG_TYPE_DELETE_BEARER_RESPONSE = 100;
//PGW to MME, MME to PGW, SGW to PGW, SGW to MME, PGW to ePDG, ePDG to PGW (S5/S8, S11, S2b)
const uint8_t GTPC_MSG_TYPE_DELETE_PDN_CONNECTION_SET_REQUEST = 101;
const uint8_t GTPC_MSG_TYPE_DELETE_PDN_CONNECTION_SET_RESPONSE = 102;
//103-127 For future use
//MME to MME, SGSN to MME, MME to SGSN, SGSN to SGSN (S3/S10/S16)
const uint8_t GTPC_MSG_TYPE_IDENTIFICATION_REQUEST = 128;
const uint8_t GTPC_MSG_TYPE_IDENTIFICATION_RESPONSE = 129;
const uint8_t GTPC_MSG_TYPE_CONTEXT_REQUEST = 130;
const uint8_t GTPC_MSG_TYPE_CONTEXT_RESPONSE = 131;
const uint8_t GTPC_MSG_TYPE_CONTEXT_ACKNOWLEDGE = 132;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_REQUEST = 133;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_RESPONSE = 134;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_COMPLETE_NOTIFICATION = 135;
const uint8_t GTPC_MSG_TYPE_FORWARD_RELOCATION_COMPLETE_ACKNOWLEDGE = 136;
const uint8_t GTPC_MSG_TYPE_FORWARD_ACCESS_CONTEXT_NOTIFICATION = 137;
const uint8_t GTPC_MSG_TYPE_FORWARD_ACCESS_CONTEXT_ACKNOWLEDGE = 138;
const uint8_t GTPC_MSG_TYPE_RELOCATION_CANCEL_REQUEST = 139;
const uint8_t GTPC_MSG_TYPE_RELOCATION_CANCEL_RESPONSE = 140;
const uint8_t GTPC_MSG_TYPE_CONFIGURATION_TRANSFER_TUNNEL = 141;
//142 - 148 For future use
const uint8_t GTPC_MSG_TYPE_RAN_INFORMATION_RELAY = 152;
//SGSN to MME, MME to SGSN (S3)
const uint8_t GTPC_MSG_TYPE_DETACH_NOTIFICATION = 149;
const uint8_t GTPC_MSG_TYPE_DETACH_ACKNOWLEDGE = 150;
const uint8_t GTPC_MSG_TYPE_CS_PAGING_INDICATION = 151;
const uint8_t GTPC_MSG_TYPE_ALERT_MME_NOTIFICATION = 153;
const uint8_t GTPC_MSG_TYPE_ALERT_MME_ACKNOWLEDGE = 154;
const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_NOTIFICATION = 155;
const uint8_t GTPC_MSG_TYPE_UE_ACTIVITY_ACKNOWLEDGE = 156;
//157 - 159 For future use
//GSN/MME to SGW, SGSN to MME (S4/S11/S3) SGSN to SGSN (S16), SGW to PGW (S5/S8)
const uint8_t GTPC_MSG_TYPE_SUSPEND_NOTIFICATION = 162;
const uint8_t GTPC_MSG_TYPE_SUSPEND_ACKNOWLEDGE = 163;
//SGSN/MME to SGW (S4/S11) const uint8_t GTPC_IE_TYPE_
const uint8_t GTPC_MSG_TYPE_CREATE_FORWARDING_TUNNEL_REQUEST = 160;
const uint8_t GTPC_MSG_TYPE_CREATE_FORWARDING_TUNNEL_RESPONSE = 161;
const uint8_t GTPC_MSG_TYPE_CREATE_INDIRECT_DATA_FORWARDING_TUNNEL_REQUEST = 166;
const uint8_t GTPC_MSG_TYPE_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_RESPONSE = 169;
const uint8_t GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_REQUEST = 170;
const uint8_t GTPC_MSG_TYPE_RELEASE_ACCESS_BEARERS_RESPONSE = 171;
//172 - 175 For future use
//SGW to SGSN/MME (S4/S11)
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION = 176;
const uint8_t GTPC_MSG_TYPE_DOWNLINK_DATA_NOTIFICATION_ACKNOWLEDGE = 177;
const uint8_t GTPC_MSG_TYPE_PGW_RESTART_NOTIFICATION = 179;
const uint8_t GTPC_MSG_TYPE_PGW_RESTART_NOTIFICATION_ACKNOWLEDGE = 180;
//SGW to SGSN (S4)
//178 Reserved. Allocated in earlier version of the specification.
//181 -189 For future use
//SGW to PGW, PGW to SGW (S5/S8)
const uint8_t GTPC_MSG_TYPE_UPDATE_PDN_CONNECTION_SET_REQUEST = 200;
const uint8_t GTPC_MSG_TYPE_UPDATE_PDN_CONNECTION_SET_RESPONSE = 201;
//For future use
//MME to SGW (S11)
const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_REQUEST = 211;
const uint8_t GTPC_MSG_TYPE_MODIFY_ACCESS_BEARERS_RESPONSE = 212;
//For future use
//MBMS GW to MME/SGSN (Sm/Sn)
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_START_REQUEST = 231;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_START_RESPONSE = 232;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_UPDATE_REQUEST = 233;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_UPDATE_RESPONSE = 234;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_REQUEST = 235;
const uint8_t GTPC_MSG_TYPE_MBMS_SESSION_STOP_RESPONSE = 236;
//For future use
//Other
//240 - 255 For future use
/****************************************************************************
*
* GTP-C v2 Create Session Request
* 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
enum gtpc_rat_type rat_type; // M
//bool indication_flags_present;
//struct indication_flags_ indication_flags; // C
struct gtpc_f_teid_ie sender_f_teid; // M
bool pgw_addr_present;
struct gtpc_f_teid_ie pgw_addr; // C
char apn[MAX_APN_LENGTH]; // M
//bool selection_mode_present;
//enum selection_mode_ selection_mode; // C/CO
//bool pdn_type_present;
//enum gtpc_pdn_type pdn_type; // C
//bool pdn_addr_alloc_present;
//struct pdn_addr_alloc_ pdn_addr_alloc; // C/CO
//bool max_apn_restriction_present;
//enum apn_restriction_ max_apn_restriction; // C
//bool apn_ambr_present;
//struct ambr_ apn_ambr; // C
//bool linked_eps_bearer_id_present;
//uint8_t linked_eps_bearer_id; // C
//bool pco_present;
//uint8_t pco; // C
struct gtpc_bearer_context_created_ie //see TS 29.274 v10.14.0 Table 7.2.1-2
{
uint8_t ebi;
bool tft_present;
bool s1_u_enodeb_f_teid_present;
struct gtpc_f_teid_ie s1_u_enodeb_f_teid;
bool s4_u_sgsn_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgsn_f_teid;
bool s5_s8_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_sgw_f_teid;
bool s5_s8_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid;
bool s12_rnc_f_teid_present;
struct gtpc_f_teid_ie s12_rnc_f_teid;
bool s2b_u_epdg_f_teid_present;
struct gtpc_f_teid_ie s2b_u_epdg_f_teid;
} eps_bearer_context_created; // M
//bool bearer_context_deleted_present;
//struct bearer_context_ bearer_context_deleted; // C
//bool trace_information_present;
//struct trace_infromation_ trace_information; // C
//bool recovery_present
//uint8_t recovery; // C
//bool mme_fq_csid_present;
//struct fq_csid_ mme_fq_csid; // C
//bool sgw_fq_csid_present;
//struct fq_csid_ sgw_fq_csid; // C
//bool epdg_fq_csid_present;
//struct fq_csid_ epdg_fq_csid; // C
//bool ue_time_zone_present;
//struct ue_time_zone_ ue_time_zone; // CO
//bool uci_present;
//struct uci_ uci; // CO
//bool charging_caracteristics_present;
//enum charging_characteristics_ charging_caracteristics; // O
//bool mme_ldn_present;
//uint8_t mme_ldn[LDN_MAX_SIZE]; // O
//bool sgw_ldn_present;
//uint8_t sgw_ldn[LDN_MAX_SIZE]; // O
//bool epgd_ldn_present;
//uint8_t epdg_ldn[LDN_MAX_SIZE]; // O
//bool signaling_priority_indication;
//enum signalling_priority_indication_ spi; // CO
//bool acpo_present;
//uint8_t apco; // CO
//bool ext; // O
};
/****************************************************************************
*
* GTP-C v2 Create Session Response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.2-1
*
***************************************************************************/
struct gtpc_create_session_response
{
struct gtpc_cause_ie cause; //M
//Change Reporting Action //C
//CSG Information Reporting Action //CO
bool sender_f_teid_present;
struct gtpc_f_teid_ie sender_f_teid; //C
//PGW S5/S8/S2b F-TEID //C
bool paa_present;
struct gtpc_pdn_address_allocation_ie paa; //C
//apn_restriction
//apn_ambr
//linked_eps_bearer_id
//pco
struct gtpc_bearer_context_created_ie
{
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s1_u_sgw_f_teid;
bool s4_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgw_f_teid;
bool s5_s8_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_pgw_f_teid;
bool s12_sgw_f_teid_present;
struct gtpc_f_teid_ie s12_sgw_f_teid;
bool s2b_u_pgw_f_teid_present;
struct gtpc_f_teid_ie s2b_u_pgw_f_teid;
//bearer_level_qos_present
//bearer_level_qos
//charging_id_present
//charging_id
//bearer_flags_present
//bearer_flags
} eps_bearer_context_created; //M
/*
struct gtpc_bearer_context_removed_ie
{
uint8_t ebi;
//
} bearer_context_removed; //C
*/
//recovery; //C
//charging_gateway_name; //C
//charging_gateway_address; //C
//PGW-FQ-CSID //C
//SGW-FQ-CSID //C
//SGW LDN //O
//PGW LDN //O
//PGW Back-Off Time //O
//acpo //CO
};
/****************************************************************************
*
* GTP-C v2 Modify Bearer Request
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.7-1, 7.2.7-2 and 7.2.7-3
*
***************************************************************************/
struct gtpc_modify_bearer_request
{
//ME Identity (MEI)//C
//User Location Information (ULI)//C
//Serving Network //CO
//RAT Type //C/CO
//Indication Flags
//Sender F-TEID for Control Plane
//APN-AMBR
//Delay Downlink Packet Notification Request
struct gtpc_bearer_context_modified_ie
{
uint8_t ebi;
gtpc_cause_ie cause;
bool s1_u_enb_f_teid_present;
struct gtpc_f_teid_ie s1_u_enb_f_teid;
bool s5_s8_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s5_s8_u_sgw_f_teid;
bool s12_rnc_f_teid_present;
struct gtpc_f_teid_ie s12_rnc_f_teid;
bool s4_u_sgsn_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgsn_f_teid;
} eps_bearer_context_to_modify;
//Bearer Contexts to be removed
//Recovery
//UE Time Zone
//MME-FQ-CSID
//SGW-FQ-CSID
//User CSG Information (UCI)
//MME/S4-SGSN LDN
//SGW LDN
};
/****************************************************************************
*
* GTP-C v2 Modify Bearer Response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.8-1
*
***************************************************************************/
struct gtpc_modify_bearer_response
{
struct gtpc_cause_ie cause;
//MSISDN
//Linked EPS Bearer ID
//APN-AMBR
//APN Restriction
//Protocol Configuration Options
struct gtpc_bearer_context_modified_ie
{
uint8_t ebi;
struct gtpc_cause_ie cause;
bool s1_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s1_u_sgw_f_teid;
bool s12_sgw_f_teid_present;
struct gtpc_f_teid_ie s12_sgw_f_teid;
bool s4_u_sgw_f_teid_present;
struct gtpc_f_teid_ie s4_u_sgw_f_teid;
//charging id
//bearer flags
} eps_bearer_context_modified;
//Bearer Contexts marked for removal
//Change Reporting action
//CSG information reporting action
//Charging gateway name
//charging gateway address
//P-GW FQ-CSID
//S-GW FQ-CSID
//Recovery
//S-GW LDN
//P-GW LDN
//indication Flags
//ext
};
/****************************************************************************
*
* GTP-C v2 Delete Session Resquest
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.9.1-1
*
***************************************************************************/
struct gtpc_delete_session_request
{
struct gtpc_cause_ie cause;
//Linked EPS Bearer ID
//User Location Information
//Indication Flags
//Protocol Configuration Options
//Originating Node
//Private extension
};
/****************************************************************************
*
* GTP-C v2 Delete Session Response
* Ref: 3GPP TS 29.274 v10.14.0 Table 7.2.10.1-1
*
***************************************************************************/
struct gtpc_delete_session_response
{
struct gtpc_cause_ie cause;
//Recovery
//Protocol Configuration Options
//Private extension
};
} //namespace
#endif //GTPC_V2_MSG_H

@ -3759,6 +3759,10 @@ typedef struct{
uint8 proc_transaction_id;
}LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT;
// Functions
LIBLTE_ERROR_ENUM srslte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT *esm_info_req,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT *esm_info_req,
LIBLTE_BYTE_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
@ -3789,6 +3793,8 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
LIBLTE_BYTE_MSG_STRUCT *msg);
LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp);
LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp);
/*********************************************************************
Message Name: ESM Status

@ -120,6 +120,78 @@ inline std::string plmn_id_to_string(LIBLTE_RRC_PLMN_IDENTITY_STRUCT plmn_id) {
return mcc_str + mnc_str;
}
/******************************************************************************
* Convert PLMN to BCD-coded MCC and MNC.
* Digits are represented by 4-bit nibbles. Unused nibbles are filled with 0xF.
* MNC 001 represented as 0xF001
* MNC 01 represented as 0xFF01
* PLMN encoded as per TS 36.413 sec 9.2.3.8
*****************************************************************************/
inline void s1ap_plmn_to_mccmnc(uint32_t plmn, uint16_t *mcc, uint16_t *mnc)
{
uint8_t nibbles[6];
nibbles[0] = (plmn & 0xF00000) >> 20;
nibbles[1] = (plmn & 0x0F0000) >> 16;
nibbles[2] = (plmn & 0x00F000) >> 12;
nibbles[3] = (plmn & 0x000F00) >> 8;
nibbles[4] = (plmn & 0x0000F0) >> 4;
nibbles[5] = (plmn & 0x00000F);
*mcc = 0xF000;
*mnc = 0xF000;
*mcc |= nibbles[1] << 8; // MCC digit 1
*mcc |= nibbles[0] << 4; // MCC digit 2
*mcc |= nibbles[3]; // MCC digit 3
if(nibbles[2] == 0xF) {
// 2-digit MNC
*mnc |= 0x0F00; // MNC digit 1
*mnc |= nibbles[5] << 4; // MNC digit 2
*mnc |= nibbles[4]; // MNC digit 3
} else {
// 3-digit MNC
*mnc |= nibbles[5] << 8; // MNC digit 1
*mnc |= nibbles[4] << 4; // MNC digit 2
*mnc |= nibbles[2] ; // MNC digit 3
}
}
/******************************************************************************
* Convert BCD-coded MCC and MNC to PLMN.
* Digits are represented by 4-bit nibbles. Unused nibbles are filled with 0xF.
* MNC 001 represented as 0xF001
* MNC 01 represented as 0xFF01
* PLMN encoded as per TS 36.413 sec 9.2.3.8
*****************************************************************************/
inline void s1ap_mccmnc_to_plmn(uint16_t mcc, uint16_t mnc, uint32_t *plmn)
{
uint8_t nibbles[6];
nibbles[1] = (mcc & 0x0F00) >> 8; // MCC digit 1
nibbles[0] = (mcc & 0x00F0) >> 4; // MCC digit 2
nibbles[3] = (mcc & 0x000F); // MCC digit 3
if((mnc & 0xFF00) == 0xFF00) {
// 2-digit MNC
nibbles[2] = 0x0F; // MNC digit 1
nibbles[5] = (mnc & 0x00F0) >> 4; // MNC digit 2
nibbles[4] = (mnc & 0x000F); // MNC digit 3
} else {
// 3-digit MNC
nibbles[5] = (mnc & 0x0F00) >> 8; // MNC digit 1
nibbles[4] = (mnc & 0x00F0) >> 4; // MNC digit 2
nibbles[2] = (mnc & 0x000F); // MNC digit 3
}
*plmn = 0x000000;
*plmn |= nibbles[0] << 20;
*plmn |= nibbles[1] << 16;
*plmn |= nibbles[2] << 12;
*plmn |= nibbles[3] << 8;
*plmn |= nibbles[4] << 4;
*plmn |= nibbles[5];
}
} // namespace srslte
#endif // BCD_HELPERS

@ -0,0 +1,95 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef SRSLTE_GTPU_H
#define SRSLTE_GTPU_H
#include <stdint.h>
#include "srslte/common/common.h"
namespace srslte {
/****************************************************************************
* GTPU Header
* Ref: 3GPP TS 29.281 v10.1.0 Section 5
*
* | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
*
* 1 | Version |PT | * | E | S |PN |
* 2 | Message Type |
* 3 | Length (1st Octet) |
* 4 | Length (2nd Octet) |
* 5 | TEID (1st Octet) |
* 6 | TEID (2nd Octet) |
* 7 | TEID (3rd Octet) |
* 8 | TEID (4th Octet) |
***************************************************************************/
#define GTPU_HEADER_LEN 8
typedef struct{
uint8_t flags; // Only support 0x30 - v1, PT1 (GTP), no other flags
uint8_t message_type; // Only support 0xFF - T-PDU type
uint16_t length;
uint32_t teid;
}gtpu_header_t;
bool gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header);
bool gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu);
inline void uint8_to_uint32(uint8_t *buf, uint32_t *i)
{
*i = (uint32_t)buf[0] << 24 |
(uint32_t)buf[1] << 16 |
(uint32_t)buf[2] << 8 |
(uint32_t)buf[3];
}
inline void uint32_to_uint8(uint32_t i, uint8_t *buf)
{
buf[0] = (i >> 24) & 0xFF;
buf[1] = (i >> 16) & 0xFF;
buf[2] = (i >> 8) & 0xFF;
buf[3] = i & 0xFF;
}
inline void uint8_to_uint16(uint8_t *buf, uint16_t *i)
{
*i = (uint32_t)buf[0] << 8 |
(uint32_t)buf[1];
}
inline void uint16_to_uint8(uint16_t i, uint8_t *buf)
{
buf[0] = (i >> 8) & 0xFF;
buf[1] = i & 0xFF;
}
}//namespace
#endif

@ -24,5 +24,6 @@ add_library(srslte_asn1 STATIC
liblte_rrc.cc
liblte_mme.cc
liblte_s1ap.cc
gtpc.cc
)
install(TARGETS srslte_asn1 DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,40 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdint.h>
#include "srslte/asn1/gtpc.h"
#include "srslte/common/common.h"
namespace srslte{
int
gtpc_pack_create_session_request(struct gtpc_create_session_request *cs_req, srslte::byte_buffer_t)
{
//FIXME
return 0;
}
};

@ -7111,7 +7111,6 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_request_msg(LIBLTE_BYTE_MSG_STRUCT
return(err);
}
/*********************************************************************
Message Name: Identity Response
@ -7149,6 +7148,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_identity_response_msg(LIBLTE_MME_ID_RESPONSE_M
return(err);
}
LIBLTE_ERROR_ENUM liblte_mme_unpack_identity_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ID_RESPONSE_MSG_STRUCT *id_resp)
{
@ -9893,6 +9893,64 @@ LIBLTE_ERROR_ENUM liblte_mme_unpack_deactivate_eps_bearer_context_request_msg(LI
return(err);
}
/*********************************************************************
Message Name: ESM Information Request
Description: Sent by the network to the UE to request the UE to
provide ESM information, i.e. protocol configuration
options or APN or both. This function is being added
to support encryption and integrety protection on
ESM information transfer.
Document Reference: 24.301 v10.2.0 Section 8.3.13
*********************************************************************/
LIBLTE_ERROR_ENUM srslte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT *esm_info_req,
uint8 sec_hdr_type,
uint32 count,
LIBLTE_BYTE_MSG_STRUCT *msg)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
if(esm_info_req != NULL &&
msg != NULL)
{
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS != sec_hdr_type)
{
// Protocol Discriminator and Security Header Type
*msg_ptr = (sec_hdr_type << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT);
msg_ptr++;
// MAC will be filled in later
msg_ptr += 4;
// Sequence Number
*msg_ptr = count & 0xFF;
msg_ptr++;
}
// Protocol Discriminator and EPS Bearer ID
*msg_ptr = (esm_info_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT);
msg_ptr++;
// Procedure Transaction ID
*msg_ptr = esm_info_req->proc_transaction_id;
msg_ptr++;
// Message Type
*msg_ptr = LIBLTE_MME_MSG_TYPE_ESM_INFORMATION_REQUEST;
msg_ptr++;
// Fill in the number of bytes used
msg->N_bytes = msg_ptr - msg->msg;
err = LIBLTE_SUCCESS;
}
return(err);
}
/*********************************************************************
Message Name: ESM Information Request
@ -9911,6 +9969,7 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INF
if(esm_info_req != NULL &&
msg != NULL)
{
// Protocol Discriminator and EPS Bearer ID
*msg_ptr = (esm_info_req->eps_bearer_id << 4) | (LIBLTE_MME_PD_EPS_SESSION_MANAGEMENT);
msg_ptr++;
@ -9931,6 +9990,9 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_request_msg(LIBLTE_MME_ESM_INF
return(err);
}
LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_request_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_REQUEST_MSG_STRUCT *esm_info_req)
{
@ -10011,6 +10073,62 @@ LIBLTE_ERROR_ENUM liblte_mme_pack_esm_information_response_msg(LIBLTE_MME_ESM_IN
return(err);
}
LIBLTE_ERROR_ENUM srslte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp)
{
LIBLTE_ERROR_ENUM err = LIBLTE_ERROR_INVALID_INPUTS;
uint8 *msg_ptr = msg->msg;
uint8 sec_hdr_type;
if(msg != NULL &&
esm_info_resp != NULL)
{
// Security Header Type
sec_hdr_type = (msg->msg[0] & 0xF0) >> 4;
if(LIBLTE_MME_SECURITY_HDR_TYPE_PLAIN_NAS == sec_hdr_type)
{
msg_ptr++;
}else{
msg_ptr += 7;
}
// EPS Bearer ID
esm_info_resp->eps_bearer_id = (*msg_ptr >> 4);
msg_ptr++;
// Procedure Transaction ID
esm_info_resp->proc_transaction_id = *msg_ptr;
msg_ptr++;
// Skip Message Type
msg_ptr++;
// Access Point Name
if(LIBLTE_MME_ACCESS_POINT_NAME_IEI == *msg_ptr)
{
msg_ptr++;
liblte_mme_unpack_access_point_name_ie(&msg_ptr, &esm_info_resp->apn);
esm_info_resp->apn_present = true;
}else{
esm_info_resp->apn_present = false;
}
// Protocol Configuration Options
if(LIBLTE_MME_PROTOCOL_CONFIGURATION_OPTIONS_IEI == *msg_ptr)
{
msg_ptr++;
liblte_mme_unpack_protocol_config_options_ie(&msg_ptr, &esm_info_resp->protocol_cnfg_opts);
esm_info_resp->protocol_cnfg_opts_present = true;
}else{
esm_info_resp->protocol_cnfg_opts_present = false;
}
err = LIBLTE_SUCCESS;
}
return(err);
}
LIBLTE_ERROR_ENUM liblte_mme_unpack_esm_information_response_msg(LIBLTE_BYTE_MSG_STRUCT *msg,
LIBLTE_MME_ESM_INFORMATION_RESPONSE_MSG_STRUCT *esm_info_resp)
{

@ -40,7 +40,7 @@ logger_file::logger_file()
logger_file::~logger_file() {
not_done = false;
log(new std::string("Closing log"));
log(new std::string("Closing log\n"));
if(inited) {
wait_thread_finish();
flush();

@ -0,0 +1,96 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of the srsLTE library.
*
* srsUE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsUE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include "srslte/upper/gtpu.h"
namespace srslte {
/****************************************************************************
* Header pack/unpack helper functions
* Ref: 3GPP TS 29.281 v10.1.0 Section 5
***************************************************************************/
bool gtpu_write_header(gtpu_header_t *header, srslte::byte_buffer_t *pdu)
{
if(header->flags != 0x30) {
//gtpu_log->error("gtpu_write_header - Unhandled header flags: 0x%x\n", header->flags);
return false;
}
if(header->message_type != 0xFF) {
//gtpu_log->error("gtpu_write_header - Unhandled message type: 0x%x\n", header->message_type);
return false;
}
if(pdu->get_headroom() < GTPU_HEADER_LEN) {
//gtpu_log->error("gtpu_write_header - No room in PDU for header\n");
return false;
}
pdu->msg -= GTPU_HEADER_LEN;
pdu->N_bytes += GTPU_HEADER_LEN;
uint8_t *ptr = pdu->msg;
*ptr = header->flags;
ptr++;
*ptr = header->message_type;
ptr++;
uint16_to_uint8(header->length, ptr);
ptr += 2;
uint32_to_uint8(header->teid, ptr);
return true;
}
bool gtpu_read_header(srslte::byte_buffer_t *pdu, gtpu_header_t *header)
{
uint8_t *ptr = pdu->msg;
pdu->msg += GTPU_HEADER_LEN;
pdu->N_bytes -= GTPU_HEADER_LEN;
header->flags = *ptr;
ptr++;
header->message_type = *ptr;
ptr++;
uint8_to_uint16(ptr, &header->length);
ptr += 2;
uint8_to_uint32(ptr, &header->teid);
if(header->flags != 0x30) {
//gtpu_log->error("gtpu_read_header - Unhandled header flags: 0x%x\n", header->flags);
return false;
}
if(header->message_type != 0xFF) {
//gtpu_log->error("gtpu_read_header - Unhandled message type: 0x%x\n", header->message_type);
return false;
}
return true;
}
} // namespace srslte

@ -22,8 +22,8 @@ phy_cell_id = 1
tac = 0x0007
mcc = 001
mnc = 01
mme_addr = 127.0.1.100
gtp_bind_addr = 127.0.1.1
mme_addr = 127.0.0.1
gtp_bind_addr = 127.0.0.1
n_prb = 25
#####################################################################

@ -0,0 +1,50 @@
#
# Copyright 2013-2017 Software Radio Systems Limited
#
# This file is part of srsLTE
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
find_package(LibConfig REQUIRED)
find_package(SCTP REQUIRED)
if(BUILD_STATIC)
set(LIBCONFIGPP_LIBRARIES "${LIBCONFIGPP_STATIC_LIBRARY_PATH}")
endif(BUILD_STATIC)
if(NOT Boost_FOUND)
message(FATAL_ERROR "Boost required to compile srsEPC")
endif()
########################################################################
# Setup the include and linker paths
########################################################################
include_directories(
${Boost_INCLUDE_DIRS}
${SEC_INCLUDE_DIRS}
${PROJECT_SOURCE_DIR}/srsepc/hdr
)
link_directories(
${Boost_LIBRARY_DIRS}
${SEC_LIBRARY_DIRS}
)
########################################################################
# Add subdirectories
########################################################################
add_subdirectory(src)
#add_subdirectory(test)

@ -0,0 +1,72 @@
#####################################################################
# srsEPC configuration file
#####################################################################
#####################################################################
# MME configuration
#
# mme_code: 8-bit MME code identifies the MME within a group.
# mme_group: 16-bit MME group identifier.
# tac: 16-bit Tracking Area Code.
# mcc: Mobile Country Code
# mnc: Mobile Network Code
# mme_bindx_addr: IP subnet to listen for eNB S1 connnections
#
#####################################################################
[mme]
mme_code = 0x1a
mme_group = 0x0001
tac = 0x0007
mcc = 001
mnc = 01
mme_bind_addr = 127.0.1.100
#####################################################################
# HSS configuration
#
# db_file: Location of .csv file that stores UEs information.
#
#####################################################################
[hss]
auth_algo = xor
db_file = user_db.csv
#####################################################################
# SP-GW configuration
#
# gtpu_bind_addr: Location of .csv file that stores UEs information.
#
#####################################################################
[spgw]
gtpu_bind_addr=127.0.1.100
sgi_if_addr=172.16.0.1
####################################################################
# Log configuration
#
# Log levels can be set for individual layers. "all_level" sets log
# level for all layers unless otherwise configured.
# Format: e.g. s1ap_level = info
#
# In the same way, packet hex dumps can be limited for each level.
# "all_hex_limit" sets the hex limit for all layers unless otherwise
# configured.
# Format: e.g. s1ap_hex_limit = 32
#
# Logging layers: s1ap, gtpc, spgw, hss, all
# Logging levels: debug, info, warning, error, none
#
# filename: File path to use for log output. Can be set to stdout
# to print logs to standard output
#####################################################################
[log]
all_level = debug
all_hex_limit = 32
filename = /tmp/epc.log
#s1ap_level = debug
#gtpc_level = debug
#spgw_level = debug
#hss_level = debug

@ -0,0 +1,5 @@
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/version.h.in
${PROJECT_BINARY_DIR}/version.h
)

@ -0,0 +1,106 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: hss.h
* Description: Top-level HSS class. Creates and links all
* interfaces and helpers.
*****************************************************************************/
#ifndef HSS_H
#define HSS_H
#include <cstddef>
#include "srslte/common/log.h"
#include "srslte/common/logger_file.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h"
#include <fstream>
#include <map>
namespace srsepc{
typedef struct{
std::string auth_algo;
std::string db_file;
}hss_args_t;
typedef struct{
std::string name;
uint64_t imsi;
uint8_t key[16];
uint8_t op[16];
uint8_t amf[2];
}hss_ue_ctx_t;
enum hss_auth_algo {
HSS_ALGO_XOR,
HSS_ALGO_MILENAGE
};
class hss
{
public:
static hss* get_instance(void);
static void cleanup(void);
int init(hss_args_t *hss_args, srslte::log_filter* hss_log);
void stop(void);
bool set_auth_algo(std::string auth_algo);
bool read_db_file(std::string db_file);
void get_sqn(uint8_t sqn[6]);
void gen_rand(uint8_t rand_[16]);
bool get_k_amf_op(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op);
bool gen_auth_info_answer(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);
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);
private:
hss();
virtual ~hss();
static hss *m_instance;
uint64_t m_sqn; //48 bits
srslte::byte_buffer_pool *m_pool;
std::ifstream m_db_file;
std::map<uint64_t,hss_ue_ctx_t*> m_imsi_to_ue_ctx;
enum hss_auth_algo m_auth_algo;
/*Logs*/
srslte::log_filter *m_hss_log;
};
} // namespace srsepc
#endif // MME_H

@ -0,0 +1,92 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: mme.h
* Description: Top-level MME class. Creates and links all
* interfaces and helpers.
*****************************************************************************/
#ifndef MME_H
#define MME_H
#include <cstddef>
#include "srslte/common/log.h"
#include "srslte/common/logger_file.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/threads.h"
#include "s1ap.h"
namespace srsepc{
/*
typedef struct {
std::string s1ap_level;
std::string all_level;
int s1ap_hex_limit;
std::string filename;
}log_args_t;
*/
typedef struct{
s1ap_args_t s1ap_args;
//diameter_args_t diameter_args;
//gtpc_args_t gtpc_args;
} mme_args_t;
class mme:
public thread
{
public:
static mme* get_instance(void);
static void cleanup(void);
int init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log);
void stop();
int get_s1_mme();
void run_thread();
private:
mme();
virtual ~mme();
static mme *m_instance;
s1ap *m_s1ap;
mme_gtpc *m_mme_gtpc;
bool m_running;
srslte::byte_buffer_pool *m_pool;
/*Logs*/
srslte::log_filter *m_s1ap_log;
srslte::log_filter *m_mme_gtpc_log;
};
} // namespace srsepc
#endif // MME_H

@ -0,0 +1,76 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef MME_GTPC_H
#define MME_GTPC_H
#include "srslte/common/log.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h"
#include <boost/thread/mutex.hpp>
#include "srslte/asn1/gtpc.h"
#include "mme/s1ap_common.h"
namespace srsepc
{
class spgw;
class s1ap;
class mme_gtpc
{
public:
static mme_gtpc* get_instance(void);
static void cleanup(void);
bool init(srslte::log_filter *mme_gtpc_log);
uint32_t get_new_ctrl_teid();
void send_create_session_request(uint64_t imsi, uint32_t mme_s1ap_id);
void handle_create_session_response(srslte::gtpc_pdu *cs_resp_pdu);
void send_modify_bearer_request(erab_ctx_t *bearer_ctx);
void handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu);
void send_delete_session_request(ue_ctx_t *ue_ctx);
private:
mme_gtpc();
virtual ~mme_gtpc();
static mme_gtpc *m_instance;
srslte::log_filter *m_mme_gtpc_log;
srslte::byte_buffer_pool *m_pool;
s1ap* m_s1ap;
spgw* m_spgw;
in_addr_t m_mme_gtpc_ip;
uint32_t m_next_ctrl_teid;
std::map<uint32_t,uint32_t> m_teid_to_mme_s1ap_id;
};
}
#endif

@ -0,0 +1,128 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef S1AP_H
#define S1AP_H
#include "srslte/asn1/gtpc.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/asn1/liblte_mme.h"
#include "srslte/common/common.h"
#include "srslte/common/log.h"
#include <strings.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/sctp.h>
#include <unistd.h>
#include <map>
#include <set>
#include "mme/s1ap_common.h"
#include "mme/s1ap_mngmt_proc.h"
#include "mme/s1ap_nas_transport.h"
#include "mme/s1ap_ctx_mngmt_proc.h"
#include "mme/mme_gtpc.h"
#include "hss/hss.h"
namespace srsepc{
const uint16_t S1MME_PORT = 36412;
class s1ap
{
public:
static s1ap* get_instance();
static void cleanup();
int enb_listen();
int init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log);
void stop();
int get_s1_mme();
void delete_enb_ctx(int32_t assoc_id);
void delete_ues_in_enb(uint16_t enb_id);
bool handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri);
bool handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri);
bool handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg);
void activate_eps_bearer(uint32_t mme_s1ap_id, uint8_t ebi);
void print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx);
uint32_t get_plmn();
uint32_t get_next_mme_ue_s1ap_id();
enb_ctx_t* find_enb_ctx(uint16_t enb_id);
void add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo* enb_sri);
ue_ctx_t* find_ue_ctx(uint32_t mme_ue_s1ap_id);
void add_new_ue_ctx(const ue_ctx_t &ue_ctx);
bool delete_ue_ctx(ue_ctx_t *ue_ctx);
uint32_t allocate_m_tmsi(uint32_t mme_ue_s1ap_id);
s1ap_args_t m_s1ap_args;
srslte::log_filter *m_s1ap_log;
s1ap_mngmt_proc* m_s1ap_mngmt_proc;
s1ap_nas_transport* m_s1ap_nas_transport;
s1ap_ctx_mngmt_proc* m_s1ap_ctx_mngmt_proc;
std::map<uint32_t, uint32_t> m_tmsi_to_s1ap_id;
private:
s1ap();
virtual ~s1ap();
static s1ap *m_instance;
uint32_t m_plmn;
srslte::byte_buffer_pool *m_pool;
hss *m_hss;
int m_s1mme;
std::map<uint16_t, enb_ctx_t*> m_active_enbs;
std::map<int32_t, uint16_t> m_sctp_to_enb_id;
std::map<uint32_t, ue_ctx_t*> m_active_ues;
std::map<uint16_t,std::set<uint32_t> > m_enb_id_to_ue_ids;
uint32_t m_next_mme_ue_s1ap_id;
uint32_t m_next_m_tmsi;
//FIXME the GTP-C should be moved to the MME class, the the packaging of GTP-C messages is done.
mme_gtpc *m_mme_gtpc;
};
inline uint32_t
s1ap::get_plmn()
{
return m_plmn;
}
} //namespace srsepc
#endif //S1AP_H

@ -0,0 +1,101 @@
/*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef S1AP_COMMON_H
#define S1AP_COMMON_H
#include "srslte/common/security.h"
#include "srslte/asn1/gtpc_ies.h"
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/asn1/liblte_mme.h"
#include <netinet/sctp.h>
namespace srsepc{
static const uint8_t MAX_TA=255; //Maximum TA supported
static const uint8_t MAX_BPLMN=6; //Maximum broadcasted PLMNs per TAC
static const uint8_t MAX_ERABS_PER_UE = 16;
enum erab_state
{
ERAB_DEACTIVATED,
ERAB_CTX_REQUESTED,
ERAB_CTX_SETUP,
ERAB_ACTIVE
};
typedef struct{
uint8_t mme_code;
uint16_t mme_group;
uint16_t tac; // 16-bit tac
uint16_t mcc; // BCD-coded with 0xF filler
uint16_t mnc; // BCD-coded with 0xF filler
std::string mme_bind_addr;
std::string mme_name;
} s1ap_args_t;
typedef struct{
bool enb_name_present;
uint32_t enb_id;
uint8_t enb_name[150];
uint16_t mcc, mnc;
uint32_t plmn;
uint8_t nof_supported_ta;
uint16_t tac[MAX_TA];
uint8_t nof_supported_bplmns[MAX_TA];
uint16_t bplmns[MAX_TA][MAX_BPLMN];
LIBLTE_S1AP_PAGINGDRX_ENUM drx;
struct sctp_sndrcvinfo sri;
} enb_ctx_t;
typedef struct{
uint8_t k_asme[32];
uint8_t xres[16]; //minimum 6, maximum 16
uint32_t dl_nas_count;
uint32_t ul_nas_count;
srslte::CIPHERING_ALGORITHM_ID_ENUM cipher_algo;
srslte::INTEGRITY_ALGORITHM_ID_ENUM integ_algo;
uint8_t k_nas_enc[32];
uint8_t k_nas_int[32];
} eps_security_ctx_t;
typedef struct{
enum erab_state state;
uint8_t erab_id;
srslte::gtpc_f_teid_ie enb_fteid;
srslte::gtpc_f_teid_ie sgw_ctrl_fteid;
} erab_ctx_t;
typedef struct{
uint64_t imsi;
uint32_t enb_ue_s1ap_id;
uint32_t mme_ue_s1ap_id;
uint16_t enb_id;
struct sctp_sndrcvinfo enb_sri;
eps_security_ctx_t security_ctxt;
erab_ctx_t erabs_ctx[MAX_ERABS_PER_UE];
LIBLTE_MME_UE_NETWORK_CAPABILITY_STRUCT ue_network_cap;
bool ms_network_cap_present;
LIBLTE_MME_MS_NETWORK_CAPABILITY_STRUCT ms_network_cap;
bool eit;
uint8_t procedure_transaction_id;
} ue_ctx_t;
}//namespace
#endif

@ -0,0 +1,70 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef S1AP_CTX_MNGMT_PROC_H
#define S1AP_CTX_MNGMT_PROC_H
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/common.h"
#include "mme/s1ap_common.h"
#include "srslte/common/log_filter.h"
#include "mme/mme_gtpc.h"
#include "srslte/common/buffer_pool.h"
namespace srsepc{
class s1ap;
class s1ap_ctx_mngmt_proc
{
public:
static s1ap_ctx_mngmt_proc *m_instance;
static s1ap_ctx_mngmt_proc* get_instance(void);
static void cleanup(void);
void init(void);
bool send_initial_context_setup_request(uint32_t mme_ue_s1ap_id, struct srslte::gtpc_create_session_response *cs_resp, struct srslte::gtpc_f_teid_ie sgw_ctrl_fteid);
bool 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);
private:
s1ap_ctx_mngmt_proc();
virtual ~s1ap_ctx_mngmt_proc();
s1ap* m_s1ap;
s1ap_nas_transport* m_s1ap_nas_transport;
srslte::log_filter *m_s1ap_log;
s1ap_args_t m_s1ap_args;
mme_gtpc* m_mme_gtpc;
srslte::byte_buffer_pool *m_pool;
};
} //namespace srsepc
#endif //S1AP_MNGMT_PROC

@ -0,0 +1,68 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef S1AP_MNGMT_PROC_H
#define S1AP_MNGMT_PROC_H
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/common.h"
#include "mme/s1ap_common.h"
#include "srslte/common/log_filter.h"
namespace srsepc{
class s1ap;
class s1ap_mngmt_proc
{
public:
static s1ap_mngmt_proc *m_instance;
static s1ap_mngmt_proc* get_instance(void);
static void cleanup(void);
void init(void);
bool handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
//Packing/unpacking helper functions
bool unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, enb_ctx_t* enb_ctx);
bool pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte::byte_buffer_t* msg);
bool pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buffer_t* msg);
private:
s1ap_mngmt_proc();
virtual ~s1ap_mngmt_proc();
s1ap* m_s1ap;
srslte::log_filter *m_s1ap_log;
int m_s1mme;
s1ap_args_t m_s1ap_args;
};
} //namespace srsepc
#endif //S1AP_MNGMT_PROC

@ -0,0 +1,106 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#ifndef S1AP_NAS_TRANSPORT_H
#define S1AP_NAS_TRANSPORT_H
#include "srslte/asn1/liblte_s1ap.h"
#include "srslte/common/buffer_pool.h"
#include "mme/s1ap_common.h"
#include "srslte/asn1/gtpc.h"
#include "hss/hss.h"
#include "mme/mme_gtpc.h"
namespace srsepc{
class s1ap_nas_transport
{
public:
static s1ap_nas_transport* m_instance;
static s1ap_nas_transport* get_instance(void);
static void cleanup(void);
void init(void);
bool handle_initial_ue_message(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_uplink_nas_transport(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_nas_attach_request( uint32_t enb_ue_s1ap_id,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
srslte::byte_buffer_t *reply_buffer,
bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_imsi_attach_request(uint32_t enb_ue_s1ap_id,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
srslte::byte_buffer_t *reply_buffer,
bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_guti_attach_request(uint32_t enb_ue_s1ap_id,
const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT &attach_req,
const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT &pdn_con_req,
srslte::byte_buffer_t *reply_buffer,
bool* reply_flag,
struct sctp_sndrcvinfo *enb_sri);
bool handle_nas_authentication_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool* reply_flag);
bool handle_nas_security_mode_complete(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_nas_attach_complete(srslte::byte_buffer_t *nas_msg, ue_ctx_t *ue_ctx, srslte::byte_buffer_t *reply_buffer, bool *reply_flag);
bool handle_esm_information_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool handle_identity_response(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool handle_tracking_area_update_request(srslte::byte_buffer_t *nas_msg, ue_ctx_t* ue_ctx, srslte::byte_buffer_t *reply_msg, bool *reply_flag);
bool pack_authentication_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t next_mme_ue_s1ap_id, uint8_t *autn,uint8_t *rand);
bool pack_authentication_reject(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
bool unpack_authentication_response(LIBLTE_S1AP_MESSAGE_UPLINKNASTRANSPORT_STRUCT *ul_xport, LIBLTE_MME_AUTHENTICATION_RESPONSE_MSG_STRUCT *auth_resp);
bool pack_security_mode_command(srslte::byte_buffer_t *reply_msg, ue_ctx_t *ue_ctx);
bool pack_esm_information_request(srslte::byte_buffer_t *reply_msg, ue_ctx_t *ue_ctx);
bool pack_attach_accept(ue_ctx_t *ue_ctx, LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab_ctxt, struct srslte::gtpc_pdn_address_allocation_ie *paa, srslte::byte_buffer_t *nas_buffer);
bool pack_identity_request(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
bool pack_emm_information(srslte::byte_buffer_t *reply_msg, uint32_t enb_ue_s1ap_id, uint32_t mme_ue_s1ap_id);
void log_unhandled_attach_request_ies(const LIBLTE_MME_ATTACH_REQUEST_MSG_STRUCT *attach_req);
void log_unhandled_pdn_con_request_ies(const LIBLTE_MME_PDN_CONNECTIVITY_REQUEST_MSG_STRUCT *pdn_con_req);
void log_unhandled_initial_ue_message_ies(LIBLTE_S1AP_MESSAGE_INITIALUEMESSAGE_STRUCT *init_ue);
private:
s1ap_nas_transport();
virtual ~s1ap_nas_transport();
srslte::log *m_s1ap_log;
srslte::byte_buffer_pool *m_pool;
s1ap* m_s1ap;
hss* m_hss;
mme_gtpc* m_mme_gtpc;
};
} //namespace srsepc
#endif //S1AP_NAS_TRANSPORT

@ -0,0 +1,127 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
/******************************************************************************
* File: spgw.h
* Description: Top-level SP-GW class. Creates and links all
* interfaces and helpers.
*****************************************************************************/
#ifndef SPGW_H
#define SPGW_H
#include <cstddef>
#include "srslte/common/log.h"
#include "srslte/common/logger_file.h"
#include "srslte/common/log_filter.h"
#include "srslte/common/buffer_pool.h"
#include "srslte/common/threads.h"
#include "srslte/asn1/gtpc.h"
namespace srsepc{
class mme_gtpc;
const uint16_t GTPU_RX_PORT = 2152;
typedef struct {
std::string gtpu_bind_addr;
std::string sgi_if_addr;
} spgw_args_t;
typedef struct spgw_tunnel_ctx {
uint64_t imsi;
in_addr_t ue_ipv4;
uint8_t ebi;
struct srslte::gtpc_f_teid_ie up_ctrl_fteid;
struct srslte::gtpc_f_teid_ie up_user_fteid;
struct srslte::gtpc_f_teid_ie dw_ctrl_fteid;
struct srslte::gtpc_f_teid_ie dw_user_fteid;
} spgw_tunnel_ctx_t;
class spgw:
public thread
{
public:
static spgw* get_instance(void);
static void cleanup(void);
int init(spgw_args_t* args, srslte::log_filter *spgw_log);
void stop();
void run_thread();
void handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu);
void handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct srslte::gtpc_pdu *mb_resp_pdu);
void handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct srslte::gtpc_pdu *del_resp_pdu);
void handle_sgi_pdu(srslte::byte_buffer_t *msg);
void handle_s1u_pdu(srslte::byte_buffer_t *msg);
private:
spgw();
virtual ~spgw();
static spgw *m_instance;
srslte::error_t init_sgi_if(spgw_args_t *args);
srslte::error_t init_s1u(spgw_args_t *args);
srslte::error_t init_ue_ip(spgw_args_t *args);
uint64_t get_new_ctrl_teid();
uint64_t get_new_user_teid();
in_addr_t get_new_ue_ipv4();
bool m_running;
srslte::byte_buffer_pool *m_pool;
mme_gtpc *m_mme_gtpc;
bool m_sgi_up;
int m_sgi_if;
int m_sgi_sock;
bool m_s1u_up;
int m_s1u;
uint64_t m_next_ctrl_teid;
uint64_t m_next_user_teid;
sockaddr_in m_s1u_addr;
pthread_mutex_t m_mutex;
std::map<uint32_t,spgw_tunnel_ctx*> m_teid_to_tunnel_ctx; //Map control TEID to tunnel ctx. Usefull to get reply ctrl TEID, UE IP, etc.
std::map<in_addr_t,srslte::gtpc_f_teid_ie> m_ip_to_teid; //Map IP to User-plane TEID for downlink traffic
uint32_t m_h_next_ue_ip;
/*Logs*/
srslte::log_filter *m_spgw_log;
};
} // namespace srsepc
#endif // SGW_H

@ -0,0 +1,37 @@
#/bin/bash
###################################################################
#
# This file is part of srsLTE.
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
###################################################################
#Check for sudo rights
sudo -v || exit
#Check if outbound interface was specified
if [ ! $# -eq 1 ]
then
echo "Usage :'sudo ./if_masq.sh <Interface Name>' "
exit
fi
echo "Masquerading Interface "$1
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward 1>/dev/null
sudo iptables -t nat -A POSTROUTING -o $1 -j MASQUERADE

@ -0,0 +1,45 @@
add_subdirectory(mme)
add_subdirectory(hss)
add_subdirectory(spgw)
# Link libstdc++ and libgcc
if(BUILD_STATIC)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -static-libstdc++ -static-libgcc")
endif(BUILD_STATIC)
if (RPATH)
SET(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
endif (RPATH)
add_executable(srsepc main.cc )
target_link_libraries(srsepc srsepc_mme
srsepc_hss
srsepc_sgw
srslte_upper
srslte_common
${CMAKE_THREAD_LIBS_INIT}
${Boost_LIBRARIES}
${SEC_LIBRARIES}
${LIBCONFIGPP_LIBRARIES}
${SCTP_LIBRARIES})
if (RPATH)
set_target_properties(srsepc PROPERTIES INSTALL_RPATH ".")
endif (RPATH)
install(TARGETS srsepc DESTINATION ${RUNTIME_DIR})
########################################################################
# Option to run command after build (useful for remote builds)
########################################################################
if (NOT ${BUILDEPC_CMD} STREQUAL "")
message(STATUS "Added custom post-build-EPC command: ${BUILDENB_CMD}")
add_custom_command(TARGET srsenb POST_BUILD COMMAND ${BUILDENB_CMD})
else(NOT ${BUILDEPC_CMD} STREQUAL "")
message(STATUS "No post-build-EPC command defined")
endif (NOT ${BUILDEPC_CMD} STREQUAL "")
install(TARGETS srsepc DESTINATION ${RUNTIME_DIR})

@ -0,0 +1,24 @@
#
# Copyright 2013-2017 Software Radio Systems Limited
#
# This file is part of srsLTE
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
file(GLOB SOURCES "*.cc")
add_library(srsepc_hss STATIC ${SOURCES})
install(TARGETS srsepc_hss DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,446 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
#include <string>
#include <sstream>
#include <boost/thread/mutex.hpp>
#include "hss/hss.h"
#include "srslte/common/security.h"
using namespace srslte;
namespace srsepc{
hss* hss::m_instance = NULL;
boost::mutex hss_instance_mutex;
hss::hss()
// :m_sqn(0x112233445566)
:m_sqn(0)
{
m_pool = srslte::byte_buffer_pool::get_instance();
return;
}
hss::~hss()
{
return;
}
hss*
hss::get_instance(void)
{
boost::mutex::scoped_lock lock(hss_instance_mutex);
if(NULL == m_instance) {
m_instance = new hss();
}
return(m_instance);
}
void
hss::cleanup(void)
{
boost::mutex::scoped_lock lock(hss_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
}
int
hss::init(hss_args_t *hss_args, srslte::log_filter *hss_log)
{
srand(time(NULL));
/*Init loggers*/
m_hss_log = hss_log;
/*Set authentication algorithm*/
if(set_auth_algo(hss_args->auth_algo) == false)
{
return -1;
}
/*Read user information from DB*/
if(read_db_file(hss_args->db_file) == false)
{
m_hss_log->console("Error reading user database file %s\n", hss_args->db_file.c_str());
return -1;
}
m_hss_log->info("HSS Initialized. DB file %s, authentication algorithm %s\n", hss_args->db_file.c_str(),hss_args->auth_algo.c_str());
m_hss_log->console("HSS Initialized\n");
return 0;
}
void
hss::stop(void)
{
std::map<uint64_t,hss_ue_ctx_t*>::iterator it = m_imsi_to_ue_ctx.begin();
while(it!=m_imsi_to_ue_ctx.end())
{
m_hss_log->info("Deleting UE context in HSS. IMSI: %lu\n", it->second->imsi);
m_hss_log->console("Deleting UE context in HSS. IMSI: %lu\n", it->second->imsi);
delete it->second;
m_imsi_to_ue_ctx.erase(it++);
}
if(m_db_file.is_open())
{
m_db_file.close();
}
return;
}
bool
hss::set_auth_algo(std::string auth_algo)
{
if(auth_algo != "xor" && auth_algo != "milenage" )
{
m_hss_log->error("Unrecognized authentication algorithm. auth_algo = %s\n", auth_algo.c_str());
return false;
}
if(auth_algo == "xor")
{
m_auth_algo = HSS_ALGO_XOR;
}
else
{
m_auth_algo = HSS_ALGO_MILENAGE;
}
return true;
}
bool
hss::read_db_file(std::string db_filename)
{
m_db_file.open(db_filename.c_str(), std::ifstream::in);
if(!m_db_file.is_open())
{
return false;
}
m_hss_log->info("Opened DB file: %s\n", db_filename.c_str() );
std::string line;
while (std::getline(m_db_file, line))
{
if(line[0] != '#')
{
std::vector<std::string> split = split_string(line,',');
if(split.size()!=5)
{
m_hss_log->error("Error parsing UE database\n");
return false;
}
hss_ue_ctx_t *ue_ctx = new hss_ue_ctx_t;
ue_ctx->name = split[0];
ue_ctx->imsi = atoll(split[1].c_str());
get_uint_vec_from_hex_str(split[2],ue_ctx->key,16);
get_uint_vec_from_hex_str(split[3],ue_ctx->op,16);
get_uint_vec_from_hex_str(split[4],ue_ctx->amf,2);
m_hss_log->debug("Added user from DB, IMSI: %015lu\n", ue_ctx->imsi);
m_hss_log->debug_hex(ue_ctx->key, 16, "User Key : ");
m_hss_log->debug_hex(ue_ctx->op, 16, "User OP : ");
m_hss_log->debug_hex(ue_ctx->amf, 2, "AMF : ");
m_imsi_to_ue_ctx.insert(std::pair<uint64_t,hss_ue_ctx_t*>(ue_ctx->imsi,ue_ctx));
}
}
return true;
}
bool
hss::gen_auth_info_answer(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
{
bool ret = false;
switch (m_auth_algo)
{
case HSS_ALGO_XOR:
ret = gen_auth_info_answer_xor(imsi, k_asme, autn, rand, xres);
break;
case HSS_ALGO_MILENAGE:
ret = gen_auth_info_answer_milenage(imsi, k_asme, autn, rand, xres);
break;
}
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)
{
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t sqn[6];
uint8_t ck[16];
uint8_t ik[16];
uint8_t ak[6];
uint8_t mac[8];
uint16_t mcc=61441; //001
uint16_t mnc=65281; //01
if(!get_k_amf_op(imsi,k,amf,op))
{
return false;
}
gen_rand(rand);
get_sqn(sqn);
security_milenage_f2345( k,
op,
rand,
xres,
ck,
ik,
ak);
security_milenage_f1( k,
op,
rand,
sqn,
amf,
mac);
// Generate K_asme
security_generate_k_asme( ck,
ik,
ak,
sqn,
mcc,
mnc,
k_asme);
//Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
autn[i] = sqn[i]^ak[i];
}
for(int i=0;i<2;i++)
{
autn[6+i]=amf[i];
}
for(int i=0;i<8;i++)
{
autn[8+i]=mac[i];
}
m_hss_log->debug_hex(sqn, 6, "User SQN : ");
m_hss_log->debug_hex(autn, 8, "User AUTN: ");
m_hss_log->debug_hex(xres, 8, "User XRES: ");
return true;
}
bool
hss::gen_auth_info_answer_xor(uint64_t imsi, uint8_t *k_asme, uint8_t *autn, uint8_t *rand, uint8_t *xres)
{
uint8_t k[16];
uint8_t amf[2];
uint8_t op[16];
uint8_t sqn[6];
uint8_t xdout[16];
uint8_t cdout[8];
uint8_t ck[16];
uint8_t ik[16];
uint8_t ak[6];
uint8_t mac[8];
uint16_t mcc=61441; //001
uint16_t mnc=65281; //01
int i = 0;
if(!get_k_amf_op(imsi,k,amf,op))
{
return false;
}
gen_rand(rand);
get_sqn(sqn);
// Use RAND and K to compute RES, CK, IK and AK
for(i=0; i<16; i++) {
xdout[i] = k[i]^rand[i];
}
for(i=0; i<16; i++) {
xres[i] = xdout[i];
ck[i] = xdout[(i+1)%16];
ik[i] = xdout[(i+2)%16];
}
for(i=0; i<6; i++) {
ak[i] = xdout[i+3];
}
// Generate cdout
for(i=0; i<6; i++) {
cdout[i] = sqn[i];
}
for(i=0; i<2; i++) {
cdout[6+i] = amf[i];
}
// Generate MAC
for(i=0;i<8;i++) {
mac[i] = xdout[i] ^ cdout[i];
}
//Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
autn[i] = sqn[i]^ak[i];
}
for(int i=0;i<2;i++)
{
autn[6+i]=amf[i];
}
for(int i=0;i<8;i++)
{
autn[8+i]=mac[i];
}
// Generate K_asme
security_generate_k_asme( ck,
ik,
ak,
sqn,
mcc,
mnc,
k_asme);
//Generate AUTN (autn = sqn ^ ak |+| amf |+| mac)
for(int i=0;i<6;i++ )
{
autn[i] = sqn[i]^ak[i];
}
for(int i=0;i<2;i++)
{
autn[6+i]=amf[i];
}
for(int i=0;i<8;i++)
{
autn[8+i]=mac[i];
}
m_hss_log->debug_hex(sqn, 6, "User SQN : ");
m_hss_log->debug_hex(autn, 8, "User AUTN: ");
m_hss_log->debug_hex(xres, 8, "User XRES: ");
return true;
}
bool
hss::get_k_amf_op(uint64_t imsi, uint8_t *k, uint8_t *amf, uint8_t *op )
{
/*
uint8_t k_tmp[16] ={0x00,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0xaa,0xbb,0xcc,0xdd,0xee,0xff};
uint8_t amf_tmp[2]={0x80,0x00};
uint8_t op_tmp[16]={0x63,0xbf,0xA5,0x0E,0xE6,0x52,0x33,0x65,0xFF,0x14,0xC1,0xF4,0x5F,0x88,0x73,0x7D};
*/
std::map<uint64_t,hss_ue_ctx_t*>::iterator ue_ctx_it = m_imsi_to_ue_ctx.find(imsi);
if(ue_ctx_it == m_imsi_to_ue_ctx.end())
{
m_hss_log->info("User not found. IMSI: %015lu\n",imsi);
m_hss_log->console("User not found. IMSI: %015lu\n",imsi);
return false;
}
hss_ue_ctx_t *ue_ctx = ue_ctx_it->second;
m_hss_log->info("Found User %015lu\n",imsi);
memcpy(k,ue_ctx->key,16);
memcpy(amf,ue_ctx->amf,2);
memcpy(op,ue_ctx->op,16);
return true;
}
void
hss::get_sqn(uint8_t sqn[6])
{
for (int i=0; i<6; i++)
{
sqn[i] = ((uint8_t *)&m_sqn)[i];
}
m_sqn++;
return; //TODO See TS 33.102, Annex C
}
void
hss::gen_rand(uint8_t rand_[16])
{
for(int i=0;i<16;i++)
{
rand_[i]=rand()%256; //Pulls on byte at a time. It's slow, but does not depend on RAND_MAX.
}
return;
}
/* Helper functions*/
std::vector<std::string>
hss::split_string(const std::string &str, char delimiter)
{
std::vector<std::string> tokens;
std::string token;
std::istringstream tokenStream(str);
while (std::getline(tokenStream, token, delimiter))
{
tokens.push_back(token);
}
return tokens;
}
void
hss::get_uint_vec_from_hex_str(const std::string &key_str, uint8_t *key, uint len)
{
const char *pos = key_str.c_str();
for (uint count = 0; count < len; count++) {
sscanf(pos, "%2hhx", &key[count]);
pos += 2;
}
return;
}
/*
uint64_t
string_to_imsi()
{
uint64_t imsi = 0;
for(int i=0;i<=14;i++){
imsi += attach_req.eps_mobile_id.imsi[i]*std::pow(10,14-i);
}
return imsi;
}
*/
} //namespace srsepc

@ -0,0 +1,333 @@
/**
*
* \section COPYRIGHT
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include <fstream>
#include <errno.h>
#include <signal.h>
#include <boost/program_options.hpp>
#include <boost/algorithm/string.hpp>
#include "srslte/common/bcd_helpers.h"
#include "mme/mme.h"
#include "hss/hss.h"
#include "spgw/spgw.h"
using namespace std;
using namespace srsepc;
namespace bpo = boost::program_options;
bool running = true;
void
sig_int_handler(int signo){
running = false;
}
typedef struct {
std::string s1ap_level;
int s1ap_hex_limit;
std::string gtpc_level;
int gtpc_hex_limit;
std::string spgw_level;
int spgw_hex_limit;
std::string hss_level;
int hss_hex_limit;
std::string all_level;
int all_hex_limit;
std::string filename;
}log_args_t;
typedef struct{
mme_args_t mme_args;
hss_args_t hss_args;
spgw_args_t spgw_args;
log_args_t log_args;
}all_args_t;
/**********************************************************************
* Program arguments processing
***********************************************************************/
string config_file;
void
parse_args(all_args_t *args, int argc, char* argv[]) {
string mme_name;
string mme_code;
string mme_group;
string tac;
string mcc;
string mnc;
string mme_bind_addr;
string spgw_bind_addr;
string sgi_if_addr;
string hss_db_file;
string hss_auth_algo;
string log_filename;
// Command line only options
bpo::options_description general("General options");
general.add_options()
("help,h", "Produce help message")
("version,v", "Print version information and exit")
;
// Command line or config file options
bpo::options_description common("Configuration options");
common.add_options()
("mme.mme_code", bpo::value<string>(&mme_code)->default_value("0x01"), "MME Code")
("mme.name", bpo::value<string>(&mme_name)->default_value("srsmme01"), "MME Name")
("mme.mme_group", bpo::value<string>(&mme_group)->default_value("0x01"), "Cell ID")
("mme.tac", bpo::value<string>(&tac)->default_value("0x0"), "Tracking Area Code")
("mme.mcc", bpo::value<string>(&mcc)->default_value("001"), "Mobile Country Code")
("mme.mnc", bpo::value<string>(&mnc)->default_value("01"), "Mobile Network Code")
("mme.mme_bind_addr", bpo::value<string>(&mme_bind_addr)->default_value("127.0.0.1"),"IP address of MME for S1 connnection")
("hss.db_file", bpo::value<string>(&hss_db_file)->default_value("ue_db.csv"),".csv file that stores UE's keys")
("hss.auth_algo", bpo::value<string>(&hss_auth_algo)->default_value("milenage"),"HSS uthentication algorithm.")
("spgw.gtpu_bind_addr", bpo::value<string>(&spgw_bind_addr)->default_value("127.0.0.1"),"IP address of SP-GW for the S1-U connection")
("spgw.sgi_if_addr", bpo::value<string>(&sgi_if_addr)->default_value("176.16.0.1"),"IP address of TUN interface for the SGi connection")
("log.s1ap_level", bpo::value<string>(&args->log_args.s1ap_level), "MME S1AP log level")
("log.s1ap_hex_limit", bpo::value<int>(&args->log_args.s1ap_hex_limit), "MME S1AP log hex dump limit")
("log.gtpc_level", bpo::value<string>(&args->log_args.gtpc_level), "MME GTPC log level")
("log.gtpc_hex_limit", bpo::value<int>(&args->log_args.gtpc_hex_limit), "MME GTPC log hex dump limit")
("log.spgw_level", bpo::value<string>(&args->log_args.spgw_level), "SPGW log level")
("log.spgw_hex_limit", bpo::value<int>(&args->log_args.spgw_hex_limit), "SPGW log hex dump limit")
//("log.gtpu_level", bpo::value<string>(&args->log.gtpu_level), "GTPU log level")
("log.hss_level", bpo::value<string>(&args->log_args.hss_level), "HSS log level")
("log.hss_hex_limit", bpo::value<int>(&args->log_args.hss_hex_limit), "HSS log hex dump limit")
//("log.gtpu_hex_limit",bpo::value<int>(&args->log.gtpu_hex_limit), "GTPU log hex dump limit")
("log.all_level", bpo::value<string>(&args->log_args.all_level)->default_value("info"), "ALL log level")
("log.all_hex_limit", bpo::value<int>(&args->log_args.all_hex_limit)->default_value(32), "ALL log hex dump limit")
("log.filename", bpo::value<string>(&args->log_args.filename)->default_value("/tmp/epc.log"),"Log filename")
;
// Positional options - config file location
bpo::options_description position("Positional options");
position.add_options()
("config_file", bpo::value< string >(&config_file), "MME configuration file")
;
bpo::positional_options_description p;
p.add("config_file", -1);
// these options are allowed on the command line
bpo::options_description cmdline_options;
cmdline_options.add(common).add(position).add(general);
// parse the command line and store result in vm
bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(cmdline_options).positional(p).run(), vm);
bpo::notify(vm);
// help option was given - print usage and exit
if (vm.count("help")) {
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
cout << common << endl << general << endl;
exit(0);
}
//Parsing Config File
if (!vm.count("config_file")) {
cout << "Error: Configuration file not provided" << endl;
cout << "Usage: " << argv[0] << " [OPTIONS] config_file" << endl << endl;
exit(0);
} else {
cout << "Reading configuration file " << config_file << "..." << endl;
ifstream conf(config_file.c_str(), ios::in);
if(conf.fail()) {
cout << "Failed to read configuration file " << config_file << " - exiting" << endl;
exit(1);
}
bpo::store(bpo::parse_config_file(conf, common), vm);
bpo::notify(vm);
}
//Concert hex strings
{
std::stringstream sstr;
sstr << std::hex << vm["mme.mme_group"].as<std::string>();
sstr >> args->mme_args.s1ap_args.mme_group;
}
{
std::stringstream sstr;
sstr << std::hex << vm["mme.mme_code"].as<std::string>();
uint16_t tmp; // Need intermediate uint16_t as uint8_t is treated as char
sstr >> tmp;
args->mme_args.s1ap_args.mme_code = tmp;
}
{
std::stringstream sstr;
sstr << std::hex << vm["mme.tac"].as<std::string>();
sstr >> args->mme_args.s1ap_args.tac;
}
// Convert MCC/MNC strings
if(!srslte::string_to_mcc(mcc, &args->mme_args.s1ap_args.mcc)) {
cout << "Error parsing enb.mcc:" << mcc << " - must be a 3-digit string." << endl;
}
if(!srslte::string_to_mnc(mnc, &args->mme_args.s1ap_args.mnc)) {
cout << "Error parsing enb.mnc:" << mnc << " - must be a 2 or 3-digit string." << endl;
}
args->mme_args.s1ap_args.mme_bind_addr = mme_bind_addr;
args->spgw_args.gtpu_bind_addr = spgw_bind_addr;
args->spgw_args.sgi_if_addr = sgi_if_addr;
args->hss_args.db_file = hss_db_file;
args->hss_args.auth_algo = hss_auth_algo;
// Apply all_level to any unset layers
if (vm.count("log.all_level")) {
if(!vm.count("log.s1ap_level")) {
args->log_args.s1ap_level = args->log_args.all_level;
}
if(!vm.count("log.gtpc_level")) {
args->log_args.gtpc_level = args->log_args.all_level;
}
if(!vm.count("log.spgw_level")) {
args->log_args.spgw_level = args->log_args.all_level;
}
if(!vm.count("log.hss_level")) {
args->log_args.hss_level = args->log_args.all_level;
}
}
// Apply all_hex_limit to any unset layers
if (vm.count("log.all_hex_limit")) {
if(!vm.count("log.s1ap_hex_limit")) {
args->log_args.s1ap_hex_limit = args->log_args.all_hex_limit;
}
if(!vm.count("log.gtpc_hex_limit")) {
args->log_args.gtpc_hex_limit = args->log_args.all_hex_limit;
}
if(!vm.count("log.spgw_hex_limit")) {
args->log_args.spgw_hex_limit = args->log_args.all_hex_limit;
}
if(!vm.count("log.hss_hex_limit")) {
args->log_args.hss_hex_limit = args->log_args.all_hex_limit;
}
}
return;
}
srslte::LOG_LEVEL_ENUM
level(std::string l)
{
boost::to_upper(l);
if("NONE" == l){
return srslte::LOG_LEVEL_NONE;
}else if("ERROR" == l){
return srslte::LOG_LEVEL_ERROR;
}else if("WARNING" == l){
return srslte::LOG_LEVEL_WARNING;
}else if("INFO" == l){
return srslte::LOG_LEVEL_INFO;
}else if("DEBUG" == l){
return srslte::LOG_LEVEL_DEBUG;
}else{
return srslte::LOG_LEVEL_NONE;
}
}
int
main (int argc,char * argv[] )
{
cout << endl <<"--- Software Radio Systems EPC ---" << endl << endl;
signal(SIGINT, sig_int_handler);
all_args_t args;
parse_args(&args, argc, argv);
srslte::logger_stdout logger_stdout;
srslte::logger_file logger_file;
srslte::logger *logger;
/*Init logger*/
if (!args.log_args.filename.compare("stdout")) {
logger = &logger_stdout;
} else {
logger_file.init(args.log_args.filename);
logger_file.log("\n--- Software Radio Systems EPC log ---\n\n");
logger = &logger_file;
}
srslte::log_filter s1ap_log;
s1ap_log.init("S1AP",logger);
s1ap_log.set_level(level(args.log_args.s1ap_level));
s1ap_log.set_hex_limit(args.log_args.s1ap_hex_limit);
srslte::log_filter mme_gtpc_log;
mme_gtpc_log.init("GTPC",logger);
mme_gtpc_log.set_level(level(args.log_args.gtpc_level));
mme_gtpc_log.set_hex_limit(args.log_args.gtpc_hex_limit);
srslte::log_filter hss_log;
hss_log.init("HSS ",logger);
hss_log.set_level(level(args.log_args.hss_level));
hss_log.set_hex_limit(args.log_args.hss_hex_limit);
srslte::log_filter spgw_log;
spgw_log.init("SPGW",logger);
spgw_log.set_level(level(args.log_args.spgw_level));
spgw_log.set_hex_limit(args.log_args.spgw_hex_limit);
mme *mme = mme::get_instance();
if (mme->init(&args.mme_args, &s1ap_log, &mme_gtpc_log)) {
cout << "Error initializing MME" << endl;
exit(1);
}
hss *hss = hss::get_instance();
if (hss->init(&args.hss_args,&hss_log)) {
cout << "Error initializing HSS" << endl;
exit(1);
}
spgw *spgw = spgw::get_instance();
if (spgw->init(&args.spgw_args,&spgw_log)) {
cout << "Error initializing SP-GW" << endl;
exit(1);
}
mme->start();
spgw->start();
while(running) {
sleep(1);
}
mme->stop();
mme->cleanup();
spgw->stop();
spgw->cleanup();
hss->stop();
hss->cleanup();
cout << std::endl <<"--- exiting ---" << endl;
return 0;
}

@ -0,0 +1,24 @@
#
# Copyright 2013-2017 Software Radio Systems Limited
#
# This file is part of srsLTE
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
file(GLOB SOURCES "*.cc")
add_library(srsepc_mme STATIC ${SOURCES})
install(TARGETS srsepc_mme DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,168 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream> //TODO Remove
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/sctp.h>
#include <boost/thread/mutex.hpp>
#include "mme/mme.h"
namespace srsepc{
mme* mme::m_instance = NULL;
boost::mutex mme_instance_mutex;
mme::mme():
m_running(false)
{
m_pool = srslte::byte_buffer_pool::get_instance();
return;
}
mme::~mme()
{
return;
}
mme*
mme::get_instance(void)
{
boost::mutex::scoped_lock lock(mme_instance_mutex);
if(NULL == m_instance) {
m_instance = new mme();
}
return(m_instance);
}
void
mme::cleanup(void)
{
boost::mutex::scoped_lock lock(mme_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
}
int
mme::init(mme_args_t* args, srslte::log_filter *s1ap_log, srslte::log_filter *mme_gtpc_log)
{
/*Init logger*/
m_s1ap_log = s1ap_log;
m_mme_gtpc_log = mme_gtpc_log;
/*Init S1AP*/
m_s1ap = s1ap::get_instance();
if(m_s1ap->init(args->s1ap_args, s1ap_log)){
m_s1ap_log->error("Error initializing MME S1APP\n");
exit(-1);
}
/*Init GTP-C*/
m_mme_gtpc = mme_gtpc::get_instance();
if(!m_mme_gtpc->init(m_mme_gtpc_log))
{
m_s1ap_log->console("Error initializing GTP-C\n");
exit(-1);
}
/*Log successful initialization*/
m_s1ap_log->info("MME Initialized. MCC: %d, MNC: %d\n",args->s1ap_args.mcc, args->s1ap_args.mnc);
m_s1ap_log->console("MME Initialized. \n");
return 0;
}
void
mme::stop()
{
if(m_running)
{
m_s1ap->stop();
m_s1ap->cleanup();
m_running = false;
thread_cancel();
wait_thread_finish();
}
return;
}
void
mme::run_thread()
{
srslte::byte_buffer_t *pdu = m_pool->allocate();
uint32_t sz = SRSLTE_MAX_BUFFER_SIZE_BYTES - SRSLTE_BUFFER_HEADER_OFFSET;
struct sockaddr_in enb_addr;
struct sctp_sndrcvinfo sri;
socklen_t fromlen = sizeof(enb_addr);
bzero(&enb_addr, sizeof(enb_addr));
int rd_sz;
int msg_flags=0;
//Mark the thread as running
m_running=true;
//Get S1-MME socket
int s1mme = m_s1ap->get_s1_mme();
while(m_running)
{
m_s1ap_log->debug("Waiting for SCTP Msg\n");
pdu->reset();
rd_sz = sctp_recvmsg(s1mme, pdu->msg, sz,(struct sockaddr*) &enb_addr, &fromlen, &sri, &msg_flags);
if (rd_sz == -1 && errno != EAGAIN){
m_s1ap_log->error("Error reading from SCTP socket: %s", strerror(errno));
}
else if (rd_sz == -1 && errno == EAGAIN){
m_s1ap_log->debug("Socket timeout reached");
}
else{
if(msg_flags & MSG_NOTIFICATION)
{
//Received notification
union sctp_notification *notification = (union sctp_notification*)pdu->msg;
m_s1ap_log->debug("SCTP Notification %d\n", notification->sn_header.sn_type);
if (notification->sn_header.sn_type == SCTP_SHUTDOWN_EVENT)
{
m_s1ap_log->info("SCTP Association Shutdown. Association: %d\n",sri.sinfo_assoc_id);
m_s1ap_log->console("SCTP Association Shutdown. Association: %d\n",sri.sinfo_assoc_id);
m_s1ap->delete_enb_ctx(sri.sinfo_assoc_id);
}
}
else
{
//Received data
pdu->N_bytes = rd_sz;
m_s1ap_log->info("Received S1AP msg. Size: %d\n", pdu->N_bytes);
m_s1ap->handle_s1ap_rx_pdu(pdu,&sri);
}
}
}
return;
}
} //namespace srsepc

@ -0,0 +1,257 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include "srslte/asn1/gtpc.h"
#include "mme/mme_gtpc.h"
#include "mme/s1ap.h"
#include "spgw/spgw.h"
namespace srsepc{
mme_gtpc* mme_gtpc::m_instance = NULL;
boost::mutex mme_gtpc_instance_mutex;
mme_gtpc::mme_gtpc()
{
}
mme_gtpc::~mme_gtpc()
{
}
mme_gtpc*
mme_gtpc::get_instance(void)
{
boost::mutex::scoped_lock lock(mme_gtpc_instance_mutex);
if(NULL == m_instance) {
m_instance = new mme_gtpc();
}
return(m_instance);
}
void
mme_gtpc::cleanup(void)
{
boost::mutex::scoped_lock lock(mme_gtpc_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
}
bool
mme_gtpc::init(srslte::log_filter *mme_gtpc_log)
{
/*Init log*/
m_mme_gtpc_log = mme_gtpc_log;
m_next_ctrl_teid = 1;
m_s1ap = s1ap::get_instance();
m_mme_gtpc_ip = inet_addr("127.0.0.1");//FIXME At the moment, the GTP-C messages are not sent over the wire. So this parameter is not used.
m_spgw = spgw::get_instance();
m_mme_gtpc_log->info("MME GTP-C Initialized\n");
m_mme_gtpc_log->console("MME GTP-C Initialized\n");
return true;
}
uint32_t
mme_gtpc::get_new_ctrl_teid()
{
return m_next_ctrl_teid++; //FIXME Use a Id pool?
}
void
mme_gtpc::send_create_session_request(uint64_t imsi, uint32_t mme_ue_s1ap_id)
{
m_mme_gtpc_log->info("Sending Create Session Request.\n");
m_mme_gtpc_log->console("Sending Create Session Request.\n");
struct srslte::gtpc_pdu cs_req_pdu;
struct srslte::gtpc_create_session_request *cs_req = &cs_req_pdu.choice.create_session_request;
struct srslte::gtpc_pdu cs_resp_pdu;
//Initialize GTP-C message to zero
bzero(&cs_req_pdu, sizeof(struct srslte::gtpc_pdu));
//Setup GTP-C Header. FIXME: Length, sequence and other fields need to be added.
cs_req_pdu.header.piggyback = false;
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.type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_REQUEST;
//Setup GTP-C Create Session Request IEs
cs_req->imsi = imsi;
// Control TEID allocated
cs_req->sender_f_teid.teid = get_new_ctrl_teid();
cs_req->sender_f_teid.ipv4 = m_mme_gtpc_ip;
m_mme_gtpc_log->info("Next control TEID: %lu \n", m_next_ctrl_teid);
m_mme_gtpc_log->info("Allocated control TEID: %lu \n", cs_req->sender_f_teid.teid);
m_mme_gtpc_log->console("Creating Session Response -- IMSI: %015lu \n", imsi);
m_mme_gtpc_log->console("Creating Session Response -- MME control TEID: %lu \n", cs_req->sender_f_teid.teid);
// APN
memcpy(cs_req->apn, "internet", sizeof("internet"));
// RAT Type
//cs_req->rat_type = srslte::GTPC_RAT_TYPE::EUTRAN;
//Save RX Control TEID
m_teid_to_mme_s1ap_id.insert(std::pair<uint32_t,uint32_t>(cs_req->sender_f_teid.teid, mme_ue_s1ap_id));
m_spgw->handle_create_session_request(cs_req, &cs_resp_pdu);
}
void
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;
m_mme_gtpc_log->info("Received Create Session Response\n");
m_mme_gtpc_log->console("Received Create Session Response\n");
if (cs_resp_pdu->header.type != srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE)
{
m_mme_gtpc_log->warning("Could not create GTPC session. Not a create session response\n");
//TODO Handle err
return;
}
if (cs_resp->cause.cause_value != srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED){
m_mme_gtpc_log->warning("Could not create GTPC session. Create Session Request not accepted\n");
//TODO Handle error
return;
}
//Get MME_UE_S1AP_ID from the control TEID
std::map<uint32_t,uint32_t>::iterator id_it = m_teid_to_mme_s1ap_id.find(cs_resp_pdu->header.teid);
if(id_it == m_teid_to_mme_s1ap_id.end())
{
//Could not find MME UE S1AP TEID
m_mme_gtpc_log->warning("Could not find MME UE S1AP TEID.\n");
return;
}
uint32_t mme_s1ap_id = id_it->second;
//Get S-GW Control F-TEID
srslte::gtpc_f_teid_ie sgw_ctrl_fteid;
sgw_ctrl_fteid.teid = cs_resp_pdu->header.teid;
sgw_ctrl_fteid.ipv4 = 0; //FIXME This is not used for now. In the future it will be obtained from the socket addr_info
m_mme_gtpc_log->console("Create Session Response -- SPGW control TEID %d\n", sgw_ctrl_fteid.teid);
in_addr s1u_addr;
s1u_addr.s_addr = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4;
m_mme_gtpc_log->console("Create Session Response -- SPGW S1-U Address: %s\n", inet_ntoa(s1u_addr));
m_s1ap->m_s1ap_ctx_mngmt_proc->send_initial_context_setup_request(mme_s1ap_id, cs_resp, sgw_ctrl_fteid);
}
void
mme_gtpc::send_modify_bearer_request(erab_ctx_t *erab_ctx)
{
m_mme_gtpc_log->info("Sending GTP-C Modify bearer request\n");
srslte::gtpc_pdu mb_req_pdu;
srslte::gtpc_f_teid_ie *enb_fteid = &erab_ctx->enb_fteid;
srslte::gtpc_f_teid_ie *sgw_ctrl_fteid = &erab_ctx->sgw_ctrl_fteid;
srslte::gtpc_header *header = &mb_req_pdu.header;
header->teid_present = true;
header->teid = sgw_ctrl_fteid->teid;
header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_REQUEST;
srslte::gtpc_modify_bearer_request *mb_req = &mb_req_pdu.choice.modify_bearer_request;
mb_req->eps_bearer_context_to_modify.ebi = erab_ctx->erab_id;
mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.ipv4 = enb_fteid->ipv4;
mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid = enb_fteid->teid;
m_mme_gtpc_log->info("GTP-C Modify bearer request -- S-GW Control TEID %d\n", sgw_ctrl_fteid->teid );
struct in_addr addr;
addr.s_addr = enb_fteid->ipv4;
m_mme_gtpc_log->info("GTP-C Modify bearer request -- S1-U TEID 0x%x, IP %s\n", enb_fteid->teid, inet_ntoa(addr) );
//
srslte::gtpc_pdu mb_resp_pdu;
m_spgw->handle_modify_bearer_request(&mb_req_pdu,&mb_resp_pdu);
handle_modify_bearer_response(&mb_resp_pdu);
return;
}
void
mme_gtpc::handle_modify_bearer_response(srslte::gtpc_pdu *mb_resp_pdu)
{
uint32_t mme_ctrl_teid = mb_resp_pdu->header.teid;
std::map<uint32_t,uint32_t>::iterator mme_s1ap_id_it = m_teid_to_mme_s1ap_id.find(mme_ctrl_teid);
if(mme_s1ap_id_it == m_teid_to_mme_s1ap_id.end())
{
m_mme_gtpc_log->error("Could not find MME S1AP Id from control TEID\n");
return;
}
uint8_t ebi = mb_resp_pdu->choice.modify_bearer_response.eps_bearer_context_modified.ebi;
m_mme_gtpc_log->debug("Activating EPS bearer with id %d\n", ebi);
m_s1ap->activate_eps_bearer(mme_s1ap_id_it->second,ebi);
return;
}
void
mme_gtpc::send_delete_session_request(ue_ctx_t *ue_ctx)
{
m_mme_gtpc_log->info("Sending GTP-C Delete Session Request request\n");
srslte::gtpc_pdu del_req_pdu;
srslte::gtpc_f_teid_ie *sgw_ctrl_fteid = NULL;
//FIXME the UE control TEID sould be stored in the UE ctxt, not in the E-RAB ctxt
//Maybe a mme_s1ap_id to ctrl teid map as well?
for(int i = 0; i<MAX_ERABS_PER_UE; i++)
{
if(ue_ctx->erabs_ctx[i].state != ERAB_DEACTIVATED)
{
sgw_ctrl_fteid = &ue_ctx->erabs_ctx[i].sgw_ctrl_fteid;
break;
}
}
//FIXME: add proper error handling
assert(sgw_ctrl_fteid != NULL);
srslte::gtpc_header *header = &del_req_pdu.header;
header->teid_present = true;
header->teid = sgw_ctrl_fteid->teid;
header->type = srslte::GTPC_MSG_TYPE_DELETE_SESSION_REQUEST;
srslte::gtpc_delete_session_request *del_req = &del_req_pdu.choice.delete_session_request;
del_req->cause.cause_value = srslte::GTPC_CAUSE_VALUE_ISR_DEACTIVATION;
m_mme_gtpc_log->info("GTP-C Delete Session Request -- S-GW Control TEID %d\n", sgw_ctrl_fteid->teid );
srslte::gtpc_pdu del_resp_pdu;
m_spgw->handle_delete_session_request(&del_req_pdu, &del_resp_pdu);
//TODO Handle delete session response
return;
}
} //namespace srsepc

@ -0,0 +1,475 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include <cmath>
#include "srslte/common/bcd_helpers.h"
#include "mme/s1ap.h"
#include "srslte/asn1/gtpc.h"
#include "srslte/common/liblte_security.h"
namespace srsepc{
s1ap* s1ap::m_instance = NULL;
boost::mutex s1ap_instance_mutex;
s1ap::s1ap():
m_s1mme(-1),
m_next_mme_ue_s1ap_id(1)
{
}
s1ap::~s1ap()
{
}
s1ap*
s1ap::get_instance(void)
{
boost::mutex::scoped_lock lock(s1ap_instance_mutex);
if(NULL == m_instance) {
m_instance = new s1ap();
}
return(m_instance);
}
void
s1ap::cleanup(void)
{
boost::mutex::scoped_lock lock(s1ap_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
}
int
s1ap::init(s1ap_args_t s1ap_args, srslte::log_filter *s1ap_log)
{
m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_args = s1ap_args;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &m_plmn);
m_next_m_tmsi = rand();
//Init log
m_s1ap_log = s1ap_log;
//Init message handlers
m_s1ap_mngmt_proc = s1ap_mngmt_proc::get_instance(); //Managment procedures
m_s1ap_mngmt_proc->init();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance(); //NAS Transport procedures
m_s1ap_nas_transport->init();
m_s1ap_ctx_mngmt_proc = s1ap_ctx_mngmt_proc::get_instance(); //Context Management Procedures
m_s1ap_ctx_mngmt_proc->init();
//Get pointer to the HSS
m_hss = hss::get_instance();
//Get pointer to GTP-C class
m_mme_gtpc = mme_gtpc::get_instance();
//Initialize S1-MME
m_s1mme = enb_listen();
m_s1ap_log->info("S1AP Initialized\n");
return 0;
}
void
s1ap::stop()
{
if (m_s1mme != -1){
close(m_s1mme);
}
std::map<uint16_t,enb_ctx_t*>::iterator it = m_active_enbs.begin();
while(it!=m_active_enbs.end())
{
m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", it->second->enb_id);
m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", it->second->enb_id);
delete_ues_in_enb(it->second->enb_id);
delete it->second;
m_active_enbs.erase(it++);
}
//Cleanup message handlers
s1ap_mngmt_proc::cleanup();
s1ap_nas_transport::cleanup();
s1ap_ctx_mngmt_proc::cleanup();
return;
}
void
s1ap::delete_enb_ctx(int32_t assoc_id)
{
std::map<int32_t,uint16_t>::iterator it_assoc = m_sctp_to_enb_id.find(assoc_id);
uint16_t enb_id = it_assoc->second;
std::map<uint16_t,enb_ctx_t*>::iterator it_ctx = m_active_enbs.find(enb_id);
if(it_ctx == m_active_enbs.end() || it_assoc == m_sctp_to_enb_id.end())
{
m_s1ap_log->error("Could not find eNB to delete. Association: %d\n",assoc_id);
return;
}
m_s1ap_log->info("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
m_s1ap_log->console("Deleting eNB context. eNB Id: 0x%x\n", enb_id);
//Delete connected UEs ctx
delete_ues_in_enb(enb_id);
//Delete eNB
delete it_ctx->second;
m_active_enbs.erase(it_ctx);
m_sctp_to_enb_id.erase(it_assoc);
return;
}
void
s1ap::delete_ues_in_enb(uint16_t enb_id)
{
//delete UEs ctx
std::map<uint16_t,std::set<uint32_t> >::iterator ues_in_enb = m_enb_id_to_ue_ids.find(enb_id);
std::set<uint32_t>::iterator ue_id = ues_in_enb->second.begin();
while(ue_id != ues_in_enb->second.end() )
{
std::map<uint32_t, ue_ctx_t*>::iterator ue_ctx = m_active_ues.find(*ue_id);
m_s1ap_log->info("Deleting UE context. UE IMSI: %lu\n", ue_ctx->second->imsi);
m_s1ap_log->console("Deleting UE context. UE IMSI: %lu\n", ue_ctx->second->imsi);
delete ue_ctx->second; //delete UE context
m_active_ues.erase(ue_ctx); //remove from general MME map
ues_in_enb->second.erase(ue_id++); //erase from the eNB's UE set
}
}
int
s1ap::get_s1_mme()
{
return m_s1mme;
}
int
s1ap::enb_listen()
{
/*This function sets up the SCTP socket for eNBs to connect to*/
int sock_fd, err;
struct sockaddr_in s1mme_addr;
struct sctp_event_subscribe evnts;
m_s1ap_log->info("S1-MME Initializing\n");
sock_fd = socket (AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
if (sock_fd == -1){
m_s1ap_log->console("Could not create SCTP socket\n");
return -1;
}
//Sets the data_io_event to be able to use sendrecv_info
//Subscribes to the SCTP_SHUTDOWN event, to handle graceful shutdown
bzero (&evnts, sizeof (evnts)) ;
evnts.sctp_data_io_event = 1;
evnts.sctp_shutdown_event=1;
if(setsockopt(sock_fd, IPPROTO_SCTP, SCTP_EVENTS, &evnts, sizeof (evnts))){
m_s1ap_log->console("Subscribing to sctp_data_io_events failed\n");
return -1;
}
//S1-MME bind
bzero(&s1mme_addr, sizeof(s1mme_addr));
s1mme_addr.sin_family = AF_INET;
inet_pton(AF_INET, m_s1ap_args.mme_bind_addr.c_str(), &(s1mme_addr.sin_addr) );
s1mme_addr.sin_port = htons(S1MME_PORT);
err = bind(sock_fd, (struct sockaddr*) &s1mme_addr, sizeof (s1mme_addr));
if (err != 0){
m_s1ap_log->error("Error binding SCTP socket\n");
m_s1ap_log->console("Error binding SCTP socket\n");
return -1;
}
//Listen for connections
err = listen(sock_fd,SOMAXCONN);
if (err != 0){
m_s1ap_log->error("Error in SCTP socket listen\n");
m_s1ap_log->console("Error in SCTP socket listen\n");
return -1;
}
return sock_fd;
}
bool
s1ap::handle_s1ap_rx_pdu(srslte::byte_buffer_t *pdu, struct sctp_sndrcvinfo *enb_sri)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT rx_pdu;
if(liblte_s1ap_unpack_s1ap_pdu((LIBLTE_BYTE_MSG_STRUCT*)pdu, &rx_pdu) != LIBLTE_SUCCESS) {
m_s1ap_log->error("Failed to unpack received PDU\n");
return false;
}
switch(rx_pdu.choice_type) {
case LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE:
m_s1ap_log->info("Received initiating PDU\n");
return handle_initiating_message(&rx_pdu.choice.initiatingMessage, enb_sri);
break;
case LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME:
m_s1ap_log->info("Received Succeseful Outcome PDU\n");
return handle_successful_outcome(&rx_pdu.choice.successfulOutcome);
break;
case LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME:
m_s1ap_log->info("Received Unsucceseful Outcome PDU\n");
return true;//TODO handle_unsuccessfuloutcome(&rx_pdu.choice.unsuccessfulOutcome);
break;
default:
m_s1ap_log->error("Unhandled PDU type %d\n", rx_pdu.choice_type);
return false;
}
return true;
}
bool
s1ap::handle_initiating_message(LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri)
{
bool reply_flag = false;
srslte::byte_buffer_t * reply_buffer = m_pool->allocate();
switch(msg->choice_type) {
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_S1SETUPREQUEST:
m_s1ap_log->info("Received S1 Setup Request.\n");
m_s1ap_mngmt_proc->handle_s1_setup_request(&msg->choice.S1SetupRequest, enb_sri, reply_buffer, &reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALUEMESSAGE:
m_s1ap_log->info("Received Initial UE Message.\n");
m_s1ap_nas_transport->handle_initial_ue_message(&msg->choice.InitialUEMessage, enb_sri, reply_buffer, &reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UPLINKNASTRANSPORT:
m_s1ap_log->info("Received Uplink NAS Transport Message.\n");
m_s1ap_nas_transport->handle_uplink_nas_transport(&msg->choice.UplinkNASTransport, enb_sri, reply_buffer, &reply_flag);
break;
case LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_UECONTEXTRELEASEREQUEST:
m_s1ap_log->info("Received UE Context Release Request Message.\n");
m_s1ap_ctx_mngmt_proc->handle_ue_context_release_request(&msg->choice.UEContextReleaseRequest, enb_sri, reply_buffer, &reply_flag);
break;
default:
m_s1ap_log->error("Unhandled intiating message: %s\n", liblte_s1ap_initiatingmessage_choice_text[msg->choice_type]);
}
//Send Reply to eNB
if(reply_flag == true)
{
ssize_t n_sent = sctp_send(m_s1mme,reply_buffer->msg, reply_buffer->N_bytes, enb_sri, 0);
if(n_sent == -1)
{
m_s1ap_log->console("Failed to send S1 Setup Setup Reply\n");
m_pool->deallocate(reply_buffer);
return false;
}
}
m_pool->deallocate(reply_buffer);
return true;
}
bool
s1ap::handle_successful_outcome(LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *msg)
{
switch(msg->choice_type) {
case LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_INITIALCONTEXTSETUPRESPONSE:
m_s1ap_log->info("Received Initial Context Setup Response.\n");
return m_s1ap_ctx_mngmt_proc->handle_initial_context_setup_response(&msg->choice.InitialContextSetupResponse);
default:
m_s1ap_log->error("Unhandled successful outcome message: %s\n", liblte_s1ap_successfuloutcome_choice_text[msg->choice_type]);
}
return true;
}
bool
s1ap::delete_ue_ctx(ue_ctx_t *ue_ctx)
{
uint32_t mme_ue_s1ap_id = ue_ctx->mme_ue_s1ap_id;
std::map<uint32_t, ue_ctx_t*>::iterator ue_ctx_it = m_active_ues.find(mme_ue_s1ap_id);
if(ue_ctx_it == m_active_ues.end() )
{
m_s1ap_log->info("UE not found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
return false;
}
//Delete UE within eNB UE set
std::map<int32_t,uint16_t>::iterator it = m_sctp_to_enb_id.find(ue_ctx->enb_sri.sinfo_assoc_id);
if(it == m_sctp_to_enb_id.end() )
{
m_s1ap_log->error("Could not find eNB for this request.\n");
return false;
}
uint16_t enb_id = it->second;
std::map<uint16_t,std::set<uint32_t> >::iterator ue_set = m_enb_id_to_ue_ids.find(enb_id);
if(ue_set == m_enb_id_to_ue_ids.end())
{
m_s1ap_log->error("Could not find the eNB's UEs.\n");
return false;
}
ue_set->second.erase(mme_ue_s1ap_id);
//Delete UE context
delete ue_ctx;
m_active_ues.erase(ue_ctx_it);
m_s1ap_log->info("Deleted UE Context.\n");
return true;
}
enb_ctx_t*
s1ap::find_enb_ctx(uint16_t enb_id)
{
std::map<uint16_t,enb_ctx_t*>::iterator it = m_active_enbs.find(enb_id);
if(it == m_active_enbs.end())
{
return NULL;
}
else
{
return it->second;
}
}
void
s1ap::add_new_enb_ctx(const enb_ctx_t &enb_ctx, const struct sctp_sndrcvinfo *enb_sri)
{
m_s1ap_log->info("Adding new eNB context. eNB ID %d\n", enb_ctx.enb_id);
std::set<uint32_t> ue_set;
enb_ctx_t *enb_ptr = new enb_ctx_t;
memcpy(enb_ptr,&enb_ctx,sizeof(enb_ctx_t));
m_active_enbs.insert(std::pair<uint16_t,enb_ctx_t*>(enb_ptr->enb_id,enb_ptr));
m_sctp_to_enb_id.insert(std::pair<int32_t,uint16_t>(enb_sri->sinfo_assoc_id, enb_ptr->enb_id));
m_enb_id_to_ue_ids.insert(std::pair<uint16_t,std::set<uint32_t> >(enb_ptr->enb_id,ue_set));
return;
}
ue_ctx_t*
s1ap::find_ue_ctx(uint32_t mme_ue_s1ap_id)
{
std::map<uint32_t, ue_ctx_t*>::iterator it = m_active_ues.find(mme_ue_s1ap_id);
if(it == m_active_ues.end())
{
return NULL;
}
else
{
return it->second;
}
}
void
s1ap::add_new_ue_ctx(const ue_ctx_t &ue_ctx)
{
ue_ctx_t *ue_ptr = new ue_ctx_t;
memcpy(ue_ptr,&ue_ctx,sizeof(ue_ctx));
m_active_ues.insert(std::pair<uint32_t,ue_ctx_t*>(ue_ptr->mme_ue_s1ap_id,ue_ptr));
std::map<int32_t,uint16_t>::iterator it_enb = m_sctp_to_enb_id.find(ue_ptr->enb_sri.sinfo_assoc_id);
uint16_t enb_id = it_enb->second;
std::map<uint16_t,std::set<uint32_t> >::iterator it_ue_id = m_enb_id_to_ue_ids.find(enb_id);
if(it_ue_id==m_enb_id_to_ue_ids.end())
{
m_s1ap_log->error("Could not find eNB's UEs\n");
return;
}
it_ue_id->second.insert(ue_ptr->mme_ue_s1ap_id);
return;
}
uint32_t
s1ap::get_next_mme_ue_s1ap_id()
{
return m_next_mme_ue_s1ap_id++;
}
void
s1ap::activate_eps_bearer(uint32_t mme_s1ap_id, uint8_t ebi)
{
std::map<uint32_t,ue_ctx_t*>::iterator ue_ctx_it = m_active_ues.find(mme_s1ap_id);
if(ue_ctx_it == m_active_ues.end())
{
m_s1ap_log->error("Could not find UE context\n");
return;
}
ue_ctx_t * ue_ctx = ue_ctx_it->second;
if (ue_ctx->erabs_ctx[ebi].state != ERAB_CTX_SETUP)
{
m_s1ap_log->error("EPS Bearer could not be activated. MME S1AP Id %d, EPS Bearer id %d, state %d\n",mme_s1ap_id,ebi,ue_ctx->erabs_ctx[ebi].state);
m_s1ap_log->console("EPS Bearer could not be activated. MME S1AP Id %d, EPS Bearer id %d\n",mme_s1ap_id,ebi,ue_ctx->erabs_ctx[ebi].state);
return;
}
ue_ctx->erabs_ctx[ebi].state = ERAB_ACTIVE;
m_s1ap_log->info("Activated EPS Bearer\n");
return;
}
uint32_t
s1ap::allocate_m_tmsi(uint32_t mme_ue_s1ap_id)
{
//uint32_t m_tmsi = m_next_m_tmsi++;
//m_tmsi_to_s1ap_id.insert(std::pair<uint32_t,uint32_t>(m_tmsi,mme_ue_s1ap_id));
uint32_t m_tmsi = 0x0123;
return m_tmsi;
}
void
s1ap::print_enb_ctx_info(const std::string &prefix, const enb_ctx_t &enb_ctx)
{
std::string mnc_str, mcc_str;
if(enb_ctx.enb_name_present)
{
m_s1ap_log->console("%s - eNB Name: %s, eNB id: 0x%x\n",prefix.c_str(), enb_ctx.enb_name, enb_ctx.enb_id);
m_s1ap_log->info("%s - eNB Name: %s, eNB id: 0x%x\n", prefix.c_str(), enb_ctx.enb_name, enb_ctx.enb_id);
}
else
{
m_s1ap_log->console("%s - eNB Id 0x%x\n",prefix.c_str(), enb_ctx.enb_id);
m_s1ap_log->info("%s - eNB Id 0x%x\n", prefix.c_str(), enb_ctx.enb_id);
}
srslte::mcc_to_string(enb_ctx.mcc, &mcc_str);
srslte::mnc_to_string(enb_ctx.mnc, &mnc_str);
m_s1ap_log->info("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(), enb_ctx.plmn);
m_s1ap_log->console("%s - MCC:%s, MNC:%s, PLMN: %d\n", prefix.c_str(), mcc_str.c_str(), mnc_str.c_str(), enb_ctx.plmn);
for(int i=0;i<enb_ctx.nof_supported_ta;i++)
{
for(int j=0;i<enb_ctx.nof_supported_ta;i++)
{
m_s1ap_log->info("%s - TAC %d, B-PLMN %d\n",prefix.c_str(), enb_ctx.tac[i],enb_ctx.bplmns[i][j]);
m_s1ap_log->console("%s - TAC %d, B-PLMN %d\n",prefix.c_str(), enb_ctx.tac[i],enb_ctx.bplmns[i][j]);
}
}
m_s1ap_log->console("%s - Paging DRX %d\n",prefix.c_str(),enb_ctx.drx);
return;
}
} //namespace srsepc

@ -0,0 +1,302 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
//#include "srslte/upper/s1ap_common.h"
#include "srslte/common/bcd_helpers.h"
#include "mme/s1ap.h"
#include "mme/s1ap_ctx_mngmt_proc.h"
#include "srslte/common/liblte_security.h"
namespace srsepc{
s1ap_ctx_mngmt_proc* s1ap_ctx_mngmt_proc::m_instance = NULL;
boost::mutex s1ap_ctx_mngmt_proc_instance_mutex;
s1ap_ctx_mngmt_proc::s1ap_ctx_mngmt_proc()
{
}
s1ap_ctx_mngmt_proc::~s1ap_ctx_mngmt_proc()
{
}
s1ap_ctx_mngmt_proc*
s1ap_ctx_mngmt_proc::get_instance(void)
{
boost::mutex::scoped_lock lock(s1ap_ctx_mngmt_proc_instance_mutex);
if(NULL == m_instance) {
m_instance = new s1ap_ctx_mngmt_proc();
}
return(m_instance);
}
void
s1ap_ctx_mngmt_proc::cleanup(void)
{
boost::mutex::scoped_lock lock(s1ap_ctx_mngmt_proc_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
}
void
s1ap_ctx_mngmt_proc::init(void)
{
m_s1ap = s1ap::get_instance();
m_mme_gtpc = mme_gtpc::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1ap_args = m_s1ap->m_s1ap_args;
m_pool = srslte::byte_buffer_pool::get_instance();
m_s1ap_nas_transport = s1ap_nas_transport::get_instance();
}
bool
s1ap_ctx_mngmt_proc::send_initial_context_setup_request(uint32_t mme_ue_s1ap_id, struct srslte::gtpc_create_session_response *cs_resp, struct srslte::gtpc_f_teid_ie sgw_ctrl_fteid)
{
int s1mme = m_s1ap->get_s1_mme();
//Prepare reply PDU
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_INITIATINGMESSAGE;
LIBLTE_S1AP_INITIATINGMESSAGE_STRUCT *init = &pdu.choice.initiatingMessage;
init->procedureCode = LIBLTE_S1AP_PROC_ID_INITIALCONTEXTSETUP;
init->choice_type = LIBLTE_S1AP_INITIATINGMESSAGE_CHOICE_INITIALCONTEXTSETUPREQUEST;
LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPREQUEST_STRUCT *in_ctxt_req = &init->choice.InitialContextSetupRequest;
LIBLTE_S1AP_E_RABTOBESETUPITEMCTXTSUREQ_STRUCT *erab_ctxt = &in_ctxt_req->E_RABToBeSetupListCtxtSUReq.buffer[0]; //FIXME support more than one erab
srslte::byte_buffer_t *reply_buffer = m_pool->allocate();
m_s1ap_log->info("Preparing to send Initial Context Setup request\n");
//Find UE Context
ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx(mme_ue_s1ap_id);
if(ue_ctx == NULL)
{
m_s1ap_log->error("Could not find UE to send Setup Context Request. MME S1AP Id: %d", mme_ue_s1ap_id);
return false;
}
//Add MME and eNB S1AP Ids
in_ctxt_req->MME_UE_S1AP_ID.MME_UE_S1AP_ID = ue_ctx->mme_ue_s1ap_id;
in_ctxt_req->eNB_UE_S1AP_ID.ENB_UE_S1AP_ID = ue_ctx->enb_ue_s1ap_id;
//Set UE-AMBR
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateDL.BitRate=1000000000;//2^32-1
in_ctxt_req->uEaggregateMaximumBitrate.uEaggregateMaximumBitRateUL.BitRate=1000000000;//FIXME Get UE-AMBR from HSS
//Setup eRAB context
in_ctxt_req->E_RABToBeSetupListCtxtSUReq.len = 1;
erab_ctxt->e_RAB_ID.E_RAB_ID = cs_resp->eps_bearer_context_created.ebi;
//Setup E-RAB QoS parameters
erab_ctxt->e_RABlevelQoSParameters.qCI.QCI = 9;
erab_ctxt->e_RABlevelQoSParameters.allocationRetentionPriority.priorityLevel.PriorityLevel = 15 ;//Lowest
erab_ctxt->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionCapability = LIBLTE_S1AP_PRE_EMPTIONCAPABILITY_SHALL_NOT_TRIGGER_PRE_EMPTION;
erab_ctxt->e_RABlevelQoSParameters.allocationRetentionPriority.pre_emptionVulnerability = LIBLTE_S1AP_PRE_EMPTIONVULNERABILITY_PRE_EMPTABLE;
erab_ctxt->e_RABlevelQoSParameters.gbrQosInformation_present=false;
//Set E-RAB S-GW F-TEID
if (cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present == false){
m_s1ap_log->error("Did not receive S1-U TEID in create session response\n");
return false;
}
erab_ctxt->transportLayerAddress.n_bits = 32; //IPv4
uint32_t sgw_s1u_ip = htonl(cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4);
//uint32_t sgw_s1u_ip = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4;
uint8_t *tmp_ptr = erab_ctxt->transportLayerAddress.buffer;
liblte_value_2_bits(sgw_s1u_ip, &tmp_ptr, 32);//FIXME consider ipv6
uint32_t tmp_teid = cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.teid;
memcpy(erab_ctxt->gTP_TEID.buffer, &tmp_teid, sizeof(uint32_t));
//Set UE security capabilities and k_enb
bzero(in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer,sizeof(uint8_t)*16);
bzero(in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer,sizeof(uint8_t)*16);
for(int i = 0; i<3; i++)
{
if(ue_ctx->ue_network_cap.eea[i+1] == true)
{
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 1; //EEA supported
}
else
{
in_ctxt_req->UESecurityCapabilities.encryptionAlgorithms.buffer[i] = 0; //EEA not supported
}
if(ue_ctx->ue_network_cap.eia[i+1] == true)
{
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 1; //EEA supported
}
else
{
in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[i] = 0; //EEA not supported
}
// in_ctxt_req->UESecurityCapabilities.integrityProtectionAlgorithms.buffer[0] = 1; //EIA1
}
uint8_t key_enb[32];
liblte_security_generate_k_enb(ue_ctx->security_ctxt.k_asme, ue_ctx->security_ctxt.ul_nas_count, key_enb);
liblte_unpack(key_enb, 32, in_ctxt_req->SecurityKey.buffer);
m_s1ap_log->info("Generating KeNB with UL NAS COUNT: %d\n",ue_ctx->security_ctxt.ul_nas_count);
//Set Attach accepted and activat default bearer NAS messages
if(cs_resp->paa_present != true)
{
m_s1ap_log->error("PAA not present\n");
return false;
}
if(cs_resp->paa.pdn_type != srslte::GTPC_PDN_TYPE_IPV4)
{
m_s1ap_log->error("IPv6 not supported yet\n");
return false;
}
srslte::byte_buffer_t *nas_buffer = m_pool->allocate();
m_s1ap_nas_transport->pack_attach_accept(ue_ctx, erab_ctxt, &cs_resp->paa, nas_buffer);
LIBLTE_ERROR_ENUM err = liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)reply_buffer);
if(err != LIBLTE_SUCCESS)
{
m_s1ap_log->error("Could not pack Initial Context Setup Request Message\n");
return false;
}
//Send Reply to eNB
ssize_t n_sent = sctp_send(s1mme,reply_buffer->msg, reply_buffer->N_bytes, &ue_ctx->enb_sri, 0);
if(n_sent == -1)
{
m_s1ap_log->error("Failed to send Initial Context Setup Request\n");
return false;
}
//Change E-RAB state to Context Setup Requested and save S-GW control F-TEID
ue_ctx->erabs_ctx[erab_ctxt->e_RAB_ID.E_RAB_ID].state = ERAB_CTX_REQUESTED;
ue_ctx->erabs_ctx[erab_ctxt->e_RAB_ID.E_RAB_ID].sgw_ctrl_fteid.teid = sgw_ctrl_fteid.teid;
ue_ctx->erabs_ctx[erab_ctxt->e_RAB_ID.E_RAB_ID].sgw_ctrl_fteid.ipv4 = sgw_ctrl_fteid.ipv4;
struct in_addr addr;
addr.s_addr = htonl(sgw_s1u_ip);
m_s1ap_log->info("Sent Intial Context Setup Request. E-RAB id %d \n",erab_ctxt->e_RAB_ID.E_RAB_ID);
m_s1ap_log->info("Initial Context -- S1-U TEID 0x%x. IP %s \n", tmp_teid,inet_ntoa(addr));
m_s1ap_log->console("Sent Intial Context Setup Request, E-RAB id %d\n",erab_ctxt->e_RAB_ID.E_RAB_ID);
m_s1ap_log->console("Initial Context -- S1-U TEID 0x%x. IP %s \n", tmp_teid,inet_ntoa(addr));
m_pool->deallocate(reply_buffer);
m_pool->deallocate(nas_buffer);
return true;
}
bool
s1ap_ctx_mngmt_proc::handle_initial_context_setup_response(LIBLTE_S1AP_MESSAGE_INITIALCONTEXTSETUPRESPONSE_STRUCT *in_ctxt_resp)
{
uint32_t mme_ue_s1ap_id = in_ctxt_resp->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx(mme_ue_s1ap_id);
if (ue_ctx == NULL)
{
m_s1ap_log->error("Could not find UE's context in active UE's map\n");
return false;
}
//Setup E-RABs
for(uint32_t i=0; i<in_ctxt_resp->E_RABSetupListCtxtSURes.len;i++)
{
uint8_t erab_id = in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].e_RAB_ID.E_RAB_ID;
erab_ctx_t *erab_ctx = &ue_ctx->erabs_ctx[erab_id];
if (erab_ctx->state != ERAB_CTX_REQUESTED)
{
m_s1ap_log->error("E-RAB requested was not active %d\n",erab_id);
return false;
}
//Mark E-RAB with context setup
erab_ctx->state = ERAB_CTX_SETUP;
//Set the GTP information
uint8_t *bit_ptr = in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].transportLayerAddress.buffer;
erab_ctx->enb_fteid.ipv4 = htonl(liblte_bits_2_value(&bit_ptr,32));
memcpy(&erab_ctx->enb_fteid.teid, in_ctxt_resp->E_RABSetupListCtxtSURes.buffer[i].gTP_TEID.buffer, 4);
erab_ctx->enb_fteid.teid = ntohl(erab_ctx->enb_fteid.teid);
char enb_addr_str[INET_ADDRSTRLEN+1];
const char *err = inet_ntop(AF_INET, &erab_ctx->enb_fteid.ipv4,enb_addr_str,sizeof(enb_addr_str));
if(err == NULL)
{
m_s1ap_log->error("Error converting IP to string\n");
}
m_s1ap_log->info("E-RAB Context Setup. E-RAB id %d\n",erab_ctx->erab_id);
m_s1ap_log->info("E-RAB Context -- eNB TEID 0x%x, eNB Address %s\n", erab_ctx->enb_fteid.teid, enb_addr_str);
m_s1ap_log->console("E-RAB Context Setup. E-RAB id %d\n",erab_ctx->erab_id);
m_s1ap_log->console("E-RAB Context -- eNB TEID 0x%x; eNB GTP-U Address %s\n", erab_ctx->enb_fteid.teid, enb_addr_str);
}
return true;
}
bool
s1ap_ctx_mngmt_proc::handle_ue_context_release_request(LIBLTE_S1AP_MESSAGE_UECONTEXTRELEASEREQUEST_STRUCT *ue_rel, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag)
{
uint32_t mme_ue_s1ap_id = ue_rel->MME_UE_S1AP_ID.MME_UE_S1AP_ID;
m_s1ap_log->info("Received UE Context Release Request. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
m_s1ap_log->console("Received UE Context Release Request. MME-UE S1AP Id %d\n", mme_ue_s1ap_id);
ue_ctx_t *ue_ctx = m_s1ap->find_ue_ctx(mme_ue_s1ap_id);
if(ue_ctx == NULL)
{
m_s1ap_log->info("UE not found. MME-UE S1AP Id: %d\n", mme_ue_s1ap_id);
return false;
}
//Delete any context at the SPGW
bool active = false;
for(int i=0;i<MAX_ERABS_PER_UE;i++)
{
if(ue_ctx->erabs_ctx[i].state != ERAB_DEACTIVATED)
{
active = true;
//ue_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
break;
}
}
if(active == true)
{
//There are active E-RABs, send delete session request
m_mme_gtpc->send_delete_session_request(ue_ctx);
}
//m_s1ap->delete_ue_ctx(ue_ctx);
for(int i=0;i<MAX_ERABS_PER_UE;i++)
{
ue_ctx->erabs_ctx[i].state = ERAB_DEACTIVATED;
}
//Delete UE context
m_s1ap_log->info("Deleted UE Context.\n");
return true;
}
} //namespace srsepc

@ -0,0 +1,266 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
//#include "srslte/upper/s1ap_common.h"
#include "srslte/common/bcd_helpers.h"
#include "mme/s1ap.h"
#include "mme/s1ap_mngmt_proc.h"
namespace srsepc{
s1ap_mngmt_proc* s1ap_mngmt_proc::m_instance = NULL;
boost::mutex s1ap_mngmt_proc_instance_mutex;
s1ap_mngmt_proc::s1ap_mngmt_proc()
{
}
s1ap_mngmt_proc::~s1ap_mngmt_proc()
{
}
s1ap_mngmt_proc*
s1ap_mngmt_proc::get_instance(void)
{
boost::mutex::scoped_lock lock(s1ap_mngmt_proc_instance_mutex);
if(NULL == m_instance) {
m_instance = new s1ap_mngmt_proc();
}
return(m_instance);
}
void
s1ap_mngmt_proc::cleanup(void)
{
boost::mutex::scoped_lock lock(s1ap_mngmt_proc_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
}
void
s1ap_mngmt_proc::init(void)
{
m_s1ap = s1ap::get_instance();
m_s1ap_log = m_s1ap->m_s1ap_log;
m_s1mme = m_s1ap->get_s1_mme();
m_s1ap_args = m_s1ap->m_s1ap_args;
}
bool
s1ap_mngmt_proc::handle_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, struct sctp_sndrcvinfo *enb_sri, srslte::byte_buffer_t *reply_buffer, bool *reply_flag)
{
enb_ctx_t enb_ctx;
LIBLTE_S1AP_S1AP_PDU_STRUCT reply_pdu;
if(!unpack_s1_setup_request(msg, &enb_ctx))
{
m_s1ap_log->error("Malformed S1 Setup Request\n");
return false;
}
//Log S1 Setup Request Info
m_s1ap_log->console("Received S1 Setup Request.\n");
m_s1ap->print_enb_ctx_info(std::string("S1 Setup Request"),enb_ctx);
//Check matching PLMNs
if(enb_ctx.plmn!=m_s1ap->get_plmn()){
m_s1ap_log->console("Sending S1 Setup Failure - Unkown PLMN\n");
m_s1ap_log->warning("Sending S1 Setup Failure - Unkown PLMN\n");
pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_UNKNOWN_PLMN,reply_buffer);
}
else{
enb_ctx_t *enb_ptr = m_s1ap->find_enb_ctx(enb_ctx.enb_id);
if(enb_ptr != NULL)
{
//eNB already registered
//TODO replace enb_ctx
}
else
{
//new eNB
m_s1ap->add_new_enb_ctx(enb_ctx,enb_sri);
}
pack_s1_setup_response(m_s1ap_args, reply_buffer);
m_s1ap_log->console("Sending S1 Setup Response\n");
m_s1ap_log->info("Sending S1 Setup Response\n");
}
*reply_flag = true;
return true;
}
/*
* Packing/Unpacking helper functions.
*/
bool
s1ap_mngmt_proc::unpack_s1_setup_request(LIBLTE_S1AP_MESSAGE_S1SETUPREQUEST_STRUCT *msg, enb_ctx_t* enb_ctx)
{
uint8_t enb_id_bits[32];
uint32_t plmn = 0;
uint16_t tac, bplmn;
uint32_t tmp32=0;
//eNB Name
enb_ctx->enb_name_present=msg->eNBname_present;
if(msg->eNBname_present)
{
bzero(enb_ctx->enb_name,sizeof(enb_ctx->enb_name));
memcpy(enb_ctx->enb_name,&msg->eNBname.buffer,msg->eNBname.n_octets);
}
//eNB Id
bzero(enb_id_bits,sizeof(enb_id_bits));
memcpy(&enb_id_bits[32-LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN], msg->Global_ENB_ID.eNB_ID.choice.macroENB_ID.buffer, LIBLTE_S1AP_MACROENB_ID_BIT_STRING_LEN);
liblte_pack(enb_id_bits, 32, (uint8_t*) &tmp32);
enb_ctx->enb_id=ntohl(tmp32);
//PLMN Id
((uint8_t*)&plmn)[1] = msg->Global_ENB_ID.pLMNidentity.buffer[0];
((uint8_t*)&plmn)[2] = msg->Global_ENB_ID.pLMNidentity.buffer[1];
((uint8_t*)&plmn)[3] = msg->Global_ENB_ID.pLMNidentity.buffer[2];
enb_ctx->plmn = ntohl(plmn);
srslte::s1ap_plmn_to_mccmnc(enb_ctx->plmn, &enb_ctx->mcc, &enb_ctx->mnc);
//SupportedTAs
enb_ctx->nof_supported_ta=msg->SupportedTAs.len;
for(uint16_t i=0; i<msg->SupportedTAs.len; i++)
{
//TAC
((uint8_t*)&enb_ctx->tac[i])[0] = msg->SupportedTAs.buffer[i].tAC.buffer[0];
((uint8_t*)&enb_ctx->tac[i])[1] = msg->SupportedTAs.buffer[i].tAC.buffer[1];
enb_ctx->tac[i]=ntohs(enb_ctx->tac[i]);
enb_ctx->nof_supported_bplmns[i]=msg->SupportedTAs.buffer[i].broadcastPLMNs.len;
for (uint16_t j=0; j<msg->SupportedTAs.buffer[i].broadcastPLMNs.len; j++)
{
//BPLMNs
((uint8_t*)&enb_ctx->bplmns[i][j])[1] = msg->SupportedTAs.buffer[i].broadcastPLMNs.buffer[j].buffer[0];
((uint8_t*)&enb_ctx->bplmns[i][j])[2] = msg->SupportedTAs.buffer[i].broadcastPLMNs.buffer[j].buffer[1];
((uint8_t*)&enb_ctx->bplmns[i][j])[3] = msg->SupportedTAs.buffer[i].broadcastPLMNs.buffer[j].buffer[2];
enb_ctx->bplmns[i][j] = ntohl(enb_ctx->bplmns[i][j]);
}
}
//Default Paging DRX
enb_ctx->drx = msg->DefaultPagingDRX.e;
return true;
}
bool
s1ap_mngmt_proc::pack_s1_setup_failure(LIBLTE_S1AP_CAUSEMISC_ENUM cause, srslte::byte_buffer_t *msg)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_UNSUCCESSFULOUTCOME;
LIBLTE_S1AP_UNSUCCESSFULOUTCOME_STRUCT *unsucc = &pdu.choice.unsuccessfulOutcome;
unsucc->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP;
unsucc->criticality = LIBLTE_S1AP_CRITICALITY_REJECT;
unsucc->choice_type = LIBLTE_S1AP_UNSUCCESSFULOUTCOME_CHOICE_S1SETUPFAILURE;
LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT* s1_fail=(LIBLTE_S1AP_MESSAGE_S1SETUPFAILURE_STRUCT*)&unsucc->choice;
s1_fail->TimeToWait_present=false;
s1_fail->CriticalityDiagnostics_present=false;
s1_fail->Cause.ext=false;
s1_fail->Cause.choice_type = LIBLTE_S1AP_CAUSE_CHOICE_MISC;
s1_fail->Cause.choice.misc.ext=false;
s1_fail->Cause.choice.misc.e=cause;
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
return true;
}
bool
s1ap_mngmt_proc::pack_s1_setup_response(s1ap_args_t s1ap_args, srslte::byte_buffer_t *msg)
{
LIBLTE_S1AP_S1AP_PDU_STRUCT pdu;
bzero(&pdu, sizeof(LIBLTE_S1AP_S1AP_PDU_STRUCT));
pdu.choice_type = LIBLTE_S1AP_S1AP_PDU_CHOICE_SUCCESSFULOUTCOME;
LIBLTE_S1AP_SUCCESSFULOUTCOME_STRUCT *succ = &pdu.choice.successfulOutcome;
succ->procedureCode = LIBLTE_S1AP_PROC_ID_S1SETUP;
succ->criticality = LIBLTE_S1AP_CRITICALITY_IGNORE;
succ->choice_type = LIBLTE_S1AP_SUCCESSFULOUTCOME_CHOICE_S1SETUPRESPONSE;
LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT* s1_resp=(LIBLTE_S1AP_MESSAGE_S1SETUPRESPONSE_STRUCT*)&succ->choice;
s1_resp->ext=false;
//MME Name
s1_resp->MMEname_present=true;
s1_resp->MMEname.ext=false;
s1_resp->MMEname.n_octets=s1ap_args.mme_name.length();
memcpy(s1_resp->MMEname.buffer,s1ap_args.mme_name.c_str(),s1ap_args.mme_name.length());
//Served GUMEIs
s1_resp->ServedGUMMEIs.len=1;//TODO Only one served GUMMEI supported
LIBLTE_S1AP_SERVEDGUMMEISITEM_STRUCT *serv_gummei = &s1_resp->ServedGUMMEIs.buffer[0];
serv_gummei->ext=false;
//serv_gummei->iE_Extensions=false;
uint32_t plmn=0;
srslte::s1ap_mccmnc_to_plmn(s1ap_args.mcc, s1ap_args.mnc, &plmn);
plmn=htonl(plmn);
serv_gummei->servedPLMNs.len = 1; //Only one PLMN supported
serv_gummei->servedPLMNs.buffer[0].buffer[0]=((uint8_t*)&plmn)[1];
serv_gummei->servedPLMNs.buffer[0].buffer[1]=((uint8_t*)&plmn)[2];
serv_gummei->servedPLMNs.buffer[0].buffer[2]=((uint8_t*)&plmn)[3];
serv_gummei->servedGroupIDs.len=1; //LIBLTE_S1AP_SERVEDGROUPIDS_STRUCT
uint16_t tmp=htons(s1ap_args.mme_group);
serv_gummei->servedGroupIDs.buffer[0].buffer[0]=((uint8_t*)&tmp)[0];
serv_gummei->servedGroupIDs.buffer[0].buffer[1]=((uint8_t*)&tmp)[1];
serv_gummei->servedMMECs.len=1; //Only one MMEC served
serv_gummei->servedMMECs.buffer[0].buffer[0]=s1ap_args.mme_code;
//Relative MME Capacity
s1_resp->RelativeMMECapacity.RelativeMMECapacity=255;
//Relay Unsupported
s1_resp->MMERelaySupportIndicator_present=false;
liblte_s1ap_pack_s1ap_pdu(&pdu, (LIBLTE_BYTE_MSG_STRUCT*)msg);
return true;
}
} //namespace srsepc

File diff suppressed because it is too large Load Diff

@ -0,0 +1,23 @@
#
# Copyright 2013-2017 Software Radio Systems Limited
#
# This file is part of srsLTE
#
# srsLTE is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# srsLTE is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# A copy of the GNU Affero General Public License can be found in
# the LICENSE file in the top-level directory of this distribution
# and at http://www.gnu.org/licenses/.
#
file(GLOB SOURCES "*.cc")
add_library(srsepc_sgw STATIC ${SOURCES})
install(TARGETS srsepc_sgw DESTINATION ${LIBRARY_DIR})

@ -0,0 +1,572 @@
/**
*
* \section COPYRIGHT
*
* Copyright 2013-2017 Software Radio Systems Limited
*
* \section LICENSE
*
* This file is part of srsLTE.
*
* srsLTE is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of
* the License, or (at your option) any later version.
*
* srsLTE is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* A copy of the GNU Affero General Public License can be found in
* the LICENSE file in the top-level directory of this distribution
* and at http://www.gnu.org/licenses/.
*
*/
#include <iostream>
#include <algorithm>
#include <boost/thread/mutex.hpp>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/ip.h>
#include "spgw/spgw.h"
#include "mme/mme_gtpc.h"
#include "srslte/upper/gtpu.h"
namespace srsepc{
spgw* spgw::m_instance = NULL;
boost::mutex spgw_instance_mutex;
const uint16_t SPGW_BUFFER_SIZE = 2500;
spgw::spgw():
m_running(false),
m_sgi_up(false),
m_s1u_up(false),
m_next_ctrl_teid(1),
m_next_user_teid(1)
{
return;
}
spgw::~spgw()
{
return;
}
spgw*
spgw::get_instance(void)
{
boost::mutex::scoped_lock lock(spgw_instance_mutex);
if(NULL == m_instance) {
m_instance = new spgw();
}
return(m_instance);
}
void
spgw::cleanup(void)
{
boost::mutex::scoped_lock lock(spgw_instance_mutex);
if(NULL != m_instance) {
delete m_instance;
m_instance = NULL;
}
}
int
spgw::init(spgw_args_t* args, srslte::log_filter *spgw_log)
{
srslte::error_t err;
m_pool = srslte::byte_buffer_pool::get_instance();
//Init log
m_spgw_log = spgw_log;
m_mme_gtpc = mme_gtpc::get_instance();
//Init SGi interface
err = init_sgi_if(args);
if (err != srslte::ERROR_NONE)
{
m_spgw_log->console("Could not initialize the SGi interface.\n");
return -1;
}
//Init S1-U
err = init_s1u(args);
if (err != srslte::ERROR_NONE)
{
m_spgw_log->console("Could not initialize the S1-U interface.\n");
return -1;
}
//Initialize UE ip pool
err = init_ue_ip(args);
if (err != srslte::ERROR_NONE)
{
m_spgw_log->console("Could not initialize the S1-U interface.\n");
return -1;
}
//Init mutex
pthread_mutex_init(&m_mutex,NULL);
m_spgw_log->info("SP-GW Initialized.\n");
m_spgw_log->console("SP-GW Initialized.\n");
return 0;
}
void
spgw::stop()
{
if(m_running)
{
m_running = false;
thread_cancel();
wait_thread_finish();
//Clean up SGi interface
if(m_sgi_up)
{
close(m_sgi_if);
close(m_sgi_sock);
}
//Clean up S1-U socket
if(m_s1u_up)
{
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())
{
m_spgw_log->info("Deleting SP-GW Tunnel. IMSI: %lu\n", it->second->imsi);
m_spgw_log->console("Deleting SP-GW Tunnel. IMSI: %lu\n", it->second->imsi);
delete it->second;
m_teid_to_tunnel_ctx.erase(it++);
}
return;
}
srslte::error_t
spgw::init_sgi_if(spgw_args_t *args)
{
char dev[IFNAMSIZ] = "srs_spgw_sgi";
struct ifreq ifr;
if(m_sgi_up)
{
return(srslte::ERROR_ALREADY_STARTED);
}
// Construct the TUN device
m_sgi_if = open("/dev/net/tun", O_RDWR);
m_spgw_log->info("TUN file descriptor = %d\n", m_sgi_if);
if(m_sgi_if < 0)
{
m_spgw_log->error("Failed to open TUN device: %s\n", strerror(errno));
return(srslte::ERROR_CANT_START);
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
strncpy(ifr.ifr_ifrn.ifrn_name, dev, IFNAMSIZ);
if(ioctl(m_sgi_if, TUNSETIFF, &ifr) < 0)
{
m_spgw_log->error("Failed to set TUN device name: %s\n", strerror(errno));
close(m_sgi_if);
return(srslte::ERROR_CANT_START);
}
// Bring up the interface
m_sgi_sock = socket(AF_INET, SOCK_DGRAM, 0);
if(ioctl(m_sgi_sock, SIOCGIFFLAGS, &ifr) < 0)
{
m_spgw_log->error("Failed to bring up socket: %s\n", strerror(errno));
close(m_sgi_if);
return(srslte::ERROR_CANT_START);
}
ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
if(ioctl(m_sgi_sock, SIOCSIFFLAGS, &ifr) < 0)
{
m_spgw_log->error("Failed to set socket flags: %s\n", strerror(errno));
close(m_sgi_if);
return(srslte::ERROR_CANT_START);
}
//Set IP of the interface
struct sockaddr_in *addr = (struct sockaddr_in*)&ifr.ifr_addr;
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = inet_addr(args->sgi_if_addr.c_str());
addr->sin_port = 0;
if (ioctl(m_sgi_sock, SIOCSIFADDR, &ifr) < 0) {
m_spgw_log->error("Failed to set TUN interface IP. Address: %s, Error: %s\n", args->sgi_if_addr.c_str(), strerror(errno));
close(m_sgi_if);
close(m_sgi_sock);
return srslte::ERROR_CANT_START;
}
ifr.ifr_netmask.sa_family = AF_INET;
((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr = inet_addr("255.255.255.0");
if (ioctl(m_sgi_sock, SIOCSIFNETMASK, &ifr) < 0) {
m_spgw_log->error("Failed to set TUN interface Netmask. Error: %s\n", strerror(errno));
close(m_sgi_if);
close(m_sgi_sock);
return srslte::ERROR_CANT_START;
}
m_sgi_up = true;
return(srslte::ERROR_NONE);
}
srslte::error_t
spgw::init_s1u(spgw_args_t *args)
{
//Open S1-U socket
m_s1u = socket(AF_INET,SOCK_DGRAM,0);
if (m_s1u == -1)
{
m_spgw_log->error("Failed to open socket: %s\n", strerror(errno));
return srslte::ERROR_CANT_START;
}
m_s1u_up = true;
//Bind the socket
m_s1u_addr.sin_family = AF_INET;
m_s1u_addr.sin_addr.s_addr=inet_addr(args->gtpu_bind_addr.c_str());
m_s1u_addr.sin_port=htons(GTPU_RX_PORT);
if (bind(m_s1u,(struct sockaddr *)&m_s1u_addr,sizeof(struct sockaddr_in))) {
m_spgw_log->error("Failed to bind socket: %s\n", strerror(errno));
return srslte::ERROR_CANT_START;
}
m_spgw_log->info("S1-U socket = %d\n", m_s1u);
m_spgw_log->info("S1-U IP = %s, Port = %d \n", inet_ntoa(m_s1u_addr.sin_addr),ntohs(m_s1u_addr.sin_port));
return srslte::ERROR_NONE;
}
srslte::error_t
spgw::init_ue_ip(spgw_args_t *args)
{
m_h_next_ue_ip = ntohl(inet_addr(args->sgi_if_addr.c_str()));
return srslte::ERROR_NONE;
}
void
spgw::run_thread()
{
//Mark the thread as running
m_running=true;
srslte::byte_buffer_t *msg;
msg = m_pool->allocate();
struct sockaddr src_addr;
socklen_t addrlen;
struct iphdr *ip_pkt;
int sgi = m_sgi_if;
fd_set set;
//struct timeval to;
int max_fd = std::max(m_s1u,sgi);
while (m_running)
{
msg->reset();
FD_ZERO(&set);
FD_SET(m_s1u, &set);
FD_SET(sgi, &set);
//m_spgw_log->info("Waiting for S1-U or SGi packets.\n");
int n = select(max_fd+1, &set, NULL, NULL, NULL);
if (n == -1)
{
m_spgw_log->error("Error from select\n");
}
else if (n)
{
//m_spgw_log->info("Data is available now.\n");
if (FD_ISSET(m_s1u, &set))
{
msg->N_bytes = recvfrom(m_s1u, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES, 0, &src_addr, &addrlen );
//m_spgw_log->console("Received PDU from S1-U. Bytes %d\n", msg->N_bytes);
//m_spgw_log->debug("Received PDU from S1-U. Bytes %d\n", msg->N_bytes);
handle_s1u_pdu(msg);
}
if (FD_ISSET(m_sgi_if, &set))
{
msg->N_bytes = read(sgi, msg->msg, SRSLTE_MAX_BUFFER_SIZE_BYTES);
//m_spgw_log->console("Received PDU from SGi. Bytes %d\n", msg->N_bytes);
//m_spgw_log->debug("Received PDU from SGi. Bytes %d\n", msg->N_bytes);
handle_sgi_pdu(msg);
}
}
else
{
m_spgw_log->debug("No data from select.\n");
}
}
m_pool->deallocate(msg);
return;
}
void
spgw::handle_sgi_pdu(srslte::byte_buffer_t *msg)
{
uint8_t version=0;
uint32_t dest_ip;
struct in_addr dest_addr;
std::map<uint32_t,srslte::gtpc_f_teid_ie>::iterator gtp_fteid_it;
bool ip_found = false;
srslte::gtpc_f_teid_ie enb_fteid;
version = msg->msg[0]>>4;
((uint8_t*)&dest_ip)[0] = msg->msg[16];
((uint8_t*)&dest_ip)[1] = msg->msg[17];
((uint8_t*)&dest_ip)[2] = msg->msg[18];
((uint8_t*)&dest_ip)[3] = msg->msg[19];
dest_addr.s_addr = dest_ip;
//m_spgw_log->console("IP version: %d\n", version);
//m_spgw_log->console("Received packet to IP: %s\n", inet_ntoa(dest_addr));
pthread_mutex_lock(&m_mutex);
gtp_fteid_it = m_ip_to_teid.find(dest_ip);
if(gtp_fteid_it != m_ip_to_teid.end())
{
ip_found = true;
enb_fteid = gtp_fteid_it->second;
}
pthread_mutex_unlock(&m_mutex);
if(ip_found == false)
{
//m_spgw_log->console("IP Packet is not for any UE\n");
return;
}
struct sockaddr_in enb_addr;
enb_addr.sin_family = AF_INET;
enb_addr.sin_port = htons(GTPU_RX_PORT);
enb_addr.sin_addr.s_addr = enb_fteid.ipv4;
//m_spgw_log->console("UE F-TEID found, TEID 0x%x, eNB IP %s\n", enb_fteid.teid, inet_ntoa(enb_addr.sin_addr));
//Setup GTP-U header
srslte::gtpu_header_t header;
header.flags = 0x30;
header.message_type = 0xFF;
header.length = msg->N_bytes;
header.teid = enb_fteid.teid;
//Write header into packet
if(!srslte::gtpu_write_header(&header, msg))
{
m_spgw_log->console("Error writing GTP-U header on PDU\n");
}
//Send packet to destination
int n = sendto(m_s1u,msg->msg,msg->N_bytes,0,(struct sockaddr*) &enb_addr,sizeof(enb_addr));
if(n<0)
{
m_spgw_log->error("Error sending packet to eNB\n");
return;
}
//m_spgw_log->console("Sent packet to %s:%d. Bytes=%d/%d\n",inet_ntoa(enb_addr.sin_addr), GTPU_RX_PORT,n,msg->N_bytes);
return;
}
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);
srslte::gtpu_header_t header;
srslte::gtpu_read_header(msg, &header);
//m_spgw_log->console("TEID 0x%x. Bytes=%d\n", header.teid, msg->N_bytes);
int n = write(m_sgi_if, msg->msg, msg->N_bytes);
if(n<0)
{
m_spgw_log->error("Could not write to TUN interface.\n",n);
}
else
{
//m_spgw_log->console("Forwarded packet to TUN interface. Bytes= %d/%d\n", n, msg->N_bytes);
}
return;
}
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
}
void
spgw::handle_create_session_request(struct srslte::gtpc_create_session_request *cs_req, struct srslte::gtpc_pdu *cs_resp_pdu)
{
srslte::gtpc_header *header = &cs_resp_pdu->header;
srslte::gtpc_create_session_response *cs_resp = &cs_resp_pdu->choice.create_session_response;
m_spgw_log->info("Received Create Session Request\n");
//Setup uplink control TEID
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();
uint8_t default_bearer_id = 5;
//Save the UE IP to User TEID map
spgw_tunnel_ctx_t *tunnel_ctx = new 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));
//Create session response message
//Setup GTP-C header
header->piggyback = false;
header->teid_present = true;
header->teid = cs_req->sender_f_teid.teid; //Send create session requesponse to the CS Request TEID
header->type = srslte::GTPC_MSG_TYPE_CREATE_SESSION_RESPONSE;
//Initialize to zero
bzero(cs_resp,sizeof(struct srslte::gtpc_create_session_response));
//Setup Cause
cs_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
//Setup sender F-TEID (ctrl)
cs_resp->sender_f_teid.ipv4_present = true;
cs_resp->sender_f_teid.teid = spgw_uplink_ctrl_teid;
cs_resp->sender_f_teid.ipv4 = 0;//FIXME This is not relevant, as the GTP-C is not transmitted over sockets yet.
//Bearer context created
cs_resp->eps_bearer_context_created.ebi = default_bearer_id;
cs_resp->eps_bearer_context_created.cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid_present=true;
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.teid = spgw_uplink_user_teid;
cs_resp->eps_bearer_context_created.s1_u_sgw_f_teid.ipv4 = m_s1u_addr.sin_addr.s_addr;
//Fill in the PAA
cs_resp->paa_present = true;
cs_resp->paa.pdn_type = srslte::GTPC_PDN_TYPE_IPV4;
cs_resp->paa.ipv4_present = true;
cs_resp->paa.ipv4 = ue_ip;
m_spgw_log->info("Sending Create Session Response\n");
m_mme_gtpc->handle_create_session_response(cs_resp_pdu);
return;
}
void
spgw::handle_modify_bearer_request(struct srslte::gtpc_pdu *mb_req_pdu, struct srslte::gtpc_pdu *mb_resp_pdu)
{
m_spgw_log->info("Received Modified Bearer Request\n");
//Get control tunnel info from mb_req PDU
uint32_t ctrl_teid = mb_req_pdu->header.teid;
std::map<uint32_t,spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
if(tunnel_it == m_teid_to_tunnel_ctx.end())
{
m_spgw_log->warning("Could not find TEID %d to modify\n",ctrl_teid);
return;
}
spgw_tunnel_ctx_t *tunnel_ctx = tunnel_it->second;
//Store user DW link TEID
srslte::gtpc_modify_bearer_request *mb_req = &mb_req_pdu->choice.modify_bearer_request;
tunnel_ctx->dw_user_fteid.teid = mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.teid;
tunnel_ctx->dw_user_fteid.ipv4 = mb_req->eps_bearer_context_to_modify.s1_u_enb_f_teid.ipv4;
//Set up actual tunnel
m_spgw_log->info("Setting Up GTP-U tunnel. Tunnel info: \n");
struct in_addr addr;
addr.s_addr = tunnel_ctx->ue_ipv4;
m_spgw_log->info("IMSI: %lu, UE IP, %s \n",tunnel_ctx->imsi, inet_ntoa(addr));
m_spgw_log->info("S-GW Rx Ctrl TEID 0x%x, MME Rx Ctrl TEID 0x%x\n", tunnel_ctx->up_ctrl_fteid.teid, tunnel_ctx->dw_ctrl_fteid.teid);
m_spgw_log->info("S-GW Rx Ctrl IP (NA), MME Rx Ctrl IP (NA)\n");
struct in_addr addr2;
addr2.s_addr = tunnel_ctx->up_user_fteid.ipv4;
m_spgw_log->info("S-GW Rx User TEID 0x%x, S-GW Rx User IP %s\n", tunnel_ctx->up_user_fteid.teid, inet_ntoa(addr2));
struct in_addr addr3;
addr3.s_addr = tunnel_ctx->dw_user_fteid.ipv4;
m_spgw_log->info("eNB Rx User TEID 0x%x, eNB Rx User IP %s\n", tunnel_ctx->dw_user_fteid.teid, inet_ntoa(addr3));
//Setup IP to F-TEID map
pthread_mutex_lock(&m_mutex);
m_ip_to_teid.insert(std::pair<uint32_t,srslte::gtpc_f_teid_ie>(tunnel_ctx->ue_ipv4, tunnel_ctx->dw_user_fteid));
pthread_mutex_unlock(&m_mutex);
//Setting up Modify bearer response PDU
//Header
srslte::gtpc_header *header = &mb_resp_pdu->header;
header->piggyback = false;
header->teid_present = true;
header->teid = tunnel_ctx->dw_ctrl_fteid.teid; //
header->type = srslte::GTPC_MSG_TYPE_MODIFY_BEARER_RESPONSE;
//PDU
srslte::gtpc_modify_bearer_response *mb_resp = &mb_resp_pdu->choice.modify_bearer_response;
mb_resp->cause.cause_value = srslte::GTPC_CAUSE_VALUE_REQUEST_ACCEPTED;
mb_resp->eps_bearer_context_modified.ebi = tunnel_ctx->ebi;
//printf("%d %d\n",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;
}
void
spgw::handle_delete_session_request(struct srslte::gtpc_pdu *del_req_pdu, struct srslte::gtpc_pdu *del_resp_pdu)
{
//Find tunel ctxt
uint32_t ctrl_teid = del_req_pdu->header.teid;
std::map<uint32_t,spgw_tunnel_ctx_t*>::iterator tunnel_it = m_teid_to_tunnel_ctx.find(ctrl_teid);
if(tunnel_it == m_teid_to_tunnel_ctx.end())
{
m_spgw_log->warning("Could not find TEID %d to delete\n",ctrl_teid);
return;
}
spgw_tunnel_ctx_t *tunnel_ctx = tunnel_it->second;
in_addr_t ue_ipv4 = tunnel_ctx->ue_ipv4;
//Delete data tunnel
pthread_mutex_lock(&m_mutex);
std::map<in_addr_t,srslte::gtpc_f_teid_ie>::iterator data_it = m_ip_to_teid.find(tunnel_ctx->ue_ipv4);
if(data_it != m_ip_to_teid.end())
{
m_ip_to_teid.erase(data_it);
}
pthread_mutex_unlock(&m_mutex);
m_teid_to_tunnel_ctx.erase(tunnel_it);
delete tunnel_ctx;
return;
}
} //namespace srsepc

@ -0,0 +1,13 @@
#
# .csv to store UE's information in HSS
# Kept in the following format: "Name,IMSI,Key,OP,AMF"
#
# Name: Human readable name to help distinguish UE's. Largely ignored by the HSS
# IMSI: UE's IMSI value
# Key: UE's key, where other keys are derived from. Stored in hexadecimal
# OP: Operator's code, sotred in hexadecimal
# AMF: Authentication management feild, stored in hexadecimal
#
# Note: Lines starting by '#' are ignored
ue1,001010123456789,00112233445566778899aabbccddeeff,63BFA50EE6523365FF14C1F45F88737D,9001
ue2,001010123456780,00112233445566778899aabbccddeeaa,63BFA50EE6523365FF14C1F45F88737D,2000
Can't render this file because it contains an unexpected character in line 3 and column 33.

@ -91,9 +91,9 @@ file_max_size = -1
# imei: 15 digit International Mobile Station Equipment Identity
#####################################################################
[usim]
algo = milenage
algo = xor
op = 63BFA50EE6523365FF14C1F45F88737D
amf = 8000
amf = 9001
k = 00112233445566778899aabbccddeeff
imsi = 001010123456789
imei = 353490069873319

Loading…
Cancel
Save