diff --git a/Makefile b/Makefile
index bf7d55c..c5127ad 100644
--- a/Makefile
+++ b/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.o net-tftp.o net-arp.o net-ethernet.o net-icmp.o net-ipv4.o net-udp.o net-dhcp.o
SRCDIR = src
OBJS := $(addprefix $(SRCDIR)/, $(OBJS))
diff --git a/src/main.cpp b/src/main.cpp
index 7f30d46..8b13317 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -2,17 +2,17 @@
// Copyright(C) 2018 Stephen White
//
// This file is part of Pi1541.
-//
+//
// Pi1541 is free software : you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
-//
+//
// Pi1541 is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
-//
+//
// You should have received a copy of the GNU General Public License
// along with Pi1541. If not, see .
@@ -377,6 +377,7 @@ void updateNetwork()
}
auto ethernetHeader = EthernetFrameHeader::Deserialize(ipBuffer);
+ const auto offset = ethernetHeader.SerializedLength();
static bool announcementSent = false;
if (!announcementSent)
@@ -388,10 +389,10 @@ void updateNetwork()
switch (ethernetHeader.type)
{
case ETHERTYPE_ARP:
- HandleArpFrame(ethernetHeader, ipBuffer + ethernetHeader.SerializedLength());
+ HandleArpFrame(ethernetHeader, ipBuffer + offset);
break;
case ETHERTYPE_IPV4:
- HandleIpv4Packet(ethernetHeader, ipBuffer + ethernetHeader.SerializedLength());
+ HandleIpv4Packet(ethernetHeader, ipBuffer + offset, sizeof(ipBuffer) - offset);
break;
}
}
@@ -659,7 +660,7 @@ void UpdateScreen()
//if (options.GetSupportUARTInput())
// UpdateUartControls(refreshUartStatusDisplay, oldLED, oldMotor, oldATN, oldDATA, oldCLOCK, oldTrack, romIndex);
-
+
updateNetwork();
// Go back to sleep. The USB irq will wake us up again.
@@ -831,7 +832,7 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser)
#endif
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();
bool extraRAM = options.GetExtraRAM();
@@ -995,7 +996,7 @@ EXIT_TYPE Emulate1541(FileBrowser* fileBrowser)
} while (ctAfter == ctBefore);
#endif
ctBefore = ctAfter;
-
+
if (!refreshOutsAfterCPUStep)
{
IEC_Bus::ReadEmulationMode1541();
@@ -1085,7 +1086,7 @@ EXIT_TYPE Emulate1581(FileBrowser* fileBrowser)
#endif
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();
DataBusReadFn dataBusRead = read6502_1581;
@@ -1440,7 +1441,7 @@ void emulator()
IEC_Bus::WaitUntilReset();
emulating = IEC_COMMANDS;
-
+
if ((exitReason == EXIT_RESET) && (options.GetOnResetChangeToStartingFolder() || selectedViaIECCommands))
fileBrowser->DisplayRoot(); // TO CHECK
@@ -1462,9 +1463,9 @@ void emulator()
//}
#ifdef HAS_MULTICORE
-extern "C"
+extern "C"
{
- void run_core()
+ void run_core()
{
enable_MMU_and_IDCaches();
_enable_unaligned_access();
@@ -1978,7 +1979,7 @@ extern "C"
#endif
inputMappings = new InputMappings();
//USPiMouseRegisterStatusHandler(MouseHandler);
-
+
while (!USPiEthernetAvailable()) {
snprintf(tempBuffer, tempBufferSize, "Waiting for ethernet...");
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
@@ -2048,4 +2049,3 @@ extern "C"
#endif
}
}
-
diff --git a/src/net-dhcp.cpp b/src/net-dhcp.cpp
new file mode 100644
index 0000000..6322807
--- /dev/null
+++ b/src/net-dhcp.cpp
@@ -0,0 +1,265 @@
+#include "net-dhcp.h"
+#include "net-udp.h"
+#include "net-ipv4.h"
+#include "net-ethernet.h"
+#include
+#include
+#include "types.h"
+#include
+#include
+
+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(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(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 offeredIpAddresses;
+ static std::vector serverIpAddresses;
+ static std::vector 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
diff --git a/src/net-dhcp.h b/src/net-dhcp.h
new file mode 100644
index 0000000..afcb2dc
--- /dev/null
+++ b/src/net-dhcp.h
@@ -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 clientHardwareAddress;
+
+ /// Optional server host name, null terminated string.
+ std::array serverHostname;
+
+ /// Boot file name, null terminated string; "generic" name or null in
+ /// DHCPDISCOVER, fully qualified directory-path name in DHCPOFFER.
+ std::array bootFile;
+
+ /// Always 99, 130, 83, 99
+ std::array 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
diff --git a/src/net-ethernet.cpp b/src/net-ethernet.cpp
index cbf2e24..6a90867 100644
--- a/src/net-ethernet.cpp
+++ b/src/net-ethernet.cpp
@@ -4,37 +4,48 @@ EthernetFrameHeader::EthernetFrameHeader()
{}
EthernetFrameHeader::EthernetFrameHeader(std::uint16_t type) :
- macDestination{255, 255, 255, 255, 255, 255},
- macSource{0, 0, 0, 0, 0, 0},
- type(type)
- {}
+ macDestination{255, 255, 255, 255, 255, 255},
+ macSource{0, 0, 0, 0, 0, 0},
+ type(type)
+{}
EthernetFrameHeader::EthernetFrameHeader(
- MacAddress macDestination, MacAddress macSource, uint16_t type
-) : macDestination(macDestination), macSource(macSource), type(type)
+ MacAddress macSource, uint16_t 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 i = 0;
+ std::size_t i = 0;
- std::memcpy(buffer + i, macDestination.data(), macDestination.size());
- i += sizeof(macDestination);
+ std::memcpy(buffer + i, macDestination.data(), macDestination.size());
+ i += sizeof(macDestination);
- std::memcpy(buffer + i, macSource.data(), macSource.size());
- i += sizeof(macSource);
+ std::memcpy(buffer + i, macSource.data(), macSource.size());
+ i += sizeof(macSource);
- buffer[i++] = type >> 8;
- buffer[i++] = type;
+ buffer[i++] = type >> 8;
+ buffer[i++] = type;
- return i;
+ return i;
}
EthernetFrameHeader EthernetFrameHeader::Deserialize(const uint8_t* buffer)
{
- EthernetFrameHeader 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];
- return self;
+ EthernetFrameHeader 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];
+ return self;
}
diff --git a/src/net-ethernet.h b/src/net-ethernet.h
index 32258bd..b5ccfa7 100644
--- a/src/net-ethernet.h
+++ b/src/net-ethernet.h
@@ -9,6 +9,7 @@ struct EthernetFrameHeader
EthernetFrameHeader();
EthernetFrameHeader(std::uint16_t type);
+ EthernetFrameHeader(MacAddress macSource, uint16_t type);
EthernetFrameHeader(MacAddress macDestination, MacAddress macSource, uint16_t type);
constexpr static std::size_t SerializedLength()
diff --git a/src/net-tftp.cpp b/src/net-tftp.cpp
index 62770e5..54bc46f 100644
--- a/src/net-tftp.cpp
+++ b/src/net-tftp.cpp
@@ -71,9 +71,15 @@ static std::unique_ptr handleTftpWriteRequest(const uint8_t* data)
return response;
}
-static std::unique_ptr handleTftpData(const uint8_t* data, size_t length)
+static std::unique_ptr 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)
{
@@ -268,11 +274,15 @@ size_t TftpAcknowledgementPacket::Serialize(uint8_t* buffer) const
//
TftpDataPacket::TftpDataPacket() : opcode(TFTP_OP_DATA) {}
-TftpDataPacket TftpDataPacket::Deserialize(const uint8_t* buffer, size_t length)
-{
- TftpDataPacket self;
- self.opcode = buffer[0] << 8 | buffer[1];
- self.blockNumber = buffer[2] << 8 | buffer[3];
- self.data = std::vector(buffer + 4, buffer + length);
- return self;
+size_t TftpDataPacket::Deserialize(
+ TftpDataPacket& out, const uint8_t* buffer, size_t size
+) {
+ if (size < sizeof(opcode) + sizeof(blockNumber)) {
+ return 0;
+ }
+
+ out.opcode = buffer[0] << 8 | buffer[1];
+ out.blockNumber = buffer[2] << 8 | buffer[3];
+ out.data = std::vector(buffer + 4, buffer + size);
+ return size;
}
diff --git a/src/net-tftp.h b/src/net-tftp.h
index 4042633..05ef1a0 100644
--- a/src/net-tftp.h
+++ b/src/net-tftp.h
@@ -64,5 +64,6 @@ struct TftpDataPacket
std::vector data;
TftpDataPacket();
- static TftpDataPacket Deserialize(const uint8_t* buffer, size_t length);
+ static size_t Deserialize(
+ TftpDataPacket& out, const uint8_t* buffer, size_t length);
};
diff --git a/src/net-udp.cpp b/src/net-udp.cpp
index 48a036a..83faf85 100644
--- a/src/net-udp.cpp
+++ b/src/net-udp.cpp
@@ -14,7 +14,7 @@ UdpDatagramHeader::UdpDatagramHeader(
checksum(0)
{}
-size_t UdpDatagramHeader::Serialize(uint8_t* buffer)
+size_t UdpDatagramHeader::Serialize(uint8_t* buffer) const
{
size_t i = 0;
buffer[i++] = sourcePort >> 8;
diff --git a/src/net-udp.h b/src/net-udp.h
index 2084a54..c18d17a 100644
--- a/src/net-udp.h
+++ b/src/net-udp.h
@@ -22,6 +22,6 @@ struct UdpDatagramHeader
sizeof(checksum);
}
- size_t Serialize(uint8_t* buffer);
+ size_t Serialize(uint8_t* buffer) const;
static UdpDatagramHeader Deserialize(const uint8_t* buffer);
};
diff --git a/src/net.cpp b/src/net.cpp
index 5c59a12..5670db3 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -6,6 +6,7 @@
#include "net-icmp.h"
#include "net-ipv4.h"
#include "net-udp.h"
+#include "net-dhcp.h"
#include "net.h"
#include "types.h"
@@ -82,9 +83,11 @@ void HandleArpFrame(const EthernetFrameHeader ethernetHeader, uint8_t* buffer)
//
// 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 offset = Ipv4Header::SerializedLength();
// Update ARP table
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)
{
- HandleUdpDatagram(
- ethernetHeader, ipv4Header, buffer + ipv4Header.SerializedLength());
+ HandleUdpDatagram(ethernetHeader, ipv4Header, buffer + offset, size - offset);
}
}
@@ -111,12 +113,20 @@ void HandleIpv4Packet(const EthernetFrameHeader ethernetHeader, const uint8_t* b
void HandleUdpDatagram(
const EthernetFrameHeader ethernetHeader,
const Ipv4Header ipv4Header,
- const uint8_t* buffer
-)
-{
+ const uint8_t* buffer,
+ const size_t size
+) {
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(
ethernetHeader,
@@ -155,8 +165,10 @@ void SendIcmpEchoRequest(MacAddress mac, uint32_t ip)
void HandleIcmpFrame(const uint8_t* buffer)
{
+ // TODO Don't re-parse the upper layers
size_t requestSize = 0;
- const auto requestEthernetHeader = EthernetFrameHeader::Deserialize(buffer + requestSize);
+ const auto requestEthernetHeader =
+ EthernetFrameHeader::Deserialize(buffer + requestSize);
requestSize += requestEthernetHeader.SerializedLength();
const auto requestIpv4Header = Ipv4Header::Deserialize(buffer + requestSize);
requestSize += requestIpv4Header.SerializedLength();
@@ -165,7 +177,8 @@ void HandleIcmpFrame(const uint8_t* buffer)
if (requestIcmpHeader.type == ICMP_ECHO_REQUEST)
{
- const auto requestEchoHeader = IcmpEchoHeader::Deserialize(buffer + requestSize);
+ const auto requestEchoHeader =
+ IcmpEchoHeader::Deserialize(buffer + requestSize);
requestSize += requestEchoHeader.SerializedLength();
const IcmpPacketHeader responseIcmpHeader(ICMP_ECHO_REPLY, 0);
@@ -309,7 +322,7 @@ MacAddress GetMacAddress()
return macAddress;
}
-const uint32_t Ipv4Address = 0xC0A80164;
+uint32_t Ipv4Address = 0xC0A80164;
const MacAddress MacBroadcast{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
bool FileUploaded = false;
diff --git a/src/net.h b/src/net.h
index dea68d5..3123512 100644
--- a/src/net.h
+++ b/src/net.h
@@ -15,6 +15,12 @@ enum ArpOperation {
ARP_OPERATION_REPLY = 2,
};
+enum UdpPort {
+ UDP_PORT_DHCP_SERVER = 67,
+ UDP_PORT_DHCP_CLIENT = 68,
+ UDP_PORT_TFTP = 69, // nice
+};
+
typedef std::array MacAddress;
struct EthernetFrameHeader;
@@ -41,7 +47,8 @@ void SendArpAnnouncement(MacAddress mac, uint32_t ip);
//
// IPv4
//
-void HandleIpv4Packet(const EthernetFrameHeader ethernetHeader, const uint8_t* buffer);
+void HandleIpv4Packet(
+ const EthernetFrameHeader ethernetHeader, const uint8_t* buffer, const size_t size);
//
// UDP
@@ -49,7 +56,8 @@ void HandleIpv4Packet(const EthernetFrameHeader ethernetHeader, const uint8_t* b
void HandleUdpDatagram(
const EthernetFrameHeader ethernetHeader,
const Ipv4Header ipv4Header,
- const uint8_t* buffer
+ const uint8_t* buffer,
+ const size_t size
);
void HandleTftpDatagram(
@@ -73,7 +81,7 @@ std::uint16_t InternetChecksum(const void* data, std::size_t size);
MacAddress GetMacAddress();
extern const MacAddress MacBroadcast;
-extern const uint32_t Ipv4Address;
+extern uint32_t Ipv4Address;
extern bool FileUploaded;
extern std::unordered_map ArpTable;