Commit 41560bed authored by gauthier's avatar gauthier

gtpv1u

parent 7f351d8e
This diff is collapsed.
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file gtpu.h
* \brief
* \author Lionel Gauthier
* \company Eurecom
* \email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_GTPU_SEEN
#define FILE_GTPU_SEEN
#include <endian.h>
#include <stdint.h>
struct gtpuhdr
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int pn:1;
unsigned int s:1;
unsigned int e:1;
unsigned int spare:1;
unsigned int pt:1;
unsigned int version:3;
#elif __BYTE_ORDER == __BIG_ENDIAN
unsigned int version:3;
unsigned int pt:1;
unsigned int spare:1;
unsigned int e:1;
unsigned int s:1;
unsigned int pn:1;
#else
# error "Please fix <bits/endian.h>"
#endif
// Message Type: This field indicates the type of GTP-U message.
uint8_t message_type;
// Length: This field indicates the length in octets of the payload, i.e. the rest of the packet following the mandatory
// part of the GTP header (that is the first 8 octets). The Sequence Number, the N-PDU Number or any Extension
// headers shall be considered to be part of the payload, i.e. included in the length count.
uint16_t message_length;
// Tunnel Endpoint Identifier (TEID): This field unambiguously identifies a tunnel endpoint in the receiving
// GTP-U protocol entity. The receiving end side of a GTP tunnel locally assigns the TEID value the transmitting
// side has to use. The TEID value shall be assigned in a non-predictable manner for PGW S5/S8/S2a/S2b
// interfaces (see 3GPP TS 33.250 [32]). The TEID shall be used by the receiving entity to find the PDP context,
// except for the following cases:
// -) The Echo Request/Response and Supported Extension Headers notification messages, where the Tunnel
// Endpoint Identifier shall be set to all zeroes
// -) The Error Indication message where the Tunnel Endpoint Identifier shall be set to all zeros.
uint32_t teid;
/*The options start here. */
};
#endif
This diff is collapsed.
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file gtpv1u.hpp
\brief
\author Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef FILE_GTPV1U_HPP_SEEN
#define FILE_GTPV1U_HPP_SEEN
#include "3gpp_29.281.hpp"
#include "itti.hpp"
#include "msg_gtpv1u.hpp"
#include <iostream>
#include <map>
#include <memory>
#include <stdint.h>
#include <string>
#include <system_error>
#include <thread>
#include <utility>
#include <vector>
namespace oai::cn::proto::gtpv1u {
class gtpu_l4_stack;
class udp_server
{
public:
udp_server(const struct in_addr& address, const uint16_t port_num)
: app_(nullptr), port_(port_num)
{
socket_ = create_socket (address, port_);
if (socket_ > 0) {
Logger::udp().debug( "udp_server::udp_server(%s:%d)", oai::cn::core::toString(address).c_str(), port_);
} else {
Logger::udp().error( "udp_server::udp_server(%s:%d)", oai::cn::core::toString(address).c_str(), port_);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
throw std::system_error(socket_, std::generic_category(), "GTPV1-U socket creation failed!");
}
}
udp_server(const struct in6_addr& address, const uint16_t port_num)
: app_(nullptr), port_(port_num)
{
socket_ = create_socket (address, port_);
if (socket_ > 0) {
Logger::udp().debug( "udp_server::udp_server(%s:%d)", oai::cn::core::toString(address).c_str(), port_);
} else {
Logger::udp().error( "udp_server::udp_server(%s:%d)", oai::cn::core::toString(address).c_str(), port_);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
throw std::system_error(socket_, std::generic_category(), "GTPV1-U socket creation failed!");
}
}
udp_server(char * address, const uint16_t port_num)
: app_(nullptr), port_(port_num)
{
socket_ = create_socket (address, port_);
if (socket_ > 0) {
Logger::udp().debug( "udp_server::udp_server(%s:%d)", address, port_);
} else {
Logger::udp().error( "udp_server::udp_server(%s:%d)", address, port_);
std::this_thread::sleep_for(std::chrono::milliseconds(500));
throw std::system_error(socket_, std::generic_category(), "GTPV1-U socket creation failed!");
}
}
~udp_server()
{
close(socket_);
}
void udp_read_loop(int cpu_id);
void async_send_to(const char* send_buffer, const ssize_t num_bytes, const struct sockaddr_in& peer_addr)
{
//Logger::udp().trace( "udp_server::async_send_to(%s:%d) %d bytes", oai::cn::core::toString(peer_addr.sin_addr).c_str(), peer_addr.sin_port, num_bytes);
ssize_t bytes_written = sendto (socket_, send_buffer, num_bytes, 0, (struct sockaddr *)&peer_addr, sizeof (struct sockaddr_in));
if (bytes_written != num_bytes) {
Logger::udp().error( "sendto failed(%d:%s)\n", errno, strerror (errno));
}
}
void async_send_to(const char* send_buffer, const ssize_t num_bytes, const struct sockaddr_in6& peer_addr)
{
ssize_t bytes_written = sendto (socket_, send_buffer, num_bytes, 0, (struct sockaddr *)&peer_addr, sizeof (struct sockaddr_in6));
if (bytes_written != num_bytes) {
Logger::udp().error( "sendto failed(%d:%s)\n", errno, strerror (errno));
}
}
void start_receive(gtpu_l4_stack * gtp_stack, const int cpu);
protected:
int create_socket (const struct in_addr& address, const uint16_t port);
int create_socket (const struct in6_addr& address, const uint16_t port);
int create_socket (char * address, const uint16_t port_num);
// void handle_receive(const int& error, std::size_t bytes_transferred);
void handle_send(const char *, /*buffer*/
const int& /*error*/,
std::size_t /*bytes_transferred*/)
{
}
gtpu_l4_stack* app_;
std::thread thread_;
int socket_;
uint16_t port_;
#define UDP_RECV_BUFFER_SIZE 8192
char recv_buffer_[UDP_RECV_BUFFER_SIZE];
};
class gtpu_l4_stack {
#define GTPV1U_T3_RESPONSE_MS 1000
#define GTPV1U_N3_REQUESTS 5
#define GTPV1U_PROC_TIME_OUT_MS ((GTPV1U_T3_RESPONSE_MS) * (GTPV1U_N3_REQUESTS + 1))
protected:
static uint64_t gtpu_tx_id_generator;
uint32_t id;
udp_server udp_s;
// seems no need for std::atomic_uint32_t
uint32_t seq_num;
uint32_t restart_counter;
boost::array<char, 4096> send_buffer;
static bool check_initial_message_type(const uint8_t initial);
static bool check_triggered_message_type(const uint8_t initial, const uint8_t triggered);
uint32_t get_next_seq_num();
public:
static const uint8_t version = 1;
gtpu_l4_stack(const struct in_addr& address, const uint16_t port_num, const int cpu);
gtpu_l4_stack(const struct in6_addr& address, const uint16_t port_num, const int cpu);
gtpu_l4_stack(char * ip_address, const uint16_t port_num, const int cpu);
virtual void handle_receive(char* recv_buffer, const std::size_t bytes_transferred, const struct sockaddr_storage& r_endpoint, const socklen_t& r_endpoint_addr_len);
void handle_receive_message_cb(const gtpv1u_msg& msg, const struct sockaddr_storage& r_endpoint, const socklen_t& r_endpoint_addr_len, const core::itti::task_id_t& task_id, bool &error, uint64_t& gtpc_tx_id);
void send_g_pdu(const struct sockaddr_in& peer_addr, const teid_t teid, const char* payload, const ssize_t payload_len);
void send_g_pdu(const struct sockaddr_in6& peer_addr, const teid_t teid, const char* payload, const ssize_t payload_len);
//virtual uint32_t send_request(const boost::asio::ip::udp::endpoint& dest, const teid_t teid, const gtpv1u_create_session_request& gtp_ies, const core::itti::task_id_t& task_id, const uint64_t gtp_tx_id);
//virtual void send_response(const boost::asio::ip::udp::endpoint& dest, const teid_t teid, const gtpv1u_create_session_response& gtp_ies, const uint64_t gtp_tx_id);
//virtual uint32_t send_gpdu(const boost::asio::ip::udp::endpoint& dest, const teid_t teid, const gtpv1u_create_session_request& gtp_ies, const core::itti::task_id_t& task_id, const uint64_t gtp_tx_id);
};
} // namespace gtpv1u
#endif /* FILE_GTPV1U_HPP_SEEN */
/*
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The OpenAirInterface Software Alliance licenses this file to You under
* the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*-------------------------------------------------------------------------------
* For more information about the OpenAirInterface (OAI) Software Alliance:
* contact@openairinterface.org
*/
/*! \file msg_gtpv1u.hpp
\brief
\author Sebastien ROUX, Lionel Gauthier
\company Eurecom
\email: lionel.gauthier@eurecom.fr
*/
#ifndef MSG_GTPV1U_HPP_INCLUDED_
#define MSG_GTPV1U_HPP_INCLUDED_
#include "3gpp_29.274.h"
#include "3gpp_29.281.h"
#include "common_defs.h"
#include <vector>
namespace oai::cn::proto::gtpv1u {
class gtpv1u_ies_container {
public:
static const uint8_t msg_id = 0;
virtual bool get(core::recovery_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_RECOVERY);}
virtual bool get(core::tunnel_endpoint_identifier_data_i_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_TUNNEL_ENDPOINT_IDENTIFIER_DATA_I);}
virtual bool get(core::gtp_u_peer_address_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_GTP_U_PEER_ADDRESS);}
virtual bool get(core::extension_header_type_list_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_EXTENSION_HEADER_TYPE_LIST);}
virtual bool get(core::private_extension_t& v) const {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_PRIVATE_EXTENSION);}
virtual void set(const core::recovery_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_RECOVERY);}
virtual void set(const core::tunnel_endpoint_identifier_data_i_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_TUNNEL_ENDPOINT_IDENTIFIER_DATA_I);}
virtual void set(const core::gtp_u_peer_address_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_GTP_U_PEER_ADDRESS);}
virtual void set(const core::extension_header_type_list_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_EXTENSION_HEADER_TYPE_LIST);}
virtual void set(const core::private_extension_t& v) {throw gtpu_msg_illegal_ie_exception(0, GTPU_IE_PRIVATE_EXTENSION);}
virtual ~gtpv1u_ies_container() {};
};
//------------------------------------------------------------------------------
class gtpv1u_echo_request : public gtpv1u_ies_container {
public:
static const uint8_t msg_id = GTPU_ECHO_REQUEST;
std::pair<bool, core::private_extension_t> private_extension;
gtpv1u_echo_request(): private_extension() {}
gtpv1u_echo_request(const gtpv1u_echo_request& i) : private_extension(i.private_extension) {}
const char* get_msg_name() const {return "GTPU_ECHO_REQUEST";};
bool get(core::private_extension_t& v) const {if (private_extension.first) {v = private_extension.second;return true;}return false;}
void set(const core::private_extension_t& v) {private_extension.first = true; private_extension.second = v;}
};
//------------------------------------------------------------------------------
class gtpv1u_echo_response : public gtpv1u_ies_container {
public:
static const uint8_t msg_id = GTPU_ECHO_RESPONSE;
std::pair<bool, core::recovery_t> recovery;
std::pair<bool, core::private_extension_t> private_extension;
gtpv1u_echo_response(): recovery(), private_extension() {}
gtpv1u_echo_response(const gtpv1u_echo_response& i): recovery(i.recovery), private_extension(i.private_extension) {}
const char* get_msg_name() const {return "GTPU_ECHO_RESPONSE";};
bool get(core::recovery_t& v) const {if (recovery.first) {v = recovery.second;return true;}return false;}
bool get(core::private_extension_t& v) const {if (private_extension.first) {v = private_extension.second;return true;}return false;}
void set(const core::recovery_t& v) {recovery.first = true; recovery.second = v;}
void set(const core::private_extension_t& v) {private_extension.first = true; private_extension.second = v;}
};
//------------------------------------------------------------------------------
class gtpv1u_error_indication : public gtpv1u_ies_container {
public:
static const uint8_t msg_id = GTPU_ERROR_INDICATION;
std::pair<bool, core::tunnel_endpoint_identifier_data_i_t> tunnel_endpoint_identifier_data_i;
std::pair<bool, core::gtp_u_peer_address_t> gtp_u_peer_address;
std::pair<bool, core::private_extension_t> private_extension;
gtpv1u_error_indication(): tunnel_endpoint_identifier_data_i(), gtp_u_peer_address(), private_extension() {}
gtpv1u_error_indication(const gtpv1u_error_indication& i) :
tunnel_endpoint_identifier_data_i(i.tunnel_endpoint_identifier_data_i),
gtp_u_peer_address(i.gtp_u_peer_address),
private_extension(i.private_extension) {}
const char* get_msg_name() const {return "GTPU_ERROR_INDICATION";};
bool get(core::tunnel_endpoint_identifier_data_i_t& v) const {if (tunnel_endpoint_identifier_data_i.first) {v = tunnel_endpoint_identifier_data_i.second;return true;}return false;}
bool get(core::gtp_u_peer_address_t& v) const {if (gtp_u_peer_address.first) {v = gtp_u_peer_address.second;return true;}return false;}
bool get(core::private_extension_t& v) const {if (private_extension.first) {v = private_extension.second;return true;}return false;}
void set(const core::tunnel_endpoint_identifier_data_i_t& v) {tunnel_endpoint_identifier_data_i.first = true; tunnel_endpoint_identifier_data_i.second = v;}
void set(const core::gtp_u_peer_address_t& v) {gtp_u_peer_address.first = true; gtp_u_peer_address.second = v;}
void set(const core::private_extension_t& v) {private_extension.first = true; private_extension.second = v;}
};
//------------------------------------------------------------------------------
class gtpv1u_supported_extension_headers_notification : public gtpv1u_ies_container {
public:
static const uint8_t msg_id = GTPU_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION;
std::pair<bool, core::extension_header_type_list_t> extension_header_type_list;
gtpv1u_supported_extension_headers_notification() :
extension_header_type_list() {}
gtpv1u_supported_extension_headers_notification(const gtpv1u_supported_extension_headers_notification& i) :
extension_header_type_list(i.extension_header_type_list) {}
const char* get_msg_name() const {return "GTPU_SUPPORTED_EXTENSION_HEADERS_NOTIFICATION";};
bool get(core::extension_header_type_list_t& v) const {if (extension_header_type_list.first) {v = extension_header_type_list.second;return true;}return false;}
void set(const core::extension_header_type_list_t& v) {extension_header_type_list.first = true; extension_header_type_list.second = v;}
};
//------------------------------------------------------------------------------
class gtpv1u_end_marker : public gtpv1u_ies_container {
public:
static const uint8_t msg_id = GTPU_END_MARKER;
std::pair<bool, core::private_extension_t> private_extension;
gtpv1u_end_marker() :
private_extension() {}
gtpv1u_end_marker(const gtpv1u_error_indication& i) :
private_extension(i.private_extension) {}
const char* get_msg_name() const {return "GTPU_END_MARKER";};
bool get(core::private_extension_t& v) const {if (private_extension.first) {v = private_extension.second;return true;}return false;}
void set(const core::private_extension_t& v) {private_extension.first = true; private_extension.second = v;}
};
} // namespace gtpv1u
#endif /* MSG_GTPV1U_HPP_INCLUDED_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment