From 9638a0dc3d3c4a1e38c509fe81bed055dbed3c36 Mon Sep 17 00:00:00 2001 From: Sijmen Schoon Date: Sun, 27 Dec 2020 22:17:36 +0100 Subject: [PATCH] Move ARP and TFTP to their own namespaces --- src/main.cpp | 4 +- src/net-arp.cpp | 169 +++++++++++----- src/net-arp.h | 91 ++++++--- src/net-tftp.cpp | 512 ++++++++++++++++++++++++----------------------- src/net-tftp.h | 115 ++++++----- src/net.cpp | 74 +------ src/net.h | 25 --- 7 files changed, 516 insertions(+), 474 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 8b13317..f1e7fe3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -382,14 +382,14 @@ void updateNetwork() static bool announcementSent = false; if (!announcementSent) { - SendArpAnnouncement(GetMacAddress(), Ipv4Address); + Net::Arp::SendAnnouncement(GetMacAddress(), Ipv4Address); announcementSent = true; } switch (ethernetHeader.type) { case ETHERTYPE_ARP: - HandleArpFrame(ethernetHeader, ipBuffer + offset); + Net::Arp::HandlePacket(ethernetHeader, ipBuffer + offset); break; case ETHERTYPE_IPV4: HandleIpv4Packet(ethernetHeader, ipBuffer + offset, sizeof(ipBuffer) - offset); diff --git a/src/net-arp.cpp b/src/net-arp.cpp index e183860..5b1c34d 100644 --- a/src/net-arp.cpp +++ b/src/net-arp.cpp @@ -1,61 +1,134 @@ #include "net-arp.h" +#include "net-ethernet.h" -Ipv4ArpPacket::Ipv4ArpPacket() -{} +#include "types.h" +#include -Ipv4ArpPacket::Ipv4ArpPacket(std::uint16_t operation) : - hardwareType(1), // Ethernet - protocolType(ETHERTYPE_IPV4), // IPv4 - hardwareAddressLength(6), - protocolAddressLength(4), - operation(operation) -{} - -std::size_t Ipv4ArpPacket::Serialize(std::uint8_t* buffer) +namespace Net::Arp { - buffer[0] = hardwareType >> 8; - buffer[1] = hardwareType; - buffer[2] = protocolType >> 8; - buffer[3] = protocolType; - buffer[4] = hardwareAddressLength; - buffer[5] = protocolAddressLength; - buffer[6] = operation >> 8; - buffer[7] = operation; + Ipv4ArpPacket::Ipv4ArpPacket() + {} - memcpy(buffer + 8, senderMac.data(), 6); + Ipv4ArpPacket::Ipv4ArpPacket(std::uint16_t operation) : + hardwareType(1), // Ethernet + protocolType(ETHERTYPE_IPV4), // IPv4 + hardwareAddressLength(6), + protocolAddressLength(4), + operation(operation) + {} - buffer[14] = senderIp >> 24; - buffer[15] = senderIp >> 16; - buffer[16] = senderIp >> 8; - buffer[17] = senderIp; + std::size_t Ipv4ArpPacket::Serialize(std::uint8_t* buffer) + { + buffer[0] = hardwareType >> 8; + buffer[1] = hardwareType; + buffer[2] = protocolType >> 8; + buffer[3] = protocolType; + buffer[4] = hardwareAddressLength; + buffer[5] = protocolAddressLength; + buffer[6] = operation >> 8; + buffer[7] = operation; - memcpy(buffer + 18, targetMac.data(), 6); + memcpy(buffer + 8, senderMac.data(), 6); - buffer[24] = targetIp >> 24; - buffer[25] = targetIp >> 16; - buffer[26] = targetIp >> 8; - buffer[27] = targetIp; + buffer[14] = senderIp >> 24; + buffer[15] = senderIp >> 16; + buffer[16] = senderIp >> 8; + buffer[17] = senderIp; - return 28; -} + memcpy(buffer + 18, targetMac.data(), 6); -// Static -Ipv4ArpPacket Ipv4ArpPacket::Deserialize(const uint8_t* buffer) -{ - Ipv4ArpPacket self; + buffer[24] = targetIp >> 24; + buffer[25] = targetIp >> 16; + buffer[26] = targetIp >> 8; + buffer[27] = targetIp; - self.hardwareType = buffer[0] << 8 | buffer[1]; - self.protocolType = buffer[2] << 8 | buffer[3]; - self.hardwareAddressLength = buffer[4]; - self.protocolAddressLength = buffer[5]; - self.operation = buffer[6] << 8 | buffer[7]; + return 28; + } - memcpy(self.senderMac.data(), buffer + 8, 6); - self.senderIp = - buffer[14] << 24 | buffer[15] << 16 | buffer[16] << 8 | buffer[17]; - memcpy(self.targetMac.data(), buffer + 18, 6); - self.targetIp = - buffer[24] << 24 | buffer[25] << 16 | buffer[26] << 8 | buffer[27]; + // Static + Ipv4ArpPacket Ipv4ArpPacket::Deserialize(const uint8_t* buffer) + { + Ipv4ArpPacket self; - return self; -} + self.hardwareType = buffer[0] << 8 | buffer[1]; + self.protocolType = buffer[2] << 8 | buffer[3]; + self.hardwareAddressLength = buffer[4]; + self.protocolAddressLength = buffer[5]; + self.operation = buffer[6] << 8 | buffer[7]; + + memcpy(self.senderMac.data(), buffer + 8, 6); + self.senderIp = + buffer[14] << 24 | buffer[15] << 16 | buffer[16] << 8 | buffer[17]; + memcpy(self.targetMac.data(), buffer + 18, 6); + self.targetIp = + buffer[24] << 24 | buffer[25] << 16 | buffer[26] << 8 | buffer[27]; + + return self; + } + + void SendPacket( + ArpOperation operation, + MacAddress targetMac, + MacAddress senderMac, + uint32_t targetIp, + uint32_t senderIp) + { + Ipv4ArpPacket arpPacket(operation); + arpPacket.targetMac = targetMac; + arpPacket.senderMac = senderMac; + arpPacket.targetIp = targetIp; + arpPacket.senderIp = senderIp; + + EthernetFrameHeader ethernetHeader(senderMac, targetMac, ETHERTYPE_ARP); + + uint8_t buffer[USPI_FRAME_BUFFER_SIZE]; + size_t size = 0; + size += ethernetHeader.Serialize(buffer + size); + size += arpPacket.Serialize(buffer + size); + USPiSendFrame(buffer, size); + } + + void SendRequest( + MacAddress targetMac, MacAddress senderMac, uint32_t targetIp, uint32_t senderIp) + { + SendPacket(ARP_OPERATION_REQUEST, targetMac, senderMac, targetIp, senderIp); + } + + void SendReply( + MacAddress targetMac, MacAddress senderMac, uint32_t targetIp, uint32_t senderIp) + { + SendPacket(ARP_OPERATION_REPLY, targetMac, senderMac, targetIp, senderIp); + } + + void SendAnnouncement(MacAddress mac, uint32_t ip) + { + SendReply(MacBroadcast, mac, ip, ip); + } + + void HandlePacket(const EthernetFrameHeader ethernetHeader, uint8_t* buffer) + { + const auto macAddress = GetMacAddress(); + const auto arpPacket = Ipv4ArpPacket::Deserialize(buffer); + + if ( + arpPacket.hardwareType == 1 && + arpPacket.protocolType == ETHERTYPE_IPV4 && + arpPacket.operation == ARP_OPERATION_REQUEST && + arpPacket.targetIp == Ipv4Address) + { + SendReply(arpPacket.senderMac, macAddress, arpPacket.senderIp, Ipv4Address); + } + + else if ( + arpPacket.hardwareType == 1 && + arpPacket.protocolType == ETHERTYPE_IPV4 && + arpPacket.operation == ARP_OPERATION_REPLY && + arpPacket.targetIp == Ipv4Address && + arpPacket.targetMac == macAddress) + { + ArpTable.insert(std::make_pair(arpPacket.senderIp, arpPacket.senderMac)); + } + } + + std::unordered_map ArpTable; +}; // namespace Net::Arp diff --git a/src/net-arp.h b/src/net-arp.h index 50ee53b..f5d1574 100644 --- a/src/net-arp.h +++ b/src/net-arp.h @@ -1,37 +1,68 @@ #pragma once #include "net.h" -struct Ipv4ArpPacket +namespace Net::Arp { - std::uint16_t hardwareType; - std::uint16_t protocolType; - std::uint8_t hardwareAddressLength; - std::uint8_t protocolAddressLength; - std::uint16_t operation; - - MacAddress senderMac; - std::uint32_t senderIp; - MacAddress targetMac; - std::uint32_t targetIp; - - Ipv4ArpPacket(); - Ipv4ArpPacket(std::uint16_t operation); - - constexpr std::size_t SerializedLength() const + struct Ipv4ArpPacket { - return - sizeof(hardwareType) + - sizeof(protocolType) + - sizeof(hardwareAddressLength) + - sizeof(protocolAddressLength) + - sizeof(operation) + - senderMac.size() + - sizeof(senderIp) + - targetMac.size() + - sizeof(targetIp); - } + std::uint16_t hardwareType; + std::uint16_t protocolType; + std::uint8_t hardwareAddressLength; + std::uint8_t protocolAddressLength; + std::uint16_t operation; - std::size_t Serialize(std::uint8_t* buffer); + MacAddress senderMac; + std::uint32_t senderIp; + MacAddress targetMac; + std::uint32_t targetIp; - static Ipv4ArpPacket Deserialize(const uint8_t* buffer); -}; + Ipv4ArpPacket(); + Ipv4ArpPacket(std::uint16_t operation); + + constexpr std::size_t SerializedLength() const + { + return + sizeof(hardwareType) + + sizeof(protocolType) + + sizeof(hardwareAddressLength) + + sizeof(protocolAddressLength) + + sizeof(operation) + + senderMac.size() + + sizeof(senderIp) + + targetMac.size() + + sizeof(targetIp); + } + + std::size_t Serialize(std::uint8_t* buffer); + + static Ipv4ArpPacket Deserialize(const uint8_t* buffer); + }; + + void HandlePacket(EthernetFrameHeader header, uint8_t* buffer); + + void SendPacket( + ArpOperation operation, + MacAddress targetMac, + MacAddress senderMac, + uint32_t senderIp, + uint32_t targetIp + ); + + void SendRequest( + MacAddress targetMac, + MacAddress senderMac, + uint32_t senderIp, + uint32_t targetIp + ); + + void SendReply( + MacAddress targetMac, + MacAddress senderMac, + uint32_t senderIp, + uint32_t targetIp + ); + + void SendAnnouncement(MacAddress mac, uint32_t ip); + + extern std::unordered_map ArpTable; +}; // namespace Net::Arp diff --git a/src/net-tftp.cpp b/src/net-tftp.cpp index 54bc46f..f5c2ec6 100644 --- a/src/net-tftp.cpp +++ b/src/net-tftp.cpp @@ -1,288 +1,308 @@ #include #include "ff.h" +#include "net-arp.h" #include "net-ethernet.h" #include "net-ipv4.h" #include "net-tftp.h" #include "net-udp.h" #include "net.h" -#include "types.h" +#include "types.h" #include -// TODO Allow multiple files open -static FIL outFile; -static bool shouldReboot = false; -static uint32_t currentBlockNumber = -1; - -static std::unique_ptr handleTftpWriteRequest(const uint8_t* data) +namespace Net::Tftp { - auto packet = TftpWriteReadRequestPacket::Deserialize(data); + // TODO Allow multiple files open + static FIL outFile; + static bool shouldReboot = false; + static uint32_t currentBlockNumber = -1; - // TODO Implement netscii, maybe - if (packet.mode != "octet") + static std::unique_ptr handleTftpWriteRequest(const uint8_t* data) { - return std::unique_ptr( - new TftpErrorPacket(0, "please use mode octet") - ); + auto packet = TftpWriteReadRequestPacket::Deserialize(data); + + // TODO Implement netscii, maybe + if (packet.mode != "octet") + { + return std::unique_ptr( + new TftpErrorPacket(0, "please use mode octet") + ); + } + + currentBlockNumber = 0; + + // TODO Return to the original working directory. + char workingDirectory[256]; + f_getcwd(workingDirectory, sizeof(workingDirectory)); + + // Try opening the file + auto separator = packet.filename.rfind('/', packet.filename.size()); + if (separator != std::string::npos) + { + auto path = "/" + packet.filename.substr(0, separator); + f_chdir(path.c_str()); + } + else + { + f_chdir("/"); + separator = 0; + } + + // Open the output file. + auto filename = packet.filename.substr(separator + 1); + const auto result = f_open(&outFile, filename.c_str(), FA_CREATE_ALWAYS | FA_WRITE); + + std::unique_ptr response; + if (result != FR_OK) + { + response = std::unique_ptr( + new TftpErrorPacket(0, "error opening target file") + ); + } + else + { + shouldReboot = + packet.filename == "kernel.img" || packet.filename == "options.txt"; + response = std::unique_ptr( + new TftpAcknowledgementPacket(currentBlockNumber) + ); + } + + // TODO Return to the original working directory here + + return response; } - currentBlockNumber = 0; - - // TODO Return to the original working directory. - char workingDirectory[256]; - f_getcwd(workingDirectory, sizeof(workingDirectory)); - - // Try opening the file - auto separator = packet.filename.rfind('/', packet.filename.size()); - if (separator != std::string::npos) + static std::unique_ptr handleTftpData(const uint8_t* buffer, size_t size) { - auto path = "/" + packet.filename.substr(0, separator); - f_chdir(path.c_str()); - } - else - { - f_chdir("/"); - separator = 0; - } + TftpDataPacket packet; + const auto tftpSize = TftpDataPacket::Deserialize(packet, buffer, size); + if (size == 0) + { + // TODO log + return nullptr; + } - // Open the output file. - auto filename = packet.filename.substr(separator + 1); - const auto result = f_open(&outFile, filename.c_str(), FA_CREATE_ALWAYS | FA_WRITE); + if (packet.blockNumber != currentBlockNumber + 1) + { + f_close(&outFile); + return std::unique_ptr( + new TftpErrorPacket(0, "invalid block number") + ); + } + currentBlockNumber = packet.blockNumber; - std::unique_ptr response; - if (result != FR_OK) - { - response = std::unique_ptr( - new TftpErrorPacket(0, "error opening target file") - ); - } - else - { - shouldReboot = - packet.filename == "kernel.img" || packet.filename == "options.txt"; - response = std::unique_ptr( + unsigned int bytesWritten; + const auto result = + f_write(&outFile, packet.data.data(), packet.data.size(), &bytesWritten); + + if (result != FR_OK || bytesWritten != packet.data.size()) + { + f_close(&outFile); + return std::unique_ptr(new TftpErrorPacket(0, "io error")); + } + + if (packet.data.size() < TFTP_BLOCK_SIZE) + { + // Close the file for the last packet. + f_close(&outFile); + } + + return std::unique_ptr( new TftpAcknowledgementPacket(currentBlockNumber) ); } - // TODO Return to the original working directory here + void HandleTftpDatagram( + const EthernetFrameHeader ethernetReqHeader, + const Ipv4Header ipv4ReqHeader, + const UdpDatagramHeader udpReqHeader, + const uint8_t* data + ) { + const auto opcode = static_cast(data[0] << 8 | data[1]); + std::unique_ptr response; + bool last = false; - return response; -} + if (opcode == Opcode::WriteRequest) + { + response = handleTftpWriteRequest(data); + } + else if (opcode == Opcode::Data) + { + const auto length = udpReqHeader.length - UdpDatagramHeader::SerializedLength(); + response = handleTftpData(data, length); + } + else + { + response = std::unique_ptr( + new TftpErrorPacket(4, "not implemented yet") + ); + } -static std::unique_ptr handleTftpData(const uint8_t* buffer, size_t size) -{ - TftpDataPacket packet; - const auto tftpSize = TftpDataPacket::Deserialize(packet, buffer, size); - if (size == 0) - { - // TODO log - return nullptr; + if (response != nullptr) + { + UdpDatagramHeader udpRespHeader( + udpReqHeader.destinationPort, + udpReqHeader.sourcePort, + response->SerializedLength() + UdpDatagramHeader::SerializedLength() + ); + Ipv4Header ipv4RespHeader( + IP_PROTO_UDP, + Ipv4Address, + ipv4ReqHeader.sourceIp, + udpRespHeader.length + Ipv4Header::SerializedLength() + ); + EthernetFrameHeader ethernetRespHeader( + Net::Arp::ArpTable[ipv4RespHeader.destinationIp], + GetMacAddress(), + ETHERTYPE_IPV4 + ); + + size_t i = 0; + uint8_t buffer[USPI_FRAME_BUFFER_SIZE]; + i += ethernetRespHeader.Serialize(buffer + i); + i += ipv4RespHeader.Serialize(buffer + i); + i += udpRespHeader.Serialize(buffer + i); + i += response->Serialize(buffer + i); + USPiSendFrame(buffer, i); + } + + if (last && shouldReboot) + { + // TODO eww + extern void Reboot_Pi(); + Reboot_Pi(); + } } - if (packet.blockNumber != currentBlockNumber + 1) - { - f_close(&outFile); - return std::unique_ptr( - new TftpErrorPacket(0, "invalid block number") - ); - } - currentBlockNumber = packet.blockNumber; + // + // TftpWriteReadRequestPacket + // + TftpWriteReadRequestPacket::TftpWriteReadRequestPacket(const Opcode opcode) : + TftpPacket(opcode) + {} - unsigned int bytesWritten; - const auto result = - f_write(&outFile, packet.data.data(), packet.data.size(), &bytesWritten); - - if (result != FR_OK || bytesWritten != packet.data.size()) + size_t TftpWriteReadRequestPacket::SerializedLength() const { - f_close(&outFile); - return std::unique_ptr(new TftpErrorPacket(0, "io error")); + return TftpPacket::SerializedLength() + filename.size() + 1 + mode.size() + 1; } - if (packet.data.size() < TFTP_BLOCK_SIZE) + size_t TftpWriteReadRequestPacket::Serialize(uint8_t* buffer) const { - // Close the file for the last packet. - f_close(&outFile); - } - - return std::unique_ptr( - new TftpAcknowledgementPacket(currentBlockNumber) - ); -} - -void HandleTftpDatagram( - const EthernetFrameHeader ethernetReqHeader, - const Ipv4Header ipv4ReqHeader, - const UdpDatagramHeader udpReqHeader, - const uint8_t* data -) { - const auto opcode = data[0] << 8 | data[1]; - std::unique_ptr response; - bool last = false; - - if (opcode == TFTP_OP_WRITE_REQUEST) - { - response = handleTftpWriteRequest(data); - } - else if (opcode == TFTP_OP_DATA) - { - const auto length = udpReqHeader.length - UdpDatagramHeader::SerializedLength(); - response = handleTftpData(data, length); - } - else - { - response = std::unique_ptr( - new TftpErrorPacket(4, "not implemented yet") - ); - } - - if (response != nullptr) - { - UdpDatagramHeader udpRespHeader( - udpReqHeader.destinationPort, - udpReqHeader.sourcePort, - response->SerializedLength() + UdpDatagramHeader::SerializedLength() - ); - Ipv4Header ipv4RespHeader( - IP_PROTO_UDP, - Ipv4Address, - ipv4ReqHeader.sourceIp, - udpRespHeader.length + Ipv4Header::SerializedLength() - ); - EthernetFrameHeader ethernetRespHeader( - ArpTable[ipv4RespHeader.destinationIp], - GetMacAddress(), - ETHERTYPE_IPV4 - ); - size_t i = 0; - uint8_t buffer[USPI_FRAME_BUFFER_SIZE]; - i += ethernetRespHeader.Serialize(buffer + i); - i += ipv4RespHeader.Serialize(buffer + i); - i += udpRespHeader.Serialize(buffer + i); - i += response->Serialize(buffer + i); - USPiSendFrame(buffer, i); + buffer[i++] = static_cast(opcode) >> 8; + buffer[i++] = static_cast(opcode); + + i += filename.copy(reinterpret_cast(buffer + i), filename.size()); + buffer[i++] = 0; + + i += mode.copy(reinterpret_cast(buffer + i), mode.size()); + buffer[i++] = 0; + + return i; } - if (last && shouldReboot) + TftpWriteReadRequestPacket TftpWriteReadRequestPacket::Deserialize(const uint8_t* buffer) { - // TODO eww - extern void Reboot_Pi(); - Reboot_Pi(); - } -} + size_t i = 0; -// -// TftpWriteReadRequestPacket -// -TftpWriteReadRequestPacket::TftpWriteReadRequestPacket(uint16_t opcode) : - TftpPacket(opcode) -{} + const auto opcode = static_cast(buffer[i] << 8 | buffer[i + 1]); + TftpWriteReadRequestPacket self(opcode); + i += 2; -size_t TftpWriteReadRequestPacket::SerializedLength() const -{ - return TftpPacket::SerializedLength() + filename.size() + 1 + mode.size() + 1; -} + self.filename = reinterpret_cast(buffer + i); + i += self.filename.size() + 1; -size_t TftpWriteReadRequestPacket::Serialize(uint8_t* buffer) const -{ - size_t i = 0; - buffer[i++] = opcode >> 8; - buffer[i++] = opcode; + self.mode = reinterpret_cast(buffer + i); + i += self.mode.size() + 1; - i += filename.copy(reinterpret_cast(buffer + i), filename.size()); - buffer[i++] = 0; - - i += mode.copy(reinterpret_cast(buffer + i), mode.size()); - buffer[i++] = 0; - - return i; -} - -TftpWriteReadRequestPacket TftpWriteReadRequestPacket::Deserialize(const uint8_t* buffer) -{ - size_t i = 0; - - TftpWriteReadRequestPacket self(buffer[i] << 8 | buffer[i + 1]); - i += 2; - - self.filename = reinterpret_cast(buffer + i); - i += self.filename.size() + 1; - - self.mode = reinterpret_cast(buffer + i); - i += self.mode.size() + 1; - - return self; -} - -// -// TftpErrorPacket -// -TftpErrorPacket::TftpErrorPacket() : TftpPacket(TFTP_OP_ERROR) {} -TftpErrorPacket::TftpErrorPacket(uint16_t errorCode, std::string message) : - TftpPacket(TFTP_OP_ERROR), errorCode(errorCode), message(message) -{} - -size_t TftpErrorPacket::SerializedLength() const -{ - return TftpPacket::SerializedLength() + sizeof(errorCode) + message.size() + 1; -} - -size_t TftpErrorPacket::Serialize(uint8_t* buffer) const -{ - size_t i = 0; - buffer[i++] = opcode >> 8; - buffer[i++] = opcode; - buffer[i++] = errorCode >> 8; - buffer[i++] = errorCode; - - i += message.copy(reinterpret_cast(buffer + i), message.size()); - buffer[i++] = 0; - - return i; -} - -// -// TftpAcknowledgementPacket -// -TftpAcknowledgementPacket::TftpAcknowledgementPacket() : - TftpPacket(TFTP_OP_ACKNOWLEDGEMENT) -{} - -TftpAcknowledgementPacket::TftpAcknowledgementPacket(uint16_t blockNumber) : - TftpPacket(TFTP_OP_ACKNOWLEDGEMENT), blockNumber(blockNumber) -{} - -size_t TftpAcknowledgementPacket::SerializedLength() const -{ - return TftpPacket::SerializedLength() + sizeof(blockNumber); -} - -size_t TftpAcknowledgementPacket::Serialize(uint8_t* buffer) const -{ - size_t i = 0; - buffer[i++] = opcode >> 8; - buffer[i++] = opcode; - buffer[i++] = blockNumber >> 8; - buffer[i++] = blockNumber; - return i; -} - -// -// TftpDataPacket -// -TftpDataPacket::TftpDataPacket() : opcode(TFTP_OP_DATA) {} - -size_t TftpDataPacket::Deserialize( - TftpDataPacket& out, const uint8_t* buffer, size_t size -) { - if (size < sizeof(opcode) + sizeof(blockNumber)) { - return 0; + return self; } - out.opcode = buffer[0] << 8 | buffer[1]; - out.blockNumber = buffer[2] << 8 | buffer[3]; - out.data = std::vector(buffer + 4, buffer + size); - return size; -} + // + // TftpErrorPacket + // + TftpErrorPacket::TftpErrorPacket() : TftpPacket(Opcode::Error) {} + TftpErrorPacket::TftpErrorPacket(uint16_t errorCode, std::string message) : + TftpPacket(Opcode::Error), errorCode(errorCode), message(message) + {} + + size_t TftpErrorPacket::SerializedLength() const + { + return TftpPacket::SerializedLength() + sizeof(errorCode) + message.size() + 1; + } + + size_t TftpErrorPacket::Serialize(uint8_t* buffer) const + { + size_t i = 0; + buffer[i++] = static_cast(opcode) >> 8; + buffer[i++] = static_cast(opcode); + buffer[i++] = errorCode >> 8; + buffer[i++] = errorCode; + + i += message.copy(reinterpret_cast(buffer + i), message.size()); + buffer[i++] = 0; + + return i; + } + + // + // TftpAcknowledgementPacket + // + TftpAcknowledgementPacket::TftpAcknowledgementPacket() : + TftpPacket(Opcode::Acknowledgement) + {} + + TftpAcknowledgementPacket::TftpAcknowledgementPacket(uint16_t blockNumber) : + TftpPacket(Opcode::Acknowledgement), blockNumber(blockNumber) + {} + + size_t TftpAcknowledgementPacket::SerializedLength() const + { + return TftpPacket::SerializedLength() + sizeof(blockNumber); + } + + size_t TftpAcknowledgementPacket::Serialize(uint8_t* buffer) const + { + size_t i = 0; + buffer[i++] = static_cast(opcode) >> 8; + buffer[i++] = static_cast(opcode); + buffer[i++] = blockNumber >> 8; + buffer[i++] = blockNumber; + return i; + } + + // + // TftpDataPacket + // + TftpDataPacket::TftpDataPacket() : TftpPacket(Opcode::Data), blockNumber(0) + {} + + size_t TftpDataPacket::Serialize(uint8_t* buffer) const + { + size_t i = 0; + buffer[i++] = static_cast(opcode) >> 8; + buffer[i++] = static_cast(opcode); + buffer[i++] = blockNumber >> 8; + buffer[i++] = blockNumber; + + std::memcpy(buffer + i, data.data(), data.size()); + i += data.size(); + + return i; + } + + size_t TftpDataPacket::Deserialize( + TftpDataPacket& out, const uint8_t* buffer, size_t size + ) { + if (size < sizeof(opcode) + sizeof(blockNumber)) { + return 0; + } + + out.opcode = static_cast(buffer[0] << 8 | buffer[1]); + out.blockNumber = buffer[2] << 8 | buffer[3]; + out.data = std::vector(buffer + 4, buffer + size); + return size; + } +}; // namespace Net::Tftp diff --git a/src/net-tftp.h b/src/net-tftp.h index 05ef1a0..79add71 100644 --- a/src/net-tftp.h +++ b/src/net-tftp.h @@ -1,69 +1,78 @@ #pragma once #include -const size_t TFTP_BLOCK_SIZE = 512; +namespace Net::Tftp { + const size_t TFTP_BLOCK_SIZE = 512; -enum TftpOperation -{ - TFTP_OP_READ_REQUEST = 1, - TFTP_OP_WRITE_REQUEST = 2, - TFTP_OP_DATA = 3, - TFTP_OP_ACKNOWLEDGEMENT = 4, - TFTP_OP_ERROR = 5, -}; + enum class Opcode : uint16_t + { + ReadRequest = 1, + WriteRequest = 2, + Data = 3, + Acknowledgement = 4, + Error = 5, + }; -struct TftpPacket -{ - uint16_t opcode; + struct TftpPacket + { + Opcode opcode; - TftpPacket(uint16_t opcode) : opcode(opcode) {} + TftpPacket(Opcode opcode) : opcode(opcode) {} - virtual size_t SerializedLength() const { - return sizeof(opcode); - } + virtual size_t SerializedLength() const { + return sizeof(opcode); + } - virtual size_t Serialize(uint8_t* buffer) const = 0; -}; + virtual size_t Serialize(uint8_t* buffer) const = 0; + }; -struct TftpWriteReadRequestPacket : public TftpPacket -{ - std::string filename; - std::string mode; + struct TftpWriteReadRequestPacket : public TftpPacket + { + std::string filename; + std::string mode; - TftpWriteReadRequestPacket(uint16_t opcode); - size_t SerializedLength() const override; - size_t Serialize(uint8_t* buffer) const override; - static TftpWriteReadRequestPacket Deserialize(const uint8_t* buffer); -}; + TftpWriteReadRequestPacket(const Opcode opcode); + size_t SerializedLength() const override; + size_t Serialize(uint8_t* buffer) const override; + static TftpWriteReadRequestPacket Deserialize(const uint8_t* buffer); + }; -struct TftpErrorPacket : public TftpPacket -{ - uint16_t errorCode; - std::string message; + struct TftpErrorPacket : public TftpPacket + { + uint16_t errorCode; + std::string message; - TftpErrorPacket(); - TftpErrorPacket(uint16_t errorCode, std::string message); - size_t SerializedLength() const override; - size_t Serialize(uint8_t* buffer) const override; -}; + TftpErrorPacket(); + TftpErrorPacket(uint16_t errorCode, std::string message); + size_t SerializedLength() const override; + size_t Serialize(uint8_t* buffer) const override; + }; -struct TftpAcknowledgementPacket : public TftpPacket -{ - uint16_t blockNumber; + struct TftpAcknowledgementPacket : public TftpPacket + { + uint16_t blockNumber; - TftpAcknowledgementPacket(); - TftpAcknowledgementPacket(uint16_t blockNumber); - size_t SerializedLength() const override; - size_t Serialize(uint8_t* buffer) const override; -}; + TftpAcknowledgementPacket(); + TftpAcknowledgementPacket(uint16_t blockNumber); + size_t SerializedLength() const override; + size_t Serialize(uint8_t* buffer) const override; + }; -struct TftpDataPacket -{ - uint16_t opcode; - uint16_t blockNumber; - std::vector data; + struct TftpDataPacket : public TftpPacket + { + uint16_t blockNumber; + std::vector data; - TftpDataPacket(); - static size_t Deserialize( - TftpDataPacket& out, const uint8_t* buffer, size_t length); -}; + TftpDataPacket(); + size_t Serialize(uint8_t* buffer) const override; + static size_t Deserialize( + TftpDataPacket& out, const uint8_t* buffer, size_t length); + }; + + void HandleTftpDatagram( + const EthernetFrameHeader ethernetReqHeader, + const Ipv4Header ipv4ReqHeader, + const UdpDatagramHeader udpReqHeader, + const uint8_t* buffer + ); +}; // namespace Net::Tftp diff --git a/src/net.cpp b/src/net.cpp index 5670db3..4e9a7f5 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -7,79 +7,13 @@ #include "net-ipv4.h" #include "net-udp.h" #include "net-dhcp.h" +#include "net-tftp.h" #include "net.h" #include "types.h" #include #include -// -// ARP -// -void SendArpPacket( - ArpOperation operation, - MacAddress targetMac, - MacAddress senderMac, - uint32_t targetIp, - uint32_t senderIp) -{ - Ipv4ArpPacket arpPacket(operation); - arpPacket.targetMac = targetMac; - arpPacket.senderMac = senderMac; - arpPacket.targetIp = targetIp; - arpPacket.senderIp = senderIp; - - EthernetFrameHeader ethernetHeader(senderMac, targetMac, ETHERTYPE_ARP); - - uint8_t buffer[USPI_FRAME_BUFFER_SIZE]; - size_t size = 0; - size += ethernetHeader.Serialize(buffer + size); - size += arpPacket.Serialize(buffer + size); - USPiSendFrame(buffer, size); -} - -void SendArpRequest( - MacAddress targetMac, MacAddress senderMac, uint32_t targetIp, uint32_t senderIp) -{ - SendArpPacket(ARP_OPERATION_REQUEST, targetMac, senderMac, targetIp, senderIp); -} - -void SendArpReply( - MacAddress targetMac, MacAddress senderMac, uint32_t targetIp, uint32_t senderIp) -{ - SendArpPacket(ARP_OPERATION_REPLY, targetMac, senderMac, targetIp, senderIp); -} - -void SendArpAnnouncement(MacAddress mac, uint32_t ip) -{ - SendArpReply(MacBroadcast, mac, ip, ip); -} - -void HandleArpFrame(const EthernetFrameHeader ethernetHeader, uint8_t* buffer) -{ - const auto macAddress = GetMacAddress(); - const auto arpPacket = Ipv4ArpPacket::Deserialize(buffer); - - if ( - arpPacket.hardwareType == 1 && - arpPacket.protocolType == ETHERTYPE_IPV4 && - arpPacket.operation == ARP_OPERATION_REQUEST && - arpPacket.targetIp == Ipv4Address) - { - SendArpReply(arpPacket.senderMac, macAddress, arpPacket.senderIp, Ipv4Address); - } - - else if ( - arpPacket.hardwareType == 1 && - arpPacket.protocolType == ETHERTYPE_IPV4 && - arpPacket.operation == ARP_OPERATION_REPLY && - arpPacket.targetIp == Ipv4Address && - arpPacket.targetMac == macAddress) - { - ArpTable.insert(std::make_pair(arpPacket.senderIp, arpPacket.senderMac)); - } -} - // // IPv4 // @@ -90,7 +24,8 @@ void HandleIpv4Packet( const auto offset = Ipv4Header::SerializedLength(); // Update ARP table - ArpTable.insert(std::make_pair(ipv4Header.sourceIp, ethernetHeader.macSource)); + Net::Arp::ArpTable.insert( + std::make_pair(ipv4Header.sourceIp, ethernetHeader.macSource)); if (ipv4Header.version != 4) return; if (ipv4Header.ihl != 5) return; // Not supported @@ -128,7 +63,7 @@ void HandleUdpDatagram( } else if (udpHeader.destinationPort == UDP_PORT_TFTP) { - HandleTftpDatagram( + Net::Tftp::HandleTftpDatagram( ethernetHeader, ipv4Header, udpHeader, @@ -326,4 +261,3 @@ uint32_t Ipv4Address = 0xC0A80164; const MacAddress MacBroadcast{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; bool FileUploaded = false; -std::unordered_map ArpTable; diff --git a/src/net.h b/src/net.h index 3123512..d0b7ec0 100644 --- a/src/net.h +++ b/src/net.h @@ -27,23 +27,6 @@ struct EthernetFrameHeader; struct UdpDatagramHeader; struct Ipv4Header; -// -// ARP -// -void HandleArpFrame(EthernetFrameHeader header, uint8_t* buffer); -void SendArpPacket( - ArpOperation operation, - MacAddress targetMac, - MacAddress senderMac, - uint32_t senderIp, - uint32_t targetIp -); -void SendArpRequest( - MacAddress targetMac, MacAddress senderMac, uint32_t senderIp, uint32_t targetIp); -void SendArpReply( - MacAddress targetMac, MacAddress senderMac, uint32_t senderIp, uint32_t targetIp); -void SendArpAnnouncement(MacAddress mac, uint32_t ip); - // // IPv4 // @@ -60,13 +43,6 @@ void HandleUdpDatagram( const size_t size ); -void HandleTftpDatagram( - const EthernetFrameHeader ethernetReqHeader, - const Ipv4Header ipv4ReqHeader, - const UdpDatagramHeader udpReqHeader, - const uint8_t* buffer -); - // // ICMP // @@ -84,4 +60,3 @@ extern const MacAddress MacBroadcast; extern uint32_t Ipv4Address; extern bool FileUploaded; -extern std::unordered_map ArpTable;