• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
get_buffer_from_free_list(tap_win32_overlapped_t * const overlapped)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 
put_buffer_on_free_list(tap_win32_overlapped_t * const overlapped,tun_buffer_t * const buffer)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 
get_buffer_from_output_queue(tap_win32_overlapped_t * const overlapped,const int block)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 
get_buffer_from_output_queue_immediate(tap_win32_overlapped_t * const overlapped)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 
put_buffer_on_output_queue(tap_win32_overlapped_t * const overlapped,tun_buffer_t * const buffer)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 
is_tap_win32_dev(const char * guid)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 
get_device_guid(char * name,int name_size,char * actual_name,int actual_name_size)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 
tap_win32_set_status(HANDLE handle,int status)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 
tap_win32_overlapped_init(tap_win32_overlapped_t * const overlapped,const HANDLE handle)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 
tap_win32_write(tap_win32_overlapped_t * overlapped,const void * buffer,unsigned long size)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 
tap_win32_thread_entry(LPVOID param)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 
tap_win32_read(tap_win32_overlapped_t * overlapped,uint8_t ** pbuf,int max_size)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 
tap_win32_free_buffer(tap_win32_overlapped_t * overlapped,uint8_t * pbuf)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 
tap_win32_open(tap_win32_overlapped_t ** phandle,const char * prefered_name)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 
tap_cleanup(VLANClientState * vc)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 
tap_receive(VLANClientState * vc,const uint8_t * buf,size_t size)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 
tap_win32_send(void * opaque)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 
tap_win32_init(VLANState * vlan,const char * model,const char * name,const char * ifname)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