mirror of
https://github.com/kanjitalk755/macemu.git
synced 2025-01-27 07:30:12 +00:00
Add experimental TAP-Win32 support. It looks rather sluggish to me, something
is probably wrong somewhere...
This commit is contained in:
parent
6590198dd8
commit
11ff11d205
@ -20,11 +20,13 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include "sysdeps.h"
|
||||
|
||||
#include <process.h>
|
||||
#include <windowsx.h>
|
||||
#include <winioctl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "sysdeps.h"
|
||||
#include "cpu_emulation.h"
|
||||
#include "main.h"
|
||||
#include "macos_util.h"
|
||||
@ -58,9 +60,32 @@ enum {
|
||||
NET_IF_B2ETHER,
|
||||
NET_IF_ROUTER,
|
||||
NET_IF_SLIRP,
|
||||
NET_IF_TAP,
|
||||
NET_IF_FAKE,
|
||||
};
|
||||
|
||||
// TAP-Win32 constants
|
||||
#define TAP_VERSION_MIN_MAJOR 7
|
||||
#define TAP_VERSION_MIN_MINOR 1
|
||||
|
||||
#define TAP_CONTROL_CODE(request, method) \
|
||||
CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
|
||||
|
||||
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED)
|
||||
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED)
|
||||
|
||||
#define OLD_TAP_CONTROL_CODE(request, method) \
|
||||
CTL_CODE (FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS)
|
||||
|
||||
#define OLD_TAP_IOCTL_GET_VERSION OLD_TAP_CONTROL_CODE (3, METHOD_BUFFERED)
|
||||
|
||||
// Options
|
||||
bool ether_use_permanent = true;
|
||||
static int16 ether_multi_mode = ETHER_MULTICAST_MAC;
|
||||
@ -70,10 +95,10 @@ HANDLE ether_th;
|
||||
unsigned int ether_tid;
|
||||
HANDLE ether_th1;
|
||||
HANDLE ether_th2;
|
||||
static int net_if_type = -1; // Ethernet device type
|
||||
static int net_if_type = -1; // Ethernet device type
|
||||
#ifdef SHEEPSHAVER
|
||||
static bool net_open = false; // Flag: initialization succeeded, network device open
|
||||
uint8 ether_addr[6]; // Our Ethernet address
|
||||
static bool net_open = false; // Flag: initialization succeeded, network device open
|
||||
uint8 ether_addr[6]; // Our Ethernet address
|
||||
#endif
|
||||
|
||||
// These are protected by queue_csection
|
||||
@ -143,6 +168,13 @@ static HANDLE int_sig2 = 0;
|
||||
static HANDLE int_send_now = 0;
|
||||
|
||||
// Prototypes
|
||||
static LPADAPTER tap_open_adapter(const char *dev_name);
|
||||
static void tap_close_adapter(LPADAPTER fd);
|
||||
static bool tap_check_version(LPADAPTER fd);
|
||||
static bool tap_set_status(LPADAPTER fd, ULONG status);
|
||||
static bool tap_get_mac(LPADAPTER fd, LPBYTE addr);
|
||||
static bool tap_receive_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync);
|
||||
static bool tap_send_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync, BOOLEAN recycle);
|
||||
static WINAPI unsigned int slirp_receive_func(void *arg);
|
||||
static WINAPI unsigned int ether_thread_feed_int(void *arg);
|
||||
static WINAPI unsigned int ether_thread_get_packets_nt(void *arg);
|
||||
@ -202,6 +234,8 @@ bool ether_init(void)
|
||||
net_if_type = NET_IF_ROUTER;
|
||||
else if (strcmp(name, "slirp") == 0)
|
||||
net_if_type = NET_IF_SLIRP;
|
||||
else if (strcmp(name, "tap") == 0)
|
||||
net_if_type = NET_IF_TAP;
|
||||
else
|
||||
net_if_type = NET_IF_B2ETHER;
|
||||
|
||||
@ -226,6 +260,9 @@ bool ether_init(void)
|
||||
case NET_IF_B2ETHER:
|
||||
dev_name = PrefsFindString("etherguid");
|
||||
break;
|
||||
case NET_IF_TAP:
|
||||
dev_name = PrefsFindString("etherguid");
|
||||
break;
|
||||
}
|
||||
if (net_if_type == NET_IF_B2ETHER) {
|
||||
if (dev_name == NULL) {
|
||||
@ -261,6 +298,62 @@ bool ether_init(void)
|
||||
D(bug("Fake ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
|
||||
}
|
||||
}
|
||||
else if (net_if_type == NET_IF_TAP) {
|
||||
if (dev_name == NULL) {
|
||||
WarningAlert("No ethernet device GUID specified. Ethernet is not available.");
|
||||
goto open_error;
|
||||
}
|
||||
|
||||
fd = tap_open_adapter(dev_name);
|
||||
if (!fd) {
|
||||
sprintf(str, "Could not open ethernet adapter %s.", dev_name);
|
||||
WarningAlert(str);
|
||||
goto open_error;
|
||||
}
|
||||
|
||||
if (!tap_check_version(fd)) {
|
||||
sprintf(str, "Minimal TAP-Win32 version supported is %d.%d.", TAP_VERSION_MIN_MAJOR, TAP_VERSION_MIN_MINOR);
|
||||
WarningAlert(str);
|
||||
goto open_error;
|
||||
}
|
||||
|
||||
if (!tap_set_status(fd, true)) {
|
||||
sprintf(str, "Could not set media status to connected.");
|
||||
WarningAlert(str);
|
||||
goto open_error;
|
||||
}
|
||||
|
||||
if (!tap_get_mac(fd, ether_addr)) {
|
||||
sprintf(str, "Could not get hardware address of device %s. Ethernet is not available.", dev_name);
|
||||
WarningAlert(str);
|
||||
goto open_error;
|
||||
}
|
||||
D(bug("Real ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
|
||||
|
||||
const char *ether_fake_address;
|
||||
ether_fake_address = PrefsFindString("etherfakeaddress");
|
||||
if (ether_fake_address && strlen(ether_fake_address) == 12) {
|
||||
char sm[10];
|
||||
strcpy( sm, "0x00" );
|
||||
for( int i=0; i<6; i++ ) {
|
||||
sm[2] = ether_fake_address[i*2];
|
||||
sm[3] = ether_fake_address[i*2+1];
|
||||
ether_addr[i] = (uint8)strtoul(sm,0,0);
|
||||
}
|
||||
}
|
||||
#if 1
|
||||
/*
|
||||
If we bridge the underlying ethernet connection and the TAP
|
||||
device altogether, we have to use a fake address.
|
||||
*/
|
||||
else {
|
||||
ether_addr[0] = 0x52;
|
||||
ether_addr[1] = 0x54;
|
||||
ether_addr[2] = 0x00;
|
||||
}
|
||||
#endif
|
||||
D(bug("Fake ethernet address %02x %02x %02x %02x %02x %02x\n", ether_addr[0], ether_addr[1], ether_addr[2], ether_addr[3], ether_addr[4], ether_addr[5]));
|
||||
}
|
||||
else if (net_if_type == NET_IF_SLIRP) {
|
||||
ether_addr[0] = 0x52;
|
||||
ether_addr[1] = 0x54;
|
||||
@ -337,9 +430,16 @@ bool ether_init(void)
|
||||
thread_active = true;
|
||||
|
||||
unsigned int dummy;
|
||||
ether_th2 = (HANDLE)_beginthreadex( 0, 0,
|
||||
net_if_type == NET_IF_SLIRP ? slirp_receive_func : ether_thread_get_packets_nt,
|
||||
0, 0, &dummy );
|
||||
unsigned int (WINAPI *receive_func)(void *);
|
||||
switch (net_if_type) {
|
||||
case NET_IF_SLIRP:
|
||||
receive_func = slirp_receive_func;
|
||||
break;
|
||||
default:
|
||||
receive_func = ether_thread_get_packets_nt;
|
||||
break;
|
||||
}
|
||||
ether_th2 = (HANDLE)_beginthreadex( 0, 0, receive_func, 0, 0, &dummy );
|
||||
ether_th1 = (HANDLE)_beginthreadex( 0, 0, ether_thread_write_packets, 0, 0, &dummy );
|
||||
|
||||
// Everything OK
|
||||
@ -363,10 +463,17 @@ bool ether_init(void)
|
||||
int_send_now = 0;
|
||||
thread_active = false;
|
||||
}
|
||||
if(net_if_type == NET_IF_B2ETHER) {
|
||||
PacketCloseAdapter(fd);
|
||||
if (fd) {
|
||||
switch (net_if_type) {
|
||||
case NET_IF_B2ETHER:
|
||||
PacketCloseAdapter(fd);
|
||||
break;
|
||||
case NET_IF_TAP:
|
||||
tap_close_adapter(fd);
|
||||
break;
|
||||
}
|
||||
fd = 0;
|
||||
}
|
||||
fd = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -437,8 +544,15 @@ void ether_exit(void)
|
||||
}
|
||||
|
||||
// Close ethernet device
|
||||
if(fd) {
|
||||
PacketCloseAdapter(fd);
|
||||
if (fd) {
|
||||
switch (net_if_type) {
|
||||
case NET_IF_B2ETHER:
|
||||
PacketCloseAdapter(fd);
|
||||
break;
|
||||
case NET_IF_TAP:
|
||||
tap_close_adapter(fd);
|
||||
break;
|
||||
}
|
||||
fd = 0;
|
||||
}
|
||||
|
||||
@ -904,6 +1018,11 @@ static unsigned int ether_thread_write_packets(void *arg)
|
||||
// already recycled if async
|
||||
}
|
||||
break;
|
||||
case NET_IF_TAP:
|
||||
if (!tap_send_packet(fd, Packet, FALSE, TRUE)) {
|
||||
// already recycled if async
|
||||
}
|
||||
break;
|
||||
case NET_IF_SLIRP:
|
||||
slirp_input((uint8 *)Packet->Buffer, Packet->Length);
|
||||
Packet->bIoComplete = TRUE;
|
||||
@ -1059,6 +1178,178 @@ static bool set_wait_request(void)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* TAP-Win32 glue
|
||||
*/
|
||||
|
||||
static LPADAPTER tap_open_adapter(const char *dev_name)
|
||||
{
|
||||
fd = (LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*fd));
|
||||
if (fd == NULL)
|
||||
return NULL;
|
||||
|
||||
char dev_path[MAX_PATH];
|
||||
snprintf(dev_path, sizeof(dev_path),
|
||||
"\\\\.\\Global\\%s.tap", dev_name);
|
||||
|
||||
HANDLE handle = CreateFile(
|
||||
dev_path,
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
if (handle == NULL || handle == INVALID_HANDLE_VALUE)
|
||||
return NULL;
|
||||
|
||||
fd->hFile = handle;
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void tap_close_adapter(LPADAPTER fd)
|
||||
{
|
||||
if (fd) {
|
||||
if (fd->hFile) {
|
||||
tap_set_status(fd, false);
|
||||
CloseHandle(fd->hFile);
|
||||
}
|
||||
GlobalFreePtr(fd);
|
||||
}
|
||||
}
|
||||
|
||||
static bool tap_check_version(LPADAPTER fd)
|
||||
{
|
||||
ULONG len;
|
||||
ULONG info[3] = { 0, };
|
||||
|
||||
if (!DeviceIoControl(fd->hFile, TAP_IOCTL_GET_VERSION,
|
||||
&info, sizeof(info),
|
||||
&info, sizeof(info), &len, NULL)
|
||||
&& !DeviceIoControl(fd->hFile, OLD_TAP_IOCTL_GET_VERSION,
|
||||
&info, sizeof(info),
|
||||
&info, sizeof(info), &len, NULL))
|
||||
return false;
|
||||
|
||||
if (info[0] > TAP_VERSION_MIN_MAJOR)
|
||||
return true;
|
||||
if (info[0] == TAP_VERSION_MIN_MAJOR && info[1] >= TAP_VERSION_MIN_MINOR)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool tap_set_status(LPADAPTER fd, ULONG status)
|
||||
{
|
||||
DWORD len = 0;
|
||||
return DeviceIoControl(fd->hFile, TAP_IOCTL_SET_MEDIA_STATUS,
|
||||
&status, sizeof (status),
|
||||
&status, sizeof (status), &len, NULL);
|
||||
}
|
||||
|
||||
static bool tap_get_mac(LPADAPTER fd, LPBYTE addr)
|
||||
{
|
||||
DWORD len = 0;
|
||||
return DeviceIoControl(fd->hFile, TAP_IOCTL_GET_MAC,
|
||||
addr, 6,
|
||||
addr, 6, &len, NULL);
|
||||
|
||||
}
|
||||
|
||||
static VOID CALLBACK tap_write_completion(
|
||||
DWORD dwErrorCode,
|
||||
DWORD dwNumberOfBytesTransfered,
|
||||
LPOVERLAPPED lpOverLapped
|
||||
)
|
||||
{
|
||||
LPPACKET lpPacket = CONTAINING_RECORD(lpOverLapped, PACKET, OverLapped);
|
||||
|
||||
lpPacket->bIoComplete = TRUE;
|
||||
recycle_write_packet(lpPacket);
|
||||
}
|
||||
|
||||
static bool tap_send_packet(
|
||||
LPADAPTER fd,
|
||||
LPPACKET lpPacket,
|
||||
BOOLEAN Sync,
|
||||
BOOLEAN RecyclingAllowed)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
|
||||
lpPacket->OverLapped.Offset = 0;
|
||||
lpPacket->OverLapped.OffsetHigh = 0;
|
||||
lpPacket->bIoComplete = FALSE;
|
||||
|
||||
if (Sync) {
|
||||
Result = WriteFile(fd->hFile,
|
||||
lpPacket->Buffer,
|
||||
lpPacket->Length,
|
||||
&lpPacket->BytesReceived,
|
||||
&lpPacket->OverLapped);
|
||||
if (Result) {
|
||||
GetOverlappedResult(fd->hFile,
|
||||
&lpPacket->OverLapped,
|
||||
&lpPacket->BytesReceived,
|
||||
TRUE);
|
||||
}
|
||||
lpPacket->bIoComplete = TRUE;
|
||||
if (RecyclingAllowed)
|
||||
PacketFreePacket(lpPacket);
|
||||
}
|
||||
else {
|
||||
Result = WriteFileEx(fd->hFile,
|
||||
lpPacket->Buffer,
|
||||
lpPacket->Length,
|
||||
&lpPacket->OverLapped,
|
||||
tap_write_completion);
|
||||
|
||||
if (!Result && RecyclingAllowed)
|
||||
recycle_write_packet(lpPacket);
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static bool tap_receive_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync)
|
||||
{
|
||||
BOOLEAN Result;
|
||||
|
||||
lpPacket->OverLapped.Offset = 0;
|
||||
lpPacket->OverLapped.OffsetHigh = 0;
|
||||
lpPacket->bIoComplete = FALSE;
|
||||
|
||||
if (Sync) {
|
||||
Result = ReadFile(fd->hFile,
|
||||
lpPacket->Buffer,
|
||||
lpPacket->Length,
|
||||
&lpPacket->BytesReceived,
|
||||
&lpPacket->OverLapped);
|
||||
if (Result) {
|
||||
Result = GetOverlappedResult(fd->hFile,
|
||||
&lpPacket->OverLapped,
|
||||
&lpPacket->BytesReceived,
|
||||
TRUE);
|
||||
if (Result)
|
||||
lpPacket->bIoComplete = TRUE;
|
||||
else
|
||||
lpPacket->free = TRUE;
|
||||
}
|
||||
}
|
||||
else {
|
||||
Result = ReadFileEx(fd->hFile,
|
||||
lpPacket->Buffer,
|
||||
lpPacket->Length,
|
||||
&lpPacket->OverLapped,
|
||||
packet_read_completion);
|
||||
|
||||
if (!Result)
|
||||
lpPacket->BytesReceived = 0;
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* SLIRP output buffer glue
|
||||
*/
|
||||
@ -1073,7 +1364,7 @@ void slirp_output(const uint8 *packet, int len)
|
||||
enqueue_packet(packet, len);
|
||||
}
|
||||
|
||||
unsigned int slirp_receive_func(void *arg)
|
||||
static unsigned int slirp_receive_func(void *arg)
|
||||
{
|
||||
D(bug("slirp_receive_func\n"));
|
||||
thread_active_2 = true;
|
||||
@ -1151,6 +1442,11 @@ VOID CALLBACK packet_read_completion(
|
||||
break;
|
||||
}
|
||||
}
|
||||
// XXX drop packets that are not for us
|
||||
if (net_if_type == NET_IF_TAP) {
|
||||
if (memcmp((LPBYTE)lpPacket->Buffer, ether_addr, 6) != 0)
|
||||
dwNumberOfBytesTransfered = 0;
|
||||
}
|
||||
if(dwNumberOfBytesTransfered) {
|
||||
if(net_if_type != NET_IF_ROUTER || !router_read_packet((uint8 *)lpPacket->Buffer, dwNumberOfBytesTransfered)) {
|
||||
enqueue_packet( (LPBYTE)lpPacket->Buffer, dwNumberOfBytesTransfered );
|
||||
@ -1223,12 +1519,21 @@ static unsigned int ether_thread_get_packets_nt(void *arg)
|
||||
// Obey the golden rules; keep the reads pending.
|
||||
while(thread_active) {
|
||||
|
||||
if(net_if_type == NET_IF_B2ETHER) {
|
||||
if(net_if_type == NET_IF_B2ETHER || net_if_type == NET_IF_TAP) {
|
||||
D(bug("Pending reads\n"));
|
||||
for( i=0; thread_active && i<PACKET_POOL_COUNT; i++ ) {
|
||||
if(packets[i]->free) {
|
||||
packets[i]->free = FALSE;
|
||||
if(PacketReceivePacket(fd,packets[i],FALSE)) {
|
||||
BOOLEAN Result;
|
||||
switch (net_if_type) {
|
||||
case NET_IF_B2ETHER:
|
||||
Result = PacketReceivePacket(fd, packets[i], FALSE);
|
||||
break;
|
||||
case NET_IF_TAP:
|
||||
Result = tap_receive_packet(fd, packets[i], FALSE);
|
||||
break;
|
||||
}
|
||||
if (Result) {
|
||||
if(packets[i]->bIoComplete) {
|
||||
D(bug("Early io completion...\n"));
|
||||
packet_read_completion(
|
||||
|
Loading…
x
Reference in New Issue
Block a user