Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions tests/test_arp.cxx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#include <gtest/gtest.h>
#include "vbvx/header_view.hxx"
#include "vbvx/auto_swap.hxx"

#include "vbvx/arp.hxx"
#include "vbvx/ether.hxx"

#include <array>
#include <cstring>
Expand Down
7 changes: 4 additions & 3 deletions tests/test_buffer_view.cxx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include "buffer_view.hxx"
#include "auto_swap.hxx"
#include "utils.hxx"

#include <array>
#include <bit>
Expand Down Expand Up @@ -192,7 +192,8 @@ TEST(BufferViewTest, IPv4UdpHeaderPresent) {
}

TEST(BufferViewTest, IPv6Icmpv6) {
const auto total = sizeof(vbvx::EtherHeader) + 40 + sizeof(vbvx::ICMPHeader);
const auto total =
sizeof(vbvx::EtherHeader) + 40 + sizeof(vbvx::ICMPv4Header);
std::vector<uint8_t> buf_bytes(total);
std::memset(buf_bytes.data(), 0, buf_bytes.size());

Expand All @@ -206,7 +207,7 @@ TEST(BufferViewTest, IPv6Icmpv6) {
// next_header field is at offset 6 within the IPv6 header
buf_bytes[ip_off + 6] = static_cast<uint8_t>(IpProtocol::ICMPv6);

ICMPHeader icmp{};
ICMPv4Header icmp{};
icmp.type = static_cast<uint8_t>(ICMPv4Type::EchoRequest);
icmp.code = 0;
icmp.set_checksum(0x1234);
Expand Down
2 changes: 1 addition & 1 deletion tests/test_header_view.cxx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include "header_view.hxx"
#include "auto_swap.hxx"
#include "utils.hxx"

#include "vbvx/ether.hxx"
#include "vbvx/arp.hxx"
Expand Down
18 changes: 9 additions & 9 deletions tests/test_icmp4.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ using enum ICMPv4Type;

class IcmpHeaderBytesFixture : public ::testing::Test {
protected:
ICMPHeader tmp{};
std::array<uint8_t, sizeof(ICMPHeader)> raw{};
ICMPv4Header tmp{};
std::array<uint8_t, sizeof(ICMPv4Header)> raw{};

void SetUp() override {
tmp.type = static_cast<uint8_t>(EchoRequest);
Expand All @@ -18,13 +18,13 @@ class IcmpHeaderBytesFixture : public ::testing::Test {
std::memcpy(raw.data(), &tmp, sizeof(tmp));
}

HeaderView<ICMPHeader> hv_view() const {
return HeaderView<ICMPHeader>(raw.data());
HeaderView<ICMPv4Header> hv_view() const {
return HeaderView<ICMPv4Header>(raw.data());
}
};

TEST(IcmpTypeTest, KnownTypes) {
ICMPHeader h{};
ICMPv4Header h{};

h.type = 0;
ASSERT_TRUE(h.type_known().has_value());
Expand Down Expand Up @@ -64,7 +64,7 @@ TEST(IcmpTypeTest, KnownTypes) {
}

TEST(IcmpTypeTest, UnassignedReturnsNullopt) {
ICMPHeader h{};
ICMPv4Header h{};
h.type = 7; // unassigned
EXPECT_FALSE(h.type_known().has_value());

Expand All @@ -73,9 +73,9 @@ TEST(IcmpTypeTest, UnassignedReturnsNullopt) {
}

TEST(IcmpHeaderTest, LayoutAndAlignment) {
static_assert(sizeof(ICMPHeader) == 4, "Wrong ICMP header size");
EXPECT_EQ(sizeof(ICMPHeader), 4u);
EXPECT_EQ(alignof(ICMPHeader), 1u);
static_assert(sizeof(ICMPv4Header) == 4, "Wrong ICMP header size");
EXPECT_EQ(sizeof(ICMPv4Header), 4u);
EXPECT_EQ(alignof(ICMPv4Header), 1u);
}

TEST_F(IcmpHeaderBytesFixture, HeaderFieldsParsed) {
Expand Down
2 changes: 1 addition & 1 deletion tests/test_ip4_header.cxx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include "header_view.hxx"
#include "auto_swap.hxx"
#include "utils.hxx"
#include "vbvx/ip4_header.hxx"

#include <array>
Expand Down
2 changes: 1 addition & 1 deletion tests/test_ip6_header.cxx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <gtest/gtest.h>

#include "header_view.hxx"
#include "auto_swap.hxx"
#include "utils.hxx"
#include "buffer_view.hxx"
#include "vbvx/ether.hxx"
#include "vbvx/ip_protocol.hxx"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_tcp_header.cxx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#include <gtest/gtest.h>
#include "buffer_view.hxx"
#include "auto_swap.hxx"
#include "utils.hxx"
#include "vbvx/ether.hxx"
#include "vbvx/ip4_header.hxx"
#include "vbvx/tcp_header.hxx"
Expand Down
2 changes: 1 addition & 1 deletion tests/test_udp_header.cxx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include <gtest/gtest.h>
#include "vbvx/udp_header.hxx"
#include "buffer_view.hxx"
#include "auto_swap.hxx"
#include "utils.hxx"
#include "vbvx/ether.hxx"
#include "vbvx/ip4_header.hxx"

Expand Down
8 changes: 3 additions & 5 deletions vbvx/arp.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
#include <span>
#include <cstring>

#include "auto_swap.hxx"
#include "utils.hxx"
#include "ether.hxx"

namespace vbvx {
Expand Down Expand Up @@ -64,13 +64,11 @@ struct [[gnu::packed]] ArpHeader {
}

constexpr auto sender_ipv4_host() const noexcept -> uint32_t {
std::array<uint8_t, 4> a{spa[0], spa[1], spa[2], spa[3]};
return autoswap(std::bit_cast<uint32_t>(a));
return autoswap(read_from_bytes<uint32_t>(spa));
}

constexpr auto target_ipv4_host() const noexcept -> uint32_t {
std::array<uint8_t, 4> a{tpa[0], tpa[1], tpa[2], tpa[3]};
return autoswap(std::bit_cast<uint32_t>(a));
return autoswap(read_from_bytes<uint32_t>(tpa));
}

constexpr void set_opcode(ArpOpCode code) noexcept {
Expand Down
16 changes: 0 additions & 16 deletions vbvx/auto_swap.hxx

This file was deleted.

40 changes: 26 additions & 14 deletions vbvx/buffer_view.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "arp.hxx"
#include "ether.hxx"
#include "icmp4.hxx"
#include "icmp6.hxx"
#include "ip_protocol.hxx"
#include "ip4_header.hxx"
#include "ip6_header.hxx"
Expand All @@ -31,19 +32,23 @@ public:
constexpr BufferView(const void* data, uint16_t length) noexcept
: data_{static_cast<const buffer_t*>(data)}, length_{length} {}

/** @brief Get the underlying buffer data as a span. */
constexpr auto data() const noexcept -> std::span<const buffer_t> {
if (!data_) {
return {};
}
return {data_, length_};
}

/** @brief Get the length of the buffer. */
constexpr auto length() const noexcept -> uint16_t { return length_; }

/** @brief Get Ethernet header view. */
constexpr auto ether_header() const noexcept -> HeaderView<EtherHeader> {
return header_at<EtherHeader>(0);
}

/** @brief Get the EtherType of the packet for possible VLAN tag. */
constexpr auto ether_type() const noexcept -> std::optional<EtherType> {
auto eth = ether_header();
if (!eth) {
Expand All @@ -62,6 +67,7 @@ public:
return static_cast<EtherType>(type);
}

/** @brief Get VLAN header view. */
constexpr auto vlan_header() const noexcept -> HeaderView<VlanHeader> {
auto eth = ether_header();
if (!eth) {
Expand All @@ -76,6 +82,7 @@ public:
return header_at<VlanHeader>(sizeof(EtherHeader));
}

/** @brief Get VLAN ID if VLAN tag is present. */
constexpr auto vlan_id() const noexcept -> std::optional<uint16_t> {
auto vlan = vlan_header();
if (!vlan) {
Expand All @@ -84,6 +91,7 @@ public:
return static_cast<uint16_t>(vlan->tci() & 0x0FFFu);
}

/** @brief Get the offset of the Layer 3 header. */
constexpr auto l3_offset() const noexcept -> uint16_t {
auto eth = ether_header();
if (!eth) {
Expand All @@ -95,6 +103,7 @@ public:
: static_cast<uint16_t>(sizeof(EtherHeader));
}

/** @brief Get ARP header view. */
constexpr auto arp_header() const noexcept -> HeaderView<ArpHeader> {
auto et = ether_type();
if (!et || *et != EtherType::ARP) {
Expand All @@ -103,6 +112,7 @@ public:
return header_at<ArpHeader>(l3_offset());
}

/** @brief Get IPv4 header view. */
constexpr auto ip4_header() const noexcept -> HeaderView<IPv4Header> {
auto et = ether_type();
if (!et || *et != EtherType::IPv4) {
Expand All @@ -111,6 +121,7 @@ public:
return header_at<IPv4Header>(l3_offset());
}

/** @brief Get IPv6 header view. */
constexpr auto ip6_header() const noexcept -> HeaderView<IPv6Header> {
auto et = ether_type();
if (!et || *et != EtherType::IPv6) {
Expand All @@ -119,6 +130,7 @@ public:
return header_at<IPv6Header>(l3_offset());
}

/** @brief Get the number of bytes in the IPv4 header. */
constexpr auto ip4_ihl_bytes() const noexcept -> std::optional<uint8_t> {
auto ip = ip4_header();
if (!ip) {
Expand All @@ -132,6 +144,7 @@ public:
return bytes;
}

/** @brief Get the IP protocol (IPv4 or IPv6). */
constexpr auto ip_protocol() const noexcept -> std::optional<IpProtocol> {
if (auto ip4 = ip4_header()) {
return static_cast<IpProtocol>(ip4->protocol);
Expand All @@ -142,6 +155,7 @@ public:
return std::nullopt;
}

/** @brief Get the offset of the Layer 4 header. */
constexpr auto l4_offset() const noexcept -> std::optional<uint16_t> {
if (ip4_header()) {
auto ihl = ip4_ihl_bytes();
Expand All @@ -156,6 +170,7 @@ public:
return std::nullopt;
}

/** @brief Get TCP header view. */
constexpr auto tcp_header() const noexcept -> HeaderView<TCPHeader> {
auto proto = ip_protocol();
auto off = l4_offset();
Expand All @@ -168,6 +183,7 @@ public:
return header_at<TCPHeader>(*off);
}

/** @brief Get UDP header view. */
constexpr auto udp_header() const noexcept -> HeaderView<UDPHeader> {
auto proto = ip_protocol();
auto off = l4_offset();
Expand All @@ -180,33 +196,29 @@ public:
return header_at<UDPHeader>(*off);
}

constexpr auto icmp4_header() const noexcept -> HeaderView<ICMPHeader> {
/** @brief Get ICMPv4 header view. */
constexpr auto icmp4_header() const noexcept -> HeaderView<ICMPv4Header> {
auto proto = ip_protocol();
auto off = l4_offset();
if (!proto || !off) {
return {};
}
if (*proto != IpProtocol::ICMP && *proto != IpProtocol::ICMPv6) {
if (!proto || !off || *proto != IpProtocol::ICMPv4) {
return {};
}
return header_at<ICMPHeader>(*off);

return header_at<ICMPv4Header>(*off);
}

constexpr auto icmp6_header() const noexcept -> HeaderView<ICMPHeader> {
/** @brief Get ICMPv6 header view. */
constexpr auto icmp6_header() const noexcept -> HeaderView<ICMPv6Header> {
auto proto = ip_protocol();
auto off = l4_offset();
if (!proto || !off || *proto != IpProtocol::ICMPv6) {
return {};
}
return header_at<ICMPHeader>(*off);

return header_at<ICMPv6Header>(*off);
}

/**
* @brief Get SRv6 Header view if present.
*
* @return HeaderView<SRv6Header> if SRv6 header is present, empty optional
* otherwise.
*/
/** @brief Get SRv6 Header view if present. */
constexpr auto srv6_header() const noexcept -> HeaderView<SRv6Header> {
auto ip6 = ip6_header();
if (!ip6) {
Expand Down
2 changes: 1 addition & 1 deletion vbvx/ether.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <cstdint>
#include <span>

#include "auto_swap.hxx"
#include "utils.hxx"

namespace vbvx {

Expand Down
11 changes: 7 additions & 4 deletions vbvx/flags_view.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,22 @@ namespace vbvx {
* Specialize this template for your enum to enable the bitwise operators.
*
* Example:
* enum class MyFlags : uint8_t {
* @code
* enum class MyFlags : uint8_t {
* FlagA = 0x01,
* FlagB = 0x02,
* FlagC = 0x04
* };
*
* template <>
* struct enable_bitmask_operators<MyFlags> : std::true_type {};
* @endcode
*/
template <typename T> struct enable_bitmask_operators : std::false_type {};
template <typename _Tp> struct enable_bitmask_operators : std::false_type {};

template <typename T>
constexpr bool enable_bitmask_operators_v = enable_bitmask_operators<T>::value;
template <typename _Tp>
constexpr bool enable_bitmask_operators_v =
enable_bitmask_operators<_Tp>::value;

template <typename E>
requires enable_bitmask_operators_v<E>
Expand Down
6 changes: 3 additions & 3 deletions vbvx/header_view.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

namespace vbvx {

template <typename T>
concept WireHeader = std::is_trivially_copyable_v<T> &&
std::is_standard_layout_v<T> && (alignof(T) == 1);
template <typename _Tp>
concept WireHeader = std::is_trivially_copyable_v<_Tp> &&
std::is_standard_layout_v<_Tp> && (alignof(_Tp) == 1);

/**
* @brief A lightweight view over a header inside a packet buffer.
Expand Down
Loading