Compare commits

...
Sign in to create a new pull request.

9 commits
master ... u2

Author SHA1 Message Date
Andrea Odetti
a4bdf7ec53 Uthernet II: implement getMACAddress for libslirp.
Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
2022-03-20 18:22:43 +00:00
Andrea Odetti
b5ec2343fb PCAP: fix Windows build.
Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
2022-03-19 20:26:06 +00:00
Andrea Odetti
a2601b44fe Network: add pcap dump file.
Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
2022-03-19 20:26:06 +00:00
Andrea Odetti
be515136e1 IPRAW Fix compilation in linux.
Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
2022-03-19 20:26:06 +00:00
Andrea Odetti
0c548d7d26 Uthernet II: fix IPRaw for Windows.
Signed-off-by: Andrea Odetti <mariofutire@gmail.com>

# Conflicts:
#	source/Uthernet2.cpp
2022-03-19 20:26:06 +00:00
Andrea Odetti
ed073cccc3 SendArp 2022-03-19 20:26:06 +00:00
Andrea Odetti
69036f6601 Uthernet II: add partial support for IPRAW.
Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
2022-03-19 20:26:06 +00:00
Andrea Odetti
0e24e443f7 wip 2022-03-19 20:26:06 +00:00
Andrea Odetti
86975f4e54 Uthernet II: correctly initialise all default register values.
Signed-off-by: Andrea Odetti <mariofutire@gmail.com>
2022-03-19 20:26:06 +00:00
17 changed files with 622 additions and 54 deletions

View file

@ -114,6 +114,7 @@
<ClInclude Include="source\StrFormat.h" />
<ClInclude Include="source\SynchronousEventManager.h" />
<ClInclude Include="source\Tape.h" />
<ClInclude Include="source\Tfe\IPRaw.h" />
<ClInclude Include="source\Tfe\NetworkBackend.h" />
<ClInclude Include="source\Tfe\Bpf.h" />
<ClInclude Include="source\Tfe\Ip6_misc.h" />
@ -222,6 +223,7 @@
<ClCompile Include="source\StrFormat.cpp" />
<ClCompile Include="source\SynchronousEventManager.cpp" />
<ClCompile Include="source\Tape.cpp" />
<ClCompile Include="source\Tfe\IPRaw.cpp" />
<ClCompile Include="source\Tfe\NetworkBackend.cpp" />
<ClCompile Include="source\Tfe\PCapBackend.cpp" />
<ClCompile Include="source\Tfe\tfearch.cpp">
@ -467,7 +469,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>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)</AdditionalDependencies>
<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)</AdditionalDependencies>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
</Link>
@ -495,7 +497,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>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)</AdditionalDependencies>
<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)</AdditionalDependencies>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
</Link>
@ -522,7 +524,7 @@
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>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)</AdditionalDependencies>
<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)</AdditionalDependencies>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
</Link>
@ -553,7 +555,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>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)</AdditionalDependencies>
<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)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
@ -586,7 +588,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>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)</AdditionalDependencies>
<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)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>
@ -619,7 +621,7 @@
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>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)</AdditionalDependencies>
<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)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
<AdditionalManifestDependencies>"type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'"</AdditionalManifestDependencies>
<MinimumRequiredVersion>5.01</MinimumRequiredVersion>

View file

@ -259,6 +259,9 @@
<ClCompile Include="source\Uthernet2.cpp">
<Filter>Source Files\Uthernet</Filter>
</ClCompile>
<ClCompile Include="source\Tfe\IPRaw.cpp">
<Filter>Source Files\Uthernet</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\CommonVICE\6510core.h">
@ -594,6 +597,9 @@
<ClInclude Include="source\Uthernet2.h">
<Filter>Source Files\Uthernet</Filter>
</ClInclude>
<ClInclude Include="source\Tfe\IPRaw.h">
<Filter>Source Files\Uthernet</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="resource\Applewin.bmp">

View file

@ -35,6 +35,7 @@ set(SOURCE_FILES
Tfe/tfesupp.cpp
Tfe/NetworkBackend.cpp
Tfe/PCapBackend.cpp
Tfe/IPRaw.cpp
Debugger/Debug.cpp
Debugger/Debugger_Help.cpp
@ -124,6 +125,7 @@ set(HEADER_FILES
Tfe/tfesupp.h
Tfe/NetworkBackend.h
Tfe/PCapBackend.h
Tfe/IPRaw.h
Uthernet1.h
Uthernet2.h

161
source/Tfe/IPRaw.cpp Normal file
View file

@ -0,0 +1,161 @@
/*
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"
#include <cstring>
#ifndef _MSC_VER
#include <arpa/inet.h>
#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<const uint16_t *>(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<const uint8_t *>(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;
}
}
std::vector<uint8_t> createETH2Frame(const std::vector<uint8_t> &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<uint8_t> frame(total);
ETH2Frame *eth2frame = reinterpret_cast<ETH2Frame *>(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<IP4Header *>(frame.data() + sizeof(ETH2Frame));
ip4header->version = IPV4;
ip4header->ihl = 0x05;
ip4header->tos = tos;
ip4header->len = htons(static_cast<uint16_t>(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;
}
int getIPMinimumSize()
{
const int minimumSize = sizeof(ETH2Frame) + sizeof(IP4Header) + 0; // 0 len
return minimumSize;
}
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<const ETH2Frame *>(frame);
const IP4Header *ip4header = reinterpret_cast<const IP4Header *>(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;
}

19
source/Tfe/IPRaw.h Normal file
View file

@ -0,0 +1,19 @@
#pragma once
#include <vector>
#include <cstdint>
#include <cstddef>
struct MACAddress;
std::vector<uint8_t> createETH2Frame(const std::vector<uint8_t> &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);
// get the minimum size of a ETH Frame that contains a IP payload
// 34 = 14 bytes for ETH2 + 20 byes IPv4 (minimum)
int getIPMinimumSize();
void getIPPayload(const int lengthOfFrame, const uint8_t *frame,
size_t &lengthOfPayload, const uint8_t *&payload, uint32_t &destination, uint8_t &protocol);

View file

@ -21,6 +21,52 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#include "NetworkBackend.h"
#include "Tfe/tfearch.h"
#ifdef _MSC_VER
#define PCAP_FILENAME "AppleWin.pcap"
#else
#define PCAP_FILENAME "/tmp/AppleWin.pcap"
#endif
NetworkBackend::~NetworkBackend()
{
}
namespace
{
class PCAPDumper
{
private:
pcap_t *myPcap;
pcap_dumper_t *myDumper;
public:
PCAPDumper()
{
tfe_pcap_dump_open(PCAP_FILENAME, 16384, myPcap, myDumper);
}
~PCAPDumper()
{
tfe_pcap_dump_close(myPcap, myDumper);
}
void dumpPacket(
const int txlength, /* Frame length */
uint8_t *txframe /* Data */)
{
tfe_pcap_dump(myDumper, txlength, txframe);
}
};
PCAPDumper dumper;
}
void NetworkBackend::dumpPacket(
const int txlength, /* Frame length */
uint8_t *txframe /* Data */)
{
dumper.dumpPacket(txlength, txframe);
}

View file

@ -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,14 @@ public:
// process pending packets
virtual void update(const ULONG nExecutedCycles) = 0;
// get MAC for IPRAW
virtual void getMACAddress(const uint32_t address, MACAddress & mac) = 0;
// if the backend is usable
virtual bool isValid() = 0;
static void dumpPacket(
const int txlength, /* Frame length */
uint8_t *txframe /* Data */
);
};

View file

@ -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 <iphlpapi.h>
#endif
std::string PCapBackend::tfe_interface;
PCapBackend::PCapBackend(const std::string & pcapInterface)
@ -46,6 +50,7 @@ void PCapBackend::transmit(
if (tfePcapFP)
{
tfe_arch_transmit(tfePcapFP, txlength, txframe);
dumpPacket(txlength, txframe);
}
}
@ -53,7 +58,9 @@ int PCapBackend::receive(const int size, uint8_t * rxframe)
{
if (tfePcapFP)
{
return tfe_arch_receive(tfePcapFP, size, rxframe);
const int rxlength = tfe_arch_receive(tfePcapFP, size, rxframe);
dumpPacket(rxlength, rxframe);
return rxlength;
}
else
{
@ -71,6 +78,33 @@ void PCapBackend::update(const ULONG /* nExecutedCycles */)
// nothing to do
}
void PCapBackend::getMACAddress(const uint32_t address, MACAddress & mac)
{
#ifdef _MSC_VER
DWORD dwSourceAddress = INADDR_ANY;
MIB_IPFORWARDROW res;
DWORD result = GetBestRoute(address, dwSourceAddress, &res);
if (result == NO_ERROR)
{
ULONG len = sizeof(MACAddress::address);
IPAddr ip;
switch (res.ForwardType)
{
case MIB_IPROUTE_TYPE_DIRECT:
ip = address;
break;
case MIB_IPROUTE_TYPE_INDIRECT:
ip = res.dwForwardNextHop;
break;
default:
ip = INADDR_ANY; // ???
break;
}
result = SendARP(ip, dwSourceAddress, mac.address, &len);
}
#endif
}
int PCapBackend::tfe_enumadapter_open(void)
{
return tfe_arch_enumadapter_open();

View file

@ -29,6 +29,9 @@ public:
// process pending packets
virtual bool isValid();
// get MAC for IPRAW
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);

View file

@ -29,6 +29,7 @@
#ifdef _MSC_VER
#include "pcap.h"
#undef min
#else
// on Linux and Mac OS X, we use system's pcap.h, which needs to be included as <>
#include <pcap.h>
@ -39,11 +40,12 @@
#include <stdlib.h>
#include <string.h>
#include <chrono>
#include <StdAfx.h> // this is necessary in linux, but in MSVC windows.h MUST come after winsock2.h (from pcap.h above)
#include "tfearch.h"
#include "../Log.h"
/** #define TFE_DEBUG_ARCH 1 **/
/** #define TFE_DEBUG_PKTDUMP 1 **/
@ -56,6 +58,7 @@ int tfe_cannot_use = 0;
#ifdef _MSC_VER
typedef pcap_t *(*pcap_open_live_t)(const char *, int, int, int, char *);
typedef pcap_t *(*pcap_open_dead_t)(int, int);
typedef void (*pcap_close_t)(pcap_t *);
typedef int (*pcap_dispatch_t)(pcap_t *, int, pcap_handler, u_char *);
typedef int (*pcap_setnonblock_t)(pcap_t *, int, char *);
@ -64,8 +67,12 @@ typedef int (*pcap_findalldevs_t)(pcap_if_t **, char *);
typedef void (*pcap_freealldevs_t)(pcap_if_t *);
typedef int (*pcap_sendpacket_t)(pcap_t *p, u_char *buf, int size);
typedef const char *(*pcap_lib_version_t)(void);
typedef pcap_dumper_t *(*pcap_dump_open_t)(pcap_t *, const char *);
typedef void (*pcap_dump_close_t)(pcap_dumper_t *);
typedef void (*pcap_dump_t)(u_char *, const struct pcap_pkthdr *, const u_char *);
static pcap_open_live_t p_pcap_open_live;
static pcap_open_dead_t p_pcap_open_dead;
static pcap_close_t p_pcap_close;
static pcap_dispatch_t p_pcap_dispatch;
static pcap_setnonblock_t p_pcap_setnonblock;
@ -74,6 +81,9 @@ static pcap_freealldevs_t p_pcap_freealldevs;
static pcap_sendpacket_t p_pcap_sendpacket;
static pcap_datalink_t p_pcap_datalink;
static pcap_lib_version_t p_pcap_lib_version;
static pcap_dump_open_t p_pcap_dump_open;
static pcap_dump_close_t p_pcap_dump_close;
static pcap_dump_t p_pcap_dump;
static HINSTANCE pcap_library = NULL;
@ -87,6 +97,7 @@ void TfePcapFreeLibrary(void)
pcap_library = NULL;
p_pcap_open_live = NULL;
p_pcap_open_dead = NULL;
p_pcap_close = NULL;
p_pcap_dispatch = NULL;
p_pcap_setnonblock = NULL;
@ -95,6 +106,9 @@ void TfePcapFreeLibrary(void)
p_pcap_sendpacket = NULL;
p_pcap_datalink = NULL;
p_pcap_lib_version = NULL;
p_pcap_dump_open = NULL;
p_pcap_dump_close = NULL;
p_pcap_dump = NULL;
}
}
@ -127,6 +141,7 @@ BOOL TfePcapLoadLibrary(void)
}
GET_PROC_ADDRESS_AND_TEST(pcap_open_live);
GET_PROC_ADDRESS_AND_TEST(pcap_open_dead);
GET_PROC_ADDRESS_AND_TEST(pcap_close);
GET_PROC_ADDRESS_AND_TEST(pcap_dispatch);
GET_PROC_ADDRESS_AND_TEST(pcap_setnonblock);
@ -135,6 +150,9 @@ BOOL TfePcapLoadLibrary(void)
GET_PROC_ADDRESS_AND_TEST(pcap_sendpacket);
GET_PROC_ADDRESS_AND_TEST(pcap_datalink);
GET_PROC_ADDRESS_AND_TEST(pcap_lib_version);
GET_PROC_ADDRESS_AND_TEST(pcap_dump_open);
GET_PROC_ADDRESS_AND_TEST(pcap_dump_close);
GET_PROC_ADDRESS_AND_TEST(pcap_dump);
LogOutput("%s\n", p_pcap_lib_version());
LogFileOutput("%s\n", p_pcap_lib_version());
}
@ -148,6 +166,7 @@ BOOL TfePcapLoadLibrary(void)
// libpcap is a standard package, just link to it
#define p_pcap_open_live pcap_open_live
#define p_pcap_open_dead pcap_open_dead
#define p_pcap_close pcap_close
#define p_pcap_dispatch pcap_dispatch
#define p_pcap_setnonblock pcap_setnonblock
@ -156,6 +175,9 @@ BOOL TfePcapLoadLibrary(void)
#define p_pcap_sendpacket pcap_sendpacket
#define p_pcap_datalink pcap_datalink
#define p_pcap_lib_version pcap_lib_version
#define p_pcap_dump_open pcap_dump_open
#define p_pcap_dump_close pcap_dump_close
#define p_pcap_dump pcap_dump
static BOOL TfePcapLoadLibrary(void)
{
@ -540,4 +562,45 @@ int tfe_arch_receive(pcap_t * TfePcapFP,
return -1;
}
void tfe_pcap_dump_open(const char *fname, const int len, pcap_t *&pcap, pcap_dumper_t *&dumper)
{
pcap = NULL;
dumper = NULL;
if (TfePcapLoadLibrary())
{
pcap = p_pcap_open_dead(DLT_EN10MB, len);
dumper = p_pcap_dump_open(pcap, fname);
}
}
void tfe_pcap_dump_close(pcap_t *pcap, pcap_dumper_t *dumper)
{
if (pcap)
{
p_pcap_close(pcap);
}
if (dumper)
{
p_pcap_dump_close(dumper);
}
}
void tfe_pcap_dump(pcap_dumper_t *dumper, const int txlength, uint8_t *txframe)
{
if (dumper && txlength > 0)
{
pcap_pkthdr header;
header.caplen = static_cast<bpf_u_int32>(txlength);
header.len = header.caplen;
const uint64_t microseconds_since_epoch = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
header.ts.tv_sec = static_cast<long>(microseconds_since_epoch / 1000000);
header.ts.tv_usec = static_cast<long>(microseconds_since_epoch % 1000000);
p_pcap_dump(reinterpret_cast<u_char *>(dumper), &header, txframe);
}
}
//#endif /* #ifdef HAVE_TFE */

View file

@ -39,6 +39,8 @@ extern int tfe_cannot_use;
struct pcap;
typedef struct pcap pcap_t;
struct pcap_dumper;
typedef struct pcap_dumper pcap_dumper_t;
pcap_t * TfePcapOpenAdapter(const std::string & interface_name);
void TfePcapCloseAdapter(pcap_t * TfePcapFP);
@ -71,4 +73,8 @@ extern int tfe_arch_enumadapter_open(void);
extern int tfe_arch_enumadapter(std::string & name, std::string & description);
extern int tfe_arch_enumadapter_close(void);
extern void tfe_pcap_dump_open(const char *fname, const int len, pcap_t *&pcap, pcap_dumper_t *&dumper);
extern void tfe_pcap_dump_close(pcap_t *pcap, pcap_dumper_t *dumper);
extern void tfe_pcap_dump(pcap_dumper_t *dumper, const int txlength, uint8_t *txframe);
#endif

View file

@ -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
@ -74,9 +75,9 @@ typedef int socklen_t;
#endif
// #define U2_LOG_VERBOSE
// #define U2_LOG_TRAFFIC
// #define U2_LOG_STATE
// #define U2_LOG_UNKNOWN
#define U2_LOG_TRAFFIC
#define U2_LOG_STATE
#define U2_LOG_UNKNOWN
#define MAC_FMT "%02X:%02X:%02X:%02X:%02X:%02X"
#define MAC_DEST(p) p[0], p[1], p[2], p[3], p[4], p[5]
@ -95,6 +96,12 @@ namespace
return host;
}
uint32_t readAddress(const uint8_t *ptr)
{
const uint32_t address = *reinterpret_cast<const uint32_t *>(ptr);
return address;
}
uint8_t getIByte(const uint16_t value, const size_t shift)
{
return (value >> shift) & 0xFF;
@ -141,6 +148,13 @@ namespace
writeData(socket, memory, data, len);
}
void writeDataIPRaw(Socket &socket, std::vector<uint8_t> &memory, const uint8_t *data, const size_t len, const uint32_t destination)
{
writeAny(socket, memory, destination);
write16(socket, memory, static_cast<uint16_t>(len));
writeData(socket, memory, data, len);
}
void writeDataForProtocol(Socket &socket, std::vector<uint8_t> &memory, const uint8_t *data, const size_t len, const sockaddr_in &source)
{
if (socket.sn_sr == W5100_SN_SR_SOCK_UDP)
@ -283,7 +297,7 @@ const std::string& Uthernet2::GetSnapshotCardName()
return name;
}
Uthernet2::Uthernet2(UINT slot) : Card(CT_Uthernet2, slot)
Uthernet2::Uthernet2(UINT slot) : Card(CT_Uthernet2, slot), myIPMinimumSize(getIPMinimumSize())
{
Reset(true);
}
@ -434,7 +448,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 +456,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 >= myIPMinimumSize)
{
if (acceptAll)
{
return len;
}
if (data[0] == mac[0] &&
data[1] == mac[1] &&
data[2] == mac[2] &&
@ -458,6 +466,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 +477,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 +494,109 @@ 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
}
}
}
}
// 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
#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 +649,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 +665,29 @@ void Uthernet2::receiveOnePacket(const size_t i)
};
}
void Uthernet2::sendDataIPRaw(const size_t i, std::vector<uint8_t> &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<const MACAddress *>(myMemory.data() + W5100_SHAR0);
const MACAddress * destinationMac;
getMACAddress(destination, destinationMac);
std::vector<uint8_t> 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<uint8_t> &packet) const
{
#ifdef U2_LOG_TRAFFIC
@ -656,6 +772,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 +973,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 +1107,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 +1192,7 @@ void Uthernet2::Reset(const bool powerCycle)
// dataAddress is NOT reset, see page 10 of Uthernet II
myDataAddress = 0;
myNetworkBackend = GetFrame().CreateNetworkBackend();
myARPTable.clear();
}
mySockets.clear();
@ -1084,14 +1204,25 @@ void Uthernet2::Reset(const bool powerCycle)
{
resetRXTXBuffers(i);
mySockets[i].clearFD();
mySockets[i].registerAddress = static_cast<uint16_t>(W5100_S0_BASE + (i << 8));
const uint16_t registerAddress = static_cast<uint16_t>(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_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 +1293,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 = myARPTable.find(address);
if (it != myARPTable.end())
{
mac = &it->second;
}
else
{
MACAddress & macAddr = myARPTable[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);

View file

@ -3,8 +3,10 @@
#include "Card.h"
#include <vector>
#include <map>
class NetworkBackend;
struct MACAddress;
struct Socket
{
@ -47,6 +49,7 @@ struct Socket
* Documentation from
* http://dserver.macgui.com/Uthernet%20II%20manual%2017%20Nov%2018.pdf
* https://www.wiznet.io/wp-content/uploads/wiznethome/Chip/W5100/Document/W5100_DS_V128E.pdf
* https://www.wiznet.io/wp-content/uploads/wiznethome/Chip/W5100/Document/3150Aplus_5100_ES_V260E.pdf
*/
class Uthernet2 : public Card
@ -54,6 +57,8 @@ class Uthernet2 : public Card
public:
static const std::string& GetSnapshotCardName();
enum PacketDestination { HOST, BROADCAST, OTHER };
Uthernet2(UINT slot);
virtual void Destroy(void) {}
@ -66,12 +71,18 @@ public:
BYTE IO_C0(WORD programcounter, WORD address, BYTE write, BYTE value, ULONG nCycles);
private:
const int myIPMinimumSize;
std::vector<uint8_t> myMemory;
std::vector<Socket> mySockets;
uint8_t myModeRegister;
uint16_t myDataAddress;
std::shared_ptr<NetworkBackend> myNetworkBackend;
std::map<uint32_t, MACAddress> myARPTable;
void getMACAddress(const uint32_t address, const MACAddress * & mac);
void setSocketModeRegister(const size_t i, const uint16_t address, const uint8_t value);
void setTXSizes(const uint16_t address, uint8_t value);
void setRXSizes(const uint16_t address, uint8_t value);
@ -79,11 +90,14 @@ private:
uint8_t getTXFreeSizeRegister(const size_t i, const size_t shift) const;
uint8_t getRXDataSizeRegister(const size_t i, const size_t shift) const;
void receiveOnePacketMacRaw(const size_t i);
void receiveOnePacketRaw();
void receiveOnePacketIPRaw(const size_t i, const size_t lengthOfPayload, const uint8_t * payload, const uint32_t destination, const uint8_t protocol, const int len);
void receiveOnePacketMacRaw(const size_t i, const int size, uint8_t * data);
void receiveOnePacketFromSocket(const size_t i);
void receiveOnePacket(const size_t i);
int receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data);
int receiveForMacAddress(const bool acceptAll, const int size, uint8_t * data, PacketDestination & packetDestination);
void sendDataIPRaw(const size_t i, std::vector<uint8_t> &data);
void sendDataMacRaw(const size_t i, std::vector<uint8_t> &data) const;
void sendDataToSocket(const size_t i, std::vector<uint8_t> &data);
void sendData(const size_t i);

View file

@ -20,8 +20,10 @@
#define W5100_SIPR3 0x0012
#define W5100_RTR0 0x0017
#define W5100_RTR1 0x0018
#define W5100_RCR 0x0019
#define W5100_RMSR 0x001A
#define W5100_TMSR 0x001B
#define W5100_PTIMER 0x0028
#define W5100_UPORT1 0x002F
#define W5100_S0_BASE 0x0400
#define W5100_S3_MAX 0x07FF
@ -58,6 +60,12 @@
#define W5100_SN_SR 0x03
#define W5100_SN_PORT0 0x04
#define W5100_SN_PORT1 0x05
#define W5100_SN_DHAR0 0x06
#define W5100_SN_DHAR1 0x07
#define W5100_SN_DHAR2 0x08
#define W5100_SN_DHAR3 0x09
#define W5100_SN_DHAR4 0x0A
#define W5100_SN_DHAR5 0x0B
#define W5100_SN_DIPR0 0x0C
#define W5100_SN_DIPR1 0x0D
#define W5100_SN_DIPR2 0x0E

View file

@ -110,7 +110,7 @@ SlirpBackend::SlirpBackend()
.vnetmask = { .s_addr = IP_PACK(255, 255, 255, 0) },
.vhost = { .s_addr = IP_PACK(10, 0, 0, 1) },
.vhostname = "applewin",
.vdhcp_start = { .s_addr = IP_PACK(10, 0, 0, 2) },
.vdhcp_start = { .s_addr = IP_PACK(10, 0, 0, 10) },
};
static const SlirpCb slirp_cb =
{
@ -131,6 +131,7 @@ SlirpBackend::SlirpBackend()
void SlirpBackend::transmit(const int txlength, uint8_t *txframe)
{
slirp_input(mySlirp.get(), txframe, txlength);
dumpPacket(txlength, txframe);
}
int SlirpBackend::receive(const int size, uint8_t * rxframe)
@ -146,6 +147,7 @@ int SlirpBackend::receive(const int size, uint8_t * rxframe)
++received;
}
myQueue.pop();
dumpPacket(received, rxframe);
return received;
}
else
@ -200,4 +202,15 @@ bool SlirpBackend::isValid()
return true;
}
void SlirpBackend::getMACAddress(const uint32_t address, MACAddress & mac)
{
// a bit of a hack, I've found out that slirp uses
/* emulated hosts use the MAC addr 52:55:IP:IP:IP:IP */
// https://gitlab.freedesktop.org/slirp/libslirp/-/blob/bf917b89d64f57d9302aba4b2f027ea68fb78c13/src/slirp.c#L78
mac.address[0] = 0x52;
mac.address[1] = 0x55;
uint32_t * ptr = reinterpret_cast<uint32_t *>(mac.address + 2);
*ptr = address;
}
#endif

View file

@ -30,6 +30,9 @@ public:
void update(const ULONG nExecutedCycles) override;
bool isValid() override;
// get MAC for IPRAW
void getMACAddress(const uint32_t address, MACAddress & mac) override;
void sendToGuest(const uint8_t *pkt, int pkt_len);
int addPoll(const int fd, const int events);

View file

@ -99,6 +99,7 @@
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>iphlpapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug v141_xp|Win32'">