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