1 /* 2 * TAP-Win32 -- A kernel driver to provide virtual tap device functionality 3 * on Windows. Originally derived from the CIPE-Win32 4 * project by Damion K. Wilson, with extensive modifications by 5 * James Yonan. 6 * 7 * All source code which derives from the CIPE-Win32 project is 8 * Copyright (C) Damion K. Wilson, 2003, and is released under the 9 * GPL version 2 (see below). 10 * 11 * All other source code is Copyright (C) James Yonan, 2003-2004, 12 * and is released under the GPL version 2 (see below). 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program (see the file COPYING included with this 26 * distribution); if not, write to the Free Software Foundation, Inc., 27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 28 */ 29 #include "qemu-common.h" 30 #include "net/net.h" 31 #include "sysemu/sysemu.h" 32 #include <stdio.h> 33 #include <windows.h> 34 #include <winioctl.h> 35 36 //============= 37 // TAP IOCTLs 38 //============= 39 40 #define TAP_CONTROL_CODE(request,method) \ 41 CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS) 42 43 #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED) 44 #define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED) 45 #define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED) 46 #define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED) 47 #define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED) 48 #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED) 49 #define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED) 50 #define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED) 51 #define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED) 52 53 //================= 54 // Registry keys 55 //================= 56 57 #define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}" 58 59 #define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" 60 61 //====================== 62 // Filesystem prefixes 63 //====================== 64 65 #define USERMODEDEVICEDIR "\\\\.\\Global\\" 66 #define TAPSUFFIX ".tap" 67 68 69 //====================== 70 // Compile time configuration 71 //====================== 72 73 //#define DEBUG_TAP_WIN32 74 75 #define TUN_ASYNCHRONOUS_WRITES 1 76 77 #define TUN_BUFFER_SIZE 1560 78 #define TUN_MAX_BUFFER_COUNT 32 79 80 /* 81 * The data member "buffer" must be the first element in the tun_buffer 82 * structure. See the function, tap_win32_free_buffer. 83 */ 84 typedef struct tun_buffer_s { 85 unsigned char buffer [TUN_BUFFER_SIZE]; 86 unsigned long read_size; 87 struct tun_buffer_s* next; 88 } tun_buffer_t; 89 90 typedef struct tap_win32_overlapped { 91 HANDLE handle; 92 HANDLE read_event; 93 HANDLE write_event; 94 HANDLE output_queue_semaphore; 95 HANDLE free_list_semaphore; 96 HANDLE tap_semaphore; 97 CRITICAL_SECTION output_queue_cs; 98 CRITICAL_SECTION free_list_cs; 99 OVERLAPPED read_overlapped; 100 OVERLAPPED write_overlapped; 101 tun_buffer_t buffers[TUN_MAX_BUFFER_COUNT]; 102 tun_buffer_t* free_list; 103 tun_buffer_t* output_queue_front; 104 tun_buffer_t* output_queue_back; 105 } tap_win32_overlapped_t; 106 107 static tap_win32_overlapped_t tap_overlapped; 108 109 static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped) 110 { 111 tun_buffer_t* buffer = NULL; 112 WaitForSingleObject(overlapped->free_list_semaphore, INFINITE); 113 EnterCriticalSection(&overlapped->free_list_cs); 114 buffer = overlapped->free_list; 115 // assert(buffer != NULL); 116 overlapped->free_list = buffer->next; 117 LeaveCriticalSection(&overlapped->free_list_cs); 118 buffer->next = NULL; 119 return buffer; 120 } 121 122 static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer) 123 { 124 EnterCriticalSection(&overlapped->free_list_cs); 125 buffer->next = overlapped->free_list; 126 overlapped->free_list = buffer; 127 LeaveCriticalSection(&overlapped->free_list_cs); 128 ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL); 129 } 130 131 static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block) 132 { 133 tun_buffer_t* buffer = NULL; 134 DWORD result, timeout = block ? INFINITE : 0L; 135 136 // Non-blocking call 137 result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout); 138 139 switch (result) 140 { 141 // The semaphore object was signaled. 142 case WAIT_OBJECT_0: 143 EnterCriticalSection(&overlapped->output_queue_cs); 144 145 buffer = overlapped->output_queue_front; 146 overlapped->output_queue_front = buffer->next; 147 148 if(overlapped->output_queue_front == NULL) { 149 overlapped->output_queue_back = NULL; 150 } 151 152 LeaveCriticalSection(&overlapped->output_queue_cs); 153 break; 154 155 // Semaphore was nonsignaled, so a time-out occurred. 156 case WAIT_TIMEOUT: 157 // Cannot open another window. 158 break; 159 } 160 161 return buffer; 162 } 163 164 static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped) 165 { 166 return get_buffer_from_output_queue(overlapped, 0); 167 } 168 169 static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer) 170 { 171 EnterCriticalSection(&overlapped->output_queue_cs); 172 173 if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) { 174 overlapped->output_queue_front = overlapped->output_queue_back = buffer; 175 } else { 176 buffer->next = NULL; 177 overlapped->output_queue_back->next = buffer; 178 overlapped->output_queue_back = buffer; 179 } 180 181 LeaveCriticalSection(&overlapped->output_queue_cs); 182 183 ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL); 184 } 185 186 187 static int is_tap_win32_dev(const char *guid) 188 { 189 HKEY netcard_key; 190 LONG status; 191 DWORD len; 192 int i = 0; 193 194 status = RegOpenKeyEx( 195 HKEY_LOCAL_MACHINE, 196 ADAPTER_KEY, 197 0, 198 KEY_READ, 199 &netcard_key); 200 201 if (status != ERROR_SUCCESS) { 202 return FALSE; 203 } 204 205 for (;;) { 206 char enum_name[256]; 207 char unit_string[256]; 208 HKEY unit_key; 209 char component_id_string[] = "ComponentId"; 210 char component_id[256]; 211 char net_cfg_instance_id_string[] = "NetCfgInstanceId"; 212 char net_cfg_instance_id[256]; 213 DWORD data_type; 214 215 len = sizeof (enum_name); 216 status = RegEnumKeyEx( 217 netcard_key, 218 i, 219 enum_name, 220 &len, 221 NULL, 222 NULL, 223 NULL, 224 NULL); 225 226 if (status == ERROR_NO_MORE_ITEMS) 227 break; 228 else if (status != ERROR_SUCCESS) { 229 return FALSE; 230 } 231 232 snprintf (unit_string, sizeof(unit_string), "%s\\%s", 233 ADAPTER_KEY, enum_name); 234 235 status = RegOpenKeyEx( 236 HKEY_LOCAL_MACHINE, 237 unit_string, 238 0, 239 KEY_READ, 240 &unit_key); 241 242 if (status != ERROR_SUCCESS) { 243 return FALSE; 244 } else { 245 len = sizeof (component_id); 246 status = RegQueryValueEx( 247 unit_key, 248 component_id_string, 249 NULL, 250 &data_type, 251 (LPBYTE)component_id, 252 &len); 253 254 if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) { 255 len = sizeof (net_cfg_instance_id); 256 status = RegQueryValueEx( 257 unit_key, 258 net_cfg_instance_id_string, 259 NULL, 260 &data_type, 261 (LPBYTE)net_cfg_instance_id, 262 &len); 263 264 if (status == ERROR_SUCCESS && data_type == REG_SZ) { 265 if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/ 266 !strcmp (net_cfg_instance_id, guid)) { 267 RegCloseKey (unit_key); 268 RegCloseKey (netcard_key); 269 return TRUE; 270 } 271 } 272 } 273 RegCloseKey (unit_key); 274 } 275 ++i; 276 } 277 278 RegCloseKey (netcard_key); 279 return FALSE; 280 } 281 282 static int get_device_guid( 283 char *name, 284 int name_size, 285 char *actual_name, 286 int actual_name_size) 287 { 288 LONG status; 289 HKEY control_net_key; 290 DWORD len; 291 int i = 0; 292 int stop = 0; 293 294 status = RegOpenKeyEx( 295 HKEY_LOCAL_MACHINE, 296 NETWORK_CONNECTIONS_KEY, 297 0, 298 KEY_READ, 299 &control_net_key); 300 301 if (status != ERROR_SUCCESS) { 302 return -1; 303 } 304 305 while (!stop) 306 { 307 char enum_name[256]; 308 char connection_string[256]; 309 HKEY connection_key; 310 char name_data[256]; 311 DWORD name_type; 312 const char name_string[] = "Name"; 313 314 len = sizeof (enum_name); 315 status = RegEnumKeyEx( 316 control_net_key, 317 i, 318 enum_name, 319 &len, 320 NULL, 321 NULL, 322 NULL, 323 NULL); 324 325 if (status == ERROR_NO_MORE_ITEMS) 326 break; 327 else if (status != ERROR_SUCCESS) { 328 return -1; 329 } 330 331 snprintf(connection_string, 332 sizeof(connection_string), 333 "%s\\%s\\Connection", 334 NETWORK_CONNECTIONS_KEY, enum_name); 335 336 status = RegOpenKeyEx( 337 HKEY_LOCAL_MACHINE, 338 connection_string, 339 0, 340 KEY_READ, 341 &connection_key); 342 343 if (status == ERROR_SUCCESS) { 344 len = sizeof (name_data); 345 status = RegQueryValueEx( 346 connection_key, 347 name_string, 348 NULL, 349 &name_type, 350 (LPBYTE)name_data, 351 &len); 352 353 if (status != ERROR_SUCCESS || name_type != REG_SZ) { 354 return -1; 355 } 356 else { 357 if (is_tap_win32_dev(enum_name)) { 358 snprintf(name, name_size, "%s", enum_name); 359 if (actual_name) { 360 if (strcmp(actual_name, "") != 0) { 361 if (strcmp(name_data, actual_name) != 0) { 362 RegCloseKey (connection_key); 363 ++i; 364 continue; 365 } 366 } 367 else { 368 snprintf(actual_name, actual_name_size, "%s", name_data); 369 } 370 } 371 stop = 1; 372 } 373 } 374 375 RegCloseKey (connection_key); 376 } 377 ++i; 378 } 379 380 RegCloseKey (control_net_key); 381 382 if (stop == 0) 383 return -1; 384 385 return 0; 386 } 387 388 static int tap_win32_set_status(HANDLE handle, int status) 389 { 390 unsigned long len = 0; 391 392 return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS, 393 &status, sizeof (status), 394 &status, sizeof (status), &len, NULL); 395 } 396 397 static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle) 398 { 399 overlapped->handle = handle; 400 401 overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL); 402 overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL); 403 404 overlapped->read_overlapped.Offset = 0; 405 overlapped->read_overlapped.OffsetHigh = 0; 406 overlapped->read_overlapped.hEvent = overlapped->read_event; 407 408 overlapped->write_overlapped.Offset = 0; 409 overlapped->write_overlapped.OffsetHigh = 0; 410 overlapped->write_overlapped.hEvent = overlapped->write_event; 411 412 InitializeCriticalSection(&overlapped->output_queue_cs); 413 InitializeCriticalSection(&overlapped->free_list_cs); 414 415 overlapped->output_queue_semaphore = CreateSemaphore( 416 NULL, // default security attributes 417 0, // initial count 418 TUN_MAX_BUFFER_COUNT, // maximum count 419 NULL); // unnamed semaphore 420 421 if(!overlapped->output_queue_semaphore) { 422 fprintf(stderr, "error creating output queue semaphore!\n"); 423 } 424 425 overlapped->free_list_semaphore = CreateSemaphore( 426 NULL, // default security attributes 427 TUN_MAX_BUFFER_COUNT, // initial count 428 TUN_MAX_BUFFER_COUNT, // maximum count 429 NULL); // unnamed semaphore 430 431 if(!overlapped->free_list_semaphore) { 432 fprintf(stderr, "error creating free list semaphore!\n"); 433 } 434 435 overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL; 436 437 { 438 unsigned index; 439 for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) { 440 tun_buffer_t* element = &overlapped->buffers[index]; 441 element->next = overlapped->free_list; 442 overlapped->free_list = element; 443 } 444 } 445 /* To count buffers, initially no-signal. */ 446 overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL); 447 if(!overlapped->tap_semaphore) 448 fprintf(stderr, "error creating tap_semaphore.\n"); 449 } 450 451 static int tap_win32_write(tap_win32_overlapped_t *overlapped, 452 const void *buffer, unsigned long size) 453 { 454 unsigned long write_size; 455 BOOL result; 456 DWORD error; 457 458 result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped, 459 &write_size, FALSE); 460 461 if (!result && GetLastError() == ERROR_IO_INCOMPLETE) 462 WaitForSingleObject(overlapped->write_event, INFINITE); 463 464 result = WriteFile(overlapped->handle, buffer, size, 465 &write_size, &overlapped->write_overlapped); 466 467 if (!result) { 468 switch (error = GetLastError()) 469 { 470 case ERROR_IO_PENDING: 471 #ifndef TUN_ASYNCHRONOUS_WRITES 472 WaitForSingleObject(overlapped->write_event, INFINITE); 473 #endif 474 break; 475 default: 476 return -1; 477 } 478 } 479 480 return 0; 481 } 482 483 static DWORD WINAPI tap_win32_thread_entry(LPVOID param) 484 { 485 tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param; 486 unsigned long read_size; 487 BOOL result; 488 DWORD dwError; 489 tun_buffer_t* buffer = get_buffer_from_free_list(overlapped); 490 491 492 for (;;) { 493 result = ReadFile(overlapped->handle, 494 buffer->buffer, 495 sizeof(buffer->buffer), 496 &read_size, 497 &overlapped->read_overlapped); 498 if (!result) { 499 dwError = GetLastError(); 500 if (dwError == ERROR_IO_PENDING) { 501 WaitForSingleObject(overlapped->read_event, INFINITE); 502 result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped, 503 &read_size, FALSE); 504 if (!result) { 505 #ifdef DEBUG_TAP_WIN32 506 LPVOID lpBuffer; 507 dwError = GetLastError(); 508 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 509 NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 510 (LPTSTR) & lpBuffer, 0, NULL ); 511 fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer); 512 LocalFree( lpBuffer ); 513 #endif 514 } 515 } else { 516 #ifdef DEBUG_TAP_WIN32 517 LPVOID lpBuffer; 518 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 519 NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 520 (LPTSTR) & lpBuffer, 0, NULL ); 521 fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer); 522 LocalFree( lpBuffer ); 523 #endif 524 } 525 } 526 527 if(read_size > 0) { 528 buffer->read_size = read_size; 529 put_buffer_on_output_queue(overlapped, buffer); 530 ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL); 531 buffer = get_buffer_from_free_list(overlapped); 532 } 533 } 534 535 return 0; 536 } 537 538 static int tap_win32_read(tap_win32_overlapped_t *overlapped, 539 uint8_t **pbuf, int max_size) 540 { 541 int size = 0; 542 543 tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped); 544 545 if(buffer != NULL) { 546 *pbuf = buffer->buffer; 547 size = (int)buffer->read_size; 548 if(size > max_size) { 549 size = max_size; 550 } 551 } 552 553 return size; 554 } 555 556 static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, 557 uint8_t *pbuf) 558 { 559 tun_buffer_t* buffer = (tun_buffer_t*)pbuf; 560 put_buffer_on_free_list(overlapped, buffer); 561 } 562 563 static int tap_win32_open(tap_win32_overlapped_t **phandle, 564 const char *prefered_name) 565 { 566 char device_path[256]; 567 char device_guid[0x100]; 568 int rc; 569 HANDLE handle; 570 BOOL bret; 571 char name_buffer[0x100] = {0, }; 572 struct { 573 unsigned long major; 574 unsigned long minor; 575 unsigned long debug; 576 } version; 577 DWORD version_len; 578 DWORD idThread; 579 580 if (prefered_name != NULL) 581 snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name); 582 583 rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer)); 584 if (rc) 585 return -1; 586 587 snprintf (device_path, sizeof(device_path), "%s%s%s", 588 USERMODEDEVICEDIR, 589 device_guid, 590 TAPSUFFIX); 591 592 handle = CreateFile ( 593 device_path, 594 GENERIC_READ | GENERIC_WRITE, 595 0, 596 0, 597 OPEN_EXISTING, 598 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 599 0 ); 600 601 if (handle == INVALID_HANDLE_VALUE) { 602 return -1; 603 } 604 605 bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION, 606 &version, sizeof (version), 607 &version, sizeof (version), &version_len, NULL); 608 609 if (bret == FALSE) { 610 CloseHandle(handle); 611 return -1; 612 } 613 614 if (!tap_win32_set_status(handle, TRUE)) { 615 return -1; 616 } 617 618 tap_win32_overlapped_init(&tap_overlapped, handle); 619 620 *phandle = &tap_overlapped; 621 622 (void) CreateThread(NULL, 0, tap_win32_thread_entry, 623 (LPVOID)&tap_overlapped, 0, &idThread); 624 return 0; 625 } 626 627 /********************************************/ 628 629 typedef struct TAPState { 630 VLANClientState *vc; 631 tap_win32_overlapped_t *handle; 632 } TAPState; 633 634 static void tap_cleanup(VLANClientState *vc) 635 { 636 TAPState *s = vc->opaque; 637 638 qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL); 639 640 /* FIXME: need to kill thread and close file handle: 641 tap_win32_close(s); 642 */ 643 g_free(s); 644 } 645 646 static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size) 647 { 648 TAPState *s = vc->opaque; 649 650 return tap_win32_write(s->handle, buf, size); 651 } 652 653 static void tap_win32_send(void *opaque) 654 { 655 TAPState *s = opaque; 656 uint8_t *buf; 657 int max_size = 4096; 658 int size; 659 660 size = tap_win32_read(s->handle, &buf, max_size); 661 if (size > 0) { 662 qemu_send_packet(s->vc, buf, size); 663 tap_win32_free_buffer(s->handle, buf); 664 } 665 } 666 667 int tap_win32_init(VLANState *vlan, const char *model, 668 const char *name, const char *ifname) 669 { 670 TAPState *s; 671 672 s = g_malloc0(sizeof(TAPState)); 673 if (!s) 674 return -1; 675 if (tap_win32_open(&s->handle, ifname) < 0) { 676 printf("tap: Could not open '%s'\n", ifname); 677 return -1; 678 } 679 680 s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive, 681 NULL, tap_cleanup, s); 682 683 snprintf(s->vc->info_str, sizeof(s->vc->info_str), 684 "tap: ifname=%s", ifname); 685 686 qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s); 687 return 0; 688 } 689