mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-24 14:49:42 -06:00
Merge pull request #10690 from schthack/BBA-tapless
BBA: Added BuiltIn device that allow BBA emulation without the need o…
This commit is contained in:
@ -5,6 +5,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <netinet/in.h>
|
||||
@ -16,6 +17,7 @@
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "Common/BitUtils.h"
|
||||
#include "Common/Random.h"
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
@ -113,6 +115,11 @@ u16 IPv4Header::Size() const
|
||||
return static_cast<u16>(SIZE);
|
||||
}
|
||||
|
||||
u8 IPv4Header::DefinedSize() const
|
||||
{
|
||||
return (version_ihl & 0xf) * 4;
|
||||
}
|
||||
|
||||
TCPHeader::TCPHeader() = default;
|
||||
|
||||
TCPHeader::TCPHeader(const sockaddr_in& from, const sockaddr_in& to, u32 seq, const u8* data,
|
||||
@ -141,6 +148,23 @@ TCPHeader::TCPHeader(const sockaddr_in& from, const sockaddr_in& to, u32 seq, co
|
||||
checksum = htons(static_cast<u16>(tcp_checksum));
|
||||
}
|
||||
|
||||
TCPHeader::TCPHeader(const sockaddr_in& from, const sockaddr_in& to, u32 seq, u32 ack, u16 flags)
|
||||
{
|
||||
source_port = from.sin_port;
|
||||
destination_port = to.sin_port;
|
||||
sequence_number = htonl(seq);
|
||||
acknowledgement_number = htonl(ack);
|
||||
properties = htons(flags);
|
||||
|
||||
window_size = 0x7c;
|
||||
checksum = 0;
|
||||
}
|
||||
|
||||
u8 TCPHeader::GetHeaderSize() const
|
||||
{
|
||||
return (ntohs(properties) & 0xf000) >> 10;
|
||||
}
|
||||
|
||||
u16 TCPHeader::Size() const
|
||||
{
|
||||
return static_cast<u16>(SIZE);
|
||||
@ -170,6 +194,92 @@ u8 UDPHeader::IPProto() const
|
||||
return static_cast<u8>(IPPROTO_UDP);
|
||||
}
|
||||
|
||||
ARPHeader::ARPHeader() = default;
|
||||
|
||||
ARPHeader::ARPHeader(u32 from_ip, const MACAddress& from_mac, u32 to_ip, const MACAddress& to_mac)
|
||||
{
|
||||
hardware_type = htons(BBA_HARDWARE_TYPE);
|
||||
protocol_type = IPV4_HEADER_TYPE;
|
||||
hardware_size = MAC_ADDRESS_SIZE;
|
||||
protocol_size = IPV4_ADDR_LEN;
|
||||
opcode = 0x200;
|
||||
sender_ip = from_ip;
|
||||
target_ip = to_ip;
|
||||
targer_address = to_mac;
|
||||
sender_address = from_mac;
|
||||
}
|
||||
|
||||
u16 ARPHeader::Size() const
|
||||
{
|
||||
return static_cast<u16>(SIZE);
|
||||
}
|
||||
|
||||
DHCPBody::DHCPBody() = default;
|
||||
|
||||
DHCPBody::DHCPBody(u32 transaction, const MACAddress& client_address, u32 new_ip, u32 serv_ip)
|
||||
{
|
||||
transaction_id = transaction;
|
||||
message_type = DHCPConst::MESSAGE_REPLY;
|
||||
hardware_type = BBA_HARDWARE_TYPE;
|
||||
hardware_addr = MAC_ADDRESS_SIZE;
|
||||
client_mac = client_address;
|
||||
your_ip = new_ip;
|
||||
server_ip = serv_ip;
|
||||
}
|
||||
|
||||
DHCPPacket::DHCPPacket() = default;
|
||||
|
||||
DHCPPacket::DHCPPacket(const std::vector<u8>& data)
|
||||
{
|
||||
if (data.size() < DHCPBody::SIZE)
|
||||
return;
|
||||
body = Common::BitCastPtr<DHCPBody>(data.data());
|
||||
std::size_t offset = DHCPBody::SIZE;
|
||||
|
||||
while (offset < data.size() - 1)
|
||||
{
|
||||
const u8 fnc = data[offset];
|
||||
if (fnc == 0)
|
||||
{
|
||||
++offset;
|
||||
continue;
|
||||
}
|
||||
if (fnc == 255)
|
||||
break;
|
||||
const u8 len = data[offset + 1];
|
||||
const auto opt_begin = data.begin() + offset;
|
||||
offset += 2 + len;
|
||||
if (offset > data.size())
|
||||
break;
|
||||
const auto opt_end = data.begin() + offset;
|
||||
options.emplace_back(opt_begin, opt_end);
|
||||
}
|
||||
}
|
||||
|
||||
void DHCPPacket::AddOption(u8 fnc, const std::vector<u8>& params)
|
||||
{
|
||||
if (params.size() > 255)
|
||||
return;
|
||||
std::vector<u8> opt = {fnc, u8(params.size())};
|
||||
opt.insert(opt.end(), params.begin(), params.end());
|
||||
options.emplace_back(std::move(opt));
|
||||
}
|
||||
|
||||
std::vector<u8> DHCPPacket::Build() const
|
||||
{
|
||||
const u8* body_ptr = reinterpret_cast<const u8*>(&body);
|
||||
std::vector<u8> result(body_ptr, body_ptr + DHCPBody::SIZE);
|
||||
|
||||
for (auto& opt : options)
|
||||
{
|
||||
result.insert(result.end(), opt.begin(), opt.end());
|
||||
}
|
||||
const std::vector<u8> no_option = {255, 0, 0, 0};
|
||||
result.insert(result.end(), no_option.begin(), no_option.end());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Compute the network checksum with a 32-bit accumulator using the
|
||||
// "Normal" order, see RFC 1071 for more details.
|
||||
u16 ComputeNetworkChecksum(const void* data, u16 length, u32 initial_value)
|
||||
@ -187,6 +297,257 @@ u16 ComputeNetworkChecksum(const void* data, u16 length, u32 initial_value)
|
||||
return ~static_cast<u16>(checksum);
|
||||
}
|
||||
|
||||
// Compute the TCP checksum with its pseudo header
|
||||
u16 ComputeTCPNetworkChecksum(const IPAddress& from, const IPAddress& to, const void* data,
|
||||
u16 length, u8 protocol)
|
||||
{
|
||||
const u32 source_addr = ntohl(Common::BitCast<u32>(from));
|
||||
const u32 destination_addr = ntohl(Common::BitCast<u32>(to));
|
||||
const u32 initial_value = (source_addr >> 16) + (source_addr & 0xFFFF) +
|
||||
(destination_addr >> 16) + (destination_addr & 0xFFFF) + protocol +
|
||||
length;
|
||||
const u32 tcp_checksum = ComputeNetworkChecksum(data, length, initial_value);
|
||||
return htons(static_cast<u16>(tcp_checksum));
|
||||
}
|
||||
|
||||
ARPPacket::ARPPacket() = default;
|
||||
|
||||
u16 ARPPacket::Size() const
|
||||
{
|
||||
return static_cast<u16>(SIZE);
|
||||
}
|
||||
|
||||
ARPPacket::ARPPacket(const MACAddress& destination, const MACAddress& source)
|
||||
{
|
||||
eth_header.destination = destination;
|
||||
eth_header.source = source;
|
||||
eth_header.ethertype = htons(ARP_ETHERTYPE);
|
||||
}
|
||||
|
||||
std::vector<u8> ARPPacket::Build() const
|
||||
{
|
||||
std::vector<u8> result;
|
||||
result.reserve(EthernetHeader::SIZE + ARPHeader::SIZE);
|
||||
const u8* eth_ptr = reinterpret_cast<const u8*>(ð_header);
|
||||
result.insert(result.end(), eth_ptr, eth_ptr + EthernetHeader::SIZE);
|
||||
const u8* arp_ptr = reinterpret_cast<const u8*>(&arp_header);
|
||||
result.insert(result.end(), arp_ptr, arp_ptr + ARPHeader::SIZE);
|
||||
return result;
|
||||
}
|
||||
|
||||
TCPPacket::TCPPacket() = default;
|
||||
|
||||
TCPPacket::TCPPacket(const MACAddress& destination, const MACAddress& source)
|
||||
{
|
||||
eth_header.destination = destination;
|
||||
eth_header.source = source;
|
||||
eth_header.ethertype = htons(IPV4_ETHERTYPE);
|
||||
}
|
||||
|
||||
TCPPacket::TCPPacket(const MACAddress& destination, const MACAddress& source,
|
||||
const sockaddr_in& from, const sockaddr_in& to, u32 seq, u32 ack, u16 flags)
|
||||
{
|
||||
eth_header.destination = destination;
|
||||
eth_header.source = source;
|
||||
eth_header.ethertype = htons(IPV4_ETHERTYPE);
|
||||
|
||||
ip_header = Common::IPv4Header(Common::TCPHeader::SIZE, IPPROTO_TCP, from, to);
|
||||
tcp_header = Common::TCPHeader(from, to, seq, ack, flags);
|
||||
}
|
||||
|
||||
std::vector<u8> TCPPacket::Build()
|
||||
{
|
||||
std::vector<u8> result;
|
||||
result.reserve(Size());
|
||||
|
||||
// recalc size
|
||||
ip_header.total_len = htons(static_cast<u16>(IPv4Header::SIZE + ipv4_options.size() +
|
||||
TCPHeader::SIZE + tcp_options.size() + data.size()));
|
||||
|
||||
// copy data
|
||||
const u8* eth_ptr = reinterpret_cast<const u8*>(ð_header);
|
||||
result.insert(result.end(), eth_ptr, eth_ptr + EthernetHeader::SIZE);
|
||||
const u8* ip_ptr = reinterpret_cast<const u8*>(&ip_header);
|
||||
result.insert(result.end(), ip_ptr, ip_ptr + IPv4Header::SIZE);
|
||||
std::size_t offset = EthernetHeader::SIZE + IPv4Header::SIZE;
|
||||
if (ipv4_options.size() > 0)
|
||||
{
|
||||
result.insert(result.end(), ipv4_options.begin(), ipv4_options.end());
|
||||
offset += ipv4_options.size();
|
||||
}
|
||||
tcp_header.checksum = 0;
|
||||
const u16 props = (ntohs(tcp_header.properties) & 0xfff) |
|
||||
(static_cast<u16>((tcp_options.size() + TCPHeader::SIZE) & 0x3c) << 10);
|
||||
tcp_header.properties = htons(props);
|
||||
const u8* tcp_ptr = reinterpret_cast<const u8*>(&tcp_header);
|
||||
result.insert(result.end(), tcp_ptr, tcp_ptr + TCPHeader::SIZE);
|
||||
const std::size_t tcp_offset = offset;
|
||||
offset += TCPHeader::SIZE;
|
||||
if (tcp_options.size() > 0)
|
||||
{
|
||||
result.insert(result.end(), tcp_options.begin(), tcp_options.end());
|
||||
offset += tcp_options.size();
|
||||
}
|
||||
if (data.size() > 0)
|
||||
{
|
||||
result.insert(result.end(), data.begin(), data.end());
|
||||
}
|
||||
tcp_header.checksum = ComputeTCPNetworkChecksum(
|
||||
ip_header.source_addr, ip_header.destination_addr, &result[tcp_offset],
|
||||
static_cast<u16>(result.size() - tcp_offset), IPPROTO_TCP);
|
||||
std::copy(tcp_ptr, tcp_ptr + TCPHeader::SIZE, result.begin() + tcp_offset);
|
||||
return result;
|
||||
}
|
||||
|
||||
u16 TCPPacket::Size() const
|
||||
{
|
||||
return static_cast<u16>(MIN_SIZE + data.size() + ipv4_options.size() + tcp_options.size());
|
||||
}
|
||||
|
||||
UDPPacket::UDPPacket() = default;
|
||||
|
||||
UDPPacket::UDPPacket(const MACAddress& destination, const MACAddress& source)
|
||||
{
|
||||
eth_header.destination = destination;
|
||||
eth_header.source = source;
|
||||
eth_header.ethertype = htons(IPV4_ETHERTYPE);
|
||||
}
|
||||
|
||||
UDPPacket::UDPPacket(const MACAddress& destination, const MACAddress& source,
|
||||
const sockaddr_in& from, const sockaddr_in& to, const std::vector<u8>& payload)
|
||||
{
|
||||
eth_header.destination = destination;
|
||||
eth_header.source = source;
|
||||
eth_header.ethertype = htons(IPV4_ETHERTYPE);
|
||||
|
||||
ip_header = Common::IPv4Header(static_cast<u16>(payload.size() + Common::UDPHeader::SIZE),
|
||||
IPPROTO_UDP, from, to);
|
||||
udp_header = Common::UDPHeader(from, to, static_cast<u16>(payload.size()));
|
||||
data = payload;
|
||||
}
|
||||
|
||||
std::vector<u8> UDPPacket::Build()
|
||||
{
|
||||
std::vector<u8> result;
|
||||
result.reserve(Size());
|
||||
|
||||
// recalc size
|
||||
ip_header.total_len = htons(
|
||||
static_cast<u16>(IPv4Header::SIZE + ipv4_options.size() + UDPHeader::SIZE + data.size()));
|
||||
udp_header.length = htons(static_cast<u16>(UDPHeader::SIZE + data.size()));
|
||||
|
||||
// copy data
|
||||
const u8* eth_ptr = reinterpret_cast<const u8*>(ð_header);
|
||||
result.insert(result.end(), eth_ptr, eth_ptr + EthernetHeader::SIZE);
|
||||
const u8* ip_ptr = reinterpret_cast<const u8*>(&ip_header);
|
||||
result.insert(result.end(), ip_ptr, ip_ptr + IPv4Header::SIZE);
|
||||
std::size_t offset = EthernetHeader::SIZE + IPv4Header::SIZE;
|
||||
if (ipv4_options.size() > 0)
|
||||
{
|
||||
result.insert(result.end(), ipv4_options.begin(), ipv4_options.end());
|
||||
offset += ipv4_options.size();
|
||||
}
|
||||
udp_header.checksum = 0;
|
||||
const u8* udp_ptr = reinterpret_cast<const u8*>(&udp_header);
|
||||
result.insert(result.end(), udp_ptr, udp_ptr + UDPHeader::SIZE);
|
||||
const std::size_t udp_offset = offset;
|
||||
offset += UDPHeader::SIZE;
|
||||
if (data.size() > 0)
|
||||
{
|
||||
result.insert(result.end(), data.begin(), data.end());
|
||||
}
|
||||
udp_header.checksum = ComputeTCPNetworkChecksum(
|
||||
ip_header.source_addr, ip_header.destination_addr, &result[udp_offset],
|
||||
static_cast<u16>(result.size() - udp_offset), IPPROTO_UDP);
|
||||
std::copy(udp_ptr, udp_ptr + UDPHeader::SIZE, result.begin() + udp_offset);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u16 UDPPacket::Size() const
|
||||
{
|
||||
return static_cast<u16>(MIN_SIZE + data.size() + ipv4_options.size());
|
||||
}
|
||||
|
||||
PacketView::PacketView(const u8* ptr, std::size_t size) : m_ptr(ptr), m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
std::optional<u16> PacketView::GetEtherType() const
|
||||
{
|
||||
if (m_size < EthernetHeader::SIZE)
|
||||
return std::nullopt;
|
||||
const std::size_t offset = offsetof(EthernetHeader, ethertype);
|
||||
return ntohs(Common::BitCastPtr<u16>(m_ptr + offset));
|
||||
}
|
||||
|
||||
std::optional<ARPPacket> PacketView::GetARPPacket() const
|
||||
{
|
||||
if (m_size < ARPPacket::SIZE)
|
||||
return std::nullopt;
|
||||
return Common::BitCastPtr<ARPPacket>(m_ptr);
|
||||
}
|
||||
|
||||
std::optional<u8> PacketView::GetIPProto() const
|
||||
{
|
||||
if (m_size < EthernetHeader::SIZE + IPv4Header::SIZE)
|
||||
return std::nullopt;
|
||||
return m_ptr[EthernetHeader::SIZE + offsetof(IPv4Header, protocol)];
|
||||
}
|
||||
|
||||
std::optional<TCPPacket> PacketView::GetTCPPacket() const
|
||||
{
|
||||
if (m_size < TCPPacket::MIN_SIZE)
|
||||
return std::nullopt;
|
||||
TCPPacket result;
|
||||
result.eth_header = Common::BitCastPtr<EthernetHeader>(m_ptr);
|
||||
result.ip_header = Common::BitCastPtr<IPv4Header>(m_ptr + EthernetHeader::SIZE);
|
||||
const u16 offset = result.ip_header.DefinedSize() + EthernetHeader::SIZE;
|
||||
if (m_size < offset + TCPHeader::SIZE)
|
||||
return std::nullopt;
|
||||
result.ipv4_options =
|
||||
std::vector<u8>(m_ptr + EthernetHeader::SIZE + IPv4Header::SIZE, m_ptr + offset);
|
||||
result.tcp_header = Common::BitCastPtr<TCPHeader>(m_ptr + offset);
|
||||
const u16 data_offset = result.tcp_header.GetHeaderSize() + offset;
|
||||
|
||||
const u16 total_len = ntohs(result.ip_header.total_len);
|
||||
const std::size_t end = EthernetHeader::SIZE + total_len;
|
||||
|
||||
if (m_size < end || end < data_offset)
|
||||
return std::nullopt;
|
||||
|
||||
result.tcp_options = std::vector<u8>(m_ptr + offset + TCPHeader::SIZE, m_ptr + data_offset);
|
||||
result.data = std::vector<u8>(m_ptr + data_offset, m_ptr + end);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<UDPPacket> PacketView::GetUDPPacket() const
|
||||
{
|
||||
if (m_size < UDPPacket::MIN_SIZE)
|
||||
return std::nullopt;
|
||||
UDPPacket result;
|
||||
result.eth_header = Common::BitCastPtr<EthernetHeader>(m_ptr);
|
||||
result.ip_header = Common::BitCastPtr<IPv4Header>(m_ptr + EthernetHeader::SIZE);
|
||||
const u16 offset = result.ip_header.DefinedSize() + EthernetHeader::SIZE;
|
||||
if (m_size < offset + UDPHeader::SIZE)
|
||||
return std::nullopt;
|
||||
result.ipv4_options =
|
||||
std::vector<u8>(m_ptr + EthernetHeader::SIZE + IPv4Header::SIZE, m_ptr + offset);
|
||||
result.udp_header = Common::BitCastPtr<UDPHeader>(m_ptr + offset);
|
||||
const u16 data_offset = UDPHeader::SIZE + offset;
|
||||
|
||||
const u16 total_len = ntohs(result.udp_header.length);
|
||||
const std::size_t end = offset + total_len;
|
||||
|
||||
if (m_size < end || end < data_offset)
|
||||
return std::nullopt;
|
||||
|
||||
result.data = std::vector<u8>(m_ptr + data_offset, m_ptr + end);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
NetworkErrorState SaveNetworkErrorState()
|
||||
{
|
||||
return {
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
@ -22,11 +23,25 @@ enum class MACConsumer
|
||||
|
||||
enum
|
||||
{
|
||||
MAC_ADDRESS_SIZE = 6
|
||||
BBA_HARDWARE_TYPE = 1,
|
||||
MAC_ADDRESS_SIZE = 6,
|
||||
IPV4_HEADER_TYPE = 8
|
||||
};
|
||||
|
||||
enum DHCPConst
|
||||
{
|
||||
MESSAGE_QUERY = 1,
|
||||
MESSAGE_REPLY = 2
|
||||
};
|
||||
|
||||
using MACAddress = std::array<u8, MAC_ADDRESS_SIZE>;
|
||||
constexpr std::size_t IPV4_ADDR_LEN = 4;
|
||||
using IPAddress = std::array<u8, IPV4_ADDR_LEN>;
|
||||
constexpr IPAddress IP_ADDR_ANY = {0, 0, 0, 0};
|
||||
constexpr IPAddress IP_ADDR_BROADCAST = {255, 255, 255, 255};
|
||||
constexpr IPAddress IP_ADDR_SSDP = {239, 255, 255, 250};
|
||||
constexpr u16 IPV4_ETHERTYPE = 0x800;
|
||||
constexpr u16 ARP_ETHERTYPE = 0x806;
|
||||
|
||||
struct EthernetHeader
|
||||
{
|
||||
@ -47,6 +62,7 @@ struct IPv4Header
|
||||
IPv4Header();
|
||||
IPv4Header(u16 data_size, u8 ip_proto, const sockaddr_in& from, const sockaddr_in& to);
|
||||
u16 Size() const;
|
||||
u8 DefinedSize() const;
|
||||
|
||||
static constexpr std::size_t SIZE = 20;
|
||||
|
||||
@ -58,8 +74,8 @@ struct IPv4Header
|
||||
u8 ttl = 0;
|
||||
u8 protocol = 0;
|
||||
u16 header_checksum = 0;
|
||||
std::array<u8, IPV4_ADDR_LEN> source_addr{};
|
||||
std::array<u8, IPV4_ADDR_LEN> destination_addr{};
|
||||
IPAddress source_addr{};
|
||||
IPAddress destination_addr{};
|
||||
};
|
||||
static_assert(sizeof(IPv4Header) == IPv4Header::SIZE);
|
||||
|
||||
@ -67,6 +83,8 @@ struct TCPHeader
|
||||
{
|
||||
TCPHeader();
|
||||
TCPHeader(const sockaddr_in& from, const sockaddr_in& to, u32 seq, const u8* data, u16 length);
|
||||
TCPHeader(const sockaddr_in& from, const sockaddr_in& to, u32 seq, u32 ack, u16 flags);
|
||||
u8 GetHeaderSize() const;
|
||||
u16 Size() const;
|
||||
u8 IPProto() const;
|
||||
|
||||
@ -99,6 +117,134 @@ struct UDPHeader
|
||||
};
|
||||
static_assert(sizeof(UDPHeader) == UDPHeader::SIZE);
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct ARPHeader
|
||||
{
|
||||
ARPHeader();
|
||||
ARPHeader(u32 from_ip, const MACAddress& from_mac, u32 to_ip, const MACAddress& to_mac);
|
||||
u16 Size() const;
|
||||
|
||||
static constexpr std::size_t SIZE = 28;
|
||||
|
||||
u16 hardware_type = 0;
|
||||
u16 protocol_type = 0;
|
||||
u8 hardware_size = 0;
|
||||
u8 protocol_size = 0;
|
||||
u16 opcode = 0;
|
||||
MACAddress sender_address{};
|
||||
u32 sender_ip = 0;
|
||||
MACAddress targer_address{};
|
||||
u32 target_ip = 0;
|
||||
};
|
||||
static_assert(sizeof(ARPHeader) == ARPHeader::SIZE);
|
||||
#pragma pack(pop)
|
||||
|
||||
struct DHCPBody
|
||||
{
|
||||
DHCPBody();
|
||||
DHCPBody(u32 transaction, const MACAddress& client_address, u32 new_ip, u32 serv_ip);
|
||||
static constexpr std::size_t SIZE = 240;
|
||||
u8 message_type = 0;
|
||||
u8 hardware_type = 0;
|
||||
u8 hardware_addr = 0;
|
||||
u8 hops = 0;
|
||||
u32 transaction_id = 0;
|
||||
u16 seconds = 0;
|
||||
u16 boot_flag = 0;
|
||||
u32 client_ip = 0;
|
||||
u32 your_ip = 0;
|
||||
u32 server_ip = 0;
|
||||
u32 relay_ip = 0;
|
||||
MACAddress client_mac{};
|
||||
unsigned char padding[10]{};
|
||||
unsigned char hostname[0x40]{};
|
||||
unsigned char boot_file[0x80]{};
|
||||
u8 magic_cookie[4] = {0x63, 0x82, 0x53, 0x63};
|
||||
};
|
||||
static_assert(sizeof(DHCPBody) == DHCPBody::SIZE);
|
||||
|
||||
struct DHCPPacket
|
||||
{
|
||||
DHCPPacket();
|
||||
DHCPPacket(const std::vector<u8>& data);
|
||||
void AddOption(u8 fnc, const std::vector<u8>& params);
|
||||
std::vector<u8> Build() const;
|
||||
|
||||
DHCPBody body;
|
||||
std::vector<std::vector<u8>> options;
|
||||
};
|
||||
|
||||
// The compiler might add 2 bytes after EthernetHeader to enforce 16-bytes alignment
|
||||
#pragma pack(push, 1)
|
||||
struct ARPPacket
|
||||
{
|
||||
ARPPacket();
|
||||
ARPPacket(const MACAddress& destination, const MACAddress& source);
|
||||
std::vector<u8> Build() const;
|
||||
u16 Size() const;
|
||||
|
||||
EthernetHeader eth_header;
|
||||
ARPHeader arp_header;
|
||||
|
||||
static constexpr std::size_t SIZE = EthernetHeader::SIZE + ARPHeader::SIZE;
|
||||
};
|
||||
static_assert(sizeof(ARPPacket) == ARPPacket::SIZE);
|
||||
#pragma pack(pop)
|
||||
|
||||
struct TCPPacket
|
||||
{
|
||||
TCPPacket();
|
||||
TCPPacket(const MACAddress& destination, const MACAddress& source);
|
||||
TCPPacket(const MACAddress& destination, const MACAddress& source, const sockaddr_in& from,
|
||||
const sockaddr_in& to, u32 seq, u32 ack, u16 flags);
|
||||
std::vector<u8> Build();
|
||||
u16 Size() const;
|
||||
|
||||
EthernetHeader eth_header;
|
||||
IPv4Header ip_header;
|
||||
TCPHeader tcp_header;
|
||||
std::vector<u8> ipv4_options;
|
||||
std::vector<u8> tcp_options;
|
||||
std::vector<u8> data;
|
||||
|
||||
static constexpr std::size_t MIN_SIZE = EthernetHeader::SIZE + IPv4Header::SIZE + TCPHeader::SIZE;
|
||||
};
|
||||
|
||||
struct UDPPacket
|
||||
{
|
||||
UDPPacket();
|
||||
UDPPacket(const MACAddress& destination, const MACAddress& source);
|
||||
UDPPacket(const MACAddress& destination, const MACAddress& source, const sockaddr_in& from,
|
||||
const sockaddr_in& to, const std::vector<u8>& payload);
|
||||
std::vector<u8> Build();
|
||||
u16 Size() const;
|
||||
|
||||
EthernetHeader eth_header;
|
||||
IPv4Header ip_header;
|
||||
UDPHeader udp_header;
|
||||
|
||||
std::vector<u8> ipv4_options;
|
||||
std::vector<u8> data;
|
||||
|
||||
static constexpr std::size_t MIN_SIZE = EthernetHeader::SIZE + IPv4Header::SIZE + UDPHeader::SIZE;
|
||||
};
|
||||
|
||||
class PacketView
|
||||
{
|
||||
public:
|
||||
PacketView(const u8* ptr, std::size_t size);
|
||||
|
||||
std::optional<u16> GetEtherType() const;
|
||||
std::optional<ARPPacket> GetARPPacket() const;
|
||||
std::optional<u8> GetIPProto() const;
|
||||
std::optional<TCPPacket> GetTCPPacket() const;
|
||||
std::optional<UDPPacket> GetUDPPacket() const;
|
||||
|
||||
private:
|
||||
const u8* m_ptr;
|
||||
std::size_t m_size;
|
||||
};
|
||||
|
||||
struct NetworkErrorState
|
||||
{
|
||||
int error;
|
||||
@ -111,6 +257,8 @@ MACAddress GenerateMacAddress(MACConsumer type);
|
||||
std::string MacAddressToString(const MACAddress& mac);
|
||||
std::optional<MACAddress> StringToMacAddress(std::string_view mac_string);
|
||||
u16 ComputeNetworkChecksum(const void* data, u16 length, u32 initial_value = 0);
|
||||
u16 ComputeTCPNetworkChecksum(const IPAddress& from, const IPAddress& to, const void* data,
|
||||
u16 length, u8 protocol);
|
||||
NetworkErrorState SaveNetworkErrorState();
|
||||
void RestoreNetworkErrorState(const NetworkErrorState& state);
|
||||
} // namespace Common
|
||||
|
Reference in New Issue
Block a user