ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/Windows/ether_windows.cpp
(Generate patch)

Comparing BasiliskII/src/Windows/ether_windows.cpp (file contents):
Revision 1.6 by gbeauche, 2006-04-29T10:57:56Z vs.
Revision 1.9 by gbeauche, 2008-01-01T09:40:33Z

# Line 1 | Line 1
1   /*
2   *  ether_windows.cpp - Ethernet device driver
3   *
4 < *  Basilisk II (C) 1997-2005 Christian Bauer
4 > *  Basilisk II (C) 1997-2008 Christian Bauer
5   *
6   *  Windows platform specific code copyright (C) Lauri Pesonen
7   *
# Line 20 | Line 20
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"
# Line 58 | Line 60 | enum {
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;
# Line 70 | Line 95 | HANDLE ether_th;
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
# Line 143 | Line 168 | static HANDLE int_sig2 = 0;
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);
# Line 198 | Line 230 | bool ether_init(void)
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  
# Line 225 | Line 259 | bool ether_init(void)
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) {
# Line 261 | Line 300 | bool ether_init(void)
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;
# Line 337 | Line 432 | bool ether_init(void)
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
# Line 363 | Line 465 | bool ether_init(void)
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  
# Line 437 | Line 546 | void ether_exit(void)
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  
# Line 904 | Line 1020 | static unsigned int ether_thread_write_p
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;
# Line 1060 | Line 1181 | static bool set_wait_request(void)
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  
# Line 1073 | Line 1366 | void slirp_output(const uint8 *packet, i
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;
# Line 1151 | Line 1444 | VOID CALLBACK packet_read_completion(
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 );
# Line 1223 | Line 1521 | static unsigned int ether_thread_get_pac
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(

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines