Keep the colleague's microbu-esp32c5 tree in this repository
obu-firmware builds against vanetza-idf from microbu-esp32c5/external, but that tree was gitignored, so a clone of this repository could not build the firmware it ships. It is now committed here as ordinary files in its own folder, microbu-esp32c5/: the colleague's commit cf4b99f plus the V2X2MAP bridge's signature verification (--trust) used on the bench. Nothing is fetched from or pushed to the colleague's repository; this repository and its remotes carry everything. The folder's own .gitignore keeps build output, downloaded components and private key material out, as it did there; the committed file set is identical to that repository's tracked files. The ESP32-C5 is still flashed from obu-firmware/, which only takes vanetza-idf from microbu-esp32c5/, so the two stay separate folders. FLASHING.md says how to take a newer version of the colleague's tree (copy it over the folder, rebuild, test, commit).
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
set(CXX_SOURCES
|
||||
buffer_packet.cpp
|
||||
chunk_packet.cpp
|
||||
cohesive_packet.cpp
|
||||
ethernet_header.cpp
|
||||
mac_address.cpp
|
||||
packet_variant.cpp
|
||||
packet.cpp
|
||||
proxy_header.cpp
|
||||
)
|
||||
|
||||
set(CXX_SOURCES_POSIX
|
||||
io_vector.cpp
|
||||
sockaddr.cpp
|
||||
)
|
||||
|
||||
option(VANETZA_NET_WITH_POSIX "Build network module with POSIX extension" ${UNIX})
|
||||
if(VANETZA_NET_WITH_POSIX)
|
||||
list(APPEND CXX_SOURCES ${CXX_SOURCES_POSIX})
|
||||
endif()
|
||||
|
||||
add_vanetza_component(net ${CXX_SOURCES})
|
||||
target_link_libraries(net PUBLIC common)
|
||||
|
||||
add_test_subdirectory(tests)
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "buffer_packet.hpp"
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
BufferPacket::BufferPacket()
|
||||
{
|
||||
}
|
||||
|
||||
void BufferPacket::swap(OsiLayer layer, ByteBuffer& replacement)
|
||||
{
|
||||
ByteBuffer& stored = mBuffers[layer];
|
||||
stored.swap(replacement);
|
||||
}
|
||||
|
||||
const ByteBuffer& BufferPacket::operator[](OsiLayer layer) const
|
||||
{
|
||||
auto match = mBuffers.find(layer);
|
||||
if (match == mBuffers.end()) {
|
||||
static const ByteBuffer scEmptyBuffer;
|
||||
return scEmptyBuffer;
|
||||
} else {
|
||||
return match->second;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t BufferPacket::size() const
|
||||
{
|
||||
std::size_t packet_size = 0;
|
||||
for (const auto& it : *this) {
|
||||
packet_size += it.second.size();
|
||||
}
|
||||
return packet_size;
|
||||
}
|
||||
|
||||
void BufferPacket::clear()
|
||||
{
|
||||
for (auto& it : mBuffers) {
|
||||
it.second.clear();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef BUFFER_PACKET_HPP_QYLSJSX5
|
||||
#define BUFFER_PACKET_HPP_QYLSJSX5
|
||||
|
||||
#include <vanetza/common/byte_buffer.hpp>
|
||||
#include <vanetza/net/osi_layer.hpp>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
class BufferPacket
|
||||
{
|
||||
public:
|
||||
typedef std::map<OsiLayer, ByteBuffer> map_t;
|
||||
BufferPacket();
|
||||
void swap(OsiLayer layer, ByteBuffer&);
|
||||
const ByteBuffer& operator[](OsiLayer layer) const;
|
||||
ByteBuffer& operator[](OsiLayer layer) { return mBuffers[layer]; }
|
||||
std::size_t size() const;
|
||||
void clear();
|
||||
|
||||
map_t::iterator begin() { return mBuffers.begin(); }
|
||||
map_t::iterator end() { return mBuffers.end(); }
|
||||
map_t::const_iterator begin() const { return mBuffers.begin(); }
|
||||
map_t::const_iterator end() const { return mBuffers.end(); }
|
||||
|
||||
private:
|
||||
map_t mBuffers;
|
||||
};
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* BUFFER_PACKET_HPP_QYLSJSX5 */
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "chunk_packet.hpp"
|
||||
#include "cohesive_packet.hpp"
|
||||
#include <cassert>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
static const ByteBufferConvertible empty_byte_buffer_convertible;
|
||||
|
||||
ChunkPacket::ChunkPacket()
|
||||
{
|
||||
}
|
||||
|
||||
ChunkPacket::ChunkPacket(const ChunkPacket& other)
|
||||
{
|
||||
for (auto& layer : other.m_layers) {
|
||||
m_layers.insert(layer);
|
||||
}
|
||||
}
|
||||
|
||||
ChunkPacket& ChunkPacket::operator=(const ChunkPacket& other)
|
||||
{
|
||||
ChunkPacket tmp = other;
|
||||
m_layers.swap(tmp.m_layers);
|
||||
return *this;
|
||||
}
|
||||
|
||||
ByteBufferConvertible& ChunkPacket::layer(OsiLayer layer)
|
||||
{
|
||||
return m_layers[layer];
|
||||
}
|
||||
|
||||
const ByteBufferConvertible& ChunkPacket::layer(OsiLayer layer) const
|
||||
{
|
||||
auto found = m_layers.find(layer);
|
||||
if (found != m_layers.end()) {
|
||||
assert(found->first == layer);
|
||||
return found->second;
|
||||
} else {
|
||||
return empty_byte_buffer_convertible;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t ChunkPacket::size() const
|
||||
{
|
||||
std::size_t size = 0;
|
||||
for(auto& it : m_layers)
|
||||
{
|
||||
size += it.second.size();
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
std::size_t ChunkPacket::size(OsiLayer from, OsiLayer to) const
|
||||
{
|
||||
assert(from <= to);
|
||||
std::size_t size = 0;
|
||||
for (auto& layer : m_layers) {
|
||||
if (layer.first >= from && layer.first <= to) {
|
||||
size += layer.second.size();
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
ChunkPacket ChunkPacket::extract(OsiLayer from, OsiLayer to)
|
||||
{
|
||||
ChunkPacket result;
|
||||
for (auto layer : osi_layer_range(from, to)) {
|
||||
using namespace std;
|
||||
swap(result[layer], (*this)[layer]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ChunkPacket& ChunkPacket::merge(ChunkPacket& source, OsiLayer from, OsiLayer to)
|
||||
{
|
||||
for (auto layer : osi_layer_range(from, to)) {
|
||||
(*this)[layer] = std::move(source[layer]);
|
||||
source[layer] = empty_byte_buffer_convertible;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
#ifndef CHUNK_PACKET_HPP_AT4GYSLD
|
||||
#define CHUNK_PACKET_HPP_AT4GYSLD
|
||||
|
||||
#include <vanetza/common/byte_buffer_convertible.hpp>
|
||||
#include <vanetza/net/osi_layer.hpp>
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
/**
|
||||
* \brief ChunckPacket is a packet consisting of several memory chunks
|
||||
*
|
||||
* ChunkPacket is the preferred packet type when it is getting assembled step by step.
|
||||
* Each layer can easily add further bytes without caring about other layers at all.
|
||||
*/
|
||||
class ChunkPacket
|
||||
{
|
||||
public:
|
||||
ChunkPacket();
|
||||
|
||||
// copy semantics
|
||||
ChunkPacket(const ChunkPacket&);
|
||||
ChunkPacket& operator=(const ChunkPacket&);
|
||||
|
||||
// move semantics
|
||||
ChunkPacket(ChunkPacket&&) = default;
|
||||
ChunkPacket& operator=(ChunkPacket&&) = default;
|
||||
|
||||
/**
|
||||
* Access ByteBufferConvertible of specific layer
|
||||
* \param layer ol Access this layer's data
|
||||
* \return ByteBufferConvertible, might be empty
|
||||
*/
|
||||
ByteBufferConvertible& layer(OsiLayer ol);
|
||||
/** \copydoc ChunkPacket::layer */
|
||||
const ByteBufferConvertible& layer(OsiLayer ol) const;
|
||||
|
||||
/** \copydoc ChunkPacket::layer */
|
||||
inline ByteBufferConvertible& operator[](OsiLayer ol)
|
||||
{
|
||||
return layer(ol);
|
||||
}
|
||||
|
||||
/** \copydoc ChunkPacket::layer */
|
||||
inline const ByteBufferConvertible& operator[](OsiLayer ol) const
|
||||
{
|
||||
return layer(ol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get size of whole payload
|
||||
* \return payload size in bytes
|
||||
*/
|
||||
std::size_t size() const;
|
||||
|
||||
/**
|
||||
* Get size of payload from specified layer range
|
||||
* \param from start counting including this layer
|
||||
* \param to stop counting including this layer
|
||||
* \return payload size in bytes
|
||||
*/
|
||||
std::size_t size(OsiLayer from, OsiLayer to) const;
|
||||
|
||||
/**
|
||||
* Extract a range of layers from this packet to a new one.
|
||||
* The respective layers of this ChunkPacket are empty afterwards.
|
||||
* \param from start at this layer (inclusive)
|
||||
* \param to stop at this layer (inclusive)
|
||||
* \return new packet containing layers of specified range
|
||||
*/
|
||||
ChunkPacket extract(OsiLayer from, OsiLayer to);
|
||||
|
||||
/**
|
||||
* Merge layers from another packet
|
||||
* \param packet source packet (layers will be moved from there)
|
||||
* \param from start at this layer (inclusive)
|
||||
* \param to stop at this layer (inclusive)
|
||||
* \return reference to this packet
|
||||
*/
|
||||
ChunkPacket& merge(ChunkPacket& packet, OsiLayer from, OsiLayer to);
|
||||
|
||||
private:
|
||||
typedef std::map<OsiLayer, ByteBufferConvertible> map_type;
|
||||
map_type m_layers;
|
||||
};
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* CHUNK_PACKET_HPP_AT4GYSLD */
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
#include "cohesive_packet.hpp"
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
constexpr unsigned layer_index(OsiLayer layer)
|
||||
{
|
||||
return static_cast<unsigned>(layer);
|
||||
}
|
||||
|
||||
static_assert(layer_index(min_osi_layer()) == 1, "Lowest OSI layer index broken");
|
||||
|
||||
|
||||
CohesivePacket::CohesivePacket(const ByteBuffer& buffer, OsiLayer layer) :
|
||||
m_buffer(buffer)
|
||||
{
|
||||
reset_iterators(layer);
|
||||
}
|
||||
|
||||
CohesivePacket::CohesivePacket(ByteBuffer&& buffer, OsiLayer layer) :
|
||||
m_buffer(std::move(buffer))
|
||||
{
|
||||
reset_iterators(layer);
|
||||
}
|
||||
|
||||
CohesivePacket::CohesivePacket(const CohesivePacket& other) :
|
||||
m_buffer(other.m_buffer)
|
||||
{
|
||||
rebuild_iterators(other);
|
||||
}
|
||||
|
||||
CohesivePacket& CohesivePacket::operator=(const CohesivePacket& other)
|
||||
{
|
||||
m_buffer = other.m_buffer;
|
||||
rebuild_iterators(other);
|
||||
return *this;
|
||||
}
|
||||
|
||||
auto CohesivePacket::operator[](OsiLayer layer) const -> buffer_const_range
|
||||
{
|
||||
return get(layer_index(layer));
|
||||
}
|
||||
|
||||
auto CohesivePacket::operator[](OsiLayer layer) -> buffer_range
|
||||
{
|
||||
return get(layer_index(layer));
|
||||
}
|
||||
|
||||
void CohesivePacket::set_boundary(OsiLayer layer, unsigned bytes)
|
||||
{
|
||||
const unsigned layer_idx = layer_index(layer);
|
||||
assert(get(layer_idx).size() >= bytes);
|
||||
m_iterators[layer_idx] = m_iterators[layer_idx - 1] + bytes;
|
||||
}
|
||||
|
||||
void CohesivePacket::trim(OsiLayer from, unsigned bytes)
|
||||
{
|
||||
if (size(from, max_osi_layer()) > bytes) {
|
||||
const auto from_idx = layer_index(from) - 1;
|
||||
const auto max_idx = layer_index(max_osi_layer());
|
||||
m_iterators[max_idx] = m_iterators[from_idx] + bytes;
|
||||
assert(&m_iterators.back() == &m_iterators[max_idx]);
|
||||
assert(m_iterators.back() >= m_iterators.front());
|
||||
for (auto idx = from_idx; idx < max_idx; ++idx) {
|
||||
if (m_iterators[idx] > m_iterators[max_idx]) {
|
||||
m_iterators[idx] = m_iterators[max_idx];
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(size(from, max_osi_layer()) <= bytes);
|
||||
}
|
||||
|
||||
std::size_t CohesivePacket::size() const
|
||||
{
|
||||
return std::distance(m_iterators.front(), m_iterators.back());
|
||||
}
|
||||
|
||||
std::size_t CohesivePacket::size(OsiLayer single_layer) const
|
||||
{
|
||||
return get(layer_index(single_layer)).size();
|
||||
}
|
||||
|
||||
std::size_t CohesivePacket::size(OsiLayer from, OsiLayer to) const
|
||||
{
|
||||
auto begin = m_iterators[layer_index(from) - 1];
|
||||
auto end = m_iterators[layer_index(to)];
|
||||
auto dist = std::distance(begin, end);
|
||||
return dist < 0 ? 0 : dist;
|
||||
}
|
||||
|
||||
void CohesivePacket::reset_iterators(OsiLayer ins_layer)
|
||||
{
|
||||
unsigned layer_idx = 0;
|
||||
|
||||
const unsigned ins_layer_idx = layer_index(ins_layer);
|
||||
for (unsigned i = 0; i < ins_layer_idx; ++i) {
|
||||
m_iterators[layer_idx++] = m_buffer.begin();
|
||||
}
|
||||
|
||||
const unsigned max_layer_idx = layer_index(max_osi_layer());
|
||||
for (unsigned i = ins_layer_idx; i <= max_layer_idx; ++i) {
|
||||
m_iterators[layer_idx++] = m_buffer.end();
|
||||
}
|
||||
|
||||
assert(m_iterators.size() == layer_idx);
|
||||
}
|
||||
|
||||
void CohesivePacket::rebuild_iterators(const CohesivePacket& other)
|
||||
{
|
||||
assert(m_buffer.size() == other.m_buffer.size());
|
||||
m_iterators.front() = m_buffer.begin();
|
||||
auto next = m_iterators.front();
|
||||
for (unsigned i = 1; i < m_iterators.size(); ++i) {
|
||||
next += other.m_iterators[i] - other.m_iterators[i - 1];
|
||||
m_iterators[i] = next;
|
||||
}
|
||||
}
|
||||
|
||||
auto CohesivePacket::get(unsigned layer_idx) -> buffer_range
|
||||
{
|
||||
assert(layer_idx > 0);
|
||||
assert(layer_idx < m_iterators.size());
|
||||
return buffer_range(m_iterators[layer_idx - 1], m_iterators[layer_idx]);
|
||||
}
|
||||
|
||||
auto CohesivePacket::get(unsigned layer_idx) const -> buffer_const_range
|
||||
{
|
||||
assert(layer_idx > 0);
|
||||
assert(layer_idx < m_iterators.size());
|
||||
return buffer_const_range(m_iterators[layer_idx - 1], m_iterators[layer_idx]);
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
#ifndef COHESIVE_PACKET_HPP_VG2XKSCV
|
||||
#define COHESIVE_PACKET_HPP_VG2XKSCV
|
||||
|
||||
#include <vanetza/common/byte_buffer.hpp>
|
||||
#include <vanetza/net/osi_layer.hpp>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <array>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
/**
|
||||
* A cohesive packet is stored in contiguous memory
|
||||
*/
|
||||
class CohesivePacket
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_range<ByteBuffer::iterator> buffer_range;
|
||||
typedef boost::iterator_range<ByteBuffer::const_iterator> buffer_const_range;
|
||||
|
||||
/**
|
||||
* Create packet from buffer and assign all bytes to given layer
|
||||
* \param buffer copy data from this buffer
|
||||
* \param layer all bytes belong to this layer (at least at first)
|
||||
*/
|
||||
CohesivePacket(const ByteBuffer& buffer, OsiLayer layer);
|
||||
CohesivePacket(ByteBuffer&& buffer, OsiLayer layer);
|
||||
|
||||
CohesivePacket(const CohesivePacket&);
|
||||
CohesivePacket& operator=(const CohesivePacket&);
|
||||
|
||||
CohesivePacket(CohesivePacket&&) = default;
|
||||
CohesivePacket& operator=(CohesivePacket&&) = default;
|
||||
|
||||
/**
|
||||
* Access a certain sub-range of packet data belonging to a specific layer
|
||||
* \param layer requested layer data
|
||||
* \return buffer range with data, might be empty
|
||||
*/
|
||||
buffer_const_range operator[](OsiLayer layer) const;
|
||||
buffer_range operator[](OsiLayer layer);
|
||||
|
||||
/**
|
||||
* Set boundary of layer data.
|
||||
* Data beyond boundary belongs to next upper layer afterwards.
|
||||
* \param layer set boundary of this layer
|
||||
* \param bytes length of layer
|
||||
* \note Never set boundary larger than previous layer length!
|
||||
*/
|
||||
void set_boundary(OsiLayer, unsigned bytes);
|
||||
|
||||
/**
|
||||
* Trim size of packet, i.e. cut bytes at the end if too long.
|
||||
* \param from start counting with this layer
|
||||
* \param bytes target length in bytes
|
||||
*/
|
||||
void trim(OsiLayer from, unsigned bytes);
|
||||
|
||||
/**
|
||||
* Get size of whole packet
|
||||
* \return length in bytes
|
||||
*/
|
||||
std::size_t size() const;
|
||||
|
||||
/**
|
||||
* Get size of a single layer in packet
|
||||
* \param single_layer which layer has to be considered
|
||||
* \return length in bytes
|
||||
*/
|
||||
std::size_t size(OsiLayer single_layer) const;
|
||||
|
||||
/**
|
||||
* Get size of several layers
|
||||
* \param from start counting with this layer
|
||||
* \param to stop counting after this layer
|
||||
* \return length in bytes
|
||||
*/
|
||||
std::size_t size(OsiLayer from, OsiLayer to) const;
|
||||
|
||||
/**
|
||||
* Non-mutable access to internal byte buffer
|
||||
* \return const byte buffer reference
|
||||
*/
|
||||
const ByteBuffer& buffer() const { return m_buffer; }
|
||||
|
||||
private:
|
||||
void reset_iterators(OsiLayer layer);
|
||||
void rebuild_iterators(const CohesivePacket&);
|
||||
buffer_const_range get(unsigned idx) const;
|
||||
buffer_range get(unsigned idx);
|
||||
|
||||
ByteBuffer m_buffer;
|
||||
std::array<ByteBuffer::iterator, osi_layers.size() + 1> m_iterators;
|
||||
};
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* COHESIVE_PACKET_HPP_VG2XKSCV */
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#include "ethernet_header.hpp"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
ByteBuffer create_ethernet_header(const MacAddress& dest, const MacAddress& src, uint16be_t proto)
|
||||
{
|
||||
ByteBuffer buffer;
|
||||
buffer.reserve(EthernetHeader::length_bytes);
|
||||
auto inserter = std::back_inserter(buffer);
|
||||
std::copy(dest.octets.begin(), dest.octets.end(), inserter);
|
||||
std::copy(src.octets.begin(), src.octets.end(), inserter);
|
||||
uint16_t host_proto = proto.host();
|
||||
inserter = (host_proto >> 8) & 0xff;
|
||||
inserter = host_proto & 0xff;
|
||||
assert(buffer.size() == EthernetHeader::length_bytes);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
ByteBuffer create_ethernet_header(const EthernetHeader& hdr)
|
||||
{
|
||||
return create_ethernet_header(hdr.destination, hdr.source, hdr.type);
|
||||
}
|
||||
|
||||
EthernetHeader decode_ethernet_header(ByteBuffer::const_iterator begin, ByteBuffer::const_iterator end)
|
||||
{
|
||||
EthernetHeader hdr;
|
||||
const std::size_t buflen = std::distance(begin, end);
|
||||
if (buflen < EthernetHeader::length_bytes) {
|
||||
throw std::runtime_error("buffer is too short for EthernetHeader decoding");
|
||||
} else {
|
||||
std::copy_n(begin, MacAddress::length_bytes, hdr.destination.octets.begin());
|
||||
begin += MacAddress::length_bytes;
|
||||
std::copy_n(begin, MacAddress::length_bytes, hdr.source.octets.begin());
|
||||
begin += MacAddress::length_bytes;
|
||||
uint16_t proto = (begin[0] << 8) | begin[1];
|
||||
hdr.type = host_cast(proto);
|
||||
}
|
||||
return hdr;
|
||||
}
|
||||
|
||||
EthernetHeader decode_ethernet_header(const ByteBuffer& buf)
|
||||
{
|
||||
return decode_ethernet_header(buf.begin(), buf.end());
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#ifndef ETHERNET_HEADER_HPP_
|
||||
#define ETHERNET_HEADER_HPP_
|
||||
|
||||
#include <vanetza/common/byte_buffer.hpp>
|
||||
#include <vanetza/common/byte_order.hpp>
|
||||
#include <vanetza/net/mac_address.hpp>
|
||||
#include <cstddef>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
/**
|
||||
* Get length of ethernet header in bytes
|
||||
* \param header length in bytes
|
||||
*/
|
||||
constexpr std::size_t ethernet_header_length()
|
||||
{
|
||||
return 2 * sizeof(MacAddress::octets) + sizeof(uint16_t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Link-level header of type Ethernet II
|
||||
*
|
||||
* EthernetHeader is suitable for Linux raw packet sockets, see man 7 packet
|
||||
*/
|
||||
class EthernetHeader
|
||||
{
|
||||
public:
|
||||
using EtherType = uint16be_t;
|
||||
static constexpr std::size_t length_bytes = ethernet_header_length();
|
||||
|
||||
MacAddress destination;
|
||||
MacAddress source;
|
||||
EtherType type;
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a byte buffer containing an ethernet header
|
||||
* \param dest Destination MAC address
|
||||
* \param src Source MAC address
|
||||
* \param proto EtherType number
|
||||
*/
|
||||
ByteBuffer create_ethernet_header(const MacAddress& dest, const MacAddress& src, uint16be_t proto);
|
||||
ByteBuffer create_ethernet_header(const EthernetHeader&);
|
||||
|
||||
/**
|
||||
* Parse ethernet header from byte buffer
|
||||
* \param buffer byte buffer (throws exception if too short)
|
||||
* \return ethernet header
|
||||
*/
|
||||
EthernetHeader decode_ethernet_header(const ByteBuffer&);
|
||||
EthernetHeader decode_ethernet_header(ByteBuffer::const_iterator, ByteBuffer::const_iterator);
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif // ETHERNET_HEADER_HPP_
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "io_vector.hpp"
|
||||
#include "buffer_packet.hpp"
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
void IoVector::clear()
|
||||
{
|
||||
m_vector.clear();
|
||||
}
|
||||
|
||||
void IoVector::append(const void* base, std::size_t length)
|
||||
{
|
||||
iovec node;
|
||||
node.iov_base = const_cast<void*>(base);
|
||||
node.iov_len = length;
|
||||
m_vector.push_back(node);
|
||||
}
|
||||
|
||||
void IoVector::append(const BufferPacket& packet)
|
||||
{
|
||||
for (auto& kv : packet) {
|
||||
const ByteBuffer& buffer = kv.second;
|
||||
append(buffer.data(), buffer.size());
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t IoVector::length() const
|
||||
{
|
||||
return m_vector.size();
|
||||
}
|
||||
|
||||
const iovec* IoVector::base() const
|
||||
{
|
||||
return m_vector.empty() ? nullptr : &m_vector[0];
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef IO_VECTOR_HPP_A3ANMI8B
|
||||
#define IO_VECTOR_HPP_A3ANMI8B
|
||||
|
||||
#include <vector>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
// forward declaration
|
||||
class BufferPacket;
|
||||
|
||||
/**
|
||||
* IoVector eaeses population of struct msghdr.
|
||||
* struct msghdr is required for sendmsg() calls.
|
||||
*/
|
||||
class IoVector
|
||||
{
|
||||
public:
|
||||
void append(const void* base, std::size_t length);
|
||||
void append(const BufferPacket&);
|
||||
void clear();
|
||||
std::size_t length() const;
|
||||
const iovec* base() const;
|
||||
|
||||
private:
|
||||
std::vector<iovec> m_vector;
|
||||
};
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* IO_VECTOR_HPP_A3ANMI8B */
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#include "mac_address.hpp"
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cctype>
|
||||
#include <iomanip>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
const MacAddress cBroadcastMacAddress = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
constexpr std::size_t MacAddress::length_bytes;
|
||||
|
||||
MacAddress::MacAddress()
|
||||
{
|
||||
std::fill_n(octets.begin(), octets.size(), 0x00);
|
||||
}
|
||||
|
||||
MacAddress::MacAddress(std::initializer_list<uint8_t> args)
|
||||
{
|
||||
assert(args.size() == octets.size());
|
||||
std::copy_n(args.begin(), std::min(args.size(), octets.size()), octets.begin());
|
||||
}
|
||||
|
||||
bool operator==(const MacAddress& lhs, const MacAddress& rhs)
|
||||
{
|
||||
return (lhs.octets == rhs.octets);
|
||||
}
|
||||
|
||||
bool operator<(const MacAddress& lhs, const MacAddress& rhs)
|
||||
{
|
||||
for (std::size_t i = 0; i < MacAddress::length_bytes; ++i) {
|
||||
if (lhs.octets[i] < rhs.octets[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool parse_mac_address(const std::string& str, MacAddress& addr)
|
||||
{
|
||||
bool parsed = false;
|
||||
std::vector<std::string> octets;
|
||||
boost::algorithm::split(octets, str, boost::algorithm::is_any_of(":"));
|
||||
|
||||
// lambda returning true if string consists of two hex digits
|
||||
auto octet_checker = [](const std::string& str) {
|
||||
return str.size() == 2 && std::isxdigit(str[0]) && std::isxdigit(str[1]);
|
||||
};
|
||||
|
||||
if (octets.size() == addr.octets.size() && std::all_of(octets.begin(), octets.end(), octet_checker)) {
|
||||
std::transform(octets.begin(), octets.end(), addr.octets.begin(),
|
||||
[](const std::string& octet) {
|
||||
return std::strtol(octet.c_str(), nullptr, 16);
|
||||
});
|
||||
parsed = true;
|
||||
}
|
||||
|
||||
return parsed;
|
||||
}
|
||||
|
||||
boost::optional<MacAddress> parse_mac_address(const std::string& str)
|
||||
{
|
||||
boost::optional<MacAddress> addr_result;
|
||||
MacAddress addr_tmp;
|
||||
if (parse_mac_address(str, addr_tmp)) {
|
||||
addr_result.reset(addr_tmp);
|
||||
}
|
||||
return addr_result;
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const MacAddress& addr)
|
||||
{
|
||||
boost::io::ios_all_saver ifs(os);
|
||||
os << std::hex << std::setfill('0');
|
||||
os << std::setw(2) << unsigned(addr.octets[0]);
|
||||
for (unsigned i = 1; i < addr.octets.size(); ++i) {
|
||||
os << ":" << std::setw(2) << unsigned(addr.octets[i]);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
void serialize(OutputArchive& ar, const MacAddress& addr)
|
||||
{
|
||||
for (std::uint8_t octet : addr.octets) {
|
||||
ar << octet;
|
||||
}
|
||||
}
|
||||
|
||||
void deserialize(InputArchive& ar, MacAddress& addr)
|
||||
{
|
||||
for (std::uint8_t& octet : addr.octets) {
|
||||
ar >> octet;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
#ifndef MAC_ADDRESS_HPP_FDINBLBS
|
||||
#define MAC_ADDRESS_HPP_FDINBLBS
|
||||
|
||||
#include <vanetza/common/serialization.hpp>
|
||||
#include <boost/operators.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <functional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
class MacAddress : public boost::totally_ordered<MacAddress>
|
||||
{
|
||||
public:
|
||||
static constexpr std::size_t length_bytes = 6;
|
||||
|
||||
MacAddress();
|
||||
MacAddress(std::initializer_list<uint8_t> args);
|
||||
MacAddress(const MacAddress&) = default;
|
||||
MacAddress& operator=(const MacAddress&) = default;
|
||||
MacAddress(MacAddress&&) = default;
|
||||
MacAddress& operator=(MacAddress&&) = default;
|
||||
|
||||
std::array<uint8_t, length_bytes> octets;
|
||||
};
|
||||
|
||||
extern const MacAddress cBroadcastMacAddress;
|
||||
bool operator==(const MacAddress& lhs, const MacAddress& rhs);
|
||||
bool operator<(const MacAddress& lhs, const MacAddress& rhs);
|
||||
std::ostream& operator<<(std::ostream& os, const MacAddress&);
|
||||
|
||||
/**
|
||||
* Try to parse MAC address from string
|
||||
* \param str source string with "XX:XX:XX:XX:XX:XX" format
|
||||
* \param addr pass parsed address by reference
|
||||
* \return true if successfully parsed
|
||||
*/
|
||||
bool parse_mac_address(const std::string& str, MacAddress& addr);
|
||||
|
||||
/**
|
||||
* Try to parse MAC address from string
|
||||
* \param str source string with "XX:XX:XX:XX:XX:XX" format
|
||||
* \return parsed address if successful
|
||||
*/
|
||||
boost::optional<MacAddress> parse_mac_address(const std::string& str);
|
||||
|
||||
/**
|
||||
* Derive a MAC address from an arbitrary integral value.
|
||||
* \param value used to derive MAC address, it's size does not matter
|
||||
* \return New MAC address
|
||||
*/
|
||||
template<typename T>
|
||||
MacAddress create_mac_address(T value)
|
||||
{
|
||||
MacAddress mac;
|
||||
const std::size_t octets = std::min(mac.octets.size(), sizeof(T));
|
||||
for (std::size_t i = 0; i < octets; ++i) {
|
||||
mac.octets[i] = value >> (8 * (octets - i - 1)) & 0xff;
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize MAC address
|
||||
* \param out output sink
|
||||
* \param addr MAC address
|
||||
*/
|
||||
void serialize(OutputArchive& out, const MacAddress& addr);
|
||||
|
||||
/**
|
||||
* Deserialize MAC address
|
||||
* \param in input source
|
||||
* \param addr deserialize into this object
|
||||
*/
|
||||
void deserialize(InputArchive& in, MacAddress& addr);
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
// specialization
|
||||
namespace std {
|
||||
|
||||
template<>
|
||||
struct hash<vanetza::MacAddress>
|
||||
{
|
||||
size_t operator()(const vanetza::MacAddress& addr) const
|
||||
{
|
||||
size_t tmp = 0;
|
||||
for (auto octet : addr.octets) {
|
||||
tmp ^= hash<decltype(octet)>()(octet);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif /* MAC_ADDRESS_HPP_FDINBLBS */
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
#ifndef OSI_LAYER_HPP_C4VTEZJP
|
||||
#define OSI_LAYER_HPP_C4VTEZJP
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
enum class OsiLayer : uint8_t
|
||||
{
|
||||
Physical = 1,
|
||||
Link = 2,
|
||||
Network = 3,
|
||||
Transport = 4,
|
||||
Session = 5,
|
||||
Presentation = 6,
|
||||
Application = 7
|
||||
};
|
||||
|
||||
constexpr OsiLayer min_osi_layer() { return OsiLayer::Physical; }
|
||||
constexpr OsiLayer max_osi_layer() { return OsiLayer::Application; }
|
||||
|
||||
constexpr std::array<OsiLayer, 7> osi_layers {{
|
||||
OsiLayer::Physical,
|
||||
OsiLayer::Link,
|
||||
OsiLayer::Network,
|
||||
OsiLayer::Transport,
|
||||
OsiLayer::Session,
|
||||
OsiLayer::Presentation,
|
||||
OsiLayer::Application
|
||||
}};
|
||||
|
||||
/**
|
||||
* Calculate distance between layers
|
||||
* \param from start counting at this layer
|
||||
* \param to stop counting here
|
||||
* \return 0 if equal layers, positive if "to" is a higher layer, negative if "to" is below "from"
|
||||
*/
|
||||
constexpr int distance(OsiLayer from, OsiLayer to)
|
||||
{
|
||||
return static_cast<int>(to) - static_cast<int>(from);
|
||||
}
|
||||
|
||||
constexpr std::size_t num_osi_layers(OsiLayer from, OsiLayer to)
|
||||
{
|
||||
return (from <= to ? distance(from, to) + 1 : 0);
|
||||
}
|
||||
|
||||
template<OsiLayer FROM, OsiLayer TO>
|
||||
std::array<OsiLayer, num_osi_layers(FROM, TO)> osi_layer_range()
|
||||
{
|
||||
static_assert(FROM <= TO, "FROM layer is above TO layer");
|
||||
typedef typename std::underlying_type<OsiLayer>::type num_type;
|
||||
|
||||
num_type num = static_cast<num_type>(FROM);
|
||||
std::array<OsiLayer, num_osi_layers(FROM, TO)> layers;
|
||||
for (auto& layer : layers) {
|
||||
layer = static_cast<OsiLayer>(num++);
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
inline boost::iterator_range<decltype(osi_layers)::const_iterator>
|
||||
osi_layer_range(OsiLayer from, OsiLayer to)
|
||||
{
|
||||
if (from <= to) {
|
||||
auto begin = osi_layers.cbegin() + distance(min_osi_layer(), from);
|
||||
auto end = osi_layers.cend() - distance(to, max_osi_layer());
|
||||
return boost::make_iterator_range(begin, end);
|
||||
} else {
|
||||
return boost::make_iterator_range(osi_layers.cend(), osi_layers.cend());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* OSI_LAYER_HPP_C4VTEZJP */
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <vanetza/net/packet.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
std::unique_ptr<DownPacket> duplicate(const PacketVariant& packet)
|
||||
{
|
||||
struct duplication_visitor : public boost::static_visitor<>
|
||||
{
|
||||
void operator()(const CohesivePacket& packet)
|
||||
{
|
||||
m_duplicate.reset(new ChunkPacket());
|
||||
for (auto layer : osi_layers) {
|
||||
const auto source = packet[layer];
|
||||
auto& dest = m_duplicate->layer(layer);
|
||||
dest = ByteBuffer(source.begin(), source.end());
|
||||
}
|
||||
}
|
||||
|
||||
void operator()(const ChunkPacket& packet)
|
||||
{
|
||||
m_duplicate = duplicate(packet);
|
||||
}
|
||||
|
||||
std::unique_ptr<ChunkPacket> m_duplicate;
|
||||
};
|
||||
|
||||
duplication_visitor visitor;
|
||||
boost::apply_visitor(visitor, packet);
|
||||
return std::move(visitor.m_duplicate);
|
||||
}
|
||||
|
||||
std::unique_ptr<DownPacket> duplicate(const DownPacket& packet)
|
||||
{
|
||||
return std::unique_ptr<DownPacket> { new DownPacket(packet) };
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef PACKETS_HPP_XB5AOPWE
|
||||
#define PACKETS_HPP_XB5AOPWE
|
||||
|
||||
#include <vanetza/net/packet_variant.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
using DownPacket = ChunkPacket;
|
||||
using UpPacket = PacketVariant;
|
||||
|
||||
/**
|
||||
* Create clone of a packet
|
||||
*/
|
||||
std::unique_ptr<DownPacket> duplicate(const DownPacket&);
|
||||
std::unique_ptr<DownPacket> duplicate(const UpPacket&);
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* PACKETS_HPP_XB5AOPWE */
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
#include "packet_variant.hpp"
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
byte_view_range create_byte_view(const ChunkPacket& packet, OsiLayer layer)
|
||||
{
|
||||
return create_byte_view(packet[layer]);
|
||||
}
|
||||
|
||||
byte_view_range create_byte_view(const CohesivePacket& packet, OsiLayer layer)
|
||||
{
|
||||
CohesivePacket::buffer_const_range range = packet[layer];
|
||||
return byte_view_range { range.begin(), range.end() };
|
||||
}
|
||||
|
||||
byte_view_range create_byte_view(const ChunkPacket& packet, OsiLayer from, OsiLayer to)
|
||||
{
|
||||
ByteBuffer buffer_range;
|
||||
for (auto layer : osi_layer_range(from, to)) {
|
||||
ByteBuffer buffer_layer;
|
||||
packet[layer].convert(buffer_layer); // convert clears passed buffer (does not append)
|
||||
buffer_range.insert(buffer_range.end(), buffer_layer.begin(), buffer_layer.end());
|
||||
}
|
||||
return create_byte_view(std::move(buffer_range));
|
||||
}
|
||||
|
||||
byte_view_range create_byte_view(const CohesivePacket& packet, OsiLayer from, OsiLayer to)
|
||||
{
|
||||
ByteBuffer::const_iterator from_begin = packet[from].begin();
|
||||
ByteBuffer::const_iterator to_end = packet[to].end();
|
||||
return byte_view_range(from_begin, to_end);
|
||||
}
|
||||
|
||||
|
||||
void serialize(OutputArchive& oa, const ChunkPacket& packet)
|
||||
{
|
||||
ByteBuffer buf;
|
||||
for (auto layer : osi_layers) {
|
||||
buf.clear();
|
||||
packet[layer].convert(buf);
|
||||
oa.save_binary(buf.data(), buf.size());
|
||||
}
|
||||
}
|
||||
|
||||
void serialize(OutputArchive& oa, const CohesivePacket& packet)
|
||||
{
|
||||
oa.save_binary(packet.buffer().data(), packet.buffer().size());
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
using namespace vanetza;
|
||||
|
||||
std::size_t size(const PacketVariant& packet, OsiLayer layer)
|
||||
{
|
||||
struct size_visitor : public boost::static_visitor<std::size_t>
|
||||
{
|
||||
size_visitor(OsiLayer layer) : m_layer(layer) {}
|
||||
|
||||
std::size_t operator()(const CohesivePacket& packet)
|
||||
{
|
||||
return size(packet, m_layer);
|
||||
}
|
||||
|
||||
std::size_t operator()(const ChunkPacket& packet)
|
||||
{
|
||||
return size(packet, m_layer);
|
||||
}
|
||||
|
||||
OsiLayer m_layer;
|
||||
};
|
||||
|
||||
size_visitor visitor(layer);
|
||||
return boost::apply_visitor(visitor, packet);
|
||||
}
|
||||
|
||||
std::size_t size(const PacketVariant& packet, OsiLayer from, OsiLayer to)
|
||||
{
|
||||
struct size_visitor : public boost::static_visitor<std::size_t>
|
||||
{
|
||||
size_visitor(OsiLayer from, OsiLayer to) : m_from(from), m_to(to) {}
|
||||
|
||||
std::size_t operator()(const CohesivePacket& packet)
|
||||
{
|
||||
return size(packet, m_from, m_to);
|
||||
}
|
||||
|
||||
std::size_t operator()(const ChunkPacket& packet)
|
||||
{
|
||||
return size(packet, m_from, m_to);
|
||||
}
|
||||
|
||||
OsiLayer m_from;
|
||||
OsiLayer m_to;
|
||||
};
|
||||
|
||||
size_visitor visitor(from, to);
|
||||
return boost::apply_visitor(visitor, packet);
|
||||
}
|
||||
|
||||
std::size_t size(const PacketVariant& packet)
|
||||
{
|
||||
struct size_visitor : public boost::static_visitor<std::size_t>
|
||||
{
|
||||
std::size_t operator()(const CohesivePacket& packet)
|
||||
{
|
||||
return packet.size();
|
||||
}
|
||||
|
||||
std::size_t operator()(const ChunkPacket& packet)
|
||||
{
|
||||
return packet.size();
|
||||
}
|
||||
};
|
||||
|
||||
size_visitor visitor;
|
||||
return boost::apply_visitor(visitor, packet);
|
||||
}
|
||||
|
||||
byte_view_range create_byte_view(const PacketVariant& packet, OsiLayer layer)
|
||||
{
|
||||
struct payload_visitor : public boost::static_visitor<byte_view_range>
|
||||
{
|
||||
payload_visitor(OsiLayer layer) : m_layer(layer) {}
|
||||
|
||||
byte_view_range operator()(const CohesivePacket& packet)
|
||||
{
|
||||
return create_byte_view(packet, m_layer);
|
||||
}
|
||||
|
||||
byte_view_range operator()(const ChunkPacket& packet)
|
||||
{
|
||||
return create_byte_view(packet, m_layer);
|
||||
}
|
||||
|
||||
OsiLayer m_layer;
|
||||
};
|
||||
|
||||
payload_visitor visitor(layer);
|
||||
return boost::apply_visitor(visitor, packet);
|
||||
}
|
||||
|
||||
byte_view_range create_byte_view(const PacketVariant& packet, OsiLayer from, OsiLayer to)
|
||||
{
|
||||
struct payload_visitor : public boost::static_visitor<byte_view_range>
|
||||
{
|
||||
payload_visitor(OsiLayer from, OsiLayer to) : m_from(from), m_to(to) {}
|
||||
|
||||
byte_view_range operator()(const CohesivePacket& packet)
|
||||
{
|
||||
return create_byte_view(packet, m_from, m_to);
|
||||
}
|
||||
|
||||
byte_view_range operator()(const ChunkPacket& packet)
|
||||
{
|
||||
return create_byte_view(packet, m_from, m_to);
|
||||
}
|
||||
|
||||
OsiLayer m_from;
|
||||
OsiLayer m_to;
|
||||
};
|
||||
|
||||
payload_visitor visitor(from, to);
|
||||
return boost::apply_visitor(visitor, packet);
|
||||
}
|
||||
|
||||
void serialize(OutputArchive& ar, const PacketVariant& packet)
|
||||
{
|
||||
struct serialize_visitor : public boost::static_visitor<>
|
||||
{
|
||||
serialize_visitor(OutputArchive& _oa) : oa(_oa) {}
|
||||
|
||||
void operator()(const ChunkPacket& packet)
|
||||
{
|
||||
serialize(oa, packet);
|
||||
}
|
||||
|
||||
void operator()(const CohesivePacket& packet)
|
||||
{
|
||||
serialize(oa, packet);
|
||||
}
|
||||
|
||||
OutputArchive& oa;
|
||||
};
|
||||
|
||||
serialize_visitor visitor(ar);
|
||||
boost::apply_visitor(visitor, packet);
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
@@ -0,0 +1,82 @@
|
||||
#ifndef PACKET_VARIANT_HPP_LILZ0UWN
|
||||
#define PACKET_VARIANT_HPP_LILZ0UWN
|
||||
|
||||
#include <vanetza/common/byte_view.hpp>
|
||||
#include <vanetza/common/serialization.hpp>
|
||||
#include <vanetza/net/chunk_packet.hpp>
|
||||
#include <vanetza/net/cohesive_packet.hpp>
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
using PacketVariant = boost::variant<ChunkPacket, CohesivePacket>;
|
||||
|
||||
inline std::size_t
|
||||
size(const CohesivePacket& packet, OsiLayer from, OsiLayer to)
|
||||
{
|
||||
return packet.size(from, to);
|
||||
}
|
||||
|
||||
inline std::size_t
|
||||
size(const CohesivePacket& packet, OsiLayer layer)
|
||||
{
|
||||
return packet.size(layer);
|
||||
}
|
||||
|
||||
inline std::size_t
|
||||
size(const ChunkPacket& packet, OsiLayer from, OsiLayer to)
|
||||
{
|
||||
return packet.size(from, to);
|
||||
}
|
||||
|
||||
inline std::size_t
|
||||
size(const ChunkPacket& packet, OsiLayer layer)
|
||||
{
|
||||
return packet[layer].size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a view of a packet's bytes assigned to a certain layer
|
||||
* \param packet
|
||||
* \param layer
|
||||
* \return a byte view, possibly empty
|
||||
*/
|
||||
byte_view_range create_byte_view(const ChunkPacket&, OsiLayer);
|
||||
byte_view_range create_byte_view(const CohesivePacket&, OsiLayer);
|
||||
|
||||
/**
|
||||
* Create a byte view for a sub-range of layers
|
||||
* \param packet
|
||||
* \param from first byte will be from this layer
|
||||
* \param to last byte will be from this layer
|
||||
* \return a byte view
|
||||
*/
|
||||
byte_view_range create_byte_view(const ChunkPacket& packet, OsiLayer from, OsiLayer to);
|
||||
byte_view_range create_byte_view(const CohesivePacket& packet, OsiLayer from, OsiLayer to);
|
||||
|
||||
/**
|
||||
* Serialize a whole packet from physical to application layer
|
||||
* \param archive destination archive
|
||||
* \param packet source packet
|
||||
*/
|
||||
void serialize(OutputArchive&, const ChunkPacket&);
|
||||
void serialize(OutputArchive&, const CohesivePacket&);
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// PacketVariant is only a type alias, so we need this quirk for proper name lookup
|
||||
std::size_t size(const vanetza::PacketVariant&, vanetza::OsiLayer from, vanetza::OsiLayer to);
|
||||
std::size_t size(const vanetza::PacketVariant&, vanetza::OsiLayer);
|
||||
std::size_t size(const vanetza::PacketVariant&);
|
||||
vanetza::byte_view_range create_byte_view(const vanetza::PacketVariant&, vanetza::OsiLayer);
|
||||
vanetza::byte_view_range create_byte_view(const vanetza::PacketVariant&, vanetza::OsiLayer from, vanetza::OsiLayer to);
|
||||
void serialize(vanetza::OutputArchive&, const vanetza::PacketVariant&);
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif /* PACKET_VARIANT_HPP_LILZ0UWN */
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "proxy_header.hpp"
|
||||
#include <vanetza/common/byte_order.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
double get_signal_power(const ProxyHeader& header)
|
||||
{
|
||||
double power = ntoh(header.signal_power);
|
||||
power /= 256.0;
|
||||
return power;
|
||||
}
|
||||
|
||||
void set_signal_power(ProxyHeader& header, double dbm)
|
||||
{
|
||||
auto power = static_cast<decltype(ProxyHeader::signal_power)>(dbm * 256.0);
|
||||
header.signal_power = hton(power);
|
||||
}
|
||||
|
||||
access::AccessCategory get_access_category(const ProxyHeader& header)
|
||||
{
|
||||
return static_cast<access::AccessCategory>(header.access_category & 0x07);
|
||||
}
|
||||
|
||||
void set_access_category(ProxyHeader& header, access::AccessCategory ac)
|
||||
{
|
||||
header.access_category = static_cast<uint8_t>(ac);
|
||||
}
|
||||
|
||||
boost::iterator_range<const uint8_t*> get_payload(const ProxyHeader& header, std::size_t size)
|
||||
{
|
||||
const auto payload_offset = ntoh(header.payload_offset);
|
||||
const auto payload_size = ntoh(header.payload_size);
|
||||
|
||||
assert(size >= payload_offset + payload_size);
|
||||
assert(payload_offset >= sizeof(ProxyHeader));
|
||||
|
||||
const uint8_t* begin = reinterpret_cast<const uint8_t*>(&header);
|
||||
const uint8_t* end = begin;
|
||||
|
||||
if (size >= payload_offset + payload_size) {
|
||||
begin += payload_offset;
|
||||
end = begin + payload_size;
|
||||
}
|
||||
|
||||
return boost::make_iterator_range(begin, end);
|
||||
}
|
||||
|
||||
void set_payload(ProxyHeader& header, std::size_t size)
|
||||
{
|
||||
header.payload_offset = hton<decltype(header.payload_offset)>(sizeof(ProxyHeader));
|
||||
header.payload_size = hton<decltype(header.payload_size)>(size);
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef PROXY_HEADER_HPP_JWTV3BDT
|
||||
#define PROXY_HEADER_HPP_JWTV3BDT
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <vanetza/access/access_category.hpp>
|
||||
#include <cstdint>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// GCC and Clang support packed attribute
|
||||
#define PACKED_STRUCT(name, block) struct name { block } __attribute__((__packed__));
|
||||
#else
|
||||
// MSVC variant
|
||||
#define PACKED_STRUCT(name, block) \
|
||||
__pragma(pack(push, 1)) \
|
||||
struct name { block }; \
|
||||
__pragma(pack(pop))
|
||||
#endif
|
||||
|
||||
PACKED_STRUCT(ProxyHeader,
|
||||
/** offset in bytes to payload's first byte, counting from packet start */
|
||||
uint16_t payload_offset;
|
||||
|
||||
/** length of payload in bytes */
|
||||
uint32_t payload_size;
|
||||
|
||||
/** signal power in dBm, fixed point format 8.8 = trunc(double * 256) */
|
||||
int16_t signal_power;
|
||||
|
||||
/** access category (transmission only) */
|
||||
uint8_t access_category;
|
||||
)
|
||||
|
||||
static_assert(sizeof(ProxyHeader) == 9, "ProxyHeader has invalid size");
|
||||
|
||||
double get_signal_power(const ProxyHeader&);
|
||||
void set_signal_power(ProxyHeader&, double dbm);
|
||||
access::AccessCategory get_access_category(const ProxyHeader&);
|
||||
void set_access_category(ProxyHeader&, access::AccessCategory);
|
||||
boost::iterator_range<const uint8_t*> get_payload(const ProxyHeader&, std::size_t);
|
||||
void set_payload(ProxyHeader&, std::size_t);
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* PROXY_HEADER_HPP_JWTV3BDT */
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "sockaddr.hpp"
|
||||
#include "mac_address.hpp"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <net/ethernet.h>
|
||||
#include <netpacket/packet.h>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
void assign(sockaddr_ll& sockaddr, const MacAddress& mac)
|
||||
{
|
||||
assert(ETHER_ADDR_LEN == mac.octets.size());
|
||||
std::copy_n(mac.octets.begin(), mac.octets.size(), sockaddr.sll_addr);
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef SOCKADDR_HPP_YPVTVXXP
|
||||
#define SOCKADDR_HPP_YPVTVXXP
|
||||
|
||||
struct sockaddr_ll;
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
class MacAddress;
|
||||
|
||||
void assign(sockaddr_ll&, const MacAddress&);
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif /* SOCKADDR_HPP_YPVTVXXP */
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef SOCKET_TRAITS_HPP_
|
||||
#define SOCKET_TRAITS_HPP_
|
||||
|
||||
#include <vanetza/net/osi_layer.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace vanetza
|
||||
{
|
||||
|
||||
template<typename SOCKET>
|
||||
struct socket_layers
|
||||
{
|
||||
static const OsiLayer min = SOCKET::min_layer;
|
||||
static const OsiLayer max = SOCKET::max_layer;
|
||||
|
||||
static_assert(min <= max, "Corrupt layer ordering");
|
||||
};
|
||||
|
||||
namespace pdu_tags
|
||||
{
|
||||
|
||||
struct pdu_tag {};
|
||||
struct empty_pdu_tag : public pdu_tag {};
|
||||
|
||||
struct phy_tag : public pdu_tag {};
|
||||
struct mk2_tag : public phy_tag {};
|
||||
|
||||
struct mac_tag : public pdu_tag {};
|
||||
struct ethernet_tag : public mac_tag {};
|
||||
|
||||
} // namespace pdu_tags
|
||||
|
||||
template<typename SOCKET, OsiLayer LAYER>
|
||||
struct socket_layer_pdu
|
||||
{
|
||||
typedef pdu_tags::empty_pdu_tag tag;
|
||||
};
|
||||
|
||||
template<OsiLayer LAYER, typename TAG, class SOCKET>
|
||||
bool constexpr pdu_match(const SOCKET&)
|
||||
{
|
||||
return std::is_same<TAG, typename socket_layer_pdu<SOCKET, LAYER>::tag>::value;
|
||||
}
|
||||
|
||||
} // namespace vanetza
|
||||
|
||||
#endif // SOCKET_TRAITS_HPP_
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
include(UseGTest)
|
||||
configure_gtest_directory(LINK_LIBRARIES net)
|
||||
|
||||
add_gtest(ChunkPacket chunk_packet.cpp)
|
||||
add_gtest(CohesivePacket cohesive_packet.cpp)
|
||||
add_gtest(MacAddress mac_address.cpp)
|
||||
add_gtest(OsiLayer osi_layer.cpp)
|
||||
|
||||
if(VANETZA_NET_WITH_POSIX)
|
||||
add_gtest(EthernetHeader ethernet_header.cpp)
|
||||
endif()
|
||||
@@ -0,0 +1,145 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/net/chunk_packet.hpp>
|
||||
|
||||
using vanetza::ByteBuffer;
|
||||
using vanetza::ChunkPacket;
|
||||
using vanetza::OsiLayer;
|
||||
|
||||
TEST(ChunkPacket, ctor)
|
||||
{
|
||||
ChunkPacket packet;
|
||||
EXPECT_EQ(0, packet.size());
|
||||
}
|
||||
|
||||
TEST(ChunkPacket, size_from_to)
|
||||
{
|
||||
ChunkPacket packet;
|
||||
packet[OsiLayer::Link] = ByteBuffer(8);
|
||||
packet[OsiLayer::Session] = ByteBuffer(19);
|
||||
packet[OsiLayer::Application] = ByteBuffer(5);
|
||||
|
||||
EXPECT_EQ(8, packet.size(OsiLayer::Link, OsiLayer::Link));
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Network, OsiLayer::Transport));
|
||||
EXPECT_EQ(27, packet.size(OsiLayer::Physical, OsiLayer::Session));
|
||||
EXPECT_EQ(24, packet.size(OsiLayer::Session, OsiLayer::Application));
|
||||
}
|
||||
|
||||
TEST(ChunkPacket, access)
|
||||
{
|
||||
const ByteBuffer data { 3, 8, 7, 5, 6 };
|
||||
ChunkPacket packet;
|
||||
packet[OsiLayer::Transport] = ByteBuffer { data };
|
||||
|
||||
EXPECT_EQ(data.size(), packet.size());
|
||||
EXPECT_EQ(data.size(), packet[OsiLayer::Transport].size());
|
||||
|
||||
ByteBuffer tmp;
|
||||
packet[OsiLayer::Transport].convert(tmp);
|
||||
EXPECT_EQ(data, tmp);
|
||||
}
|
||||
|
||||
TEST(ChunkPacket, copy)
|
||||
{
|
||||
ChunkPacket original;
|
||||
original[OsiLayer::Physical] = ByteBuffer(12);
|
||||
original[OsiLayer::Presentation] = ByteBuffer(34);
|
||||
|
||||
ChunkPacket copy { original };
|
||||
EXPECT_EQ(46, copy.size());
|
||||
EXPECT_EQ(12, copy[OsiLayer::Physical].size());
|
||||
EXPECT_EQ(34, copy[OsiLayer::Presentation].size());
|
||||
|
||||
ChunkPacket tmp;
|
||||
tmp = original;
|
||||
EXPECT_EQ(46, tmp.size());
|
||||
}
|
||||
|
||||
TEST(ChunkPacket, self_assignment)
|
||||
{
|
||||
ChunkPacket data;
|
||||
data[OsiLayer::Physical] = ByteBuffer(20);
|
||||
ASSERT_EQ(20, data.size());
|
||||
data = data;
|
||||
EXPECT_EQ(20, data.size());
|
||||
}
|
||||
|
||||
TEST(ChunkPacket, extract)
|
||||
{
|
||||
std::array<ByteBuffer, 5> buffer;
|
||||
for (unsigned i = 0; i < buffer.size(); ++i) {
|
||||
ByteBuffer tmp;
|
||||
tmp.resize(10, static_cast<ByteBuffer::value_type>(i));
|
||||
buffer[i] = std::move(tmp);
|
||||
}
|
||||
|
||||
ChunkPacket a;
|
||||
a[OsiLayer::Link] = ByteBuffer { buffer[0] };
|
||||
a[OsiLayer::Network] = ByteBuffer { buffer[1] };
|
||||
a[OsiLayer::Transport] = ByteBuffer { buffer[2] };
|
||||
a[OsiLayer::Session] = ByteBuffer { buffer[3] };
|
||||
a[OsiLayer::Application] = ByteBuffer { buffer[4] };
|
||||
EXPECT_EQ(50, a.size());
|
||||
|
||||
ChunkPacket b = a.extract(OsiLayer::Network, OsiLayer::Presentation);
|
||||
EXPECT_EQ(20, a.size());
|
||||
EXPECT_EQ(30, b.size());
|
||||
|
||||
ByteBuffer tmp;
|
||||
a[OsiLayer::Link].convert(tmp);
|
||||
EXPECT_EQ(buffer[0], tmp);
|
||||
a[OsiLayer::Application].convert(tmp);
|
||||
EXPECT_EQ(buffer[4], tmp);
|
||||
|
||||
b[OsiLayer::Network].convert(tmp);
|
||||
EXPECT_EQ(buffer[1], tmp);
|
||||
b[OsiLayer::Transport].convert(tmp);
|
||||
EXPECT_EQ(buffer[2], tmp);
|
||||
b[OsiLayer::Session].convert(tmp);
|
||||
EXPECT_EQ(buffer[3], tmp);
|
||||
}
|
||||
|
||||
TEST(ChunkPacket, merge)
|
||||
{
|
||||
std::array<ByteBuffer, 11> buffer;
|
||||
for (unsigned i = 0; i < buffer.size(); ++i) {
|
||||
ByteBuffer tmp;
|
||||
tmp.resize(10, static_cast<ByteBuffer::value_type>(i));
|
||||
buffer[i] = std::move(tmp);
|
||||
}
|
||||
|
||||
ChunkPacket a;
|
||||
a[OsiLayer::Physical] = ByteBuffer { buffer[0] };
|
||||
a[OsiLayer::Link] = ByteBuffer { buffer[1] };
|
||||
a[OsiLayer::Network] = ByteBuffer { buffer[2] };
|
||||
a[OsiLayer::Transport] = ByteBuffer { buffer[3] };
|
||||
a[OsiLayer::Session] = ByteBuffer { buffer[4] };
|
||||
a[OsiLayer::Application] = ByteBuffer { buffer[5] };
|
||||
ASSERT_EQ(60, a.size());
|
||||
|
||||
ChunkPacket b;
|
||||
b[OsiLayer::Physical] = ByteBuffer { buffer[6] };
|
||||
b[OsiLayer::Link] = ByteBuffer { buffer[7] };
|
||||
b[OsiLayer::Network] = ByteBuffer { buffer[8] };
|
||||
b[OsiLayer::Transport] = ByteBuffer { buffer[9] };
|
||||
b[OsiLayer::Application] = ByteBuffer { buffer[10] };
|
||||
ASSERT_EQ(50, b.size());
|
||||
|
||||
a.merge(b, OsiLayer::Link, OsiLayer::Presentation);
|
||||
EXPECT_EQ(50, a.size());
|
||||
|
||||
ByteBuffer tmp;
|
||||
a[OsiLayer::Physical].convert(tmp);
|
||||
EXPECT_EQ(buffer[0], tmp);
|
||||
a[OsiLayer::Link].convert(tmp);
|
||||
EXPECT_EQ(buffer[7], tmp);
|
||||
a[OsiLayer::Network].convert(tmp);
|
||||
EXPECT_EQ(buffer[8], tmp);
|
||||
a[OsiLayer::Transport].convert(tmp);
|
||||
EXPECT_EQ(buffer[9], tmp);
|
||||
a[OsiLayer::Session].convert(tmp);
|
||||
EXPECT_TRUE(tmp.empty());
|
||||
a[OsiLayer::Presentation].convert(tmp);
|
||||
EXPECT_TRUE(tmp.empty());
|
||||
a[OsiLayer::Application].convert(tmp);
|
||||
EXPECT_EQ(buffer[5], tmp);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/net/cohesive_packet.hpp>
|
||||
#include <vanetza/common/byte_buffer.hpp>
|
||||
|
||||
using vanetza::ByteBuffer;
|
||||
using vanetza::CohesivePacket;
|
||||
using vanetza::OsiLayer;
|
||||
|
||||
TEST(CohesivePacket, ctor_and_size)
|
||||
{
|
||||
const ByteBuffer buffer(892);
|
||||
CohesivePacket packet(buffer, OsiLayer::Transport);
|
||||
|
||||
EXPECT_EQ(892, packet.size());
|
||||
EXPECT_EQ(892, packet.size(OsiLayer::Transport));
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Network));
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Session));
|
||||
}
|
||||
|
||||
TEST(CohesivePacket, set_boundary)
|
||||
{
|
||||
CohesivePacket packet(ByteBuffer(512), OsiLayer::Link);
|
||||
ASSERT_EQ(512, packet.size(OsiLayer::Link));
|
||||
|
||||
packet.set_boundary(OsiLayer::Link, 64);
|
||||
EXPECT_EQ(64, packet.size(OsiLayer::Link));
|
||||
EXPECT_EQ(512, packet.size());
|
||||
|
||||
ASSERT_EQ(448, packet.size(OsiLayer::Network));
|
||||
packet.set_boundary(OsiLayer::Network, 128);
|
||||
EXPECT_EQ(128, packet.size(OsiLayer::Network));
|
||||
|
||||
ASSERT_EQ(320, packet.size(OsiLayer::Transport));
|
||||
packet.set_boundary(OsiLayer::Transport, 0);
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Transport));
|
||||
EXPECT_EQ(320, packet.size(OsiLayer::Session));
|
||||
EXPECT_EQ(512, packet.size());
|
||||
|
||||
EXPECT_EQ(448, packet.size(OsiLayer::Network, OsiLayer::Application));
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Application, OsiLayer::Network));
|
||||
}
|
||||
|
||||
TEST(CohesivePacket, access)
|
||||
{
|
||||
ByteBuffer buffer;
|
||||
for (unsigned i = 0; i < 512; ++i) {
|
||||
buffer.push_back(i);
|
||||
}
|
||||
CohesivePacket packet(buffer, OsiLayer::Network);
|
||||
|
||||
auto net_range = packet[OsiLayer::Network];
|
||||
ASSERT_EQ(512, net_range.size());
|
||||
|
||||
packet.set_boundary(OsiLayer::Network, 128);
|
||||
auto transport_range = packet[OsiLayer::Transport];
|
||||
ASSERT_EQ(384, transport_range.size());
|
||||
|
||||
ByteBuffer::value_type expected_byte = 128;
|
||||
for (auto byte : transport_range) {
|
||||
EXPECT_EQ(expected_byte, byte);
|
||||
++expected_byte;
|
||||
}
|
||||
}
|
||||
|
||||
TEST(CohesivePacket, trim_simple_boundaries)
|
||||
{
|
||||
CohesivePacket packet(ByteBuffer(128), OsiLayer::Link);
|
||||
EXPECT_EQ(128, packet.size());
|
||||
packet.trim(OsiLayer::Physical, 100);
|
||||
EXPECT_EQ(100, packet.size());
|
||||
packet.trim(OsiLayer::Physical, 130);
|
||||
EXPECT_EQ(100, packet.size());
|
||||
}
|
||||
|
||||
TEST(CohesivePacket, trim_advanced_boundaries)
|
||||
{
|
||||
CohesivePacket packet(ByteBuffer(128), OsiLayer::Link);
|
||||
packet.set_boundary(OsiLayer::Link, 12);
|
||||
packet.set_boundary(OsiLayer::Network, 0);
|
||||
packet.set_boundary(OsiLayer::Transport, 24);
|
||||
packet.set_boundary(OsiLayer::Session, 48);
|
||||
EXPECT_EQ(128, packet.size(OsiLayer::Link, OsiLayer::Presentation));
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Physical));
|
||||
EXPECT_EQ(12, packet.size(OsiLayer::Link));
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Network));
|
||||
EXPECT_EQ(24, packet.size(OsiLayer::Transport));
|
||||
EXPECT_EQ(48, packet.size(OsiLayer::Session));
|
||||
EXPECT_EQ(44, packet.size(OsiLayer::Presentation));
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Application));
|
||||
|
||||
packet.trim(OsiLayer::Network, 24 + 48 + 20);
|
||||
EXPECT_EQ(24 + 48 + 20, packet.size(OsiLayer::Network, OsiLayer::Application));
|
||||
EXPECT_EQ(104, packet.size());
|
||||
|
||||
packet.trim(OsiLayer::Network, 24 + 8);
|
||||
EXPECT_EQ(44, packet.size());
|
||||
EXPECT_EQ(24, packet.size(OsiLayer::Transport));
|
||||
EXPECT_EQ(8, packet.size(OsiLayer::Session));
|
||||
EXPECT_EQ(0, packet.size(OsiLayer::Presentation, OsiLayer::Application));
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/common/byte_order.hpp>
|
||||
#include <vanetza/net/ethernet_header.hpp>
|
||||
#include <vanetza/net/mac_address.hpp>
|
||||
|
||||
using namespace vanetza;
|
||||
|
||||
TEST(EthernetHeader, create) {
|
||||
MacAddress dest = { 0x12, 0x34, 0x01, 0x47, 0x43, 0x43 };
|
||||
MacAddress src = { 0xfa, 0xbc, 0x8d, 0x43, 0xcb, 0x00 };
|
||||
|
||||
ByteBuffer header = create_ethernet_header(dest, src, host_cast<uint16_t>(0x3773));
|
||||
ByteBuffer expected = { 0x12, 0x34, 0x01, 0x47, 0x43, 0x43, 0xfa, 0xbc, 0x8d, 0x43, 0xcb, 0x00, 0x37, 0x73 };
|
||||
EXPECT_EQ(expected, header);
|
||||
}
|
||||
|
||||
TEST(EthernetHeader, length) {
|
||||
// magic constants are okay in unit tests
|
||||
EXPECT_EQ(14, ethernet_header_length());
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/net/mac_address.hpp>
|
||||
#include <sstream>
|
||||
|
||||
using namespace vanetza;
|
||||
|
||||
TEST(MacAddress, ctor) {
|
||||
MacAddress empty;
|
||||
EXPECT_EQ(empty.octets.size(), 6);
|
||||
for (uint8_t octet : empty.octets) {
|
||||
EXPECT_EQ(octet, 0x00);
|
||||
}
|
||||
|
||||
MacAddress init = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
|
||||
EXPECT_EQ(init.octets[0], 0x01);
|
||||
EXPECT_EQ(init.octets[1], 0x02);
|
||||
EXPECT_EQ(init.octets[2], 0x03);
|
||||
EXPECT_EQ(init.octets[3], 0x04);
|
||||
EXPECT_EQ(init.octets[4], 0x05);
|
||||
EXPECT_EQ(init.octets[5], 0x06);
|
||||
}
|
||||
|
||||
TEST(MacAddress, equality) {
|
||||
MacAddress a = { 1, 2, 3, 4, 5, 6 };
|
||||
MacAddress b = { 1, 2, 3, 4, 5, 7 };
|
||||
MacAddress c = { 0, 2, 3, 4, 5, 6 };
|
||||
MacAddress d = { 0, 2, 3, 4, 5, 6 };
|
||||
EXPECT_NE(a, b);
|
||||
EXPECT_NE(b, a);
|
||||
EXPECT_NE(a, c);
|
||||
EXPECT_NE(b, c);
|
||||
EXPECT_EQ(a, a);
|
||||
EXPECT_EQ(c, d);
|
||||
}
|
||||
|
||||
TEST(MacAddress, less) {
|
||||
MacAddress a = { 1, 2, 3, 4, 5, 6};
|
||||
MacAddress b = { 1, 2, 4, 4, 5, 6};
|
||||
MacAddress c = { 250, 0, 0, 0, 0, 0};
|
||||
MacAddress d = { 0, 2, 3, 4, 5, 6};
|
||||
MacAddress e = { 1, 2, 3, 4, 5, 5};
|
||||
EXPECT_LT(a, b);
|
||||
EXPECT_LT(a, b);
|
||||
EXPECT_LT(d, e);
|
||||
EXPECT_LT(e, a);
|
||||
EXPECT_LT(c, d);
|
||||
EXPECT_GT(b, a);
|
||||
}
|
||||
|
||||
TEST(MacAddress, ostream) {
|
||||
MacAddress mac = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 };
|
||||
std::stringstream sout;
|
||||
sout << mac;
|
||||
EXPECT_EQ(sout.str(), "01:02:03:04:05:06");
|
||||
}
|
||||
|
||||
TEST(MacAddress, parse) {
|
||||
MacAddress result;
|
||||
|
||||
ASSERT_TRUE(!!parse_mac_address("01:02:03:04:05:06", result));
|
||||
EXPECT_EQ(MacAddress({1, 2, 3, 4, 5, 6}), result);
|
||||
EXPECT_TRUE(!!parse_mac_address("01:02:03:04:05:06"));
|
||||
|
||||
EXPECT_FALSE(!!parse_mac_address(":::::0102040506", result));
|
||||
EXPECT_FALSE(!!parse_mac_address("foobarfoobarfoob", result));
|
||||
EXPECT_FALSE(!!parse_mac_address("01:02:03:04:05", result));
|
||||
EXPECT_FALSE(!!parse_mac_address("01:02:03:04:05:06:07", result));
|
||||
}
|
||||
|
||||
TEST(MacAddress, create) {
|
||||
MacAddress a = create_mac_address(static_cast<uint32_t>(0x12345678));
|
||||
EXPECT_EQ(a, MacAddress({0x12, 0x34, 0x56, 0x78, 0x00, 0x00}));
|
||||
|
||||
MacAddress b = create_mac_address(static_cast<uint64_t>(0x1234567890abcdef));
|
||||
EXPECT_EQ(b, MacAddress({0x56, 0x78, 0x90, 0xab, 0xcd, 0xef}));
|
||||
|
||||
MacAddress c = create_mac_address(static_cast<uint32_t>(0x1234));
|
||||
EXPECT_EQ(c, MacAddress({0x00, 0x00, 0x12, 0x34, 0x00, 0x00}));
|
||||
|
||||
MacAddress d = create_mac_address(static_cast<uint16_t>(0x2156));
|
||||
EXPECT_EQ(d, MacAddress({0x21, 0x56, 0x00, 0x00, 0x00, 0x00}));
|
||||
}
|
||||
|
||||
TEST(MacAddress, hash) {
|
||||
std::hash<MacAddress> hash_fn;
|
||||
|
||||
MacAddress a, b;
|
||||
EXPECT_EQ(hash_fn(a), hash_fn(b));
|
||||
|
||||
MacAddress c = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
EXPECT_NE(hash_fn(a), hash_fn(c));
|
||||
|
||||
MacAddress d = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 };
|
||||
EXPECT_NE(hash_fn(a), hash_fn(d));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <vanetza/net/osi_layer.hpp>
|
||||
|
||||
using namespace vanetza;
|
||||
|
||||
TEST(OsiLayer, ordering) {
|
||||
EXPECT_LT(OsiLayer::Physical, OsiLayer::Link);
|
||||
EXPECT_LT(OsiLayer::Link, OsiLayer::Network);
|
||||
EXPECT_LT(OsiLayer::Network, OsiLayer::Transport);
|
||||
EXPECT_LT(OsiLayer::Transport, OsiLayer::Session);
|
||||
EXPECT_LT(OsiLayer::Session, OsiLayer::Presentation);
|
||||
EXPECT_LT(OsiLayer::Presentation, OsiLayer::Application);
|
||||
|
||||
EXPECT_EQ(min_osi_layer(), OsiLayer::Physical);
|
||||
EXPECT_EQ(max_osi_layer(), OsiLayer::Application);
|
||||
}
|
||||
|
||||
TEST(OsiLayer, comparison) {
|
||||
EXPECT_LT(OsiLayer::Physical, OsiLayer::Link);
|
||||
EXPECT_GT(OsiLayer::Link, OsiLayer::Physical);
|
||||
EXPECT_EQ(OsiLayer::Physical, OsiLayer::Physical);
|
||||
EXPECT_NE(OsiLayer::Physical, OsiLayer::Link);
|
||||
EXPECT_LE(OsiLayer::Physical, OsiLayer::Physical);
|
||||
EXPECT_GE(OsiLayer::Link, OsiLayer::Link);
|
||||
}
|
||||
|
||||
TEST(OsiLayer, list) {
|
||||
auto list = osi_layers;
|
||||
ASSERT_EQ(list.size(), 7);
|
||||
|
||||
auto it = list.begin();
|
||||
EXPECT_EQ(OsiLayer::Physical, *it++);
|
||||
EXPECT_EQ(OsiLayer::Link, *it++);
|
||||
EXPECT_EQ(OsiLayer::Network, *it++);
|
||||
EXPECT_EQ(OsiLayer::Transport, *it++);
|
||||
EXPECT_EQ(OsiLayer::Session, *it++);
|
||||
EXPECT_EQ(OsiLayer::Presentation, *it++);
|
||||
EXPECT_EQ(OsiLayer::Application, *it++);
|
||||
EXPECT_EQ(list.end(), it);
|
||||
|
||||
auto prev = list.begin();
|
||||
for (it = prev + 1; it != list.end(); prev = it, ++it) {
|
||||
EXPECT_LT(*prev, *it);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(OsiLayer, num) {
|
||||
EXPECT_EQ(7, num_osi_layers(min_osi_layer(), max_osi_layer()));
|
||||
EXPECT_EQ(1, num_osi_layers(OsiLayer::Link, OsiLayer::Link));
|
||||
EXPECT_EQ(2, num_osi_layers(OsiLayer::Link, OsiLayer::Network));
|
||||
EXPECT_EQ(0, num_osi_layers(OsiLayer::Network, OsiLayer::Link));
|
||||
}
|
||||
|
||||
TEST(OsiLayer, distance) {
|
||||
EXPECT_EQ(0, distance(OsiLayer::Session, OsiLayer::Session));
|
||||
EXPECT_EQ(1, distance(OsiLayer::Network, OsiLayer::Transport));
|
||||
EXPECT_EQ(-1, distance(OsiLayer::Transport, OsiLayer::Network));
|
||||
EXPECT_EQ(num_osi_layers(min_osi_layer(), max_osi_layer()) - 1,
|
||||
distance(min_osi_layer(), max_osi_layer()));
|
||||
}
|
||||
|
||||
TEST(OsiLayer, compile_time_range) {
|
||||
const auto r1_ref = osi_layers;
|
||||
ASSERT_EQ(7, r1_ref.size());
|
||||
auto r1 = osi_layer_range<min_osi_layer(), max_osi_layer()>();
|
||||
EXPECT_EQ(r1_ref.size(), r1.size());
|
||||
for (unsigned i = 0; i < r1.size(); ++i) {
|
||||
EXPECT_EQ(r1_ref[i], r1[i]);
|
||||
}
|
||||
|
||||
auto r2 = osi_layer_range<OsiLayer::Link, OsiLayer::Transport>();
|
||||
ASSERT_EQ(3, r2.size());
|
||||
EXPECT_EQ(OsiLayer::Link, r2[0]);
|
||||
EXPECT_EQ(OsiLayer::Network, r2[1]);
|
||||
EXPECT_EQ(OsiLayer::Transport, r2[2]);
|
||||
|
||||
auto r3 = osi_layer_range<OsiLayer::Application, OsiLayer::Application>();
|
||||
EXPECT_EQ(1, r3.size());
|
||||
}
|
||||
|
||||
TEST(OsiLayer, run_time_range) {
|
||||
const auto r1_ref = osi_layers;
|
||||
ASSERT_EQ(7, r1_ref.size());
|
||||
auto r1 = osi_layer_range(min_osi_layer(), max_osi_layer());
|
||||
EXPECT_EQ(r1_ref.size(), r1.size());
|
||||
for (unsigned i = 0; i < r1.size(); ++i) {
|
||||
EXPECT_EQ(r1_ref[i], r1[i]);
|
||||
}
|
||||
|
||||
auto r2 = osi_layer_range(OsiLayer::Link, OsiLayer::Transport);
|
||||
ASSERT_EQ(3, r2.size());
|
||||
EXPECT_EQ(OsiLayer::Link, r2[0]);
|
||||
EXPECT_EQ(OsiLayer::Network, r2[1]);
|
||||
EXPECT_EQ(OsiLayer::Transport, r2[2]);
|
||||
|
||||
auto r3 = osi_layer_range(OsiLayer::Application, OsiLayer::Application);
|
||||
ASSERT_EQ(1, r3.size());
|
||||
EXPECT_EQ(OsiLayer::Application, r3[0]);
|
||||
|
||||
auto r4 = osi_layer_range(OsiLayer::Application, OsiLayer::Transport);
|
||||
EXPECT_EQ(0, r4.size());
|
||||
}
|
||||
Reference in New Issue
Block a user