Base implementation of DHCP

This commit is contained in:
Sijmen 2020-12-27 17:35:10 +01:00
parent bed8266327
commit fc39c7a99f
Signed by: vijfhoek
GPG key ID: DAF7821E067D9C48
12 changed files with 462 additions and 60 deletions

View file

@ -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))

View file

@ -2,17 +2,17 @@
// Copyright(C) 2018 Stephen White // Copyright(C) 2018 Stephen White
// //
// This file is part of Pi1541. // This file is part of Pi1541.
// //
// Pi1541 is free software : you can redistribute it and/or modify // Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by // it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or // the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version. // (at your option) any later version.
// //
// Pi1541 is distributed in the hope that it will be useful, // Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of // but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details. // GNU General Public License for more details.
// //
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see <http://www.gnu.org/licenses/>. // along with Pi1541. If not, see <http://www.gnu.org/licenses/>.
@ -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;
} }
} }
@ -659,7 +660,7 @@ void UpdateScreen()
//if (options.GetSupportUARTInput()) //if (options.GetSupportUARTInput())
// UpdateUartControls(refreshUartStatusDisplay, oldLED, oldMotor, oldATN, oldDATA, oldCLOCK, oldTrack, romIndex); // UpdateUartControls(refreshUartStatusDisplay, oldLED, oldMotor, oldATN, oldDATA, oldCLOCK, oldTrack, romIndex);
updateNetwork(); updateNetwork();
// Go back to sleep. The USB irq will wake us up again. // Go back to sleep. The USB irq will wake us up again.
@ -831,7 +832,7 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser)
#endif #endif
inputMappings->directDiskSwapRequest = 0; inputMappings->directDiskSwapRequest = 0;
// Force an update on all the buttons now before we start emulation mode. // Force an update on all the buttons now before we start emulation mode.
IEC_Bus::ReadBrowseMode(); IEC_Bus::ReadBrowseMode();
bool extraRAM = options.GetExtraRAM(); bool extraRAM = options.GetExtraRAM();
@ -995,7 +996,7 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser)
} while (ctAfter == ctBefore); } while (ctAfter == ctBefore);
#endif #endif
ctBefore = ctAfter; ctBefore = ctAfter;
if (!refreshOutsAfterCPUStep) if (!refreshOutsAfterCPUStep)
{ {
IEC_Bus::ReadEmulationMode1541(); IEC_Bus::ReadEmulationMode1541();
@ -1085,7 +1086,7 @@ EXIT_TYPE Emulate1581(FileBrowser* fileBrowser)
#endif #endif
inputMappings->directDiskSwapRequest = 0; inputMappings->directDiskSwapRequest = 0;
// Force an update on all the buttons now before we start emulation mode. // Force an update on all the buttons now before we start emulation mode.
IEC_Bus::ReadBrowseMode(); IEC_Bus::ReadBrowseMode();
DataBusReadFn dataBusRead = read6502_1581; DataBusReadFn dataBusRead = read6502_1581;
@ -1440,7 +1441,7 @@ void emulator()
IEC_Bus::WaitUntilReset(); IEC_Bus::WaitUntilReset();
emulating = IEC_COMMANDS; emulating = IEC_COMMANDS;
if ((exitReason == EXIT_RESET) && (options.GetOnResetChangeToStartingFolder() || selectedViaIECCommands)) if ((exitReason == EXIT_RESET) && (options.GetOnResetChangeToStartingFolder() || selectedViaIECCommands))
fileBrowser->DisplayRoot(); // TO CHECK fileBrowser->DisplayRoot(); // TO CHECK
@ -1462,9 +1463,9 @@ void emulator()
//} //}
#ifdef HAS_MULTICORE #ifdef HAS_MULTICORE
extern "C" extern "C"
{ {
void run_core() void run_core()
{ {
enable_MMU_and_IDCaches(); enable_MMU_and_IDCaches();
_enable_unaligned_access(); _enable_unaligned_access();
@ -1978,7 +1979,7 @@ extern "C"
#endif #endif
inputMappings = new InputMappings(); inputMappings = new InputMappings();
//USPiMouseRegisterStatusHandler(MouseHandler); //USPiMouseRegisterStatusHandler(MouseHandler);
while (!USPiEthernetAvailable()) { while (!USPiEthernetAvailable()) {
snprintf(tempBuffer, tempBufferSize, "Waiting for ethernet..."); snprintf(tempBuffer, tempBufferSize, "Waiting for ethernet...");
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK); screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
@ -2048,4 +2049,3 @@ extern "C"
#endif #endif
} }
} }

265
src/net-dhcp.cpp Normal file
View 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
View 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

View file

@ -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;
} }

View file

@ -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()

View file

@ -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;
} }

View file

@ -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);
}; };

View file

@ -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;

View file

@ -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);
}; };

View file

@ -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;

View file

@ -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;