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 "tap_int.h" 30 31 #include "qemu-common.h" 32 #include "clients.h" /* net_init_tap */ 33 #include "net/net.h" 34 #include "net/tap.h" /* tap_has_ufo, ... */ 35 #include "sysemu/sysemu.h" 36 #include "qemu/error-report.h" 37 #include <stdio.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 char unit_string[256]; 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 snprintf (unit_string, sizeof(unit_string), "%s\\%s", 243 ADAPTER_KEY, enum_name); 244 245 status = RegOpenKeyEx( 246 HKEY_LOCAL_MACHINE, 247 unit_string, 248 0, 249 KEY_READ, 250 &unit_key); 251 252 if (status != ERROR_SUCCESS) { 253 return FALSE; 254 } else { 255 len = sizeof (component_id); 256 status = RegQueryValueEx( 257 unit_key, 258 component_id_string, 259 NULL, 260 &data_type, 261 (LPBYTE)component_id, 262 &len); 263 264 if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) { 265 len = sizeof (net_cfg_instance_id); 266 status = RegQueryValueEx( 267 unit_key, 268 net_cfg_instance_id_string, 269 NULL, 270 &data_type, 271 (LPBYTE)net_cfg_instance_id, 272 &len); 273 274 if (status == ERROR_SUCCESS && data_type == REG_SZ) { 275 if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/ 276 !strcmp (net_cfg_instance_id, guid)) { 277 RegCloseKey (unit_key); 278 RegCloseKey (netcard_key); 279 return TRUE; 280 } 281 } 282 } 283 RegCloseKey (unit_key); 284 } 285 ++i; 286 } 287 288 RegCloseKey (netcard_key); 289 return FALSE; 290 } 291 292 static int get_device_guid( 293 char *name, 294 int name_size, 295 char *actual_name, 296 int actual_name_size) 297 { 298 LONG status; 299 HKEY control_net_key; 300 DWORD len; 301 int i = 0; 302 int stop = 0; 303 304 status = RegOpenKeyEx( 305 HKEY_LOCAL_MACHINE, 306 NETWORK_CONNECTIONS_KEY, 307 0, 308 KEY_READ, 309 &control_net_key); 310 311 if (status != ERROR_SUCCESS) { 312 return -1; 313 } 314 315 while (!stop) 316 { 317 char enum_name[256]; 318 char connection_string[256]; 319 HKEY connection_key; 320 char name_data[256]; 321 DWORD name_type; 322 const char name_string[] = "Name"; 323 324 len = sizeof (enum_name); 325 status = RegEnumKeyEx( 326 control_net_key, 327 i, 328 enum_name, 329 &len, 330 NULL, 331 NULL, 332 NULL, 333 NULL); 334 335 if (status == ERROR_NO_MORE_ITEMS) 336 break; 337 else if (status != ERROR_SUCCESS) { 338 return -1; 339 } 340 341 snprintf(connection_string, 342 sizeof(connection_string), 343 "%s\\%s\\Connection", 344 NETWORK_CONNECTIONS_KEY, enum_name); 345 346 status = RegOpenKeyEx( 347 HKEY_LOCAL_MACHINE, 348 connection_string, 349 0, 350 KEY_READ, 351 &connection_key); 352 353 if (status == ERROR_SUCCESS) { 354 len = sizeof (name_data); 355 status = RegQueryValueEx( 356 connection_key, 357 name_string, 358 NULL, 359 &name_type, 360 (LPBYTE)name_data, 361 &len); 362 363 if (status != ERROR_SUCCESS || name_type != REG_SZ) { 364 ++i; 365 continue; 366 } 367 else { 368 if (is_tap_win32_dev(enum_name)) { 369 snprintf(name, name_size, "%s", enum_name); 370 if (actual_name) { 371 if (strcmp(actual_name, "") != 0) { 372 if (strcmp(name_data, actual_name) != 0) { 373 RegCloseKey (connection_key); 374 ++i; 375 continue; 376 } 377 } 378 else { 379 snprintf(actual_name, actual_name_size, "%s", name_data); 380 } 381 } 382 stop = 1; 383 } 384 } 385 386 RegCloseKey (connection_key); 387 } 388 ++i; 389 } 390 391 RegCloseKey (control_net_key); 392 393 if (stop == 0) 394 return -1; 395 396 return 0; 397 } 398 399 static int tap_win32_set_status(HANDLE handle, int status) 400 { 401 unsigned long len = 0; 402 403 return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS, 404 &status, sizeof (status), 405 &status, sizeof (status), &len, NULL); 406 } 407 408 static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle) 409 { 410 overlapped->handle = handle; 411 412 overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL); 413 overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL); 414 415 overlapped->read_overlapped.Offset = 0; 416 overlapped->read_overlapped.OffsetHigh = 0; 417 overlapped->read_overlapped.hEvent = overlapped->read_event; 418 419 overlapped->write_overlapped.Offset = 0; 420 overlapped->write_overlapped.OffsetHigh = 0; 421 overlapped->write_overlapped.hEvent = overlapped->write_event; 422 423 InitializeCriticalSection(&overlapped->output_queue_cs); 424 InitializeCriticalSection(&overlapped->free_list_cs); 425 426 overlapped->output_queue_semaphore = CreateSemaphore( 427 NULL, // default security attributes 428 0, // initial count 429 TUN_MAX_BUFFER_COUNT, // maximum count 430 NULL); // unnamed semaphore 431 432 if(!overlapped->output_queue_semaphore) { 433 fprintf(stderr, "error creating output queue semaphore!\n"); 434 } 435 436 overlapped->free_list_semaphore = CreateSemaphore( 437 NULL, // default security attributes 438 TUN_MAX_BUFFER_COUNT, // initial count 439 TUN_MAX_BUFFER_COUNT, // maximum count 440 NULL); // unnamed semaphore 441 442 if(!overlapped->free_list_semaphore) { 443 fprintf(stderr, "error creating free list semaphore!\n"); 444 } 445 446 overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL; 447 448 { 449 unsigned index; 450 for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) { 451 tun_buffer_t* element = &overlapped->buffers[index]; 452 element->next = overlapped->free_list; 453 overlapped->free_list = element; 454 } 455 } 456 /* To count buffers, initially no-signal. */ 457 overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL); 458 if(!overlapped->tap_semaphore) 459 fprintf(stderr, "error creating tap_semaphore.\n"); 460 } 461 462 static int tap_win32_write(tap_win32_overlapped_t *overlapped, 463 const void *buffer, unsigned long size) 464 { 465 unsigned long write_size; 466 BOOL result; 467 DWORD error; 468 469 #ifdef TUN_ASYNCHRONOUS_WRITES 470 result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped, 471 &write_size, FALSE); 472 473 if (!result && GetLastError() == ERROR_IO_INCOMPLETE) 474 WaitForSingleObject(overlapped->write_event, INFINITE); 475 #endif 476 477 result = WriteFile(overlapped->handle, buffer, size, 478 &write_size, &overlapped->write_overlapped); 479 480 #ifdef TUN_ASYNCHRONOUS_WRITES 481 /* FIXME: we can't sensibly set write_size here, without waiting 482 * for the IO to complete! Moreover, we can't return zero, 483 * because that will disable receive on this interface, and we 484 * also can't assume it will succeed and return the full size, 485 * because that will result in the buffer being reclaimed while 486 * the IO is in progress. */ 487 #error Async writes are broken. Please disable TUN_ASYNCHRONOUS_WRITES. 488 #else /* !TUN_ASYNCHRONOUS_WRITES */ 489 if (!result) { 490 error = GetLastError(); 491 if (error == ERROR_IO_PENDING) { 492 result = GetOverlappedResult(overlapped->handle, 493 &overlapped->write_overlapped, 494 &write_size, TRUE); 495 } 496 } 497 #endif 498 499 if (!result) { 500 #ifdef DEBUG_TAP_WIN32 501 LPTSTR msgbuf; 502 error = GetLastError(); 503 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM, 504 NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 505 &msgbuf, 0, NULL); 506 fprintf(stderr, "Tap-Win32: Error WriteFile %d - %s\n", error, msgbuf); 507 LocalFree(msgbuf); 508 #endif 509 return 0; 510 } 511 512 return write_size; 513 } 514 515 static DWORD WINAPI tap_win32_thread_entry(LPVOID param) 516 { 517 tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param; 518 unsigned long read_size; 519 BOOL result; 520 DWORD dwError; 521 tun_buffer_t* buffer = get_buffer_from_free_list(overlapped); 522 523 524 for (;;) { 525 result = ReadFile(overlapped->handle, 526 buffer->buffer, 527 sizeof(buffer->buffer), 528 &read_size, 529 &overlapped->read_overlapped); 530 if (!result) { 531 dwError = GetLastError(); 532 if (dwError == ERROR_IO_PENDING) { 533 WaitForSingleObject(overlapped->read_event, INFINITE); 534 result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped, 535 &read_size, FALSE); 536 if (!result) { 537 #ifdef DEBUG_TAP_WIN32 538 LPVOID lpBuffer; 539 dwError = GetLastError(); 540 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 541 NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 542 (LPTSTR) & lpBuffer, 0, NULL ); 543 fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer); 544 LocalFree( lpBuffer ); 545 #endif 546 } 547 } else { 548 #ifdef DEBUG_TAP_WIN32 549 LPVOID lpBuffer; 550 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, 551 NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 552 (LPTSTR) & lpBuffer, 0, NULL ); 553 fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer); 554 LocalFree( lpBuffer ); 555 #endif 556 } 557 } 558 559 if(read_size > 0) { 560 buffer->read_size = read_size; 561 put_buffer_on_output_queue(overlapped, buffer); 562 ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL); 563 buffer = get_buffer_from_free_list(overlapped); 564 } 565 } 566 567 return 0; 568 } 569 570 static int tap_win32_read(tap_win32_overlapped_t *overlapped, 571 uint8_t **pbuf, int max_size) 572 { 573 int size = 0; 574 575 tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped); 576 577 if(buffer != NULL) { 578 *pbuf = buffer->buffer; 579 size = (int)buffer->read_size; 580 if(size > max_size) { 581 size = max_size; 582 } 583 } 584 585 return size; 586 } 587 588 static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped, 589 uint8_t *pbuf) 590 { 591 tun_buffer_t* buffer = (tun_buffer_t*)pbuf; 592 put_buffer_on_free_list(overlapped, buffer); 593 } 594 595 static int tap_win32_open(tap_win32_overlapped_t **phandle, 596 const char *preferred_name) 597 { 598 char device_path[256]; 599 char device_guid[0x100]; 600 int rc; 601 HANDLE handle; 602 BOOL bret; 603 char name_buffer[0x100] = {0, }; 604 struct { 605 unsigned long major; 606 unsigned long minor; 607 unsigned long debug; 608 } version; 609 DWORD version_len; 610 DWORD idThread; 611 612 if (preferred_name != NULL) { 613 snprintf(name_buffer, sizeof(name_buffer), "%s", preferred_name); 614 } 615 616 rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer)); 617 if (rc) 618 return -1; 619 620 snprintf (device_path, sizeof(device_path), "%s%s%s", 621 USERMODEDEVICEDIR, 622 device_guid, 623 TAPSUFFIX); 624 625 handle = CreateFile ( 626 device_path, 627 GENERIC_READ | GENERIC_WRITE, 628 0, 629 0, 630 OPEN_EXISTING, 631 FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 632 0 ); 633 634 if (handle == INVALID_HANDLE_VALUE) { 635 return -1; 636 } 637 638 bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION, 639 &version, sizeof (version), 640 &version, sizeof (version), &version_len, NULL); 641 642 if (bret == FALSE) { 643 CloseHandle(handle); 644 return -1; 645 } 646 647 if (!tap_win32_set_status(handle, TRUE)) { 648 return -1; 649 } 650 651 tap_win32_overlapped_init(&tap_overlapped, handle); 652 653 *phandle = &tap_overlapped; 654 655 CreateThread(NULL, 0, tap_win32_thread_entry, 656 (LPVOID)&tap_overlapped, 0, &idThread); 657 return 0; 658 } 659 660 /********************************************/ 661 662 typedef struct TAPState { 663 NetClientState nc; 664 tap_win32_overlapped_t *handle; 665 } TAPState; 666 667 static void tap_cleanup(NetClientState *nc) 668 { 669 TAPState *s = DO_UPCAST(TAPState, nc, nc); 670 671 qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL); 672 673 /* FIXME: need to kill thread and close file handle: 674 tap_win32_close(s); 675 */ 676 } 677 678 static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size) 679 { 680 TAPState *s = DO_UPCAST(TAPState, nc, nc); 681 682 return tap_win32_write(s->handle, buf, size); 683 } 684 685 static void tap_win32_send(void *opaque) 686 { 687 TAPState *s = opaque; 688 uint8_t *buf; 689 int max_size = 4096; 690 int size; 691 692 size = tap_win32_read(s->handle, &buf, max_size); 693 if (size > 0) { 694 qemu_send_packet(&s->nc, buf, size); 695 tap_win32_free_buffer(s->handle, buf); 696 } 697 } 698 699 static bool tap_has_ufo(NetClientState *nc) 700 { 701 return false; 702 } 703 704 static bool tap_has_vnet_hdr(NetClientState *nc) 705 { 706 return false; 707 } 708 709 int tap_probe_vnet_hdr_len(int fd, int len) 710 { 711 return 0; 712 } 713 714 void tap_fd_set_vnet_hdr_len(int fd, int len) 715 { 716 } 717 718 int tap_fd_set_vnet_le(int fd, int is_le) 719 { 720 return -EINVAL; 721 } 722 723 int tap_fd_set_vnet_be(int fd, int is_be) 724 { 725 return -EINVAL; 726 } 727 728 static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr) 729 { 730 } 731 732 static void tap_set_offload(NetClientState *nc, int csum, int tso4, 733 int tso6, int ecn, int ufo) 734 { 735 } 736 737 struct vhost_net *tap_get_vhost_net(NetClientState *nc) 738 { 739 return NULL; 740 } 741 742 static bool tap_has_vnet_hdr_len(NetClientState *nc, int len) 743 { 744 return false; 745 } 746 747 static void tap_set_vnet_hdr_len(NetClientState *nc, int len) 748 { 749 abort(); 750 } 751 752 static NetClientInfo net_tap_win32_info = { 753 .type = NET_CLIENT_OPTIONS_KIND_TAP, 754 .size = sizeof(TAPState), 755 .receive = tap_receive, 756 .cleanup = tap_cleanup, 757 .has_ufo = tap_has_ufo, 758 .has_vnet_hdr = tap_has_vnet_hdr, 759 .has_vnet_hdr_len = tap_has_vnet_hdr_len, 760 .using_vnet_hdr = tap_using_vnet_hdr, 761 .set_offload = tap_set_offload, 762 .set_vnet_hdr_len = tap_set_vnet_hdr_len, 763 }; 764 765 static int tap_win32_init(NetClientState *peer, const char *model, 766 const char *name, const char *ifname) 767 { 768 NetClientState *nc; 769 TAPState *s; 770 tap_win32_overlapped_t *handle; 771 772 if (tap_win32_open(&handle, ifname) < 0) { 773 printf("tap: Could not open '%s'\n", ifname); 774 return -1; 775 } 776 777 nc = qemu_new_net_client(&net_tap_win32_info, peer, model, name); 778 779 s = DO_UPCAST(TAPState, nc, nc); 780 781 snprintf(s->nc.info_str, sizeof(s->nc.info_str), 782 "tap: ifname=%s", ifname); 783 784 s->handle = handle; 785 786 qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s); 787 788 return 0; 789 } 790 791 int net_init_tap(const NetClientOptions *opts, const char *name, 792 NetClientState *peer, Error **errp) 793 { 794 /* FIXME error_setg(errp, ...) on failure */ 795 const NetdevTapOptions *tap; 796 797 assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP); 798 tap = opts->u.tap; 799 800 if (!tap->has_ifname) { 801 error_report("tap: no interface name"); 802 return -1; 803 } 804 805 if (tap_win32_init(peer, "tap", name, tap->ifname) == -1) { 806 return -1; 807 } 808 809 return 0; 810 } 811 812 int tap_enable(NetClientState *nc) 813 { 814 abort(); 815 } 816 817 int tap_disable(NetClientState *nc) 818 { 819 abort(); 820 } 821