Base implementation of DHCP
This commit is contained in:
parent
bed8266327
commit
fc39c7a99f
12 changed files with 462 additions and 60 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 \
|
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 \
|
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 \
|
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.o net-tftp.o net-arp.o net-ethernet.o net-icmp.o net-ipv4.o net-udp.o net-dhcp.o
|
||||||
|
|
||||||
SRCDIR = src
|
SRCDIR = src
|
||||||
OBJS := $(addprefix $(SRCDIR)/, $(OBJS))
|
OBJS := $(addprefix $(SRCDIR)/, $(OBJS))
|
||||||
|
|
|
@ -377,6 +377,7 @@ void updateNetwork()
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ethernetHeader = EthernetFrameHeader::Deserialize(ipBuffer);
|
auto ethernetHeader = EthernetFrameHeader::Deserialize(ipBuffer);
|
||||||
|
const auto offset = ethernetHeader.SerializedLength();
|
||||||
|
|
||||||
static bool announcementSent = false;
|
static bool announcementSent = false;
|
||||||
if (!announcementSent)
|
if (!announcementSent)
|
||||||
|
@ -388,10 +389,10 @@ void updateNetwork()
|
||||||
switch (ethernetHeader.type)
|
switch (ethernetHeader.type)
|
||||||
{
|
{
|
||||||
case ETHERTYPE_ARP:
|
case ETHERTYPE_ARP:
|
||||||
HandleArpFrame(ethernetHeader, ipBuffer + ethernetHeader.SerializedLength());
|
HandleArpFrame(ethernetHeader, ipBuffer + offset);
|
||||||
break;
|
break;
|
||||||
case ETHERTYPE_IPV4:
|
case ETHERTYPE_IPV4:
|
||||||
HandleIpv4Packet(ethernetHeader, ipBuffer + ethernetHeader.SerializedLength());
|
HandleIpv4Packet(ethernetHeader, ipBuffer + offset, sizeof(ipBuffer) - offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2048,4 +2049,3 @@ extern "C"
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
265
src/net-dhcp.cpp
Normal file
265
src/net-dhcp.cpp
Normal file
|
@ -0,0 +1,265 @@
|
||||||
|
#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>
|
||||||
|
|
||||||
|
namespace Net::Dhcp
|
||||||
|
{
|
||||||
|
DhcpHeader::DhcpHeader()
|
||||||
|
{}
|
||||||
|
|
||||||
|
DhcpHeader::DhcpHeader(Opcode opcode, uint32_t transactionId) :
|
||||||
|
opcode(opcode),
|
||||||
|
hardwareAddressType(1), // Ethernet
|
||||||
|
hops(0),
|
||||||
|
transactionId(transactionId),
|
||||||
|
secondsElapsed(0),
|
||||||
|
flags(0), // TODO assumption
|
||||||
|
clientIpAddress(0),
|
||||||
|
yourIpAddress(0),
|
||||||
|
serverIpAddress(0),
|
||||||
|
relayIpAddress(0),
|
||||||
|
clientHardwareAddress{0},
|
||||||
|
serverHostname{0},
|
||||||
|
bootFile{0},
|
||||||
|
magicValue{99, 130, 83, 99}
|
||||||
|
{
|
||||||
|
const auto mac = GetMacAddress();
|
||||||
|
hardwareAddressLength = mac.size();
|
||||||
|
std::memcpy(clientHardwareAddress.data(), mac.data(), mac.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DhcpHeader::Serialize(uint8_t* buffer, const size_t size) const
|
||||||
|
{
|
||||||
|
if (size < DhcpHeader::SerializedLength()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t i = 0;
|
||||||
|
buffer[i++] = static_cast<uint8_t>(opcode);
|
||||||
|
buffer[i++] = hardwareAddressType;
|
||||||
|
buffer[i++] = hardwareAddressLength;
|
||||||
|
buffer[i++] = hops;
|
||||||
|
buffer[i++] = transactionId >> 24;
|
||||||
|
buffer[i++] = transactionId >> 16;
|
||||||
|
buffer[i++] = transactionId >> 8;
|
||||||
|
buffer[i++] = transactionId;
|
||||||
|
buffer[i++] = secondsElapsed >> 8;
|
||||||
|
buffer[i++] = secondsElapsed;
|
||||||
|
buffer[i++] = flags >> 8;
|
||||||
|
buffer[i++] = flags;
|
||||||
|
buffer[i++] = clientIpAddress >> 24;
|
||||||
|
buffer[i++] = clientIpAddress >> 16;
|
||||||
|
buffer[i++] = clientIpAddress >> 8;
|
||||||
|
buffer[i++] = clientIpAddress;
|
||||||
|
buffer[i++] = yourIpAddress >> 24;
|
||||||
|
buffer[i++] = yourIpAddress >> 16;
|
||||||
|
buffer[i++] = yourIpAddress >> 8;
|
||||||
|
buffer[i++] = yourIpAddress;
|
||||||
|
buffer[i++] = relayIpAddress >> 24;
|
||||||
|
buffer[i++] = relayIpAddress >> 16;
|
||||||
|
buffer[i++] = relayIpAddress >> 8;
|
||||||
|
buffer[i++] = relayIpAddress;
|
||||||
|
|
||||||
|
std::memcpy(buffer + i, clientHardwareAddress.data(), clientHardwareAddress.size());
|
||||||
|
i += clientHardwareAddress.size();
|
||||||
|
|
||||||
|
std::memcpy(buffer + i, serverHostname.data(), serverHostname.size());
|
||||||
|
i += serverHostname.size();
|
||||||
|
|
||||||
|
std::memcpy(buffer + i, bootFile.data(), bootFile.size());
|
||||||
|
i += bootFile.size();
|
||||||
|
|
||||||
|
std::memcpy(buffer + i, magicValue.data(), magicValue.size());
|
||||||
|
i += magicValue.size();
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DhcpHeader::Deserialize(
|
||||||
|
DhcpHeader& out, const uint8_t* buffer, const size_t size
|
||||||
|
) {
|
||||||
|
if (size < SerializedLength()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out.opcode = static_cast<Opcode>(buffer[0]);
|
||||||
|
out.hardwareAddressType = buffer[1];
|
||||||
|
out.hardwareAddressLength = buffer[2];
|
||||||
|
out.hops = buffer[3];
|
||||||
|
out.transactionId =
|
||||||
|
buffer[4] << 24 | buffer[5] << 16 | buffer[6] << 8 | buffer[7];
|
||||||
|
out.secondsElapsed = buffer[8] << 8 | buffer[9];
|
||||||
|
out.flags = buffer[10] << 8 | buffer[11];
|
||||||
|
out.clientIpAddress =
|
||||||
|
buffer[12] << 24 | buffer[13] << 16 | buffer[14] << 8 | buffer[15];
|
||||||
|
out.yourIpAddress =
|
||||||
|
buffer[16] << 24 | buffer[17] << 16 | buffer[18] << 8 | buffer[19];
|
||||||
|
out.serverIpAddress =
|
||||||
|
buffer[20] << 24 | buffer[21] << 16 | buffer[22] << 8 | buffer[23];
|
||||||
|
out.relayIpAddress =
|
||||||
|
buffer[24] << 24 | buffer[25] << 16 | buffer[26] << 8 | buffer[27];
|
||||||
|
|
||||||
|
std::memcpy(
|
||||||
|
out.clientHardwareAddress.data(),
|
||||||
|
buffer + 28,
|
||||||
|
out.clientHardwareAddress.size()
|
||||||
|
);
|
||||||
|
std::memcpy(out.serverHostname.data(), buffer + 44, out.serverHostname.size());
|
||||||
|
std::memcpy(out.bootFile.data(), buffer + 108, out.bootFile.size());
|
||||||
|
std::memcpy(out.magicValue.data(), buffer + 236, out.magicValue.size());
|
||||||
|
|
||||||
|
assert(SerializedLength() == 240);
|
||||||
|
return 240;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t transactionId;
|
||||||
|
static std::vector<uint32_t> offeredIpAddresses;
|
||||||
|
static std::vector<uint32_t> serverIpAddresses;
|
||||||
|
static std::vector<MacAddress> serverMacAddresses;
|
||||||
|
static bool serverSelected;
|
||||||
|
|
||||||
|
void sendRequest(uint32_t clientIpAddress, MacAddress serverMacAddress, uint32_t serverIpAddress)
|
||||||
|
{
|
||||||
|
const DhcpHeader dhcpHeader(Opcode::BootRequest, transactionId);
|
||||||
|
|
||||||
|
size_t udpLength =
|
||||||
|
dhcpHeader.SerializedLength() + UdpDatagramHeader::SerializedLength();
|
||||||
|
const UdpDatagramHeader udpHeader(
|
||||||
|
UDP_PORT_DHCP_CLIENT, UDP_PORT_DHCP_SERVER, udpLength);
|
||||||
|
|
||||||
|
size_t ipv4Length = udpLength + Ipv4Header::SerializedLength();
|
||||||
|
const Ipv4Header ipv4Header(
|
||||||
|
IP_PROTO_UDP, clientIpAddress, serverIpAddress, ipv4Length);
|
||||||
|
const EthernetFrameHeader ethernetHeader(
|
||||||
|
serverMacAddress, GetMacAddress(), ETHERTYPE_IPV4);
|
||||||
|
|
||||||
|
uint8_t buffer[USPI_FRAME_BUFFER_SIZE];
|
||||||
|
size_t size = 0;
|
||||||
|
const auto expectedSize =
|
||||||
|
ethernetHeader.SerializedLength() +
|
||||||
|
ipv4Header.SerializedLength() +
|
||||||
|
udpHeader.SerializedLength() +
|
||||||
|
dhcpHeader.SerializedLength();
|
||||||
|
|
||||||
|
size += ethernetHeader.Serialize(buffer + size);
|
||||||
|
size += ipv4Header.Serialize(buffer + size);
|
||||||
|
size += udpHeader.Serialize(buffer + size);
|
||||||
|
size += dhcpHeader.Serialize(buffer + size, USPI_FRAME_BUFFER_SIZE - size);
|
||||||
|
|
||||||
|
if (size != expectedSize) {
|
||||||
|
// TODO Log
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
USPiSendFrame(buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void discoverTimerHandler(unsigned int hTimer, void* nParam, void* nContext)
|
||||||
|
{
|
||||||
|
if (transactionId == 0 || offeredIpAddresses.empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select the first IP address
|
||||||
|
const auto clientIpAddress = offeredIpAddresses[0];
|
||||||
|
|
||||||
|
// Send DHCP Requests to every server with that IP address.
|
||||||
|
for (size_t i = 0; i < serverIpAddresses.size(); i++)
|
||||||
|
{
|
||||||
|
sendRequest(clientIpAddress, serverMacAddresses[i], serverIpAddresses[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendDiscover()
|
||||||
|
{
|
||||||
|
transactionId = std::rand();
|
||||||
|
offeredIpAddresses.clear();
|
||||||
|
const DhcpHeader dhcpHeader(Opcode::BootRequest, transactionId);
|
||||||
|
|
||||||
|
size_t udpLength =
|
||||||
|
dhcpHeader.SerializedLength() + UdpDatagramHeader::SerializedLength();
|
||||||
|
const UdpDatagramHeader udpHeader(
|
||||||
|
UDP_PORT_DHCP_CLIENT, UDP_PORT_DHCP_SERVER, udpLength);
|
||||||
|
|
||||||
|
size_t ipv4Length = udpLength + Ipv4Header::SerializedLength();
|
||||||
|
const Ipv4Header ipv4Header(IP_PROTO_UDP, 0, 0xFFFFFFFF, ipv4Length);
|
||||||
|
const EthernetFrameHeader ethernetHeader(GetMacAddress(), ETHERTYPE_IPV4);
|
||||||
|
|
||||||
|
uint8_t buffer[USPI_FRAME_BUFFER_SIZE];
|
||||||
|
size_t size = 0;
|
||||||
|
const auto expectedSize =
|
||||||
|
ethernetHeader.SerializedLength() +
|
||||||
|
ipv4Header.SerializedLength() +
|
||||||
|
udpHeader.SerializedLength() +
|
||||||
|
dhcpHeader.SerializedLength();
|
||||||
|
|
||||||
|
size += ethernetHeader.Serialize(buffer + size);
|
||||||
|
size += ipv4Header.Serialize(buffer + size);
|
||||||
|
size += udpHeader.Serialize(buffer + size);
|
||||||
|
size += dhcpHeader.Serialize(buffer + size, USPI_FRAME_BUFFER_SIZE - size);
|
||||||
|
|
||||||
|
if (size != expectedSize) {
|
||||||
|
// TODO Log
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
USPiSendFrame(buffer, size);
|
||||||
|
|
||||||
|
// Wait a second for responses
|
||||||
|
StartKernelTimer(1 * HZ, discoverTimerHandler, nullptr, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleOfferPacket(
|
||||||
|
const EthernetFrameHeader ethernetHeader, const DhcpHeader dhcpHeader
|
||||||
|
) {
|
||||||
|
offeredIpAddresses.push_back(dhcpHeader.yourIpAddress);
|
||||||
|
serverIpAddresses.push_back(dhcpHeader.serverIpAddress);
|
||||||
|
serverMacAddresses.push_back(ethernetHeader.macSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handleAckPacket(
|
||||||
|
const EthernetFrameHeader ethernetHeader, const DhcpHeader dhcpHeader
|
||||||
|
) {
|
||||||
|
Ipv4Address = dhcpHeader.yourIpAddress;
|
||||||
|
|
||||||
|
// TODO Schedule handler for end of lease.
|
||||||
|
|
||||||
|
transactionId = 0;
|
||||||
|
offeredIpAddresses.clear();
|
||||||
|
serverIpAddresses.clear();
|
||||||
|
serverMacAddresses.clear();
|
||||||
|
serverSelected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandlePacket(
|
||||||
|
const EthernetFrameHeader& ethernetHeader, const uint8_t* buffer, size_t size
|
||||||
|
) {
|
||||||
|
auto dhcpHeader = DhcpHeader();
|
||||||
|
const auto dhcpSize = DhcpHeader::Deserialize(dhcpHeader, buffer, size);
|
||||||
|
if (dhcpSize == 0) {
|
||||||
|
// TODO log
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dhcpHeader.opcode != Opcode::BootReply) return;
|
||||||
|
if (dhcpHeader.hardwareAddressType != 1) return;
|
||||||
|
if (dhcpHeader.hardwareAddressLength != 6) return;
|
||||||
|
if (dhcpHeader.transactionId != transactionId) return;
|
||||||
|
|
||||||
|
if (!serverSelected)
|
||||||
|
{
|
||||||
|
handleOfferPacket(ethernetHeader, dhcpHeader);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
handleAckPacket(ethernetHeader, dhcpHeader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace Net::Dhcp
|
93
src/net-dhcp.h
Normal file
93
src/net-dhcp.h
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
#pragma once
|
||||||
|
#include "net.h"
|
||||||
|
|
||||||
|
namespace Net::Dhcp
|
||||||
|
{
|
||||||
|
enum class Opcode : uint8_t
|
||||||
|
{
|
||||||
|
BootRequest = 1,
|
||||||
|
BootReply = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DhcpHeader
|
||||||
|
{
|
||||||
|
/// Message op code / message type. 1 = BOOTREQUEST, 2 = BOOTREPLY
|
||||||
|
Opcode opcode;
|
||||||
|
|
||||||
|
/// Hardware address type, see ARP section in "Assigned Numbers" RFC
|
||||||
|
uint8_t hardwareAddressType;
|
||||||
|
|
||||||
|
uint8_t hardwareAddressLength;
|
||||||
|
|
||||||
|
/// Client sets to zero, optionally used by relay agents when booting via a
|
||||||
|
/// relay agent.
|
||||||
|
uint8_t hops;
|
||||||
|
|
||||||
|
/// A random number chosen by the client, used by the client and server to
|
||||||
|
/// associate messages and responses between a client and a server.
|
||||||
|
uint32_t transactionId;
|
||||||
|
|
||||||
|
/// Filled in by client, seconds elapsed since client began address acquisition
|
||||||
|
/// or renewal process.
|
||||||
|
uint16_t secondsElapsed;
|
||||||
|
|
||||||
|
uint16_t flags;
|
||||||
|
|
||||||
|
/// Only filled in if client is in BOUND, RENEW or REBINDING state and can
|
||||||
|
/// respond to ARP requests.
|
||||||
|
uint32_t clientIpAddress;
|
||||||
|
|
||||||
|
/// 'your' (client) IP address.
|
||||||
|
uint32_t yourIpAddress;
|
||||||
|
|
||||||
|
/// IP address of next server to use in bootstrap; returned in DHCPOFFER,
|
||||||
|
/// DHCPACK by server.
|
||||||
|
uint32_t serverIpAddress;
|
||||||
|
|
||||||
|
/// Relay agent IP address, used in booting via a relay agent.
|
||||||
|
uint32_t relayIpAddress;
|
||||||
|
|
||||||
|
std::array<uint8_t, 16> clientHardwareAddress;
|
||||||
|
|
||||||
|
/// Optional server host name, null terminated string.
|
||||||
|
std::array<uint8_t, 64> serverHostname;
|
||||||
|
|
||||||
|
/// Boot file name, null terminated string; "generic" name or null in
|
||||||
|
/// DHCPDISCOVER, fully qualified directory-path name in DHCPOFFER.
|
||||||
|
std::array<uint8_t, 128> bootFile;
|
||||||
|
|
||||||
|
/// Always 99, 130, 83, 99
|
||||||
|
std::array<uint8_t, 4> magicValue;
|
||||||
|
|
||||||
|
DhcpHeader();
|
||||||
|
DhcpHeader(Opcode opcode, uint32_t transactionId);
|
||||||
|
|
||||||
|
constexpr static size_t SerializedLength()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
sizeof(Opcode) +
|
||||||
|
sizeof(hardwareAddressType) +
|
||||||
|
sizeof(hardwareAddressLength) +
|
||||||
|
sizeof(hops) +
|
||||||
|
sizeof(transactionId) +
|
||||||
|
sizeof(secondsElapsed) +
|
||||||
|
sizeof(flags) +
|
||||||
|
sizeof(clientIpAddress) +
|
||||||
|
sizeof(yourIpAddress) +
|
||||||
|
sizeof(serverIpAddress) +
|
||||||
|
sizeof(relayIpAddress) +
|
||||||
|
sizeof(clientHardwareAddress) +
|
||||||
|
sizeof(serverHostname) +
|
||||||
|
sizeof(bootFile) +
|
||||||
|
sizeof(magicValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Serialize(uint8_t* buffer, const size_t size) const;
|
||||||
|
static size_t Deserialize(
|
||||||
|
DhcpHeader& out, const uint8_t* buffer, const size_t size);
|
||||||
|
};
|
||||||
|
|
||||||
|
void SendDiscover();
|
||||||
|
void HandlePacket(
|
||||||
|
const EthernetFrameHeader& ethernetHeader, const uint8_t* buffer, size_t size);
|
||||||
|
} // namespace Net::Dhcp
|
|
@ -4,37 +4,48 @@ EthernetFrameHeader::EthernetFrameHeader()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
EthernetFrameHeader::EthernetFrameHeader(std::uint16_t type) :
|
EthernetFrameHeader::EthernetFrameHeader(std::uint16_t type) :
|
||||||
macDestination{255, 255, 255, 255, 255, 255},
|
macDestination{255, 255, 255, 255, 255, 255},
|
||||||
macSource{0, 0, 0, 0, 0, 0},
|
macSource{0, 0, 0, 0, 0, 0},
|
||||||
type(type)
|
type(type)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
EthernetFrameHeader::EthernetFrameHeader(
|
EthernetFrameHeader::EthernetFrameHeader(
|
||||||
MacAddress macDestination, MacAddress macSource, uint16_t type
|
MacAddress macSource, uint16_t type
|
||||||
) : macDestination(macDestination), macSource(macSource), type(type)
|
) :
|
||||||
|
macDestination{255, 255, 255, 255, 255, 255},
|
||||||
|
macSource(macSource),
|
||||||
|
type(type)
|
||||||
|
{}
|
||||||
|
|
||||||
|
EthernetFrameHeader::EthernetFrameHeader(
|
||||||
|
MacAddress macDestination, MacAddress macSource, uint16_t type
|
||||||
|
) :
|
||||||
|
macDestination(macDestination),
|
||||||
|
macSource(macSource),
|
||||||
|
type(type)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::size_t EthernetFrameHeader::Serialize(uint8_t* buffer) const
|
std::size_t EthernetFrameHeader::Serialize(uint8_t* buffer) const
|
||||||
{
|
{
|
||||||
std::size_t i = 0;
|
std::size_t i = 0;
|
||||||
|
|
||||||
std::memcpy(buffer + i, macDestination.data(), macDestination.size());
|
std::memcpy(buffer + i, macDestination.data(), macDestination.size());
|
||||||
i += sizeof(macDestination);
|
i += sizeof(macDestination);
|
||||||
|
|
||||||
std::memcpy(buffer + i, macSource.data(), macSource.size());
|
std::memcpy(buffer + i, macSource.data(), macSource.size());
|
||||||
i += sizeof(macSource);
|
i += sizeof(macSource);
|
||||||
|
|
||||||
buffer[i++] = type >> 8;
|
buffer[i++] = type >> 8;
|
||||||
buffer[i++] = type;
|
buffer[i++] = type;
|
||||||
|
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
EthernetFrameHeader EthernetFrameHeader::Deserialize(const uint8_t* buffer)
|
EthernetFrameHeader EthernetFrameHeader::Deserialize(const uint8_t* buffer)
|
||||||
{
|
{
|
||||||
EthernetFrameHeader self;
|
EthernetFrameHeader self;
|
||||||
std::memcpy(self.macDestination.data(), buffer + 0, self.macDestination.size());
|
std::memcpy(self.macDestination.data(), buffer + 0, self.macDestination.size());
|
||||||
std::memcpy(self.macSource.data(), buffer + 6, self.macSource.size());
|
std::memcpy(self.macSource.data(), buffer + 6, self.macSource.size());
|
||||||
self.type = buffer[12] << 8 | buffer[13];
|
self.type = buffer[12] << 8 | buffer[13];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ struct EthernetFrameHeader
|
||||||
|
|
||||||
EthernetFrameHeader();
|
EthernetFrameHeader();
|
||||||
EthernetFrameHeader(std::uint16_t type);
|
EthernetFrameHeader(std::uint16_t type);
|
||||||
|
EthernetFrameHeader(MacAddress macSource, uint16_t type);
|
||||||
EthernetFrameHeader(MacAddress macDestination, MacAddress macSource, uint16_t type);
|
EthernetFrameHeader(MacAddress macDestination, MacAddress macSource, uint16_t type);
|
||||||
|
|
||||||
constexpr static std::size_t SerializedLength()
|
constexpr static std::size_t SerializedLength()
|
||||||
|
|
|
@ -71,9 +71,15 @@ static std::unique_ptr<TftpPacket> handleTftpWriteRequest(const uint8_t* data)
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::unique_ptr<TftpPacket> handleTftpData(const uint8_t* data, size_t length)
|
static std::unique_ptr<TftpPacket> handleTftpData(const uint8_t* buffer, size_t size)
|
||||||
{
|
{
|
||||||
auto packet = TftpDataPacket::Deserialize(data, length);
|
TftpDataPacket packet;
|
||||||
|
const auto tftpSize = TftpDataPacket::Deserialize(packet, buffer, size);
|
||||||
|
if (size == 0)
|
||||||
|
{
|
||||||
|
// TODO log
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
if (packet.blockNumber != currentBlockNumber + 1)
|
if (packet.blockNumber != currentBlockNumber + 1)
|
||||||
{
|
{
|
||||||
|
@ -268,11 +274,15 @@ size_t TftpAcknowledgementPacket::Serialize(uint8_t* buffer) const
|
||||||
//
|
//
|
||||||
TftpDataPacket::TftpDataPacket() : opcode(TFTP_OP_DATA) {}
|
TftpDataPacket::TftpDataPacket() : opcode(TFTP_OP_DATA) {}
|
||||||
|
|
||||||
TftpDataPacket TftpDataPacket::Deserialize(const uint8_t* buffer, size_t length)
|
size_t TftpDataPacket::Deserialize(
|
||||||
{
|
TftpDataPacket& out, const uint8_t* buffer, size_t size
|
||||||
TftpDataPacket self;
|
) {
|
||||||
self.opcode = buffer[0] << 8 | buffer[1];
|
if (size < sizeof(opcode) + sizeof(blockNumber)) {
|
||||||
self.blockNumber = buffer[2] << 8 | buffer[3];
|
return 0;
|
||||||
self.data = std::vector<uint8_t>(buffer + 4, buffer + length);
|
}
|
||||||
return self;
|
|
||||||
|
out.opcode = buffer[0] << 8 | buffer[1];
|
||||||
|
out.blockNumber = buffer[2] << 8 | buffer[3];
|
||||||
|
out.data = std::vector<uint8_t>(buffer + 4, buffer + size);
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,5 +64,6 @@ struct TftpDataPacket
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
TftpDataPacket();
|
TftpDataPacket();
|
||||||
static TftpDataPacket Deserialize(const uint8_t* buffer, size_t length);
|
static size_t Deserialize(
|
||||||
|
TftpDataPacket& out, const uint8_t* buffer, size_t length);
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,7 +14,7 @@ UdpDatagramHeader::UdpDatagramHeader(
|
||||||
checksum(0)
|
checksum(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
size_t UdpDatagramHeader::Serialize(uint8_t* buffer)
|
size_t UdpDatagramHeader::Serialize(uint8_t* buffer) const
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
buffer[i++] = sourcePort >> 8;
|
buffer[i++] = sourcePort >> 8;
|
||||||
|
|
|
@ -22,6 +22,6 @@ struct UdpDatagramHeader
|
||||||
sizeof(checksum);
|
sizeof(checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Serialize(uint8_t* buffer);
|
size_t Serialize(uint8_t* buffer) const;
|
||||||
static UdpDatagramHeader Deserialize(const uint8_t* buffer);
|
static UdpDatagramHeader Deserialize(const uint8_t* buffer);
|
||||||
};
|
};
|
||||||
|
|
35
src/net.cpp
35
src/net.cpp
|
@ -6,6 +6,7 @@
|
||||||
#include "net-icmp.h"
|
#include "net-icmp.h"
|
||||||
#include "net-ipv4.h"
|
#include "net-ipv4.h"
|
||||||
#include "net-udp.h"
|
#include "net-udp.h"
|
||||||
|
#include "net-dhcp.h"
|
||||||
#include "net.h"
|
#include "net.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
@ -82,9 +83,11 @@ void HandleArpFrame(const EthernetFrameHeader ethernetHeader, uint8_t* buffer)
|
||||||
//
|
//
|
||||||
// IPv4
|
// IPv4
|
||||||
//
|
//
|
||||||
void HandleIpv4Packet(const EthernetFrameHeader ethernetHeader, const uint8_t* buffer)
|
void HandleIpv4Packet(
|
||||||
{
|
const EthernetFrameHeader ethernetHeader, const uint8_t* buffer, const size_t size
|
||||||
|
) {
|
||||||
const auto ipv4Header = Ipv4Header::Deserialize(buffer);
|
const auto ipv4Header = Ipv4Header::Deserialize(buffer);
|
||||||
|
const auto offset = Ipv4Header::SerializedLength();
|
||||||
|
|
||||||
// Update ARP table
|
// Update ARP table
|
||||||
ArpTable.insert(std::make_pair(ipv4Header.sourceIp, ethernetHeader.macSource));
|
ArpTable.insert(std::make_pair(ipv4Header.sourceIp, ethernetHeader.macSource));
|
||||||
|
@ -100,8 +103,7 @@ void HandleIpv4Packet(const EthernetFrameHeader ethernetHeader, const uint8_t* b
|
||||||
}
|
}
|
||||||
else if (ipv4Header.protocol == IP_PROTO_UDP)
|
else if (ipv4Header.protocol == IP_PROTO_UDP)
|
||||||
{
|
{
|
||||||
HandleUdpDatagram(
|
HandleUdpDatagram(ethernetHeader, ipv4Header, buffer + offset, size - offset);
|
||||||
ethernetHeader, ipv4Header, buffer + ipv4Header.SerializedLength());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,12 +113,20 @@ void HandleIpv4Packet(const EthernetFrameHeader ethernetHeader, const uint8_t* b
|
||||||
void HandleUdpDatagram(
|
void HandleUdpDatagram(
|
||||||
const EthernetFrameHeader ethernetHeader,
|
const EthernetFrameHeader ethernetHeader,
|
||||||
const Ipv4Header ipv4Header,
|
const Ipv4Header ipv4Header,
|
||||||
const uint8_t* buffer
|
const uint8_t* buffer,
|
||||||
)
|
const size_t size
|
||||||
{
|
) {
|
||||||
const auto udpHeader = UdpDatagramHeader::Deserialize(buffer);
|
const auto udpHeader = UdpDatagramHeader::Deserialize(buffer);
|
||||||
|
|
||||||
if (udpHeader.destinationPort == 69) // nice
|
if (udpHeader.destinationPort == UDP_PORT_DHCP_CLIENT)
|
||||||
|
{
|
||||||
|
Net::Dhcp::HandlePacket(
|
||||||
|
ethernetHeader,
|
||||||
|
buffer + udpHeader.SerializedLength(),
|
||||||
|
size - udpHeader.SerializedLength()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else if (udpHeader.destinationPort == UDP_PORT_TFTP)
|
||||||
{
|
{
|
||||||
HandleTftpDatagram(
|
HandleTftpDatagram(
|
||||||
ethernetHeader,
|
ethernetHeader,
|
||||||
|
@ -155,8 +165,10 @@ void SendIcmpEchoRequest(MacAddress mac, uint32_t ip)
|
||||||
|
|
||||||
void HandleIcmpFrame(const uint8_t* buffer)
|
void HandleIcmpFrame(const uint8_t* buffer)
|
||||||
{
|
{
|
||||||
|
// TODO Don't re-parse the upper layers
|
||||||
size_t requestSize = 0;
|
size_t requestSize = 0;
|
||||||
const auto requestEthernetHeader = EthernetFrameHeader::Deserialize(buffer + requestSize);
|
const auto requestEthernetHeader =
|
||||||
|
EthernetFrameHeader::Deserialize(buffer + requestSize);
|
||||||
requestSize += requestEthernetHeader.SerializedLength();
|
requestSize += requestEthernetHeader.SerializedLength();
|
||||||
const auto requestIpv4Header = Ipv4Header::Deserialize(buffer + requestSize);
|
const auto requestIpv4Header = Ipv4Header::Deserialize(buffer + requestSize);
|
||||||
requestSize += requestIpv4Header.SerializedLength();
|
requestSize += requestIpv4Header.SerializedLength();
|
||||||
|
@ -165,7 +177,8 @@ void HandleIcmpFrame(const uint8_t* buffer)
|
||||||
|
|
||||||
if (requestIcmpHeader.type == ICMP_ECHO_REQUEST)
|
if (requestIcmpHeader.type == ICMP_ECHO_REQUEST)
|
||||||
{
|
{
|
||||||
const auto requestEchoHeader = IcmpEchoHeader::Deserialize(buffer + requestSize);
|
const auto requestEchoHeader =
|
||||||
|
IcmpEchoHeader::Deserialize(buffer + requestSize);
|
||||||
requestSize += requestEchoHeader.SerializedLength();
|
requestSize += requestEchoHeader.SerializedLength();
|
||||||
|
|
||||||
const IcmpPacketHeader responseIcmpHeader(ICMP_ECHO_REPLY, 0);
|
const IcmpPacketHeader responseIcmpHeader(ICMP_ECHO_REPLY, 0);
|
||||||
|
@ -309,7 +322,7 @@ MacAddress GetMacAddress()
|
||||||
return macAddress;
|
return macAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
const uint32_t Ipv4Address = 0xC0A80164;
|
uint32_t Ipv4Address = 0xC0A80164;
|
||||||
const MacAddress MacBroadcast{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
const MacAddress MacBroadcast{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||||
|
|
||||||
bool FileUploaded = false;
|
bool FileUploaded = false;
|
||||||
|
|
14
src/net.h
14
src/net.h
|
@ -15,6 +15,12 @@ enum ArpOperation {
|
||||||
ARP_OPERATION_REPLY = 2,
|
ARP_OPERATION_REPLY = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum UdpPort {
|
||||||
|
UDP_PORT_DHCP_SERVER = 67,
|
||||||
|
UDP_PORT_DHCP_CLIENT = 68,
|
||||||
|
UDP_PORT_TFTP = 69, // nice
|
||||||
|
};
|
||||||
|
|
||||||
typedef std::array<uint8_t, 6> MacAddress;
|
typedef std::array<uint8_t, 6> MacAddress;
|
||||||
|
|
||||||
struct EthernetFrameHeader;
|
struct EthernetFrameHeader;
|
||||||
|
@ -41,7 +47,8 @@ void SendArpAnnouncement(MacAddress mac, uint32_t ip);
|
||||||
//
|
//
|
||||||
// IPv4
|
// IPv4
|
||||||
//
|
//
|
||||||
void HandleIpv4Packet(const EthernetFrameHeader ethernetHeader, const uint8_t* buffer);
|
void HandleIpv4Packet(
|
||||||
|
const EthernetFrameHeader ethernetHeader, const uint8_t* buffer, const size_t size);
|
||||||
|
|
||||||
//
|
//
|
||||||
// UDP
|
// UDP
|
||||||
|
@ -49,7 +56,8 @@ void HandleIpv4Packet(const EthernetFrameHeader ethernetHeader, const uint8_t* b
|
||||||
void HandleUdpDatagram(
|
void HandleUdpDatagram(
|
||||||
const EthernetFrameHeader ethernetHeader,
|
const EthernetFrameHeader ethernetHeader,
|
||||||
const Ipv4Header ipv4Header,
|
const Ipv4Header ipv4Header,
|
||||||
const uint8_t* buffer
|
const uint8_t* buffer,
|
||||||
|
const size_t size
|
||||||
);
|
);
|
||||||
|
|
||||||
void HandleTftpDatagram(
|
void HandleTftpDatagram(
|
||||||
|
@ -73,7 +81,7 @@ std::uint16_t InternetChecksum(const void* data, std::size_t size);
|
||||||
MacAddress GetMacAddress();
|
MacAddress GetMacAddress();
|
||||||
|
|
||||||
extern const MacAddress MacBroadcast;
|
extern const MacAddress MacBroadcast;
|
||||||
extern const uint32_t Ipv4Address;
|
extern uint32_t Ipv4Address;
|
||||||
|
|
||||||
extern bool FileUploaded;
|
extern bool FileUploaded;
|
||||||
extern std::unordered_map<std::uint32_t, MacAddress> ArpTable;
|
extern std::unordered_map<std::uint32_t, MacAddress> ArpTable;
|
||||||
|
|
Loading…
Reference in a new issue