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