diff --git a/AppleWinExpress2019.vcxproj b/AppleWinExpress2019.vcxproj
index 301e31e6..573a9e0b 100644
--- a/AppleWinExpress2019.vcxproj
+++ b/AppleWinExpress2019.vcxproj
@@ -114,6 +114,7 @@
+
@@ -222,6 +223,7 @@
+
@@ -467,7 +469,7 @@
Windows
true
- htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw.lib;%(AdditionalDependencies)
+ iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw.lib;%(AdditionalDependencies)
"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"
5.01
@@ -495,7 +497,7 @@
Windows
true
- htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;ddraw_lib\x86\dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw_lib\x86\ddraw.lib;%(AdditionalDependencies)
+ iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;ddraw_lib\x86\dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw_lib\x86\ddraw.lib;%(AdditionalDependencies)
"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"
5.01
@@ -522,7 +524,7 @@
Windows
true
- htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)
+ iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)
"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"
5.01
@@ -553,7 +555,7 @@
true
true
true
- htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw.lib;%(AdditionalDependencies)
+ iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw.lib;%(AdditionalDependencies)
UseLinkTimeCodeGeneration
"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"
5.01
@@ -586,7 +588,7 @@
true
true
true
- htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;ddraw_lib\x86\dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw_lib\x86\ddraw.lib;%(AdditionalDependencies)
+ iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;ddraw_lib\x86\dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;ddraw_lib\x86\ddraw.lib;%(AdditionalDependencies)
UseLinkTimeCodeGeneration
"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"
5.01
@@ -619,7 +621,7 @@
true
true
true
- htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)
+ iphlpapi.lib;htmlhelp.lib;comctl32.lib;winmm.lib;dsound.lib;dxguid.lib;version.lib;strmiids.lib;dinput8.lib;user32.lib;gdi32.lib;advapi32.lib;shell32.lib;comdlg32.lib;ole32.lib;wsock32.lib;shlwapi.lib;%(AdditionalDependencies)
UseLinkTimeCodeGeneration
"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"
5.01
diff --git a/AppleWinExpress2019.vcxproj.filters b/AppleWinExpress2019.vcxproj.filters
index 617a7d87..c3ce4b15 100644
--- a/AppleWinExpress2019.vcxproj.filters
+++ b/AppleWinExpress2019.vcxproj.filters
@@ -259,6 +259,9 @@
Source Files\Uthernet
+
+ Source Files\Uthernet
+
@@ -594,6 +597,9 @@
Source Files\Uthernet
+
+ Source Files\Uthernet
+
diff --git a/source/Tfe/IPRaw.cpp b/source/Tfe/IPRaw.cpp
new file mode 100644
index 00000000..12a0ac4c
--- /dev/null
+++ b/source/Tfe/IPRaw.cpp
@@ -0,0 +1,162 @@
+/*
+AppleWin : An Apple //e emulator for Windows
+
+Copyright (C) 2022, Andrea Odetti
+
+AppleWin 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 2 of the License, or
+(at your option) any later version.
+
+AppleWin 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 AppleWin; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+*/
+
+#include "StdAfx.h"
+
+#include "IPRaw.h"
+
+#ifndef _MSC_VER
+#include
+#endif
+
+#define IPV4 0x04
+
+namespace
+{
+
+#pragma pack(push)
+#pragma pack(1) // Ensure struct is packed
+ struct IP4Header
+ {
+ uint8_t ihl : 4;
+ uint8_t version : 4;
+ uint8_t tos;
+ uint16_t len;
+ uint16_t id;
+ uint16_t flags : 3;
+ uint16_t fragmentOffset : 13;
+ uint8_t ttl;
+ uint8_t proto;
+ uint16_t checksum;
+ uint32_t sourceAddress;
+ uint32_t destinationAddress;
+ };
+
+ struct ETH2Frame
+ {
+ uint8_t destinationMac[6];
+ uint8_t sourceMac[6];
+ uint16_t type;
+ };
+#pragma pack(pop)
+
+ uint32_t sum_every_16bits(const void *addr, int count)
+ {
+ uint32_t sum = 0;
+ const uint16_t *ptr = reinterpret_cast(addr);
+
+ while (count > 1)
+ {
+ /* This is the inner loop */
+ sum += *ptr++;
+ count -= 2;
+ }
+
+ /* Add left-over byte, if any */
+ if (count > 0)
+ sum += *reinterpret_cast(ptr);
+
+ return sum;
+ }
+
+ uint16_t checksum(const void *addr, int count)
+ {
+ /* Compute Internet Checksum for "count" bytes
+ * beginning at location "addr".
+ * Taken from https://tools.ietf.org/html/rfc1071
+ */
+ uint32_t sum = sum_every_16bits(addr, count);
+
+ /* Fold 32-bit sum to 16 bits */
+ while (sum >> 16)
+ sum = (sum & 0xffff) + (sum >> 16);
+
+ return ~sum;
+ }
+
+ // get the minimum size of a ETH Frame that contains a IP payload
+ // 34 = 14 bytes for ETH2 + 20 bytes IPv4 (minimum)
+ int getIPMinimumSize()
+ {
+ const int minimumSize = sizeof(ETH2Frame) + sizeof(IP4Header) + 0; // 0 len
+ return minimumSize;
+ }
+
+}
+
+std::vector createETH2Frame(const std::vector &data,
+ const MACAddress *sourceMac, const MACAddress *destinationMac,
+ const uint8_t ttl, const uint8_t tos, const uint8_t protocol,
+ const uint32_t sourceAddress, const uint32_t destinationAddress)
+{
+ const size_t total = sizeof(ETH2Frame) + sizeof(IP4Header) + data.size();
+ std::vector frame(total);
+ ETH2Frame *eth2frame = reinterpret_cast(frame.data() + 0);
+ memcpy(eth2frame->destinationMac, destinationMac, sizeof(eth2frame->destinationMac));
+ memcpy(eth2frame->sourceMac, sourceMac, sizeof(eth2frame->destinationMac));
+ eth2frame->type = htons(0x0800);
+ IP4Header *ip4header = reinterpret_cast(frame.data() + sizeof(ETH2Frame));
+
+ ip4header->version = IPV4;
+ ip4header->ihl = 0x05; // minimum size = 20 bytes, without any extra option
+ ip4header->tos = tos;
+ ip4header->len = htons(static_cast(sizeof(IP4Header) + data.size()));
+ ip4header->id = 0;
+ ip4header->fragmentOffset = 0;
+ ip4header->ttl = ttl;
+ ip4header->proto = protocol;
+ ip4header->sourceAddress = sourceAddress;
+ ip4header->destinationAddress = destinationAddress;
+ ip4header->checksum = checksum(ip4header, sizeof(IP4Header));
+
+ memcpy(frame.data() + sizeof(ETH2Frame) + sizeof(IP4Header), data.data(), data.size());
+
+ return frame;
+}
+
+void getIPPayload(const int lengthOfFrame, const uint8_t *frame,
+ size_t &lengthOfPayload, const uint8_t *&payload, uint32_t &destination, uint8_t &protocol)
+{
+ const int minimumSize = getIPMinimumSize();
+ if (lengthOfFrame > minimumSize)
+ {
+ const ETH2Frame *eth2Frame = reinterpret_cast(frame);
+ const IP4Header *ip4header = reinterpret_cast(frame + sizeof(ETH2Frame));
+ if (eth2Frame->type == htons(0x0800) && ip4header->version == IPV4)
+ {
+ const uint16_t ipv4HeaderSize = ip4header->ihl * 4;
+ const uint16_t ipPacketSize = ntohs(ip4header->len);
+ const int expectedSize = sizeof(ETH2Frame) + ipPacketSize;
+ if (ipPacketSize > ipv4HeaderSize && lengthOfFrame >= expectedSize)
+ {
+ protocol = ip4header->proto;
+ payload = frame + sizeof(ETH2Frame) + ipv4HeaderSize;
+ lengthOfPayload = ipPacketSize - ipv4HeaderSize;
+ destination = ip4header->destinationAddress;
+ return;
+ }
+ }
+ }
+ // not a good packet
+ protocol = 0xFF; // reserved protocol
+ payload = nullptr;
+ lengthOfPayload = 0;
+ destination = 0;
+}
diff --git a/source/Tfe/IPRaw.h b/source/Tfe/IPRaw.h
new file mode 100644
index 00000000..cd0c534e
--- /dev/null
+++ b/source/Tfe/IPRaw.h
@@ -0,0 +1,11 @@
+#pragma once
+
+struct MACAddress;
+
+std::vector createETH2Frame(const std::vector &data,
+ const MACAddress *sourceMac, const MACAddress *destinationMac,
+ const uint8_t ttl, const uint8_t tos, const uint8_t protocol,
+ const uint32_t sourceAddress, const uint32_t destinationAddress);
+
+void getIPPayload(const int lengthOfFrame, const uint8_t *frame,
+ size_t &lengthOfPayload, const uint8_t *&payload, uint32_t &destination, uint8_t &protocol);
diff --git a/source/Tfe/NetworkBackend.h b/source/Tfe/NetworkBackend.h
index e883c9cb..3bfda5dd 100644
--- a/source/Tfe/NetworkBackend.h
+++ b/source/Tfe/NetworkBackend.h
@@ -6,6 +6,14 @@
#define MAX_RXLENGTH 1518
#define MIN_RXLENGTH 64
+#pragma pack(push)
+#pragma pack(1) // Ensure struct is packed
+struct MACAddress
+{
+ uint8_t address[6];
+};
+#pragma pack(pop)
+
class NetworkBackend
{
public:
@@ -26,6 +34,9 @@ public:
// process pending packets
virtual void update(const ULONG nExecutedCycles) = 0;
+ // get MAC for IPRAW (it is only supposed to handle addresses on the local network)
+ virtual void getMACAddress(const uint32_t address, MACAddress & mac) = 0;
+
// if the backend is usable
virtual bool isValid() = 0;
};
diff --git a/source/Tfe/PCapBackend.cpp b/source/Tfe/PCapBackend.cpp
index c2f7c5aa..58d349da 100644
--- a/source/Tfe/PCapBackend.cpp
+++ b/source/Tfe/PCapBackend.cpp
@@ -25,6 +25,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../Common.h"
#include "../Registry.h"
+#ifdef _MSC_VER
+#include
+#endif
+
std::string PCapBackend::tfe_interface;
PCapBackend::PCapBackend(const std::string & pcapInterface)
@@ -71,6 +75,16 @@ void PCapBackend::update(const ULONG /* nExecutedCycles */)
// nothing to do
}
+void PCapBackend::getMACAddress(const uint32_t address, MACAddress & mac)
+{
+ // this is only expected to be called for IP addresses on the same network
+#ifdef _MSC_VER
+ const DWORD dwSourceAddress = INADDR_ANY;
+ ULONG len = sizeof(MACAddress::address);
+ SendARP(address, dwSourceAddress, mac.address, &len);
+#endif
+}
+
int PCapBackend::tfe_enumadapter_open(void)
{
return tfe_arch_enumadapter_open();
diff --git a/source/Tfe/PCapBackend.h b/source/Tfe/PCapBackend.h
index 01952b90..a94023d7 100644
--- a/source/Tfe/PCapBackend.h
+++ b/source/Tfe/PCapBackend.h
@@ -29,6 +29,9 @@ public:
// process pending packets
virtual bool isValid();
+ // get MAC for IPRAW (it is only supposed to handle addresses on the local network)
+ virtual void getMACAddress(const uint32_t address, MACAddress & mac);
+
static void tfe_SetRegistryInterface(UINT slot, const std::string& name);
static void get_disabled_state(int * param);
diff --git a/source/Uthernet2.cpp b/source/Uthernet2.cpp
index 74b32aec..74d709d0 100644
--- a/source/Uthernet2.cpp
+++ b/source/Uthernet2.cpp
@@ -24,6 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Interface.h"
#include "Tfe/NetworkBackend.h"
#include "Tfe/PCapBackend.h"
+#include "Tfe/IPRaw.h"
#include "W5100.h"
// Linux uses EINPROGRESS while Windows returns WSAEWOULDBLOCK
@@ -73,6 +74,9 @@ typedef int socklen_t;
#define SOCK_NONBLOCK O_NONBLOCK
#endif
+// Dest MAC + Source MAC + Ether Type
+#define ETH_MINIMUM_SIZE (6 + 6 + 2)
+
// #define U2_LOG_VERBOSE
// #define U2_LOG_TRAFFIC
// #define U2_LOG_STATE
@@ -95,6 +99,12 @@ namespace
return host;
}
+ uint32_t readAddress(const uint8_t *ptr)
+ {
+ const uint32_t address = *reinterpret_cast(ptr);
+ return address;
+ }
+
uint8_t getIByte(const uint16_t value, const size_t shift)
{
return (value >> shift) & 0xFF;
@@ -141,6 +151,13 @@ namespace
writeData(socket, memory, data, len);
}
+ void writeDataIPRaw(Socket &socket, std::vector &memory, const uint8_t *data, const size_t len, const uint32_t destination)
+ {
+ writeAny(socket, memory, destination);
+ write16(socket, memory, static_cast(len));
+ writeData(socket, memory, data, len);
+ }
+
void writeDataForProtocol(Socket &socket, std::vector &memory, const uint8_t *data, const size_t len, const sockaddr_in &source)
{
if (socket.sn_sr == W5100_SN_SR_SOCK_UDP)
@@ -266,12 +283,18 @@ bool Socket::LoadSnapshot(YamlLoadHelper &yamlLoadHelper)
// transmit and receive sizes are restored from the card common registers
- if (sn_sr != W5100_SN_SR_SOCK_MACRAW)
+ switch (sn_sr)
{
+ case W5100_SN_SR_SOCK_MACRAW:
+ case W5100_SN_SR_SOCK_IPRAW:
+ // we can restore RAW sockets
+ break;
+ default:
// no point in restoring a broken UDP or TCP connection
// just reset the socket
sn_sr = W5100_SN_SR_CLOSED;
// for the same reason there is no point in saving myFD and myErrno
+ break;
}
return true;
@@ -434,7 +457,7 @@ void Uthernet2::updateRSR(const size_t i)
socket.sn_rx_rsr = dataPresent;
}
-int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data)
+int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data, PacketDestination & packetDestination)
{
const uint8_t * mac = myMemory.data() + W5100_SHAR0;
@@ -442,15 +465,9 @@ int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_
int len;
while ((len = myNetworkBackend->receive(size, data)) > 0)
{
- // minimum valid Ethernet frame is actually 64 bytes
- // 12 is the minimum to ensure valid MAC Address logging later
- if (len >= 12)
+ // smaller frames are not good anyway
+ if (len >= ETH_MINIMUM_SIZE)
{
- if (acceptAll)
- {
- return len;
- }
-
if (data[0] == mac[0] &&
data[1] == mac[1] &&
data[2] == mac[2] &&
@@ -458,6 +475,7 @@ int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_
data[4] == mac[4] &&
data[5] == mac[5])
{
+ packetDestination = HOST;
return len;
}
@@ -468,8 +486,16 @@ int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_
data[4] == 0xFF &&
data[5] == 0xFF)
{
+ packetDestination = BROADCAST;
return len;
}
+
+ if (acceptAll)
+ {
+ packetDestination = OTHER;
+ return len;
+ }
+
}
// skip this frame and try with another one
}
@@ -477,34 +503,110 @@ int Uthernet2::receiveForMacAddress(const bool acceptAll, const int size, uint8_
return len;
}
-void Uthernet2::receiveOnePacketMacRaw(const size_t i)
+void Uthernet2::receiveOnePacketRaw()
+{
+ bool acceptAll = false;
+ int macRawSocket = -1; // to which IPRaw soccket to send to (can only be 0)
+
+ Socket & socket0 = mySockets[0];
+ if (socket0.sn_sr == W5100_SN_SR_SOCK_MACRAW)
+ {
+ macRawSocket = 0; // the only MAC Raw socket is open, packet will go there as a fallback
+ const uint8_t mr = myMemory[socket0.registerAddress + W5100_SN_MR];
+
+ // see if MAC RAW filters or not
+ const bool filterMAC = mr & W5100_SN_MR_MF;
+ if (!filterMAC)
+ {
+ acceptAll = true;
+ }
+ }
+
+ uint8_t buffer[MAX_RXLENGTH];
+ PacketDestination packetDestination;
+ const int len = receiveForMacAddress(acceptAll, sizeof(buffer), buffer, packetDestination);
+ if (len > 0)
+ {
+ const uint8_t * payload;
+ size_t lengthOfPayload;
+ uint32_t destination;
+ uint8_t packetProtocol;
+ getIPPayload(len, buffer, lengthOfPayload, payload, destination, packetProtocol);
+
+ // see if there is a IPRAW socket that should accept thi spacket
+ int ipRawSocket = -1;
+ if (packetDestination != OTHER) // IPRaw always filters (HOST or BROADCAST, never OTHER)
+ {
+ for (size_t i = 0; i < mySockets.size(); ++i)
+ {
+ Socket & socket = mySockets[i];
+
+ if (socket.sn_sr == W5100_SN_SR_SOCK_IPRAW)
+ {
+ // IP only accepts by protocol & always filters MAC
+ const uint8_t socketProtocol = myMemory[socket.registerAddress + W5100_SN_PROTO];
+ if (payload && packetProtocol == socketProtocol)
+ {
+ ipRawSocket = i;
+ break; // a valid IPRAW socket has been found
+ }
+ }
+ // we should probably check for UDP & TCP sockets and filter these packets too
+ }
+ }
+
+ // priority to IPRAW
+ if (ipRawSocket >= 0)
+ {
+ receiveOnePacketIPRaw(ipRawSocket, lengthOfPayload, payload, destination, packetProtocol, len);
+ }
+ // fallback to MACRAW (if open)
+ else if (macRawSocket >= 0)
+ {
+ receiveOnePacketMacRaw(macRawSocket, len, buffer);
+ }
+ // else packet is dropped
+ }
+}
+
+void Uthernet2::receiveOnePacketMacRaw(const size_t i, const int size, uint8_t * data)
{
Socket &socket = mySockets[i];
- uint8_t buffer[MAX_RXLENGTH];
-
- const uint8_t mr = myMemory[socket.registerAddress + W5100_SN_MR];
- const bool filterMAC = mr & W5100_SN_MR_MF;
-
- const int len = receiveForMacAddress(!filterMAC, sizeof(buffer), buffer);
- if (len > 0)
+ if (socket.isThereRoomFor(size, sizeof(uint16_t)))
{
- // we know the packet is at least 12 bytes, and logging is ok
- if (socket.isThereRoomFor(len, sizeof(uint16_t)))
- {
- writeDataMacRaw(socket, myMemory, buffer, len);
+ writeDataMacRaw(socket, myMemory, data, size);
#ifdef U2_LOG_TRAFFIC
- LogFileOutput("U2: Read MACRAW[%" SIZE_T_FMT "]: " MAC_FMT " -> " MAC_FMT ": +%d -> %d bytes\n", i, MAC_SOURCE(buffer), MAC_DEST(buffer),
- len, socket.sn_rx_rsr);
+ LogFileOutput("U2: Read MACRAW[%" SIZE_T_FMT "]: " MAC_FMT " -> " MAC_FMT ": +%d -> %d bytes\n", i, MAC_SOURCE(data), MAC_DEST(data),
+ size, socket.sn_rx_rsr);
#endif
- }
- else
- {
- // drop it
+ }
+ else
+ {
+ // drop it
#ifdef U2_LOG_TRAFFIC
- LogFileOutput("U2: Skip MACRAW[%" SIZE_T_FMT "]: %d bytes\n", i, len);
+ LogFileOutput("U2: Skip MACRAW[%" SIZE_T_FMT "]: %d bytes\n", i, size);
+#endif
+ }
+}
+
+void Uthernet2::receiveOnePacketIPRaw(const size_t i, const size_t lengthOfPayload, const uint8_t * payload, const uint32_t destination, const uint8_t protocol, const int len)
+{
+ Socket &socket = mySockets[i];
+
+ if (socket.isThereRoomFor(lengthOfPayload, 4 + sizeof(uint16_t)))
+ {
+ writeDataIPRaw(socket, myMemory, payload, lengthOfPayload, destination);
+#ifdef U2_LOG_TRAFFIC
+ LogFileOutput("U2: Read IPRAW[%" SIZE_T_FMT "]: +%" SIZE_T_FMT " (%d) -> %d bytes\n", i, lengthOfPayload, len, socket.sn_rx_rsr);
+#endif
+ }
+ else
+ {
+ // drop it
+#ifdef U2_LOG_TRAFFIC
+ LogFileOutput("U2: Skip IPRAW[%" SIZE_T_FMT "]: %" SIZE_T_FMT " (%d) bytes \n", i, lengthOfPayload, len);
#endif
- }
}
}
@@ -557,7 +659,8 @@ void Uthernet2::receiveOnePacket(const size_t i)
switch (socket.sn_sr)
{
case W5100_SN_SR_SOCK_MACRAW:
- receiveOnePacketMacRaw(i);
+ case W5100_SN_SR_SOCK_IPRAW:
+ receiveOnePacketRaw();
break;
case W5100_SN_SR_ESTABLISHED:
case W5100_SN_SR_SOCK_UDP:
@@ -572,6 +675,29 @@ void Uthernet2::receiveOnePacket(const size_t i)
};
}
+void Uthernet2::sendDataIPRaw(const size_t i, std::vector &payload)
+{
+ const Socket &socket = mySockets[i];
+
+ const uint8_t ttl = myMemory[socket.registerAddress + W5100_SN_TTL];
+ const uint8_t tos = myMemory[socket.registerAddress + W5100_SN_TOS];
+ const uint8_t protocol = myMemory[socket.registerAddress + W5100_SN_PROTO];
+ const uint32_t source = readAddress(myMemory.data() + W5100_SIPR0);
+ const uint32_t destination = readAddress(myMemory.data() + socket.registerAddress + W5100_SN_DIPR0);
+
+ const MACAddress * sourceMac = reinterpret_cast(myMemory.data() + W5100_SHAR0);
+ const MACAddress * destinationMac;
+ getMACAddress(destination, destinationMac);
+
+ std::vector packet = createETH2Frame(payload, sourceMac, destinationMac, ttl, tos, protocol, source, destination);
+
+#ifdef U2_LOG_TRAFFIC
+ LogFileOutput("U2: Send IPRAW[%" SIZE_T_FMT "]: %" SIZE_T_FMT " (%" SIZE_T_FMT ") bytes\n", i, payload.size(), packet.size());
+#endif
+
+ myNetworkBackend->transmit(packet.size(), packet.data());
+}
+
void Uthernet2::sendDataMacRaw(const size_t i, std::vector &packet) const
{
#ifdef U2_LOG_TRAFFIC
@@ -656,6 +782,9 @@ void Uthernet2::sendData(const size_t i)
case W5100_SN_SR_SOCK_MACRAW:
sendDataMacRaw(i, data);
break;
+ case W5100_SN_SR_SOCK_IPRAW:
+ sendDataIPRaw(i, data);
+ break;
case W5100_SN_SR_ESTABLISHED:
case W5100_SN_SR_SOCK_UDP:
sendDataToSocket(i, data);
@@ -854,7 +983,7 @@ uint8_t Uthernet2::readSocketRegister(const uint16_t address)
break;
default:
#ifdef U2_LOG_UNKNOWN
- LogFileOutput("U2: Get unknown socket register[%" SIZE_T_FMT "]: %04x\n", i, address);
+ LogFileOutput("U2: Get unknown socket register[%d]: %04x\n", i, address);
#endif
value = myMemory[address];
break;
@@ -988,7 +1117,7 @@ void Uthernet2::writeSocketRegister(const uint16_t address, const uint8_t value)
break;
#ifdef U2_LOG_UNKNOWN
default:
- LogFileOutput("U2: Set unknown socket register[%" SIZE_T_FMT "]: %04x\n", i, address);
+ LogFileOutput("U2: Set unknown socket register[%d]: %04x\n", i, address);
break;
#endif
};
@@ -1073,6 +1202,7 @@ void Uthernet2::Reset(const bool powerCycle)
// dataAddress is NOT reset, see page 10 of Uthernet II
myDataAddress = 0;
myNetworkBackend = GetFrame().CreateNetworkBackend();
+ myARPCache.clear();
}
mySockets.clear();
@@ -1084,14 +1214,25 @@ void Uthernet2::Reset(const bool powerCycle)
{
resetRXTXBuffers(i);
mySockets[i].clearFD();
- mySockets[i].registerAddress = static_cast(W5100_S0_BASE + (i << 8));
+ const uint16_t registerAddress = static_cast(W5100_S0_BASE + (i << 8));
+ mySockets[i].registerAddress = registerAddress;
+
+ myMemory[registerAddress + W5100_SN_DHAR0] = 0xFF;
+ myMemory[registerAddress + W5100_SN_DHAR1] = 0xFF;
+ myMemory[registerAddress + W5100_SN_DHAR2] = 0xFF;
+ myMemory[registerAddress + W5100_SN_DHAR3] = 0xFF;
+ myMemory[registerAddress + W5100_SN_DHAR4] = 0xFF;
+ myMemory[registerAddress + W5100_SN_DHAR5] = 0xFF;
+ myMemory[registerAddress + W5100_SN_TTL] = 0x80;
}
// initial values
- myMemory[W5100_RTR0] = 0x07;
- myMemory[W5100_RTR1] = 0xD0;
+ myMemory[W5100_RTR0] = 0x07;
+ myMemory[W5100_RTR1] = 0xD0;
+ myMemory[W5100_RCR] = 0x08;
setRXSizes(W5100_RMSR, 0x55);
setTXSizes(W5100_TMSR, 0x55);
+ myMemory[W5100_PTIMER] = 0x28;
}
BYTE Uthernet2::IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles)
@@ -1162,6 +1303,46 @@ void Uthernet2::InitializeIO(LPBYTE pCxRomPeripheral)
RegisterIoHandler(m_slot, u2_C0, u2_C0, nullptr, nullptr, this, nullptr);
}
+void Uthernet2::getMACAddress(const uint32_t address, const MACAddress * & mac)
+{
+ const auto it = myARPCache.find(address);
+ if (it != myARPCache.end())
+ {
+ mac = &it->second;
+ }
+ else
+ {
+ MACAddress & macAddr = myARPCache[address];
+ const uint32_t source = readAddress(myMemory.data() + W5100_SIPR0);
+
+ if (address == source)
+ {
+ const uint8_t * sourceMac = myMemory.data() + W5100_SHAR0;
+ memcpy(macAddr.address, sourceMac, sizeof(macAddr.address));
+ }
+ else
+ {
+ memset(macAddr.address, 0xFF, sizeof(macAddr.address)); // fallback to broadcast
+ if (address != INADDR_BROADCAST)
+ {
+ const uint32_t subnet = readAddress(myMemory.data() + W5100_SUBR0);
+ if ((address & subnet) == (source & subnet))
+ {
+ // same network: send ARP request
+ myNetworkBackend->getMACAddress(address, macAddr);
+ }
+ else
+ {
+ const uint32_t gateway = readAddress(myMemory.data() + W5100_GAR0);
+ // different network: go via gateway
+ myNetworkBackend->getMACAddress(gateway, macAddr);
+ }
+ }
+ }
+ mac = &macAddr;
+ }
+}
+
void Uthernet2::Update(const ULONG nExecutedCycles)
{
myNetworkBackend->update(nExecutedCycles);
diff --git a/source/Uthernet2.h b/source/Uthernet2.h
index 5e7952fa..752f0b5d 100644
--- a/source/Uthernet2.h
+++ b/source/Uthernet2.h
@@ -3,8 +3,10 @@
#include "Card.h"
#include
+#include