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