Namespace ICMP and IPv4, and enum -> enum class
This commit is contained in:
parent
de644dc035
commit
40ecbd51f6
17 changed files with 368 additions and 372 deletions
2
Makefile
2
Makefile
|
@ -4,7 +4,7 @@ OBJS = armc-start.o armc-cstartup.o armc-cstubs.o armc-cppstubs.o \
|
|||
Drive.o Pi1541.o DiskImage.o iec_bus.o iec_commands.o m6502.o m6522.o \
|
||||
gcr.o prot.o lz.o emmc.o diskio.o options.o Screen.o SSD1306.o ScreenLCD.o \
|
||||
Timer.o FileBrowser.o DiskCaddy.o ROMs.o InputMappings.o xga_font_data.o m8520.o wd177x.o Pi1581.o SpinLock.o \
|
||||
net.o net-tftp.o net-arp.o net-ethernet.o net-icmp.o net-ipv4.o net-udp.o net-dhcp.o net-utils.o
|
||||
net-tftp.o net-arp.o net-ethernet.o net-icmp.o net-ipv4.o net-udp.o net-dhcp.o net-utils.o
|
||||
|
||||
SRCDIR = src
|
||||
OBJS := $(addprefix $(SRCDIR)/, $(OBJS))
|
||||
|
|
|
@ -389,11 +389,12 @@ void updateNetwork()
|
|||
|
||||
switch (ethernetHeader.type)
|
||||
{
|
||||
case Net::Ethernet::ETHERTYPE_ARP:
|
||||
case Net::Ethernet::EtherType::Arp:
|
||||
Net::Arp::HandlePacket(ethernetHeader, ipBuffer + offset);
|
||||
break;
|
||||
case Net::Ethernet::ETHERTYPE_IPV4:
|
||||
HandleIpv4Packet(ethernetHeader, ipBuffer + offset, sizeof(ipBuffer) - offset);
|
||||
case Net::Ethernet::EtherType::Ipv4:
|
||||
Net::Ipv4::HandlePacket(
|
||||
ethernetHeader, ipBuffer + offset, sizeof(ipBuffer) - offset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace Net::Arp
|
|||
|
||||
Packet::Packet(uint16_t operation) :
|
||||
hardwareType(1), // Ethernet
|
||||
protocolType(Ethernet::ETHERTYPE_IPV4),
|
||||
protocolType(Ethernet::EtherType::Ipv4),
|
||||
hardwareAddressLength(6),
|
||||
protocolAddressLength(4),
|
||||
operation(operation)
|
||||
|
@ -23,8 +23,8 @@ namespace Net::Arp
|
|||
{
|
||||
buffer[0] = hardwareType >> 8;
|
||||
buffer[1] = hardwareType;
|
||||
buffer[2] = protocolType >> 8;
|
||||
buffer[3] = protocolType;
|
||||
buffer[2] = static_cast<uint16_t>(protocolType) >> 8;
|
||||
buffer[3] = static_cast<uint16_t>(protocolType);
|
||||
buffer[4] = hardwareAddressLength;
|
||||
buffer[5] = protocolAddressLength;
|
||||
buffer[6] = operation >> 8;
|
||||
|
@ -53,7 +53,8 @@ namespace Net::Arp
|
|||
Packet self;
|
||||
|
||||
self.hardwareType = buffer[0] << 8 | buffer[1];
|
||||
self.protocolType = buffer[2] << 8 | buffer[3];
|
||||
self.protocolType =
|
||||
static_cast<Ethernet::EtherType>(buffer[2] << 8 | buffer[3]);
|
||||
self.hardwareAddressLength = buffer[4];
|
||||
self.protocolAddressLength = buffer[5];
|
||||
self.operation = buffer[6] << 8 | buffer[7];
|
||||
|
@ -82,7 +83,7 @@ namespace Net::Arp
|
|||
arpPacket.senderIp = senderIp;
|
||||
|
||||
Ethernet::Header ethernetHeader(
|
||||
senderMac, targetMac, Ethernet::ETHERTYPE_ARP);
|
||||
senderMac, targetMac, Ethernet::EtherType::Arp);
|
||||
|
||||
uint8_t buffer[USPI_FRAME_BUFFER_SIZE];
|
||||
size_t size = 0;
|
||||
|
@ -122,7 +123,7 @@ namespace Net::Arp
|
|||
|
||||
if (
|
||||
arpPacket.hardwareType == 1 &&
|
||||
arpPacket.protocolType == Ethernet::ETHERTYPE_IPV4 &&
|
||||
arpPacket.protocolType == Ethernet::EtherType::Ipv4 &&
|
||||
arpPacket.operation == ARP_OPERATION_REQUEST &&
|
||||
arpPacket.targetIp == Utils::Ipv4Address)
|
||||
{
|
||||
|
@ -136,7 +137,7 @@ namespace Net::Arp
|
|||
|
||||
else if (
|
||||
arpPacket.hardwareType == 1 &&
|
||||
arpPacket.protocolType == Ethernet::ETHERTYPE_IPV4 &&
|
||||
arpPacket.protocolType == Ethernet::EtherType::Ipv4 &&
|
||||
arpPacket.operation == ARP_OPERATION_REPLY &&
|
||||
arpPacket.targetIp == Utils::Ipv4Address &&
|
||||
arpPacket.targetMac == macAddress)
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace Net::Arp
|
|||
struct Packet
|
||||
{
|
||||
uint16_t hardwareType;
|
||||
uint16_t protocolType;
|
||||
Ethernet::EtherType protocolType;
|
||||
uint8_t hardwareAddressLength;
|
||||
uint8_t protocolAddressLength;
|
||||
uint16_t operation;
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
#include <random>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "net-dhcp.h"
|
||||
#include "net-udp.h"
|
||||
#include "net-ipv4.h"
|
||||
#include "net-ethernet.h"
|
||||
#include <random>
|
||||
#include <cassert>
|
||||
|
||||
#include "types.h"
|
||||
#include <uspi.h>
|
||||
#include <uspios.h>
|
||||
|
@ -138,14 +141,11 @@ namespace Net::Dhcp
|
|||
const Udp::Header udpHeader(
|
||||
Udp::Port::DhcpClient, Udp::Port::DhcpServer, udpLength);
|
||||
|
||||
size_t ipv4Length = udpLength + Ipv4Header::SerializedLength();
|
||||
const Ipv4Header ipv4Header(
|
||||
IP_PROTO_UDP, clientIpAddress, serverIpAddress, ipv4Length);
|
||||
size_t ipv4Length = udpLength + Ipv4::Header::SerializedLength();
|
||||
const Ipv4::Header ipv4Header(
|
||||
Ipv4::Protocol::Udp, clientIpAddress, serverIpAddress, ipv4Length);
|
||||
const Ethernet::Header ethernetHeader(
|
||||
serverMacAddress,
|
||||
Utils::GetMacAddress(),
|
||||
Ethernet::ETHERTYPE_IPV4
|
||||
);
|
||||
serverMacAddress, Utils::GetMacAddress(), Ethernet::EtherType::Ipv4);
|
||||
|
||||
uint8_t buffer[USPI_FRAME_BUFFER_SIZE];
|
||||
size_t size = 0;
|
||||
|
@ -197,10 +197,10 @@ namespace Net::Dhcp
|
|||
const Udp::Header udpHeader(
|
||||
Udp::Port::DhcpClient, Udp::Port::DhcpServer, udpLength);
|
||||
|
||||
size_t ipv4Length = udpLength + Ipv4Header::SerializedLength();
|
||||
const Ipv4Header ipv4Header(IP_PROTO_UDP, 0, 0xFFFFFFFF, ipv4Length);
|
||||
size_t ipv4Length = udpLength + Ipv4::Header::SerializedLength();
|
||||
const Ipv4::Header ipv4Header(Ipv4::Protocol::Udp, 0, 0xFFFFFFFF, ipv4Length);
|
||||
const Ethernet::Header ethernetHeader(
|
||||
Utils::GetMacAddress(), Ethernet::ETHERTYPE_IPV4);
|
||||
Utils::GetMacAddress(), Ethernet::EtherType::Ipv4);
|
||||
|
||||
uint8_t buffer[USPI_FRAME_BUFFER_SIZE];
|
||||
size_t size = 0;
|
||||
|
|
|
@ -6,14 +6,14 @@ namespace Net::Ethernet
|
|||
Header::Header()
|
||||
{}
|
||||
|
||||
Header::Header(uint16_t type) :
|
||||
Header::Header(EtherType type) :
|
||||
macDestination(Utils::MacBroadcast),
|
||||
macSource{0, 0, 0, 0, 0, 0},
|
||||
type(type)
|
||||
{}
|
||||
|
||||
Header::Header(
|
||||
MacAddress macSource, uint16_t type
|
||||
MacAddress macSource, EtherType type
|
||||
) :
|
||||
macDestination(Utils::MacBroadcast),
|
||||
macSource(macSource),
|
||||
|
@ -21,7 +21,7 @@ namespace Net::Ethernet
|
|||
{}
|
||||
|
||||
Header::Header(
|
||||
MacAddress macDestination, MacAddress macSource, uint16_t type
|
||||
MacAddress macDestination, MacAddress macSource, EtherType type
|
||||
) :
|
||||
macDestination(macDestination),
|
||||
macSource(macSource),
|
||||
|
@ -38,8 +38,8 @@ namespace Net::Ethernet
|
|||
std::memcpy(buffer + i, macSource.data(), macSource.size());
|
||||
i += sizeof(macSource);
|
||||
|
||||
buffer[i++] = type >> 8;
|
||||
buffer[i++] = type;
|
||||
buffer[i++] = static_cast<uint16_t>(type) >> 8;
|
||||
buffer[i++] = static_cast<uint16_t>(type);
|
||||
|
||||
return i;
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ namespace Net::Ethernet
|
|||
Header self;
|
||||
std::memcpy(self.macDestination.data(), buffer + 0, self.macDestination.size());
|
||||
std::memcpy(self.macSource.data(), buffer + 6, self.macSource.size());
|
||||
self.type = buffer[12] << 8 | buffer[13];
|
||||
self.type = static_cast<EtherType>(buffer[12] << 8 | buffer[13]);
|
||||
return self;
|
||||
}
|
||||
} // namespace Net::Ethernet
|
||||
|
|
|
@ -6,22 +6,22 @@ namespace Net::Ethernet
|
|||
{
|
||||
using Utils::MacAddress;
|
||||
|
||||
enum EtherType
|
||||
enum class EtherType : uint16_t
|
||||
{
|
||||
ETHERTYPE_IPV4 = 0x0800,
|
||||
ETHERTYPE_ARP = 0x0806,
|
||||
Ipv4 = 0x0800,
|
||||
Arp = 0x0806,
|
||||
};
|
||||
|
||||
struct Header
|
||||
{
|
||||
MacAddress macDestination;
|
||||
MacAddress macSource;
|
||||
uint16_t type;
|
||||
EtherType type;
|
||||
|
||||
Header();
|
||||
Header(uint16_t type);
|
||||
Header(MacAddress macSource, uint16_t type);
|
||||
Header(MacAddress macDestination, MacAddress macSource, uint16_t type);
|
||||
Header(EtherType type);
|
||||
Header(MacAddress macSource, EtherType type);
|
||||
Header(MacAddress macDestination, MacAddress macSource, EtherType type);
|
||||
|
||||
constexpr static size_t SerializedLength()
|
||||
{
|
||||
|
|
176
src/net-icmp.cpp
176
src/net-icmp.cpp
|
@ -1,54 +1,138 @@
|
|||
#include <cstring>
|
||||
|
||||
#include "net-icmp.h"
|
||||
|
||||
//
|
||||
// IcmpPacketHeader
|
||||
//
|
||||
IcmpPacketHeader::IcmpPacketHeader() {}
|
||||
#include "types.h"
|
||||
#include <uspi.h>
|
||||
|
||||
IcmpPacketHeader::IcmpPacketHeader(std::uint8_t type, std::uint8_t code) :
|
||||
type(type), code(code), checksum(0)
|
||||
{}
|
||||
|
||||
std::size_t IcmpPacketHeader::Serialize(uint8_t* buffer) const
|
||||
namespace Net::Icmp
|
||||
{
|
||||
size_t i = 0;
|
||||
buffer[i++] = type;
|
||||
buffer[i++] = code;
|
||||
buffer[i++] = checksum;
|
||||
buffer[i++] = checksum >> 8;
|
||||
return i;
|
||||
}
|
||||
//
|
||||
// PacketHeader
|
||||
//
|
||||
PacketHeader::PacketHeader() {}
|
||||
|
||||
IcmpPacketHeader IcmpPacketHeader::Deserialize(const uint8_t* buffer)
|
||||
{
|
||||
IcmpPacketHeader self;
|
||||
self.type = buffer[0];
|
||||
self.code = buffer[1];
|
||||
self.checksum = buffer[2] << 8 | buffer[3];
|
||||
return self;
|
||||
}
|
||||
PacketHeader::PacketHeader(Type type, uint8_t code) :
|
||||
type(type), code(code), checksum(0)
|
||||
{}
|
||||
|
||||
//
|
||||
// IcmpEchoHeader
|
||||
//
|
||||
IcmpEchoHeader::IcmpEchoHeader() : IcmpEchoHeader(0, 0) {}
|
||||
IcmpEchoHeader::IcmpEchoHeader(uint16_t identifier, uint16_t sequenceNumber) :
|
||||
identifier(identifier), sequenceNumber(sequenceNumber) {}
|
||||
size_t PacketHeader::Serialize(uint8_t* buffer) const
|
||||
{
|
||||
size_t i = 0;
|
||||
buffer[i++] = static_cast<uint8_t>(type);
|
||||
buffer[i++] = code;
|
||||
buffer[i++] = checksum;
|
||||
buffer[i++] = checksum >> 8;
|
||||
return i;
|
||||
}
|
||||
|
||||
size_t IcmpEchoHeader::Serialize(uint8_t* buffer) const
|
||||
{
|
||||
size_t i = 0;
|
||||
buffer[i++] = identifier >> 8;
|
||||
buffer[i++] = identifier;
|
||||
buffer[i++] = sequenceNumber >> 8;
|
||||
buffer[i++] = sequenceNumber;
|
||||
return i;
|
||||
}
|
||||
PacketHeader PacketHeader::Deserialize(const uint8_t* buffer)
|
||||
{
|
||||
PacketHeader self;
|
||||
self.type = static_cast<Type>(buffer[0]);
|
||||
self.code = buffer[1];
|
||||
self.checksum = buffer[2] << 8 | buffer[3];
|
||||
return self;
|
||||
}
|
||||
|
||||
IcmpEchoHeader IcmpEchoHeader::Deserialize(const uint8_t* buffer)
|
||||
{
|
||||
IcmpEchoHeader self;
|
||||
self.identifier = buffer[0] << 8 | buffer[1];
|
||||
self.sequenceNumber = buffer[2] << 8 | buffer[3];
|
||||
return self;
|
||||
}
|
||||
//
|
||||
// EchoHeader
|
||||
//
|
||||
EchoHeader::EchoHeader() : EchoHeader(0, 0) {}
|
||||
EchoHeader::EchoHeader(uint16_t identifier, uint16_t sequenceNumber) :
|
||||
identifier(identifier), sequenceNumber(sequenceNumber) {}
|
||||
|
||||
size_t EchoHeader::Serialize(uint8_t* buffer) const
|
||||
{
|
||||
size_t i = 0;
|
||||
buffer[i++] = identifier >> 8;
|
||||
buffer[i++] = identifier;
|
||||
buffer[i++] = sequenceNumber >> 8;
|
||||
buffer[i++] = sequenceNumber;
|
||||
return i;
|
||||
}
|
||||
|
||||
EchoHeader EchoHeader::Deserialize(const uint8_t* buffer)
|
||||
{
|
||||
EchoHeader self;
|
||||
self.identifier = buffer[0] << 8 | buffer[1];
|
||||
self.sequenceNumber = buffer[2] << 8 | buffer[3];
|
||||
return self;
|
||||
}
|
||||
|
||||
void SendEchoRequest(Utils::MacAddress mac, uint32_t ip)
|
||||
{
|
||||
Icmp::PacketHeader icmpHeader(Icmp::Type::EchoRequest, 0);
|
||||
Icmp::EchoHeader pingHeader(0, 0);
|
||||
|
||||
size_t ipv4TotalSize = Icmp::PacketHeader::SerializedLength() +
|
||||
Icmp::EchoHeader::SerializedLength() +
|
||||
Ipv4::Header::SerializedLength();
|
||||
Ipv4::Header ipv4Header(
|
||||
Ipv4::Protocol::Icmp, Utils::Ipv4Address, ip, ipv4TotalSize);
|
||||
|
||||
Ethernet::Header ethernetHeader(
|
||||
mac, Utils::GetMacAddress(), Ethernet::EtherType::Ipv4);
|
||||
|
||||
uint8_t buffer[USPI_FRAME_BUFFER_SIZE];
|
||||
size_t i = 0;
|
||||
|
||||
i += ethernetHeader.Serialize(buffer + i);
|
||||
i += ipv4Header.Serialize(buffer + i);
|
||||
i += pingHeader.Serialize(buffer + i);
|
||||
i += icmpHeader.Serialize(buffer + 1);
|
||||
|
||||
USPiSendFrame(buffer, i);
|
||||
}
|
||||
|
||||
void HandlePacket(const uint8_t* buffer)
|
||||
{
|
||||
// TODO Don't re-parse the upper layers
|
||||
size_t requestSize = 0;
|
||||
const auto requestEthernetHeader =
|
||||
Ethernet::Header::Deserialize(buffer + requestSize);
|
||||
requestSize += requestEthernetHeader.SerializedLength();
|
||||
const auto requestIpv4Header = Ipv4::Header::Deserialize(buffer + requestSize);
|
||||
requestSize += requestIpv4Header.SerializedLength();
|
||||
const auto requestIcmpHeader =
|
||||
Icmp::PacketHeader::Deserialize(buffer + requestSize);
|
||||
requestSize += requestIcmpHeader.SerializedLength();
|
||||
|
||||
if (requestIcmpHeader.type == Icmp::Type::EchoRequest)
|
||||
{
|
||||
const auto requestEchoHeader =
|
||||
Icmp::EchoHeader::Deserialize(buffer + requestSize);
|
||||
requestSize += requestEchoHeader.SerializedLength();
|
||||
|
||||
const Icmp::PacketHeader responseIcmpHeader(
|
||||
Icmp::Type::EchoReply, 0);
|
||||
const Ipv4::Header responseIpv4Header(
|
||||
Ipv4::Protocol::Icmp,
|
||||
Utils::Ipv4Address,
|
||||
requestIpv4Header.sourceIp,
|
||||
requestIpv4Header.totalLength
|
||||
);
|
||||
const Ethernet::Header responseEthernetHeader(
|
||||
requestEthernetHeader.macSource,
|
||||
Utils::GetMacAddress(),
|
||||
Ethernet::EtherType::Ipv4
|
||||
);
|
||||
|
||||
const auto payloadLength =
|
||||
requestIpv4Header.totalLength -
|
||||
requestIpv4Header.SerializedLength() -
|
||||
requestIcmpHeader.SerializedLength() -
|
||||
requestEchoHeader.SerializedLength();
|
||||
|
||||
std::array<uint8_t, USPI_FRAME_BUFFER_SIZE> bufferResp;
|
||||
size_t respSize = 0;
|
||||
respSize += responseEthernetHeader.Serialize(bufferResp.data() + respSize);
|
||||
respSize += responseIpv4Header.Serialize(bufferResp.data() + respSize);
|
||||
respSize += responseIcmpHeader.Serialize(bufferResp.data() + respSize);
|
||||
std::memcpy(
|
||||
bufferResp.data() + respSize, buffer + requestSize, payloadLength);
|
||||
respSize += payloadLength;
|
||||
USPiSendFrame(bufferResp.data(), respSize);
|
||||
}
|
||||
}
|
||||
} // namespace Net::Icmp
|
||||
|
|
|
@ -1,43 +1,49 @@
|
|||
#pragma once
|
||||
#include "net.h"
|
||||
|
||||
enum IcmpType
|
||||
namespace Net::Icmp
|
||||
{
|
||||
ICMP_ECHO_REPLY = 0,
|
||||
ICMP_ECHO_REQUEST = 8,
|
||||
};
|
||||
|
||||
struct IcmpPacketHeader
|
||||
{
|
||||
std::uint8_t type;
|
||||
std::uint8_t code;
|
||||
std::uint16_t checksum;
|
||||
|
||||
IcmpPacketHeader();
|
||||
IcmpPacketHeader(std::uint8_t type, std::uint8_t code);
|
||||
|
||||
constexpr static std::size_t SerializedLength()
|
||||
enum class Type : uint8_t
|
||||
{
|
||||
return sizeof(type) + sizeof(code) + sizeof(checksum);
|
||||
}
|
||||
EchoReply = 0,
|
||||
EchoRequest = 8,
|
||||
};
|
||||
|
||||
std::size_t Serialize(uint8_t* buffer) const;
|
||||
static IcmpPacketHeader Deserialize(const uint8_t* buffer);
|
||||
};
|
||||
|
||||
struct IcmpEchoHeader
|
||||
{
|
||||
uint16_t identifier;
|
||||
uint16_t sequenceNumber;
|
||||
|
||||
IcmpEchoHeader();
|
||||
IcmpEchoHeader(uint16_t identifier, uint16_t sequenceNumber);
|
||||
|
||||
constexpr static size_t SerializedLength()
|
||||
struct PacketHeader
|
||||
{
|
||||
return sizeof(identifier) + sizeof(sequenceNumber);
|
||||
}
|
||||
Type type;
|
||||
uint8_t code;
|
||||
uint16_t checksum;
|
||||
|
||||
size_t Serialize(uint8_t* buffer) const;
|
||||
static IcmpEchoHeader Deserialize(const uint8_t* buffer);
|
||||
};
|
||||
PacketHeader();
|
||||
PacketHeader(Type type, uint8_t code);
|
||||
|
||||
constexpr static size_t SerializedLength()
|
||||
{
|
||||
return sizeof(type) + sizeof(code) + sizeof(checksum);
|
||||
}
|
||||
|
||||
size_t Serialize(uint8_t* buffer) const;
|
||||
static PacketHeader Deserialize(const uint8_t* buffer);
|
||||
};
|
||||
|
||||
struct EchoHeader
|
||||
{
|
||||
uint16_t identifier;
|
||||
uint16_t sequenceNumber;
|
||||
|
||||
EchoHeader();
|
||||
EchoHeader(uint16_t identifier, uint16_t sequenceNumber);
|
||||
|
||||
constexpr static size_t SerializedLength()
|
||||
{
|
||||
return sizeof(identifier) + sizeof(sequenceNumber);
|
||||
}
|
||||
|
||||
size_t Serialize(uint8_t* buffer) const;
|
||||
static EchoHeader Deserialize(const uint8_t* buffer);
|
||||
};
|
||||
|
||||
void SendEchoRequest(Utils::MacAddress mac, uint32_t ip);
|
||||
void HandlePacket(const uint8_t* buffer);
|
||||
} // namespace Net::Icmp
|
||||
|
|
169
src/net-ipv4.cpp
169
src/net-ipv4.cpp
|
@ -1,83 +1,118 @@
|
|||
#include "net-ipv4.h"
|
||||
#include "net-ethernet.h"
|
||||
#include "net-arp.h"
|
||||
#include "net-icmp.h"
|
||||
#include "net-udp.h"
|
||||
#include "net-utils.h"
|
||||
|
||||
Ipv4Header::Ipv4Header() {}
|
||||
|
||||
Ipv4Header::Ipv4Header(
|
||||
uint8_t protocol, uint32_t sourceIp, uint32_t destinationIp, uint16_t totalLength
|
||||
) :
|
||||
version(4),
|
||||
ihl(5),
|
||||
dscp(0),
|
||||
ecn(0),
|
||||
totalLength(totalLength),
|
||||
identification(0),
|
||||
flags(0),
|
||||
fragmentOffset(0),
|
||||
ttl(64),
|
||||
protocol(protocol),
|
||||
headerChecksum(0),
|
||||
sourceIp(sourceIp),
|
||||
destinationIp(destinationIp)
|
||||
{}
|
||||
|
||||
size_t Ipv4Header::Serialize(uint8_t* buffer) const
|
||||
namespace Net::Ipv4
|
||||
{
|
||||
size_t i = 0;
|
||||
Header::Header() {}
|
||||
|
||||
buffer[i++] = version << 4 | ihl;
|
||||
buffer[i++] = dscp << 2 | ecn;
|
||||
buffer[i++] = totalLength >> 8;
|
||||
buffer[i++] = totalLength;
|
||||
buffer[i++] = identification >> 8;
|
||||
buffer[i++] = identification;
|
||||
buffer[i++] = (flags << 13 | fragmentOffset) >> 8;
|
||||
buffer[i++] = flags << 13 | fragmentOffset;
|
||||
buffer[i++] = ttl;
|
||||
buffer[i++] = protocol;
|
||||
Header::Header(
|
||||
Protocol protocol, uint32_t sourceIp, uint32_t destinationIp, uint16_t totalLength
|
||||
) :
|
||||
version(4),
|
||||
ihl(5),
|
||||
dscp(0),
|
||||
ecn(0),
|
||||
totalLength(totalLength),
|
||||
identification(0),
|
||||
flags(0),
|
||||
fragmentOffset(0),
|
||||
ttl(64),
|
||||
protocol(protocol),
|
||||
headerChecksum(0),
|
||||
sourceIp(sourceIp),
|
||||
destinationIp(destinationIp)
|
||||
{}
|
||||
|
||||
// Zero the checksum before calculating it
|
||||
buffer[i++] = 0;
|
||||
buffer[i++] = 0 >> 8;
|
||||
size_t Header::Serialize(uint8_t* buffer) const
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
buffer[i++] = sourceIp >> 24;
|
||||
buffer[i++] = sourceIp >> 16;
|
||||
buffer[i++] = sourceIp >> 8;
|
||||
buffer[i++] = sourceIp;
|
||||
buffer[i++] = destinationIp >> 24;
|
||||
buffer[i++] = destinationIp >> 16;
|
||||
buffer[i++] = destinationIp >> 8;
|
||||
buffer[i++] = destinationIp;
|
||||
buffer[i++] = version << 4 | ihl;
|
||||
buffer[i++] = dscp << 2 | ecn;
|
||||
buffer[i++] = totalLength >> 8;
|
||||
buffer[i++] = totalLength;
|
||||
buffer[i++] = identification >> 8;
|
||||
buffer[i++] = identification;
|
||||
buffer[i++] = (flags << 13 | fragmentOffset) >> 8;
|
||||
buffer[i++] = flags << 13 | fragmentOffset;
|
||||
buffer[i++] = ttl;
|
||||
buffer[i++] = static_cast<uint8_t>(protocol);
|
||||
|
||||
uint16_t checksum = Net::Utils::InternetChecksum(buffer, i);
|
||||
buffer[10] = checksum;
|
||||
buffer[11] = checksum >> 8;
|
||||
// Zero the checksum before calculating it
|
||||
buffer[i++] = 0;
|
||||
buffer[i++] = 0 >> 8;
|
||||
|
||||
return i;
|
||||
}
|
||||
buffer[i++] = sourceIp >> 24;
|
||||
buffer[i++] = sourceIp >> 16;
|
||||
buffer[i++] = sourceIp >> 8;
|
||||
buffer[i++] = sourceIp;
|
||||
buffer[i++] = destinationIp >> 24;
|
||||
buffer[i++] = destinationIp >> 16;
|
||||
buffer[i++] = destinationIp >> 8;
|
||||
buffer[i++] = destinationIp;
|
||||
|
||||
Ipv4Header Ipv4Header::Deserialize(const uint8_t* buffer)
|
||||
{
|
||||
Ipv4Header self;
|
||||
self.version = buffer[0] >> 4;
|
||||
self.ihl = buffer[0] & 0x0F;
|
||||
uint16_t checksum = Net::Utils::InternetChecksum(buffer, i);
|
||||
buffer[10] = checksum;
|
||||
buffer[11] = checksum >> 8;
|
||||
|
||||
self.dscp = buffer[1] >> 2;
|
||||
self.ecn = buffer[1] & 0x03;
|
||||
return i;
|
||||
}
|
||||
|
||||
self.totalLength = buffer[2] << 8 | buffer[3];
|
||||
self.identification = buffer[4] << 8 | buffer[5];
|
||||
Header Header::Deserialize(const uint8_t* buffer)
|
||||
{
|
||||
Header self;
|
||||
self.version = buffer[0] >> 4;
|
||||
self.ihl = buffer[0] & 0x0F;
|
||||
|
||||
self.flags = buffer[6] >> 5;
|
||||
self.fragmentOffset = (buffer[6] & 0x1F) << 8 | buffer[7];
|
||||
self.dscp = buffer[1] >> 2;
|
||||
self.ecn = buffer[1] & 0x03;
|
||||
|
||||
self.ttl = buffer[8];
|
||||
self.protocol = buffer[9];
|
||||
self.headerChecksum = buffer[10] << 8 | buffer[11];
|
||||
self.totalLength = buffer[2] << 8 | buffer[3];
|
||||
self.identification = buffer[4] << 8 | buffer[5];
|
||||
|
||||
self.sourceIp = buffer[12] << 24 | buffer[13] << 16 | buffer[14] << 8 | buffer[15];
|
||||
self.destinationIp =
|
||||
buffer[16] << 24 | buffer[17] << 16 | buffer[18] << 8 | buffer[19];
|
||||
self.flags = buffer[6] >> 5;
|
||||
self.fragmentOffset = (buffer[6] & 0x1F) << 8 | buffer[7];
|
||||
|
||||
return self;
|
||||
}
|
||||
self.ttl = buffer[8];
|
||||
self.protocol = static_cast<Protocol>(buffer[9]);
|
||||
self.headerChecksum = buffer[10] << 8 | buffer[11];
|
||||
|
||||
self.sourceIp = buffer[12] << 24 | buffer[13] << 16 | buffer[14] << 8 | buffer[15];
|
||||
self.destinationIp =
|
||||
buffer[16] << 24 | buffer[17] << 16 | buffer[18] << 8 | buffer[19];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void HandlePacket(
|
||||
const Ethernet::Header& ethernetHeader,
|
||||
const uint8_t* buffer,
|
||||
const size_t size
|
||||
) {
|
||||
const auto ipv4Header = Header::Deserialize(buffer);
|
||||
const auto offset = Header::SerializedLength();
|
||||
|
||||
// Update ARP table
|
||||
Arp::ArpTable.insert(
|
||||
std::make_pair(ipv4Header.sourceIp, ethernetHeader.macSource));
|
||||
|
||||
if (ipv4Header.version != 4) return;
|
||||
if (ipv4Header.ihl != 5) return; // Not supported
|
||||
if (ipv4Header.destinationIp != Utils::Ipv4Address) return;
|
||||
if (ipv4Header.fragmentOffset != 0) return; // TODO Support this
|
||||
|
||||
if (ipv4Header.protocol == Ipv4::Protocol::Icmp)
|
||||
{
|
||||
Icmp::HandlePacket(buffer);
|
||||
}
|
||||
else if (ipv4Header.protocol == Ipv4::Protocol::Udp)
|
||||
{
|
||||
Udp::HandlePacket(
|
||||
ethernetHeader, ipv4Header, buffer + offset, size - offset);
|
||||
}
|
||||
}
|
||||
} // namespace Net::Ipv4
|
||||
|
|
|
@ -1,44 +1,54 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "net-ethernet.h"
|
||||
|
||||
enum IpProtocols
|
||||
namespace Net::Ipv4
|
||||
{
|
||||
IP_PROTO_ICMP = 1,
|
||||
IP_PROTO_TCP = 6,
|
||||
IP_PROTO_UDP = 17,
|
||||
};
|
||||
|
||||
struct Ipv4Header
|
||||
{
|
||||
uint8_t version;
|
||||
uint8_t ihl;
|
||||
uint8_t dscp;
|
||||
uint8_t ecn;
|
||||
uint16_t totalLength;
|
||||
uint16_t identification;
|
||||
uint8_t flags;
|
||||
uint16_t fragmentOffset;
|
||||
uint8_t ttl;
|
||||
uint8_t protocol;
|
||||
uint16_t headerChecksum;
|
||||
uint32_t sourceIp;
|
||||
uint32_t destinationIp;
|
||||
|
||||
Ipv4Header();
|
||||
Ipv4Header(
|
||||
uint8_t protocol,
|
||||
uint32_t sourceIp,
|
||||
uint32_t destinationIp,
|
||||
uint16_t totalLength
|
||||
);
|
||||
|
||||
static constexpr size_t SerializedLength()
|
||||
enum class Protocol : uint8_t
|
||||
{
|
||||
// Hardcoded because of bitfields.
|
||||
return 20;
|
||||
}
|
||||
Icmp = 1,
|
||||
Tcp = 6,
|
||||
Udp = 17,
|
||||
};
|
||||
|
||||
size_t Serialize(uint8_t* buffer) const;
|
||||
static Ipv4Header Deserialize(const uint8_t* buffer);
|
||||
};
|
||||
struct Header
|
||||
{
|
||||
uint8_t version;
|
||||
uint8_t ihl;
|
||||
uint8_t dscp;
|
||||
uint8_t ecn;
|
||||
uint16_t totalLength;
|
||||
uint16_t identification;
|
||||
uint8_t flags;
|
||||
uint16_t fragmentOffset;
|
||||
uint8_t ttl;
|
||||
Protocol protocol;
|
||||
uint16_t headerChecksum;
|
||||
uint32_t sourceIp;
|
||||
uint32_t destinationIp;
|
||||
|
||||
Header();
|
||||
Header(
|
||||
Protocol protocol,
|
||||
uint32_t sourceIp,
|
||||
uint32_t destinationIp,
|
||||
uint16_t totalLength
|
||||
);
|
||||
|
||||
static constexpr size_t SerializedLength()
|
||||
{
|
||||
// Hardcoded because of bitfields.
|
||||
return 20;
|
||||
}
|
||||
|
||||
size_t Serialize(uint8_t* buffer) const;
|
||||
static Header Deserialize(const uint8_t* buffer);
|
||||
};
|
||||
|
||||
void HandlePacket(
|
||||
const Ethernet::Header& ethernetHeader,
|
||||
const uint8_t* buffer,
|
||||
const size_t size
|
||||
);
|
||||
} // namespace Net::Ipv4
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <memory>
|
||||
#include <cstring>
|
||||
|
||||
#include "ff.h"
|
||||
#include "net-arp.h"
|
||||
|
@ -116,7 +117,7 @@ namespace Net::Tftp
|
|||
|
||||
void HandlePacket(
|
||||
const Ethernet::Header ethernetReqHeader,
|
||||
const Ipv4Header ipv4ReqHeader,
|
||||
const Ipv4::Header ipv4ReqHeader,
|
||||
const Udp::Header udpReqHeader,
|
||||
const uint8_t* data
|
||||
) {
|
||||
|
@ -147,16 +148,16 @@ namespace Net::Tftp
|
|||
udpReqHeader.sourcePort,
|
||||
response->SerializedLength() + Udp::Header::SerializedLength()
|
||||
);
|
||||
Ipv4Header ipv4RespHeader(
|
||||
IP_PROTO_UDP,
|
||||
Ipv4::Header ipv4RespHeader(
|
||||
Ipv4::Protocol::Udp,
|
||||
Utils::Ipv4Address,
|
||||
ipv4ReqHeader.sourceIp,
|
||||
udpRespHeader.length + Ipv4Header::SerializedLength()
|
||||
udpRespHeader.length + Ipv4::Header::SerializedLength()
|
||||
);
|
||||
Ethernet::Header ethernetRespHeader(
|
||||
Arp::ArpTable[ipv4RespHeader.destinationIp],
|
||||
Utils::GetMacAddress(),
|
||||
Ethernet::ETHERTYPE_IPV4
|
||||
Ethernet::EtherType::Ipv4
|
||||
);
|
||||
|
||||
size_t i = 0;
|
||||
|
|
|
@ -77,7 +77,7 @@ namespace Net::Tftp
|
|||
|
||||
void HandlePacket(
|
||||
const Ethernet::Header ethernetReqHeader,
|
||||
const Ipv4Header ipv4ReqHeader,
|
||||
const Ipv4::Header ipv4ReqHeader,
|
||||
const Udp::Header udpReqHeader,
|
||||
const uint8_t* buffer
|
||||
);
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace Net::Udp
|
|||
|
||||
void HandlePacket(
|
||||
const Ethernet::Header ethernetHeader,
|
||||
const Ipv4Header ipv4Header,
|
||||
const Ipv4::Header ipv4Header,
|
||||
const uint8_t* buffer,
|
||||
const size_t size
|
||||
) {
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Net::Udp
|
|||
|
||||
void HandlePacket(
|
||||
const Ethernet::Header ethernetHeader,
|
||||
const Ipv4Header ipv4Header,
|
||||
const Ipv4::Header ipv4Header,
|
||||
const uint8_t* buffer,
|
||||
const size_t size
|
||||
);
|
||||
|
|
121
src/net.cpp
121
src/net.cpp
|
@ -1,121 +0,0 @@
|
|||
#include <memory>
|
||||
|
||||
#include "ff.h"
|
||||
#include "net-arp.h"
|
||||
#include "net-ethernet.h"
|
||||
#include "net-icmp.h"
|
||||
#include "net-ipv4.h"
|
||||
#include "net-udp.h"
|
||||
#include "net-dhcp.h"
|
||||
#include "net-tftp.h"
|
||||
#include "net.h"
|
||||
#include "types.h"
|
||||
|
||||
#include <uspi.h>
|
||||
#include <uspios.h>
|
||||
|
||||
//
|
||||
// IPv4
|
||||
//
|
||||
void HandleIpv4Packet(
|
||||
const Net::Ethernet::Header ethernetHeader,
|
||||
const uint8_t* buffer,
|
||||
const size_t size
|
||||
) {
|
||||
const auto ipv4Header = Ipv4Header::Deserialize(buffer);
|
||||
const auto offset = Ipv4Header::SerializedLength();
|
||||
|
||||
// Update ARP table
|
||||
Net::Arp::ArpTable.insert(
|
||||
std::make_pair(ipv4Header.sourceIp, ethernetHeader.macSource));
|
||||
|
||||
if (ipv4Header.version != 4) return;
|
||||
if (ipv4Header.ihl != 5) return; // Not supported
|
||||
if (ipv4Header.destinationIp != Net::Utils::Ipv4Address) return;
|
||||
if (ipv4Header.fragmentOffset != 0) return; // TODO Support this
|
||||
|
||||
if (ipv4Header.protocol == IP_PROTO_ICMP)
|
||||
{
|
||||
HandleIcmpFrame(buffer);
|
||||
}
|
||||
else if (ipv4Header.protocol == IP_PROTO_UDP)
|
||||
{
|
||||
Net::Udp::HandlePacket(
|
||||
ethernetHeader, ipv4Header, buffer + offset, size - offset);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// ICMP
|
||||
//
|
||||
void SendIcmpEchoRequest(Net::Utils::MacAddress mac, uint32_t ip)
|
||||
{
|
||||
IcmpPacketHeader icmpHeader(8, 0);
|
||||
IcmpEchoHeader pingHeader(0, 0);
|
||||
|
||||
size_t ipv4TotalSize = IcmpPacketHeader::SerializedLength() +
|
||||
IcmpEchoHeader::SerializedLength() +
|
||||
Ipv4Header::SerializedLength();
|
||||
Ipv4Header ipv4Header(1, Net::Utils::Ipv4Address, ip, ipv4TotalSize);
|
||||
|
||||
Net::Ethernet::Header ethernetHeader(
|
||||
mac, Net::Utils::GetMacAddress(), Net::Ethernet::ETHERTYPE_IPV4);
|
||||
|
||||
uint8_t buffer[USPI_FRAME_BUFFER_SIZE];
|
||||
size_t i = 0;
|
||||
|
||||
i += ethernetHeader.Serialize(buffer + i);
|
||||
i += ipv4Header.Serialize(buffer + i);
|
||||
i += pingHeader.Serialize(buffer + i);
|
||||
i += icmpHeader.Serialize(buffer + 1);
|
||||
|
||||
USPiSendFrame(buffer, i);
|
||||
}
|
||||
|
||||
void HandleIcmpFrame(const uint8_t* buffer)
|
||||
{
|
||||
// TODO Don't re-parse the upper layers
|
||||
size_t requestSize = 0;
|
||||
const auto requestEthernetHeader =
|
||||
Net::Ethernet::Header::Deserialize(buffer + requestSize);
|
||||
requestSize += requestEthernetHeader.SerializedLength();
|
||||
const auto requestIpv4Header = Ipv4Header::Deserialize(buffer + requestSize);
|
||||
requestSize += requestIpv4Header.SerializedLength();
|
||||
const auto requestIcmpHeader = IcmpPacketHeader::Deserialize(buffer + requestSize);
|
||||
requestSize += requestIcmpHeader.SerializedLength();
|
||||
|
||||
if (requestIcmpHeader.type == ICMP_ECHO_REQUEST)
|
||||
{
|
||||
const auto requestEchoHeader =
|
||||
IcmpEchoHeader::Deserialize(buffer + requestSize);
|
||||
requestSize += requestEchoHeader.SerializedLength();
|
||||
|
||||
const IcmpPacketHeader responseIcmpHeader(ICMP_ECHO_REPLY, 0);
|
||||
const Ipv4Header responseIpv4Header(
|
||||
IP_PROTO_ICMP,
|
||||
Net::Utils::Ipv4Address,
|
||||
requestIpv4Header.sourceIp,
|
||||
requestIpv4Header.totalLength
|
||||
);
|
||||
const Net::Ethernet::Header responseEthernetHeader(
|
||||
requestEthernetHeader.macSource,
|
||||
Net::Utils::GetMacAddress(),
|
||||
Net::Ethernet::ETHERTYPE_IPV4
|
||||
);
|
||||
|
||||
const auto payloadLength =
|
||||
requestIpv4Header.totalLength -
|
||||
requestIpv4Header.SerializedLength() -
|
||||
requestIcmpHeader.SerializedLength() -
|
||||
requestEchoHeader.SerializedLength();
|
||||
|
||||
std::array<uint8_t, USPI_FRAME_BUFFER_SIZE> bufferResp;
|
||||
size_t respSize = 0;
|
||||
respSize += responseEthernetHeader.Serialize(bufferResp.data() + respSize);
|
||||
respSize += responseIpv4Header.Serialize(bufferResp.data() + respSize);
|
||||
respSize += responseIcmpHeader.Serialize(bufferResp.data() + respSize);
|
||||
memcpy(bufferResp.data() + respSize, buffer + requestSize, payloadLength);
|
||||
respSize += payloadLength;
|
||||
USPiSendFrame(bufferResp.data(), respSize);
|
||||
}
|
||||
}
|
21
src/net.h
21
src/net.h
|
@ -1,26 +1,5 @@
|
|||
#pragma once
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "net-arp.h"
|
||||
#include "net-ethernet.h"
|
||||
#include "net-ipv4.h"
|
||||
#include "net-utils.h"
|
||||
|
||||
//
|
||||
// IPv4
|
||||
//
|
||||
void HandleIpv4Packet(
|
||||
const Net::Ethernet::Header ethernetHeader,
|
||||
const uint8_t* buffer,
|
||||
const size_t size
|
||||
);
|
||||
|
||||
//
|
||||
// ICMP
|
||||
//
|
||||
void SendIcmpEchoRequest(Net::Utils::MacAddress mac, uint32_t ip);
|
||||
void HandleIcmpFrame(const uint8_t* buffer);
|
||||
|
|
Loading…
Reference in a new issue