20 |
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 |
|
*/ |
22 |
|
|
23 |
+ |
#include "sysdeps.h" |
24 |
+ |
|
25 |
|
#include <process.h> |
26 |
|
#include <windowsx.h> |
27 |
+ |
#include <winioctl.h> |
28 |
|
#include <ctype.h> |
29 |
|
|
27 |
– |
#include "sysdeps.h" |
30 |
|
#include "cpu_emulation.h" |
31 |
|
#include "main.h" |
32 |
|
#include "macos_util.h" |
60 |
|
NET_IF_B2ETHER, |
61 |
|
NET_IF_ROUTER, |
62 |
|
NET_IF_SLIRP, |
63 |
+ |
NET_IF_TAP, |
64 |
|
NET_IF_FAKE, |
65 |
|
}; |
66 |
|
|
67 |
+ |
// TAP-Win32 constants |
68 |
+ |
#define TAP_VERSION_MIN_MAJOR 7 |
69 |
+ |
#define TAP_VERSION_MIN_MINOR 1 |
70 |
+ |
|
71 |
+ |
#define TAP_CONTROL_CODE(request, method) \ |
72 |
+ |
CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) |
73 |
+ |
|
74 |
+ |
#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) |
75 |
+ |
#define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) |
76 |
+ |
#define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) |
77 |
+ |
#define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) |
78 |
+ |
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) |
79 |
+ |
#define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) |
80 |
+ |
#define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) |
81 |
+ |
#define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) |
82 |
+ |
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) |
83 |
+ |
|
84 |
+ |
#define OLD_TAP_CONTROL_CODE(request, method) \ |
85 |
+ |
CTL_CODE (FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS) |
86 |
+ |
|
87 |
+ |
#define OLD_TAP_IOCTL_GET_VERSION OLD_TAP_CONTROL_CODE (3, METHOD_BUFFERED) |
88 |
+ |
|
89 |
|
// Options |
90 |
|
bool ether_use_permanent = true; |
91 |
|
static int16 ether_multi_mode = ETHER_MULTICAST_MAC; |
95 |
|
unsigned int ether_tid; |
96 |
|
HANDLE ether_th1; |
97 |
|
HANDLE ether_th2; |
98 |
< |
static int net_if_type = -1; // Ethernet device type |
98 |
> |
static int net_if_type = -1; // Ethernet device type |
99 |
|
#ifdef SHEEPSHAVER |
100 |
< |
static bool net_open = false; // Flag: initialization succeeded, network device open |
101 |
< |
uint8 ether_addr[6]; // Our Ethernet address |
100 |
> |
static bool net_open = false; // Flag: initialization succeeded, network device open |
101 |
> |
uint8 ether_addr[6]; // Our Ethernet address |
102 |
|
#endif |
103 |
|
|
104 |
|
// These are protected by queue_csection |
168 |
|
static HANDLE int_send_now = 0; |
169 |
|
|
170 |
|
// Prototypes |
171 |
+ |
static LPADAPTER tap_open_adapter(const char *dev_name); |
172 |
+ |
static void tap_close_adapter(LPADAPTER fd); |
173 |
+ |
static bool tap_check_version(LPADAPTER fd); |
174 |
+ |
static bool tap_set_status(LPADAPTER fd, ULONG status); |
175 |
+ |
static bool tap_get_mac(LPADAPTER fd, LPBYTE addr); |
176 |
+ |
static bool tap_receive_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync); |
177 |
+ |
static bool tap_send_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync, BOOLEAN recycle); |
178 |
|
static WINAPI unsigned int slirp_receive_func(void *arg); |
179 |
|
static WINAPI unsigned int ether_thread_feed_int(void *arg); |
180 |
|
static WINAPI unsigned int ether_thread_get_packets_nt(void *arg); |
234 |
|
net_if_type = NET_IF_ROUTER; |
235 |
|
else if (strcmp(name, "slirp") == 0) |
236 |
|
net_if_type = NET_IF_SLIRP; |
237 |
+ |
else if (strcmp(name, "tap") == 0) |
238 |
+ |
net_if_type = NET_IF_TAP; |
239 |
|
else |
240 |
|
net_if_type = NET_IF_B2ETHER; |
241 |
|
|
260 |
|
case NET_IF_B2ETHER: |
261 |
|
dev_name = PrefsFindString("etherguid"); |
262 |
|
break; |
263 |
+ |
case NET_IF_TAP: |
264 |
+ |
dev_name = PrefsFindString("etherguid"); |
265 |
+ |
break; |
266 |
|
} |
267 |
|
if (net_if_type == NET_IF_B2ETHER) { |
268 |
|
if (dev_name == NULL) { |
298 |
|
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])); |
299 |
|
} |
300 |
|
} |
301 |
+ |
else if (net_if_type == NET_IF_TAP) { |
302 |
+ |
if (dev_name == NULL) { |
303 |
+ |
WarningAlert("No ethernet device GUID specified. Ethernet is not available."); |
304 |
+ |
goto open_error; |
305 |
+ |
} |
306 |
+ |
|
307 |
+ |
fd = tap_open_adapter(dev_name); |
308 |
+ |
if (!fd) { |
309 |
+ |
sprintf(str, "Could not open ethernet adapter %s.", dev_name); |
310 |
+ |
WarningAlert(str); |
311 |
+ |
goto open_error; |
312 |
+ |
} |
313 |
+ |
|
314 |
+ |
if (!tap_check_version(fd)) { |
315 |
+ |
sprintf(str, "Minimal TAP-Win32 version supported is %d.%d.", TAP_VERSION_MIN_MAJOR, TAP_VERSION_MIN_MINOR); |
316 |
+ |
WarningAlert(str); |
317 |
+ |
goto open_error; |
318 |
+ |
} |
319 |
+ |
|
320 |
+ |
if (!tap_set_status(fd, true)) { |
321 |
+ |
sprintf(str, "Could not set media status to connected."); |
322 |
+ |
WarningAlert(str); |
323 |
+ |
goto open_error; |
324 |
+ |
} |
325 |
+ |
|
326 |
+ |
if (!tap_get_mac(fd, ether_addr)) { |
327 |
+ |
sprintf(str, "Could not get hardware address of device %s. Ethernet is not available.", dev_name); |
328 |
+ |
WarningAlert(str); |
329 |
+ |
goto open_error; |
330 |
+ |
} |
331 |
+ |
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])); |
332 |
+ |
|
333 |
+ |
const char *ether_fake_address; |
334 |
+ |
ether_fake_address = PrefsFindString("etherfakeaddress"); |
335 |
+ |
if (ether_fake_address && strlen(ether_fake_address) == 12) { |
336 |
+ |
char sm[10]; |
337 |
+ |
strcpy( sm, "0x00" ); |
338 |
+ |
for( int i=0; i<6; i++ ) { |
339 |
+ |
sm[2] = ether_fake_address[i*2]; |
340 |
+ |
sm[3] = ether_fake_address[i*2+1]; |
341 |
+ |
ether_addr[i] = (uint8)strtoul(sm,0,0); |
342 |
+ |
} |
343 |
+ |
} |
344 |
+ |
#if 1 |
345 |
+ |
/* |
346 |
+ |
If we bridge the underlying ethernet connection and the TAP |
347 |
+ |
device altogether, we have to use a fake address. |
348 |
+ |
*/ |
349 |
+ |
else { |
350 |
+ |
ether_addr[0] = 0x52; |
351 |
+ |
ether_addr[1] = 0x54; |
352 |
+ |
ether_addr[2] = 0x00; |
353 |
+ |
} |
354 |
+ |
#endif |
355 |
+ |
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])); |
356 |
+ |
} |
357 |
|
else if (net_if_type == NET_IF_SLIRP) { |
358 |
|
ether_addr[0] = 0x52; |
359 |
|
ether_addr[1] = 0x54; |
430 |
|
thread_active = true; |
431 |
|
|
432 |
|
unsigned int dummy; |
433 |
< |
ether_th2 = (HANDLE)_beginthreadex( 0, 0, |
434 |
< |
net_if_type == NET_IF_SLIRP ? slirp_receive_func : ether_thread_get_packets_nt, |
435 |
< |
0, 0, &dummy ); |
433 |
> |
unsigned int (WINAPI *receive_func)(void *); |
434 |
> |
switch (net_if_type) { |
435 |
> |
case NET_IF_SLIRP: |
436 |
> |
receive_func = slirp_receive_func; |
437 |
> |
break; |
438 |
> |
default: |
439 |
> |
receive_func = ether_thread_get_packets_nt; |
440 |
> |
break; |
441 |
> |
} |
442 |
> |
ether_th2 = (HANDLE)_beginthreadex( 0, 0, receive_func, 0, 0, &dummy ); |
443 |
|
ether_th1 = (HANDLE)_beginthreadex( 0, 0, ether_thread_write_packets, 0, 0, &dummy ); |
444 |
|
|
445 |
|
// Everything OK |
463 |
|
int_send_now = 0; |
464 |
|
thread_active = false; |
465 |
|
} |
466 |
< |
if(net_if_type == NET_IF_B2ETHER) { |
467 |
< |
PacketCloseAdapter(fd); |
466 |
> |
if (fd) { |
467 |
> |
switch (net_if_type) { |
468 |
> |
case NET_IF_B2ETHER: |
469 |
> |
PacketCloseAdapter(fd); |
470 |
> |
break; |
471 |
> |
case NET_IF_TAP: |
472 |
> |
tap_close_adapter(fd); |
473 |
> |
break; |
474 |
> |
} |
475 |
> |
fd = 0; |
476 |
|
} |
369 |
– |
fd = 0; |
477 |
|
return false; |
478 |
|
} |
479 |
|
|
544 |
|
} |
545 |
|
|
546 |
|
// Close ethernet device |
547 |
< |
if(fd) { |
548 |
< |
PacketCloseAdapter(fd); |
547 |
> |
if (fd) { |
548 |
> |
switch (net_if_type) { |
549 |
> |
case NET_IF_B2ETHER: |
550 |
> |
PacketCloseAdapter(fd); |
551 |
> |
break; |
552 |
> |
case NET_IF_TAP: |
553 |
> |
tap_close_adapter(fd); |
554 |
> |
break; |
555 |
> |
} |
556 |
|
fd = 0; |
557 |
|
} |
558 |
|
|
1018 |
|
// already recycled if async |
1019 |
|
} |
1020 |
|
break; |
1021 |
+ |
case NET_IF_TAP: |
1022 |
+ |
if (!tap_send_packet(fd, Packet, FALSE, TRUE)) { |
1023 |
+ |
// already recycled if async |
1024 |
+ |
} |
1025 |
+ |
break; |
1026 |
|
case NET_IF_SLIRP: |
1027 |
|
slirp_input((uint8 *)Packet->Buffer, Packet->Length); |
1028 |
|
Packet->bIoComplete = TRUE; |
1179 |
|
|
1180 |
|
|
1181 |
|
/* |
1182 |
+ |
* TAP-Win32 glue |
1183 |
+ |
*/ |
1184 |
+ |
|
1185 |
+ |
static LPADAPTER tap_open_adapter(const char *dev_name) |
1186 |
+ |
{ |
1187 |
+ |
fd = (LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*fd)); |
1188 |
+ |
if (fd == NULL) |
1189 |
+ |
return NULL; |
1190 |
+ |
|
1191 |
+ |
char dev_path[MAX_PATH]; |
1192 |
+ |
snprintf(dev_path, sizeof(dev_path), |
1193 |
+ |
"\\\\.\\Global\\%s.tap", dev_name); |
1194 |
+ |
|
1195 |
+ |
HANDLE handle = CreateFile( |
1196 |
+ |
dev_path, |
1197 |
+ |
GENERIC_READ | GENERIC_WRITE, |
1198 |
+ |
0, |
1199 |
+ |
NULL, |
1200 |
+ |
OPEN_EXISTING, |
1201 |
+ |
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, |
1202 |
+ |
NULL); |
1203 |
+ |
if (handle == NULL || handle == INVALID_HANDLE_VALUE) |
1204 |
+ |
return NULL; |
1205 |
+ |
|
1206 |
+ |
fd->hFile = handle; |
1207 |
+ |
return fd; |
1208 |
+ |
} |
1209 |
+ |
|
1210 |
+ |
static void tap_close_adapter(LPADAPTER fd) |
1211 |
+ |
{ |
1212 |
+ |
if (fd) { |
1213 |
+ |
if (fd->hFile) { |
1214 |
+ |
tap_set_status(fd, false); |
1215 |
+ |
CloseHandle(fd->hFile); |
1216 |
+ |
} |
1217 |
+ |
GlobalFreePtr(fd); |
1218 |
+ |
} |
1219 |
+ |
} |
1220 |
+ |
|
1221 |
+ |
static bool tap_check_version(LPADAPTER fd) |
1222 |
+ |
{ |
1223 |
+ |
ULONG len; |
1224 |
+ |
ULONG info[3] = { 0, }; |
1225 |
+ |
|
1226 |
+ |
if (!DeviceIoControl(fd->hFile, TAP_IOCTL_GET_VERSION, |
1227 |
+ |
&info, sizeof(info), |
1228 |
+ |
&info, sizeof(info), &len, NULL) |
1229 |
+ |
&& !DeviceIoControl(fd->hFile, OLD_TAP_IOCTL_GET_VERSION, |
1230 |
+ |
&info, sizeof(info), |
1231 |
+ |
&info, sizeof(info), &len, NULL)) |
1232 |
+ |
return false; |
1233 |
+ |
|
1234 |
+ |
if (info[0] > TAP_VERSION_MIN_MAJOR) |
1235 |
+ |
return true; |
1236 |
+ |
if (info[0] == TAP_VERSION_MIN_MAJOR && info[1] >= TAP_VERSION_MIN_MINOR) |
1237 |
+ |
return true; |
1238 |
+ |
|
1239 |
+ |
return false; |
1240 |
+ |
} |
1241 |
+ |
|
1242 |
+ |
static bool tap_set_status(LPADAPTER fd, ULONG status) |
1243 |
+ |
{ |
1244 |
+ |
DWORD len = 0; |
1245 |
+ |
return DeviceIoControl(fd->hFile, TAP_IOCTL_SET_MEDIA_STATUS, |
1246 |
+ |
&status, sizeof (status), |
1247 |
+ |
&status, sizeof (status), &len, NULL); |
1248 |
+ |
} |
1249 |
+ |
|
1250 |
+ |
static bool tap_get_mac(LPADAPTER fd, LPBYTE addr) |
1251 |
+ |
{ |
1252 |
+ |
DWORD len = 0; |
1253 |
+ |
return DeviceIoControl(fd->hFile, TAP_IOCTL_GET_MAC, |
1254 |
+ |
addr, 6, |
1255 |
+ |
addr, 6, &len, NULL); |
1256 |
+ |
|
1257 |
+ |
} |
1258 |
+ |
|
1259 |
+ |
static VOID CALLBACK tap_write_completion( |
1260 |
+ |
DWORD dwErrorCode, |
1261 |
+ |
DWORD dwNumberOfBytesTransfered, |
1262 |
+ |
LPOVERLAPPED lpOverLapped |
1263 |
+ |
) |
1264 |
+ |
{ |
1265 |
+ |
LPPACKET lpPacket = CONTAINING_RECORD(lpOverLapped, PACKET, OverLapped); |
1266 |
+ |
|
1267 |
+ |
lpPacket->bIoComplete = TRUE; |
1268 |
+ |
recycle_write_packet(lpPacket); |
1269 |
+ |
} |
1270 |
+ |
|
1271 |
+ |
static bool tap_send_packet( |
1272 |
+ |
LPADAPTER fd, |
1273 |
+ |
LPPACKET lpPacket, |
1274 |
+ |
BOOLEAN Sync, |
1275 |
+ |
BOOLEAN RecyclingAllowed) |
1276 |
+ |
{ |
1277 |
+ |
BOOLEAN Result; |
1278 |
+ |
|
1279 |
+ |
lpPacket->OverLapped.Offset = 0; |
1280 |
+ |
lpPacket->OverLapped.OffsetHigh = 0; |
1281 |
+ |
lpPacket->bIoComplete = FALSE; |
1282 |
+ |
|
1283 |
+ |
if (Sync) { |
1284 |
+ |
Result = WriteFile(fd->hFile, |
1285 |
+ |
lpPacket->Buffer, |
1286 |
+ |
lpPacket->Length, |
1287 |
+ |
&lpPacket->BytesReceived, |
1288 |
+ |
&lpPacket->OverLapped); |
1289 |
+ |
if (Result) { |
1290 |
+ |
GetOverlappedResult(fd->hFile, |
1291 |
+ |
&lpPacket->OverLapped, |
1292 |
+ |
&lpPacket->BytesReceived, |
1293 |
+ |
TRUE); |
1294 |
+ |
} |
1295 |
+ |
lpPacket->bIoComplete = TRUE; |
1296 |
+ |
if (RecyclingAllowed) |
1297 |
+ |
PacketFreePacket(lpPacket); |
1298 |
+ |
} |
1299 |
+ |
else { |
1300 |
+ |
Result = WriteFileEx(fd->hFile, |
1301 |
+ |
lpPacket->Buffer, |
1302 |
+ |
lpPacket->Length, |
1303 |
+ |
&lpPacket->OverLapped, |
1304 |
+ |
tap_write_completion); |
1305 |
+ |
|
1306 |
+ |
if (!Result && RecyclingAllowed) |
1307 |
+ |
recycle_write_packet(lpPacket); |
1308 |
+ |
} |
1309 |
+ |
|
1310 |
+ |
return Result; |
1311 |
+ |
} |
1312 |
+ |
|
1313 |
+ |
static bool tap_receive_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync) |
1314 |
+ |
{ |
1315 |
+ |
BOOLEAN Result; |
1316 |
+ |
|
1317 |
+ |
lpPacket->OverLapped.Offset = 0; |
1318 |
+ |
lpPacket->OverLapped.OffsetHigh = 0; |
1319 |
+ |
lpPacket->bIoComplete = FALSE; |
1320 |
+ |
|
1321 |
+ |
if (Sync) { |
1322 |
+ |
Result = ReadFile(fd->hFile, |
1323 |
+ |
lpPacket->Buffer, |
1324 |
+ |
lpPacket->Length, |
1325 |
+ |
&lpPacket->BytesReceived, |
1326 |
+ |
&lpPacket->OverLapped); |
1327 |
+ |
if (Result) { |
1328 |
+ |
Result = GetOverlappedResult(fd->hFile, |
1329 |
+ |
&lpPacket->OverLapped, |
1330 |
+ |
&lpPacket->BytesReceived, |
1331 |
+ |
TRUE); |
1332 |
+ |
if (Result) |
1333 |
+ |
lpPacket->bIoComplete = TRUE; |
1334 |
+ |
else |
1335 |
+ |
lpPacket->free = TRUE; |
1336 |
+ |
} |
1337 |
+ |
} |
1338 |
+ |
else { |
1339 |
+ |
Result = ReadFileEx(fd->hFile, |
1340 |
+ |
lpPacket->Buffer, |
1341 |
+ |
lpPacket->Length, |
1342 |
+ |
&lpPacket->OverLapped, |
1343 |
+ |
packet_read_completion); |
1344 |
+ |
|
1345 |
+ |
if (!Result) |
1346 |
+ |
lpPacket->BytesReceived = 0; |
1347 |
+ |
} |
1348 |
+ |
|
1349 |
+ |
return Result; |
1350 |
+ |
} |
1351 |
+ |
|
1352 |
+ |
|
1353 |
+ |
/* |
1354 |
|
* SLIRP output buffer glue |
1355 |
|
*/ |
1356 |
|
|
1364 |
|
enqueue_packet(packet, len); |
1365 |
|
} |
1366 |
|
|
1367 |
< |
unsigned int slirp_receive_func(void *arg) |
1367 |
> |
static unsigned int slirp_receive_func(void *arg) |
1368 |
|
{ |
1369 |
|
D(bug("slirp_receive_func\n")); |
1370 |
|
thread_active_2 = true; |
1442 |
|
break; |
1443 |
|
} |
1444 |
|
} |
1445 |
+ |
// XXX drop packets that are not for us |
1446 |
+ |
if (net_if_type == NET_IF_TAP) { |
1447 |
+ |
if (memcmp((LPBYTE)lpPacket->Buffer, ether_addr, 6) != 0) |
1448 |
+ |
dwNumberOfBytesTransfered = 0; |
1449 |
+ |
} |
1450 |
|
if(dwNumberOfBytesTransfered) { |
1451 |
|
if(net_if_type != NET_IF_ROUTER || !router_read_packet((uint8 *)lpPacket->Buffer, dwNumberOfBytesTransfered)) { |
1452 |
|
enqueue_packet( (LPBYTE)lpPacket->Buffer, dwNumberOfBytesTransfered ); |
1519 |
|
// Obey the golden rules; keep the reads pending. |
1520 |
|
while(thread_active) { |
1521 |
|
|
1522 |
< |
if(net_if_type == NET_IF_B2ETHER) { |
1522 |
> |
if(net_if_type == NET_IF_B2ETHER || net_if_type == NET_IF_TAP) { |
1523 |
|
D(bug("Pending reads\n")); |
1524 |
|
for( i=0; thread_active && i<PACKET_POOL_COUNT; i++ ) { |
1525 |
|
if(packets[i]->free) { |
1526 |
|
packets[i]->free = FALSE; |
1527 |
< |
if(PacketReceivePacket(fd,packets[i],FALSE)) { |
1527 |
> |
BOOLEAN Result; |
1528 |
> |
switch (net_if_type) { |
1529 |
> |
case NET_IF_B2ETHER: |
1530 |
> |
Result = PacketReceivePacket(fd, packets[i], FALSE); |
1531 |
> |
break; |
1532 |
> |
case NET_IF_TAP: |
1533 |
> |
Result = tap_receive_packet(fd, packets[i], FALSE); |
1534 |
> |
break; |
1535 |
> |
} |
1536 |
> |
if (Result) { |
1537 |
|
if(packets[i]->bIoComplete) { |
1538 |
|
D(bug("Early io completion...\n")); |
1539 |
|
packet_read_completion( |