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); |
230 |
|
|
231 |
|
// Determine Ethernet device type |
232 |
|
net_if_type = -1; |
233 |
< |
if (strcmp(name, "router") == 0) |
233 |
> |
if (PrefsFindBool("routerenabled") || strcmp(name, "router") == 0) |
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 |
|
|
259 |
|
switch (net_if_type) { |
260 |
|
case NET_IF_B2ETHER: |
261 |
|
dev_name = PrefsFindString("etherguid"); |
262 |
+ |
if (dev_name == NULL || strcmp(name, "b2ether") != 0) |
263 |
+ |
dev_name = name; |
264 |
+ |
break; |
265 |
+ |
case NET_IF_TAP: |
266 |
+ |
dev_name = PrefsFindString("etherguid"); |
267 |
|
break; |
268 |
|
} |
269 |
|
if (net_if_type == NET_IF_B2ETHER) { |
300 |
|
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])); |
301 |
|
} |
302 |
|
} |
303 |
+ |
else if (net_if_type == NET_IF_TAP) { |
304 |
+ |
if (dev_name == NULL) { |
305 |
+ |
WarningAlert("No ethernet device GUID specified. Ethernet is not available."); |
306 |
+ |
goto open_error; |
307 |
+ |
} |
308 |
+ |
|
309 |
+ |
fd = tap_open_adapter(dev_name); |
310 |
+ |
if (!fd) { |
311 |
+ |
sprintf(str, "Could not open ethernet adapter %s.", dev_name); |
312 |
+ |
WarningAlert(str); |
313 |
+ |
goto open_error; |
314 |
+ |
} |
315 |
+ |
|
316 |
+ |
if (!tap_check_version(fd)) { |
317 |
+ |
sprintf(str, "Minimal TAP-Win32 version supported is %d.%d.", TAP_VERSION_MIN_MAJOR, TAP_VERSION_MIN_MINOR); |
318 |
+ |
WarningAlert(str); |
319 |
+ |
goto open_error; |
320 |
+ |
} |
321 |
+ |
|
322 |
+ |
if (!tap_set_status(fd, true)) { |
323 |
+ |
sprintf(str, "Could not set media status to connected."); |
324 |
+ |
WarningAlert(str); |
325 |
+ |
goto open_error; |
326 |
+ |
} |
327 |
+ |
|
328 |
+ |
if (!tap_get_mac(fd, ether_addr)) { |
329 |
+ |
sprintf(str, "Could not get hardware address of device %s. Ethernet is not available.", dev_name); |
330 |
+ |
WarningAlert(str); |
331 |
+ |
goto open_error; |
332 |
+ |
} |
333 |
+ |
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])); |
334 |
+ |
|
335 |
+ |
const char *ether_fake_address; |
336 |
+ |
ether_fake_address = PrefsFindString("etherfakeaddress"); |
337 |
+ |
if (ether_fake_address && strlen(ether_fake_address) == 12) { |
338 |
+ |
char sm[10]; |
339 |
+ |
strcpy( sm, "0x00" ); |
340 |
+ |
for( int i=0; i<6; i++ ) { |
341 |
+ |
sm[2] = ether_fake_address[i*2]; |
342 |
+ |
sm[3] = ether_fake_address[i*2+1]; |
343 |
+ |
ether_addr[i] = (uint8)strtoul(sm,0,0); |
344 |
+ |
} |
345 |
+ |
} |
346 |
+ |
#if 1 |
347 |
+ |
/* |
348 |
+ |
If we bridge the underlying ethernet connection and the TAP |
349 |
+ |
device altogether, we have to use a fake address. |
350 |
+ |
*/ |
351 |
+ |
else { |
352 |
+ |
ether_addr[0] = 0x52; |
353 |
+ |
ether_addr[1] = 0x54; |
354 |
+ |
ether_addr[2] = 0x00; |
355 |
+ |
} |
356 |
+ |
#endif |
357 |
+ |
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])); |
358 |
+ |
} |
359 |
|
else if (net_if_type == NET_IF_SLIRP) { |
360 |
|
ether_addr[0] = 0x52; |
361 |
|
ether_addr[1] = 0x54; |
432 |
|
thread_active = true; |
433 |
|
|
434 |
|
unsigned int dummy; |
435 |
< |
ether_th2 = (HANDLE)_beginthreadex( 0, 0, |
436 |
< |
net_if_type == NET_IF_SLIRP ? slirp_receive_func : ether_thread_get_packets_nt, |
437 |
< |
0, 0, &dummy ); |
435 |
> |
unsigned int (WINAPI *receive_func)(void *); |
436 |
> |
switch (net_if_type) { |
437 |
> |
case NET_IF_SLIRP: |
438 |
> |
receive_func = slirp_receive_func; |
439 |
> |
break; |
440 |
> |
default: |
441 |
> |
receive_func = ether_thread_get_packets_nt; |
442 |
> |
break; |
443 |
> |
} |
444 |
> |
ether_th2 = (HANDLE)_beginthreadex( 0, 0, receive_func, 0, 0, &dummy ); |
445 |
|
ether_th1 = (HANDLE)_beginthreadex( 0, 0, ether_thread_write_packets, 0, 0, &dummy ); |
446 |
|
|
447 |
|
// Everything OK |
465 |
|
int_send_now = 0; |
466 |
|
thread_active = false; |
467 |
|
} |
468 |
< |
if(net_if_type == NET_IF_B2ETHER) { |
469 |
< |
PacketCloseAdapter(fd); |
468 |
> |
if (fd) { |
469 |
> |
switch (net_if_type) { |
470 |
> |
case NET_IF_B2ETHER: |
471 |
> |
PacketCloseAdapter(fd); |
472 |
> |
break; |
473 |
> |
case NET_IF_TAP: |
474 |
> |
tap_close_adapter(fd); |
475 |
> |
break; |
476 |
> |
} |
477 |
> |
fd = 0; |
478 |
|
} |
369 |
– |
fd = 0; |
479 |
|
return false; |
480 |
|
} |
481 |
|
|
546 |
|
} |
547 |
|
|
548 |
|
// Close ethernet device |
549 |
< |
if(fd) { |
550 |
< |
PacketCloseAdapter(fd); |
549 |
> |
if (fd) { |
550 |
> |
switch (net_if_type) { |
551 |
> |
case NET_IF_B2ETHER: |
552 |
> |
PacketCloseAdapter(fd); |
553 |
> |
break; |
554 |
> |
case NET_IF_TAP: |
555 |
> |
tap_close_adapter(fd); |
556 |
> |
break; |
557 |
> |
} |
558 |
|
fd = 0; |
559 |
|
} |
560 |
|
|
1020 |
|
// already recycled if async |
1021 |
|
} |
1022 |
|
break; |
1023 |
+ |
case NET_IF_TAP: |
1024 |
+ |
if (!tap_send_packet(fd, Packet, FALSE, TRUE)) { |
1025 |
+ |
// already recycled if async |
1026 |
+ |
} |
1027 |
+ |
break; |
1028 |
|
case NET_IF_SLIRP: |
1029 |
|
slirp_input((uint8 *)Packet->Buffer, Packet->Length); |
1030 |
|
Packet->bIoComplete = TRUE; |
1181 |
|
|
1182 |
|
|
1183 |
|
/* |
1184 |
+ |
* TAP-Win32 glue |
1185 |
+ |
*/ |
1186 |
+ |
|
1187 |
+ |
static LPADAPTER tap_open_adapter(const char *dev_name) |
1188 |
+ |
{ |
1189 |
+ |
fd = (LPADAPTER)GlobalAllocPtr(GMEM_MOVEABLE | GMEM_ZEROINIT, sizeof(*fd)); |
1190 |
+ |
if (fd == NULL) |
1191 |
+ |
return NULL; |
1192 |
+ |
|
1193 |
+ |
char dev_path[MAX_PATH]; |
1194 |
+ |
snprintf(dev_path, sizeof(dev_path), |
1195 |
+ |
"\\\\.\\Global\\%s.tap", dev_name); |
1196 |
+ |
|
1197 |
+ |
HANDLE handle = CreateFile( |
1198 |
+ |
dev_path, |
1199 |
+ |
GENERIC_READ | GENERIC_WRITE, |
1200 |
+ |
0, |
1201 |
+ |
NULL, |
1202 |
+ |
OPEN_EXISTING, |
1203 |
+ |
FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, |
1204 |
+ |
NULL); |
1205 |
+ |
if (handle == NULL || handle == INVALID_HANDLE_VALUE) |
1206 |
+ |
return NULL; |
1207 |
+ |
|
1208 |
+ |
fd->hFile = handle; |
1209 |
+ |
return fd; |
1210 |
+ |
} |
1211 |
+ |
|
1212 |
+ |
static void tap_close_adapter(LPADAPTER fd) |
1213 |
+ |
{ |
1214 |
+ |
if (fd) { |
1215 |
+ |
if (fd->hFile) { |
1216 |
+ |
tap_set_status(fd, false); |
1217 |
+ |
CloseHandle(fd->hFile); |
1218 |
+ |
} |
1219 |
+ |
GlobalFreePtr(fd); |
1220 |
+ |
} |
1221 |
+ |
} |
1222 |
+ |
|
1223 |
+ |
static bool tap_check_version(LPADAPTER fd) |
1224 |
+ |
{ |
1225 |
+ |
ULONG len; |
1226 |
+ |
ULONG info[3] = { 0, }; |
1227 |
+ |
|
1228 |
+ |
if (!DeviceIoControl(fd->hFile, TAP_IOCTL_GET_VERSION, |
1229 |
+ |
&info, sizeof(info), |
1230 |
+ |
&info, sizeof(info), &len, NULL) |
1231 |
+ |
&& !DeviceIoControl(fd->hFile, OLD_TAP_IOCTL_GET_VERSION, |
1232 |
+ |
&info, sizeof(info), |
1233 |
+ |
&info, sizeof(info), &len, NULL)) |
1234 |
+ |
return false; |
1235 |
+ |
|
1236 |
+ |
if (info[0] > TAP_VERSION_MIN_MAJOR) |
1237 |
+ |
return true; |
1238 |
+ |
if (info[0] == TAP_VERSION_MIN_MAJOR && info[1] >= TAP_VERSION_MIN_MINOR) |
1239 |
+ |
return true; |
1240 |
+ |
|
1241 |
+ |
return false; |
1242 |
+ |
} |
1243 |
+ |
|
1244 |
+ |
static bool tap_set_status(LPADAPTER fd, ULONG status) |
1245 |
+ |
{ |
1246 |
+ |
DWORD len = 0; |
1247 |
+ |
return DeviceIoControl(fd->hFile, TAP_IOCTL_SET_MEDIA_STATUS, |
1248 |
+ |
&status, sizeof (status), |
1249 |
+ |
&status, sizeof (status), &len, NULL); |
1250 |
+ |
} |
1251 |
+ |
|
1252 |
+ |
static bool tap_get_mac(LPADAPTER fd, LPBYTE addr) |
1253 |
+ |
{ |
1254 |
+ |
DWORD len = 0; |
1255 |
+ |
return DeviceIoControl(fd->hFile, TAP_IOCTL_GET_MAC, |
1256 |
+ |
addr, 6, |
1257 |
+ |
addr, 6, &len, NULL); |
1258 |
+ |
|
1259 |
+ |
} |
1260 |
+ |
|
1261 |
+ |
static VOID CALLBACK tap_write_completion( |
1262 |
+ |
DWORD dwErrorCode, |
1263 |
+ |
DWORD dwNumberOfBytesTransfered, |
1264 |
+ |
LPOVERLAPPED lpOverLapped |
1265 |
+ |
) |
1266 |
+ |
{ |
1267 |
+ |
LPPACKET lpPacket = CONTAINING_RECORD(lpOverLapped, PACKET, OverLapped); |
1268 |
+ |
|
1269 |
+ |
lpPacket->bIoComplete = TRUE; |
1270 |
+ |
recycle_write_packet(lpPacket); |
1271 |
+ |
} |
1272 |
+ |
|
1273 |
+ |
static bool tap_send_packet( |
1274 |
+ |
LPADAPTER fd, |
1275 |
+ |
LPPACKET lpPacket, |
1276 |
+ |
BOOLEAN Sync, |
1277 |
+ |
BOOLEAN RecyclingAllowed) |
1278 |
+ |
{ |
1279 |
+ |
BOOLEAN Result; |
1280 |
+ |
|
1281 |
+ |
lpPacket->OverLapped.Offset = 0; |
1282 |
+ |
lpPacket->OverLapped.OffsetHigh = 0; |
1283 |
+ |
lpPacket->bIoComplete = FALSE; |
1284 |
+ |
|
1285 |
+ |
if (Sync) { |
1286 |
+ |
Result = WriteFile(fd->hFile, |
1287 |
+ |
lpPacket->Buffer, |
1288 |
+ |
lpPacket->Length, |
1289 |
+ |
&lpPacket->BytesReceived, |
1290 |
+ |
&lpPacket->OverLapped); |
1291 |
+ |
if (Result) { |
1292 |
+ |
GetOverlappedResult(fd->hFile, |
1293 |
+ |
&lpPacket->OverLapped, |
1294 |
+ |
&lpPacket->BytesReceived, |
1295 |
+ |
TRUE); |
1296 |
+ |
} |
1297 |
+ |
lpPacket->bIoComplete = TRUE; |
1298 |
+ |
if (RecyclingAllowed) |
1299 |
+ |
PacketFreePacket(lpPacket); |
1300 |
+ |
} |
1301 |
+ |
else { |
1302 |
+ |
Result = WriteFileEx(fd->hFile, |
1303 |
+ |
lpPacket->Buffer, |
1304 |
+ |
lpPacket->Length, |
1305 |
+ |
&lpPacket->OverLapped, |
1306 |
+ |
tap_write_completion); |
1307 |
+ |
|
1308 |
+ |
if (!Result && RecyclingAllowed) |
1309 |
+ |
recycle_write_packet(lpPacket); |
1310 |
+ |
} |
1311 |
+ |
|
1312 |
+ |
return Result; |
1313 |
+ |
} |
1314 |
+ |
|
1315 |
+ |
static bool tap_receive_packet(LPADAPTER fd, LPPACKET lpPacket, BOOLEAN Sync) |
1316 |
+ |
{ |
1317 |
+ |
BOOLEAN Result; |
1318 |
+ |
|
1319 |
+ |
lpPacket->OverLapped.Offset = 0; |
1320 |
+ |
lpPacket->OverLapped.OffsetHigh = 0; |
1321 |
+ |
lpPacket->bIoComplete = FALSE; |
1322 |
+ |
|
1323 |
+ |
if (Sync) { |
1324 |
+ |
Result = ReadFile(fd->hFile, |
1325 |
+ |
lpPacket->Buffer, |
1326 |
+ |
lpPacket->Length, |
1327 |
+ |
&lpPacket->BytesReceived, |
1328 |
+ |
&lpPacket->OverLapped); |
1329 |
+ |
if (Result) { |
1330 |
+ |
Result = GetOverlappedResult(fd->hFile, |
1331 |
+ |
&lpPacket->OverLapped, |
1332 |
+ |
&lpPacket->BytesReceived, |
1333 |
+ |
TRUE); |
1334 |
+ |
if (Result) |
1335 |
+ |
lpPacket->bIoComplete = TRUE; |
1336 |
+ |
else |
1337 |
+ |
lpPacket->free = TRUE; |
1338 |
+ |
} |
1339 |
+ |
} |
1340 |
+ |
else { |
1341 |
+ |
Result = ReadFileEx(fd->hFile, |
1342 |
+ |
lpPacket->Buffer, |
1343 |
+ |
lpPacket->Length, |
1344 |
+ |
&lpPacket->OverLapped, |
1345 |
+ |
packet_read_completion); |
1346 |
+ |
|
1347 |
+ |
if (!Result) |
1348 |
+ |
lpPacket->BytesReceived = 0; |
1349 |
+ |
} |
1350 |
+ |
|
1351 |
+ |
return Result; |
1352 |
+ |
} |
1353 |
+ |
|
1354 |
+ |
|
1355 |
+ |
/* |
1356 |
|
* SLIRP output buffer glue |
1357 |
|
*/ |
1358 |
|
|
1366 |
|
enqueue_packet(packet, len); |
1367 |
|
} |
1368 |
|
|
1369 |
< |
unsigned int slirp_receive_func(void *arg) |
1369 |
> |
static unsigned int slirp_receive_func(void *arg) |
1370 |
|
{ |
1371 |
|
D(bug("slirp_receive_func\n")); |
1372 |
|
thread_active_2 = true; |
1444 |
|
break; |
1445 |
|
} |
1446 |
|
} |
1447 |
+ |
// XXX drop packets that are not for us |
1448 |
+ |
if (net_if_type == NET_IF_TAP) { |
1449 |
+ |
if (memcmp((LPBYTE)lpPacket->Buffer, ether_addr, 6) != 0) |
1450 |
+ |
dwNumberOfBytesTransfered = 0; |
1451 |
+ |
} |
1452 |
|
if(dwNumberOfBytesTransfered) { |
1453 |
|
if(net_if_type != NET_IF_ROUTER || !router_read_packet((uint8 *)lpPacket->Buffer, dwNumberOfBytesTransfered)) { |
1454 |
|
enqueue_packet( (LPBYTE)lpPacket->Buffer, dwNumberOfBytesTransfered ); |
1521 |
|
// Obey the golden rules; keep the reads pending. |
1522 |
|
while(thread_active) { |
1523 |
|
|
1524 |
< |
if(net_if_type == NET_IF_B2ETHER) { |
1524 |
> |
if(net_if_type == NET_IF_B2ETHER || net_if_type == NET_IF_TAP) { |
1525 |
|
D(bug("Pending reads\n")); |
1526 |
|
for( i=0; thread_active && i<PACKET_POOL_COUNT; i++ ) { |
1527 |
|
if(packets[i]->free) { |
1528 |
|
packets[i]->free = FALSE; |
1529 |
< |
if(PacketReceivePacket(fd,packets[i],FALSE)) { |
1529 |
> |
BOOLEAN Result; |
1530 |
> |
switch (net_if_type) { |
1531 |
> |
case NET_IF_B2ETHER: |
1532 |
> |
Result = PacketReceivePacket(fd, packets[i], FALSE); |
1533 |
> |
break; |
1534 |
> |
case NET_IF_TAP: |
1535 |
> |
Result = tap_receive_packet(fd, packets[i], FALSE); |
1536 |
> |
break; |
1537 |
> |
} |
1538 |
> |
if (Result) { |
1539 |
|
if(packets[i]->bIoComplete) { |
1540 |
|
D(bug("Early io completion...\n")); |
1541 |
|
packet_read_completion( |