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