qemu/net/tap-win32.c
<<
>>
Prefs
   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}
 833