Prototype implementation of TFTP PUT and move networking code to UpdateScreen (which runs on a different core)
This commit is contained in:
parent
dfb8fb16fc
commit
0c49a541ba
7 changed files with 562 additions and 140 deletions
|
@ -30,13 +30,3 @@ void operator delete (void* ptr)
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace std
|
|
||||||
{
|
|
||||||
void __throw_bad_alloc()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void __throw_length_error(char const*e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -179,6 +179,13 @@ int _lseek(int file, int ptr, int dir)
|
||||||
/* Open a file. Minimal implementation: */
|
/* Open a file. Minimal implementation: */
|
||||||
int open(const char *name, int flags, int mode)
|
int open(const char *name, int flags, int mode)
|
||||||
{
|
{
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _open(const char *name, int flags, int mode)
|
||||||
|
{
|
||||||
|
errno = ENOSYS;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
96
src/main.cpp
96
src/main.cpp
|
@ -367,6 +367,35 @@ void InitialiseLCD()
|
||||||
// printf("\E[1ALED %s%d\E[0m Motor %d Track %0d.%d ATN %d DAT %d CLK %d %s\r\n", LED ? termainalTextRed : termainalTextNormal, LED, Motor, Track >> 1, Track & 1 ? 5 : 0, ATN, DATA, CLOCK, roms.ROMNames[romIndex]);
|
// printf("\E[1ALED %s%d\E[0m Motor %d Track %0d.%d ATN %d DAT %d CLK %d %s\r\n", LED ? termainalTextRed : termainalTextNormal, LED, Motor, Track >> 1, Track & 1 ? 5 : 0, ATN, DATA, CLOCK, roms.ROMNames[romIndex]);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
void updateNetwork()
|
||||||
|
{
|
||||||
|
size_t size;
|
||||||
|
uint8_t ipBuffer[USPI_FRAME_BUFFER_SIZE];
|
||||||
|
if (!USPiEthernetAvailable() || !USPiReceiveFrame(ipBuffer, &size))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto header = EthernetFrameHeader::Deserialize(ipBuffer);
|
||||||
|
|
||||||
|
static bool announcementSent = false;
|
||||||
|
if (!announcementSent)
|
||||||
|
{
|
||||||
|
SendArpAnnouncement(GetMacAddress(), Ipv4Address);
|
||||||
|
announcementSent = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (header.type)
|
||||||
|
{
|
||||||
|
case ETHERTYPE_ARP:
|
||||||
|
HandleArpFrame(ipBuffer);
|
||||||
|
break;
|
||||||
|
case ETHERTYPE_IPV4:
|
||||||
|
HandleIpv4Frame(ipBuffer);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This runs on core0 and frees up core1 to just run the emulator.
|
// This runs on core0 and frees up core1 to just run the emulator.
|
||||||
// Care must be taken not to crowd out the shared cache with core1 as this could slow down core1 so that it no longer can perform its duties in the 1us timings it requires.
|
// Care must be taken not to crowd out the shared cache with core1 as this could slow down core1 so that it no longer can perform its duties in the 1us timings it requires.
|
||||||
void UpdateScreen()
|
void UpdateScreen()
|
||||||
|
@ -631,6 +660,8 @@ 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();
|
||||||
|
|
||||||
// Go back to sleep. The USB irq will wake us up again.
|
// Go back to sleep. The USB irq will wake us up again.
|
||||||
__asm ("WFE");
|
__asm ("WFE");
|
||||||
}
|
}
|
||||||
|
@ -1911,7 +1942,6 @@ extern "C"
|
||||||
|
|
||||||
InitialiseLCD();
|
InitialiseLCD();
|
||||||
#if not defined(EXPERIMENTALZERO)
|
#if not defined(EXPERIMENTALZERO)
|
||||||
int y_pos = 184;
|
|
||||||
snprintf(tempBuffer, tempBufferSize, "Copyright(C) 2018 Stephen White");
|
snprintf(tempBuffer, tempBufferSize, "Copyright(C) 2018 Stephen White");
|
||||||
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
|
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
|
||||||
snprintf(tempBuffer, tempBufferSize, "This program comes with ABSOLUTELY NO WARRANTY.");
|
snprintf(tempBuffer, tempBufferSize, "This program comes with ABSOLUTELY NO WARRANTY.");
|
||||||
|
@ -1949,74 +1979,12 @@ extern "C"
|
||||||
inputMappings = new InputMappings();
|
inputMappings = new InputMappings();
|
||||||
//USPiMouseRegisterStatusHandler(MouseHandler);
|
//USPiMouseRegisterStatusHandler(MouseHandler);
|
||||||
|
|
||||||
MsDelay(3000);
|
|
||||||
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);
|
||||||
MsDelay(1000);
|
MsDelay(500);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ipBuffer[USPI_FRAME_BUFFER_SIZE];
|
|
||||||
|
|
||||||
if (USPiEthernetAvailable()) {
|
|
||||||
std::array<std::uint8_t, 6> macAddress;
|
|
||||||
USPiGetMACAddress(macAddress.data());
|
|
||||||
|
|
||||||
snprintf(tempBuffer, tempBufferSize, "Ethernet found");
|
|
||||||
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
|
|
||||||
|
|
||||||
// Send an ARP announcement
|
|
||||||
SendArpAnnouncement(macAddress, Ipv4Address);
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
size_t size;
|
|
||||||
if (!USPiReceiveFrame(ipBuffer, &size))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
const auto targetIp = 0xC0A80128;
|
|
||||||
const auto targetMacIter = ArpTable.find(targetIp);
|
|
||||||
|
|
||||||
if (targetMacIter != ArpTable.end())
|
|
||||||
{
|
|
||||||
const auto targetMac = targetMacIter->second;
|
|
||||||
SendIcmpEchoRequest(targetMac, targetIp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Send an ARP request to find the MAC address belonging to this IP.
|
|
||||||
SendArpRequest(MacBroadcast, macAddress, targetIp, Ipv4Address);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
MsDelay(100);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto header = EthernetFrameHeader::Deserialize(ipBuffer);
|
|
||||||
|
|
||||||
snprintf(
|
|
||||||
tempBuffer,
|
|
||||||
tempBufferSize,
|
|
||||||
"Received frame of ethertype %04x",
|
|
||||||
header.type
|
|
||||||
);
|
|
||||||
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
|
|
||||||
|
|
||||||
if (header.type == ETHERTYPE_ARP)
|
|
||||||
{
|
|
||||||
HandleArpFrame(ipBuffer);
|
|
||||||
}
|
|
||||||
else if (header.type == ETHERTYPE_IPV4)
|
|
||||||
{
|
|
||||||
uint64_t debug = HandleIpv4Frame(ipBuffer);
|
|
||||||
snprintf(tempBuffer, tempBufferSize, "Debug: %016llx", debug);
|
|
||||||
screen.PrintText(false, 0, y_pos+=16, tempBuffer, COLOUR_WHITE, COLOUR_BLACK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
CheckOptions();
|
CheckOptions();
|
||||||
|
|
||||||
IEC_Bus::SetSplitIECLines(options.SplitIECLines());
|
IEC_Bus::SetSplitIECLines(options.SplitIECLines());
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
enum IpProtocols
|
enum IpProtocols
|
||||||
{
|
{
|
||||||
IP_PROTO_ICMP = 1,
|
IP_PROTO_ICMP = 1,
|
||||||
|
IP_PROTO_TCP = 6,
|
||||||
|
IP_PROTO_UDP = 17,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Ipv4Header
|
struct Ipv4Header
|
||||||
|
@ -43,6 +45,11 @@ struct Ipv4Header
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr size_t SerializedLength()
|
||||||
|
{
|
||||||
|
return sizeof(Ipv4Header);
|
||||||
|
}
|
||||||
|
|
||||||
size_t Serialize(uint8_t* buffer)
|
size_t Serialize(uint8_t* buffer)
|
||||||
{
|
{
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
|
|
192
src/net-udp.h
Normal file
192
src/net-udp.h
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
enum TftpOperation
|
||||||
|
{
|
||||||
|
TFTP_OP_READ_REQUEST = 1,
|
||||||
|
TFTP_OP_WRITE_REQUEST = 2,
|
||||||
|
TFTP_OP_DATA = 3,
|
||||||
|
TFTP_OP_ACKNOWLEDGEMENT = 4,
|
||||||
|
TFTP_OP_ERROR = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct UdpDatagramHeader
|
||||||
|
{
|
||||||
|
std::uint16_t sourcePort;
|
||||||
|
std::uint16_t destinationPort;
|
||||||
|
std::uint16_t length;
|
||||||
|
std::uint16_t checksum;
|
||||||
|
|
||||||
|
UdpDatagramHeader() {}
|
||||||
|
|
||||||
|
UdpDatagramHeader(uint16_t sourcePort, uint16_t destinationPort, uint16_t length) :
|
||||||
|
sourcePort(sourcePort),
|
||||||
|
destinationPort(destinationPort),
|
||||||
|
length(length),
|
||||||
|
checksum(0)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static constexpr size_t SerializedLength()
|
||||||
|
{
|
||||||
|
return
|
||||||
|
sizeof(sourcePort) +
|
||||||
|
sizeof(destinationPort) +
|
||||||
|
sizeof(length) +
|
||||||
|
sizeof(checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Serialize(uint8_t* buffer)
|
||||||
|
{
|
||||||
|
size_t i = 0;
|
||||||
|
buffer[i++] = sourcePort >> 8;
|
||||||
|
buffer[i++] = sourcePort;
|
||||||
|
buffer[i++] = destinationPort >> 8;
|
||||||
|
buffer[i++] = destinationPort;
|
||||||
|
buffer[i++] = length >> 8;
|
||||||
|
buffer[i++] = length;
|
||||||
|
buffer[i++] = checksum >> 8;
|
||||||
|
buffer[i++] = checksum;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static UdpDatagramHeader Deserialize(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
UdpDatagramHeader self;
|
||||||
|
self.sourcePort = buffer[0] << 8 | buffer[1];
|
||||||
|
self.destinationPort = buffer[2] << 8 | buffer[3];
|
||||||
|
self.length = buffer[4] << 8 | buffer[5];
|
||||||
|
self.checksum = buffer[6] << 8 | buffer[7];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
struct UdpDatagram
|
||||||
|
{
|
||||||
|
UdpDatagramHeader header;
|
||||||
|
T payload;
|
||||||
|
|
||||||
|
UdpDatagram() {}
|
||||||
|
|
||||||
|
UdpDatagram(uint16_t sourcePort, uint16_t destinationPort, T payload) :
|
||||||
|
header(sourcePort, destinationPort, sizeof(UdpDatagram<T>)),
|
||||||
|
payload(payload)
|
||||||
|
{}
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct TftpWriteReadRequestPacket
|
||||||
|
{
|
||||||
|
uint16_t opcode;
|
||||||
|
std::string filename;
|
||||||
|
std::string mode;
|
||||||
|
|
||||||
|
size_t SerializedLength() const {
|
||||||
|
return sizeof(opcode) + filename.size() + 1 + mode.size() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t Serialize(uint8_t* buffer) const {
|
||||||
|
size_t i = 0;
|
||||||
|
buffer[i++] = opcode >> 8;
|
||||||
|
buffer[i++] = opcode;
|
||||||
|
|
||||||
|
i += filename.copy(reinterpret_cast<char*>(buffer + i), filename.size());
|
||||||
|
buffer[i++] = 0;
|
||||||
|
|
||||||
|
i += mode.copy(reinterpret_cast<char*>(buffer + i), mode.size());
|
||||||
|
buffer[i++] = 0;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static TftpWriteReadRequestPacket Deserialize(const uint8_t* buffer) {
|
||||||
|
TftpWriteReadRequestPacket self;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
self.opcode = buffer[i] << 8 | buffer[i + 1];
|
||||||
|
i += 2;
|
||||||
|
|
||||||
|
self.filename = reinterpret_cast<const char*>(buffer + i);
|
||||||
|
i += self.filename.size() + 1;
|
||||||
|
|
||||||
|
self.mode = reinterpret_cast<const char*>(buffer + i);
|
||||||
|
i += self.mode.size() + 1;
|
||||||
|
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TftpErrorPacket
|
||||||
|
{
|
||||||
|
uint16_t opcode;
|
||||||
|
uint16_t errorCode;
|
||||||
|
std::string message;
|
||||||
|
|
||||||
|
TftpErrorPacket() : opcode(TFTP_OP_ERROR) {}
|
||||||
|
TftpErrorPacket(uint16_t errorCode, std::string message) :
|
||||||
|
opcode(TFTP_OP_ERROR), errorCode(errorCode), message(message)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr size_t SerializedLength()
|
||||||
|
{
|
||||||
|
return sizeof(opcode) + sizeof(errorCode) + message.size() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t 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<char*>(buffer + i), message.size());
|
||||||
|
buffer[i++] = 0;
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TftpAcknowledgementPacket
|
||||||
|
{
|
||||||
|
uint16_t opcode;
|
||||||
|
uint16_t blockNumber;
|
||||||
|
|
||||||
|
TftpAcknowledgementPacket() : opcode(TFTP_OP_ACKNOWLEDGEMENT) {}
|
||||||
|
|
||||||
|
TftpAcknowledgementPacket(uint16_t blockNumber) :
|
||||||
|
opcode(TFTP_OP_ACKNOWLEDGEMENT), blockNumber(blockNumber)
|
||||||
|
{}
|
||||||
|
|
||||||
|
constexpr size_t SerializedLength()
|
||||||
|
{
|
||||||
|
return sizeof(opcode) + sizeof(blockNumber);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t 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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TftpDataPacket
|
||||||
|
{
|
||||||
|
uint16_t opcode;
|
||||||
|
uint16_t blockNumber;
|
||||||
|
std::vector<uint8_t> data;
|
||||||
|
|
||||||
|
TftpDataPacket() : opcode(TFTP_OP_DATA) {}
|
||||||
|
|
||||||
|
static 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<uint8_t>(buffer + 4, buffer + length);
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
};
|
303
src/net.cpp
303
src/net.cpp
|
@ -3,9 +3,12 @@
|
||||||
#include "net-ipv4.h"
|
#include "net-ipv4.h"
|
||||||
#include "net-arp.h"
|
#include "net-arp.h"
|
||||||
#include "net-icmp.h"
|
#include "net-icmp.h"
|
||||||
|
#include "net-udp.h"
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include <uspi.h>
|
#include <uspi.h>
|
||||||
|
#include <uspios.h>
|
||||||
|
#include "ff.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// ARP
|
// ARP
|
||||||
|
@ -79,23 +82,303 @@ void HandleArpFrame(uint8_t* buffer)
|
||||||
//
|
//
|
||||||
// IPv4
|
// IPv4
|
||||||
//
|
//
|
||||||
uint64_t HandleIpv4Frame(const uint8_t* buffer)
|
void HandleIpv4Frame(const uint8_t* buffer)
|
||||||
{
|
{
|
||||||
const auto frame = EthernetFrame<Ipv4Header>::Deserialize(buffer);
|
const auto frame = EthernetFrame<Ipv4Header>::Deserialize(buffer);
|
||||||
const auto header = frame.payload;
|
const auto header = frame.payload;
|
||||||
|
|
||||||
if (header.version != 4) return 0x4;
|
// Update ARP table
|
||||||
if (header.ihl != 5) return 0x8; // Not supported
|
ArpTable.insert(std::make_pair(frame.payload.sourceIp, frame.header.macSource));
|
||||||
if (header.destinationIp != Ipv4Address) return 0x10 | std::uint64_t{header.destinationIp} << 32;
|
|
||||||
if (header.fragmentOffset != 0) return 0x20; // TODO Support this
|
if (header.version != 4) return;
|
||||||
|
if (header.ihl != 5) return; // Not supported
|
||||||
|
if (header.destinationIp != Ipv4Address) return;
|
||||||
|
if (header.fragmentOffset != 0) return; // TODO Support this
|
||||||
|
|
||||||
if (header.protocol == IP_PROTO_ICMP)
|
if (header.protocol == IP_PROTO_ICMP)
|
||||||
{
|
{
|
||||||
return HandleIcmpFrame(buffer) | 0x2;
|
HandleIcmpFrame(buffer);
|
||||||
|
}
|
||||||
|
else if (header.protocol == IP_PROTO_UDP)
|
||||||
|
{
|
||||||
|
return HandleUdpFrame(buffer);
|
||||||
}
|
}
|
||||||
return 0x0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// UDP
|
||||||
|
//
|
||||||
|
void HandleUdpFrame(const uint8_t* buffer)
|
||||||
|
{
|
||||||
|
const auto frame = EthernetFrame<Ipv4Packet<UdpDatagramHeader>>::Deserialize(buffer);
|
||||||
|
const auto header = frame.payload.payload;
|
||||||
|
|
||||||
|
uint8_t* data = (uint8_t*)malloc(header.length);
|
||||||
|
memcpy(
|
||||||
|
data,
|
||||||
|
buffer + sizeof(EthernetFrameHeader) + sizeof(Ipv4Header) + sizeof(UdpDatagramHeader),
|
||||||
|
header.length
|
||||||
|
);
|
||||||
|
|
||||||
|
if (header.destinationPort == 69) // nice
|
||||||
|
{
|
||||||
|
HandleTftpDatagram(
|
||||||
|
frame.header,
|
||||||
|
frame.payload.header,
|
||||||
|
frame.payload.payload,
|
||||||
|
data
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FIL tftpFp;
|
||||||
|
bool shouldReboot = false;
|
||||||
|
std::string tftpPrevCwd;
|
||||||
|
|
||||||
|
void HandleTftpDatagram(
|
||||||
|
const EthernetFrameHeader ethernetReqHeader,
|
||||||
|
const Ipv4Header ipv4ReqHeader,
|
||||||
|
const UdpDatagramHeader udpReqHeader,
|
||||||
|
const uint8_t* data
|
||||||
|
) {
|
||||||
|
const auto opcode = data[0] << 8 | data[1];
|
||||||
|
static auto currentBlockNumber = -1;
|
||||||
|
if (opcode == TFTP_OP_WRITE_REQUEST)
|
||||||
|
{
|
||||||
|
auto packet = TftpWriteReadRequestPacket::Deserialize(data);
|
||||||
|
if (packet.mode == "octet")
|
||||||
|
{
|
||||||
|
currentBlockNumber = 0;
|
||||||
|
|
||||||
|
// Try opening the file
|
||||||
|
{
|
||||||
|
char cwd[256];
|
||||||
|
f_getcwd(cwd, sizeof(cwd));
|
||||||
|
tftpPrevCwd = cwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto filename = packet.filename.substr(separator + 1);
|
||||||
|
const auto result = f_open(&tftpFp, filename.c_str(), FA_CREATE_ALWAYS | FA_WRITE);
|
||||||
|
if (result == FR_OK)
|
||||||
|
{
|
||||||
|
shouldReboot =
|
||||||
|
packet.filename == "kernel.img" || packet.filename == "options.txt";
|
||||||
|
|
||||||
|
TftpAcknowledgementPacket response(currentBlockNumber);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TftpErrorPacket response(0, "error opening target file");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TftpErrorPacket response(0, "please use mode octet");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (opcode == TFTP_OP_DATA)
|
||||||
|
{
|
||||||
|
auto packet = TftpDataPacket::Deserialize(
|
||||||
|
data,
|
||||||
|
udpReqHeader.length - UdpDatagramHeader::SerializedLength()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (packet.blockNumber == currentBlockNumber + 1)
|
||||||
|
{
|
||||||
|
const auto last = packet.data.size() < 512;
|
||||||
|
currentBlockNumber = packet.blockNumber;
|
||||||
|
|
||||||
|
unsigned int bytesWritten;
|
||||||
|
const auto response =
|
||||||
|
f_write(&tftpFp, packet.data.data(), packet.data.size(), &bytesWritten);
|
||||||
|
if (response == FR_OK || bytesWritten != packet.data.size())
|
||||||
|
{
|
||||||
|
TftpAcknowledgementPacket response(currentBlockNumber);
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (last)
|
||||||
|
{
|
||||||
|
MsDelay(500);
|
||||||
|
f_close(&tftpFp);
|
||||||
|
f_chdir(tftpPrevCwd.c_str());
|
||||||
|
tftpPrevCwd.clear();
|
||||||
|
|
||||||
|
if (shouldReboot)
|
||||||
|
{
|
||||||
|
// TODO eww
|
||||||
|
extern void Reboot_Pi();
|
||||||
|
Reboot_Pi();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
f_close(&tftpFp);
|
||||||
|
|
||||||
|
TftpErrorPacket response(0, "io error");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
TftpErrorPacket response(0, "invalid block number");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// ICMP
|
// ICMP
|
||||||
|
@ -115,7 +398,7 @@ void SendIcmpEchoRequest(MacAddress mac, uint32_t ip)
|
||||||
USPiSendFrame(buffer, size);
|
USPiSendFrame(buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t HandleIcmpFrame(const uint8_t* buffer)
|
void HandleIcmpFrame(const uint8_t* buffer)
|
||||||
{
|
{
|
||||||
const auto frame = EthernetFrame<Ipv4Packet<IcmpPacketHeader>>::Deserialize(buffer);
|
const auto frame = EthernetFrame<Ipv4Packet<IcmpPacketHeader>>::Deserialize(buffer);
|
||||||
const auto packetHeader = frame.payload.payload;
|
const auto packetHeader = frame.payload.payload;
|
||||||
|
@ -154,10 +437,7 @@ uint64_t HandleIcmpFrame(const uint8_t* buffer)
|
||||||
uint8_t bufferResp[USPI_FRAME_BUFFER_SIZE];
|
uint8_t bufferResp[USPI_FRAME_BUFFER_SIZE];
|
||||||
const auto size = frameResp.Serialize(bufferResp);
|
const auto size = frameResp.Serialize(bufferResp);
|
||||||
USPiSendFrame(bufferResp, size);
|
USPiSendFrame(bufferResp, size);
|
||||||
|
|
||||||
return 0x1;
|
|
||||||
}
|
}
|
||||||
return 0x0 | std::uint64_t{packetHeader.type} << 32;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -278,4 +558,5 @@ MacAddress GetMacAddress()
|
||||||
const uint32_t Ipv4Address = 0xC0A80164;
|
const 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;
|
||||||
std::unordered_map<std::uint32_t, MacAddress> ArpTable;
|
std::unordered_map<std::uint32_t, MacAddress> ArpTable;
|
||||||
|
|
85
src/net.h
85
src/net.h
|
@ -17,6 +17,9 @@ enum ArpOperation {
|
||||||
|
|
||||||
typedef std::array<uint8_t, 6> MacAddress;
|
typedef std::array<uint8_t, 6> MacAddress;
|
||||||
|
|
||||||
|
//
|
||||||
|
// ARP
|
||||||
|
//
|
||||||
void HandleArpFrame(uint8_t* buffer);
|
void HandleArpFrame(uint8_t* buffer);
|
||||||
void SendArpPacket(ArpOperation operation,
|
void SendArpPacket(ArpOperation operation,
|
||||||
MacAddress targetMac,
|
MacAddress targetMac,
|
||||||
|
@ -33,11 +36,36 @@ void SendArpReply(MacAddress targetMac,
|
||||||
uint32_t targetIp);
|
uint32_t targetIp);
|
||||||
void SendArpAnnouncement(MacAddress mac, uint32_t ip);
|
void SendArpAnnouncement(MacAddress mac, uint32_t ip);
|
||||||
|
|
||||||
uint64_t HandleIpv4Frame(const uint8_t* buffer);
|
//
|
||||||
|
// IPv4
|
||||||
|
//
|
||||||
|
void HandleIpv4Frame(const uint8_t* buffer);
|
||||||
|
|
||||||
|
//
|
||||||
|
// UDP
|
||||||
|
//
|
||||||
|
struct EthernetFrameHeader;
|
||||||
|
struct UdpDatagramHeader;
|
||||||
|
struct Ipv4Header;
|
||||||
|
|
||||||
|
void HandleUdpFrame(const uint8_t* buffer);
|
||||||
|
|
||||||
|
void HandleTftpDatagram(
|
||||||
|
const EthernetFrameHeader ethernetReqHeader,
|
||||||
|
const Ipv4Header ipv4ReqHeader,
|
||||||
|
const UdpDatagramHeader udpReqHeader,
|
||||||
|
const uint8_t* buffer
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// ICMP
|
||||||
|
//
|
||||||
void SendIcmpEchoRequest(MacAddress mac, uint32_t ip);
|
void SendIcmpEchoRequest(MacAddress mac, uint32_t ip);
|
||||||
uint64_t HandleIcmpFrame(const uint8_t* buffer);
|
void HandleIcmpFrame(const uint8_t* buffer);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Helpers
|
||||||
|
//
|
||||||
std::uint32_t Crc32(const std::uint8_t* buffer, std::size_t size);
|
std::uint32_t Crc32(const std::uint8_t* buffer, std::size_t size);
|
||||||
std::uint16_t InternetChecksum(const void* data, std::size_t size);
|
std::uint16_t InternetChecksum(const void* data, std::size_t size);
|
||||||
MacAddress GetMacAddress();
|
MacAddress GetMacAddress();
|
||||||
|
@ -45,56 +73,5 @@ MacAddress GetMacAddress();
|
||||||
extern const MacAddress MacBroadcast;
|
extern const MacAddress MacBroadcast;
|
||||||
extern const uint32_t Ipv4Address;
|
extern const uint32_t Ipv4Address;
|
||||||
|
|
||||||
|
extern bool FileUploaded;
|
||||||
extern std::unordered_map<std::uint32_t, MacAddress> ArpTable;
|
extern std::unordered_map<std::uint32_t, MacAddress> ArpTable;
|
||||||
|
|
||||||
struct UdpDatagramHeader
|
|
||||||
{
|
|
||||||
std::uint16_t sourcePort;
|
|
||||||
std::uint16_t destinationPort;
|
|
||||||
std::uint16_t length;
|
|
||||||
std::uint16_t checksum;
|
|
||||||
|
|
||||||
UdpDatagramHeader() {}
|
|
||||||
|
|
||||||
UdpDatagramHeader(uint16_t sourcePort, uint16_t destinationPort, uint16_t length) :
|
|
||||||
sourcePort(sourcePort), destinationPort(destinationPort), length(length)
|
|
||||||
{}
|
|
||||||
|
|
||||||
size_t Serialize(uint8_t* buffer)
|
|
||||||
{
|
|
||||||
size_t i = 0;
|
|
||||||
buffer[i++] = sourcePort >> 8;
|
|
||||||
buffer[i++] = sourcePort;
|
|
||||||
buffer[i++] = destinationPort >> 8;
|
|
||||||
buffer[i++] = destinationPort;
|
|
||||||
buffer[i++] = length >> 8;
|
|
||||||
buffer[i++] = length;
|
|
||||||
buffer[i++] = checksum >> 8;
|
|
||||||
buffer[i++] = checksum;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
UdpDatagramHeader Deserialize(const uint8_t* buffer)
|
|
||||||
{
|
|
||||||
UdpDatagramHeader self;
|
|
||||||
self.sourcePort = buffer[0] << 8 | buffer[1];
|
|
||||||
self.destinationPort = buffer[2] << 8 | buffer[3];
|
|
||||||
self.length = buffer[4] << 8 | buffer[5];
|
|
||||||
self.checksum = buffer[6] << 8 | buffer[7];
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
struct UdpDatagram
|
|
||||||
{
|
|
||||||
UdpDatagramHeader header;
|
|
||||||
T payload;
|
|
||||||
|
|
||||||
UdpDatagram() {}
|
|
||||||
|
|
||||||
UdpDatagram(uint16_t sourcePort, uint16_t destinationPort, T payload) :
|
|
||||||
header(sourcePort, destinationPort, sizeof(UdpDatagram<T>)),
|
|
||||||
payload(payload)
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
Loading…
Reference in a new issue