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