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/net.h"
  35#include "net/tap.h"            /* tap_has_ufo, ... */
  36#include "sysemu/sysemu.h"
  37#include "qemu/error-report.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 */
  94typedef 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
 100typedef 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
 117static tap_win32_overlapped_t tap_overlapped;
 118
 119static 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
 132static 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
 141static 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
 174static 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
 179static 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
 197static 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
 292static 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
 399static 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
 408static 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
 462static 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
 515static 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
 570static 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
 588static 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
 595static 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
 667static 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
 678static 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
 685static 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
 699static bool tap_has_ufo(NetClientState *nc)
 700{
 701    return false;
 702}
 703
 704static bool tap_has_vnet_hdr(NetClientState *nc)
 705{
 706    return false;
 707}
 708
 709int tap_probe_vnet_hdr_len(int fd, int len)
 710{
 711    return 0;
 712}
 713
 714void tap_fd_set_vnet_hdr_len(int fd, int len)
 715{
 716}
 717
 718int tap_fd_set_vnet_le(int fd, int is_le)
 719{
 720    return -EINVAL;
 721}
 722
 723int tap_fd_set_vnet_be(int fd, int is_be)
 724{
 725    return -EINVAL;
 726}
 727
 728static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr)
 729{
 730}
 731
 732static void tap_set_offload(NetClientState *nc, int csum, int tso4,
 733                     int tso6, int ecn, int ufo)
 734{
 735}
 736
 737struct vhost_net *tap_get_vhost_net(NetClientState *nc)
 738{
 739    return NULL;
 740}
 741
 742static bool tap_has_vnet_hdr_len(NetClientState *nc, int len)
 743{
 744    return false;
 745}
 746
 747static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
 748{
 749    abort();
 750}
 751
 752static 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
 765static 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
 791int 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.data;
 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
 812int tap_enable(NetClientState *nc)
 813{
 814    abort();
 815}
 816
 817int tap_disable(NetClientState *nc)
 818{
 819    abort();
 820}
 821