xref: /openbmc/qemu/net/tap-win32.c (revision c20d09eb)
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 "clients.h"            /* net_init_tap */
33 #include "net/eth.h"
34 #include "net/net.h"
35 #include "net/tap.h"            /* tap_has_ufo, ... */
36 #include "qemu/error-report.h"
37 #include "qemu/main-loop.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  */
94 typedef 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 
100 typedef 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 
117 static tap_win32_overlapped_t tap_overlapped;
118 
119 static 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 
132 static 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 
141 static 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 
174 static 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 
179 static 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 
197 static 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         g_autofree char *unit_string = NULL;
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         unit_string = g_strdup_printf("%s\\%s", ADAPTER_KEY, enum_name);
243 
244         status = RegOpenKeyEx(
245             HKEY_LOCAL_MACHINE,
246             unit_string,
247             0,
248             KEY_READ,
249             &unit_key);
250 
251         if (status != ERROR_SUCCESS) {
252             return FALSE;
253         } else {
254             len = sizeof (component_id);
255             status = RegQueryValueEx(
256                 unit_key,
257                 component_id_string,
258                 NULL,
259                 &data_type,
260                 (LPBYTE)component_id,
261                 &len);
262 
263             if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
264                 len = sizeof (net_cfg_instance_id);
265                 status = RegQueryValueEx(
266                     unit_key,
267                     net_cfg_instance_id_string,
268                     NULL,
269                     &data_type,
270                     (LPBYTE)net_cfg_instance_id,
271                     &len);
272 
273                 if (status == ERROR_SUCCESS && data_type == REG_SZ) {
274                     if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/
275                         !strcmp (net_cfg_instance_id, guid)) {
276                         RegCloseKey (unit_key);
277                         RegCloseKey (netcard_key);
278                         return TRUE;
279                     }
280                 }
281             }
282             RegCloseKey (unit_key);
283         }
284         ++i;
285     }
286 
287     RegCloseKey (netcard_key);
288     return FALSE;
289 }
290 
291 static int get_device_guid(
292     char *name,
293     int name_size,
294     char *actual_name,
295     int actual_name_size)
296 {
297     LONG status;
298     HKEY control_net_key;
299     DWORD len;
300     int i = 0;
301     int stop = 0;
302 
303     status = RegOpenKeyEx(
304         HKEY_LOCAL_MACHINE,
305         NETWORK_CONNECTIONS_KEY,
306         0,
307         KEY_READ,
308         &control_net_key);
309 
310     if (status != ERROR_SUCCESS) {
311         return -1;
312     }
313 
314     while (!stop)
315     {
316         char enum_name[256];
317         g_autofree char *connection_string = NULL;
318         HKEY connection_key;
319         char name_data[256];
320         DWORD name_type;
321         const char name_string[] = "Name";
322 
323         len = sizeof (enum_name);
324         status = RegEnumKeyEx(
325             control_net_key,
326             i,
327             enum_name,
328             &len,
329             NULL,
330             NULL,
331             NULL,
332             NULL);
333 
334         if (status == ERROR_NO_MORE_ITEMS)
335             break;
336         else if (status != ERROR_SUCCESS) {
337             return -1;
338         }
339 
340         connection_string = g_strdup_printf("%s\\%s\\Connection",
341              NETWORK_CONNECTIONS_KEY, enum_name);
342 
343         status = RegOpenKeyEx(
344             HKEY_LOCAL_MACHINE,
345             connection_string,
346             0,
347             KEY_READ,
348             &connection_key);
349 
350         if (status == ERROR_SUCCESS) {
351             len = sizeof (name_data);
352             status = RegQueryValueEx(
353                 connection_key,
354                 name_string,
355                 NULL,
356                 &name_type,
357                 (LPBYTE)name_data,
358                 &len);
359 
360             if (status != ERROR_SUCCESS || name_type != REG_SZ) {
361                 ++i;
362                 continue;
363             }
364             else {
365                 if (is_tap_win32_dev(enum_name)) {
366                     snprintf(name, name_size, "%s", enum_name);
367                     if (actual_name) {
368                         if (strcmp(actual_name, "") != 0) {
369                             if (strcmp(name_data, actual_name) != 0) {
370                                 RegCloseKey (connection_key);
371                                 ++i;
372                                 continue;
373                             }
374                         }
375                         else {
376                             snprintf(actual_name, actual_name_size, "%s", name_data);
377                         }
378                     }
379                     stop = 1;
380                 }
381             }
382 
383             RegCloseKey (connection_key);
384         }
385         ++i;
386     }
387 
388     RegCloseKey (control_net_key);
389 
390     if (stop == 0)
391         return -1;
392 
393     return 0;
394 }
395 
396 static int tap_win32_set_status(HANDLE handle, int status)
397 {
398     unsigned long len = 0;
399 
400     return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
401                 &status, sizeof (status),
402                 &status, sizeof (status), &len, NULL);
403 }
404 
405 static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle)
406 {
407     overlapped->handle = handle;
408 
409     overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL);
410     overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
411 
412     overlapped->read_overlapped.Offset = 0;
413     overlapped->read_overlapped.OffsetHigh = 0;
414     overlapped->read_overlapped.hEvent = overlapped->read_event;
415 
416     overlapped->write_overlapped.Offset = 0;
417     overlapped->write_overlapped.OffsetHigh = 0;
418     overlapped->write_overlapped.hEvent = overlapped->write_event;
419 
420     InitializeCriticalSection(&overlapped->output_queue_cs);
421     InitializeCriticalSection(&overlapped->free_list_cs);
422 
423     overlapped->output_queue_semaphore = CreateSemaphore(
424         NULL,   // default security attributes
425         0,   // initial count
426         TUN_MAX_BUFFER_COUNT,   // maximum count
427         NULL);  // unnamed semaphore
428 
429     if(!overlapped->output_queue_semaphore)  {
430         fprintf(stderr, "error creating output queue semaphore!\n");
431     }
432 
433     overlapped->free_list_semaphore = CreateSemaphore(
434         NULL,   // default security attributes
435         TUN_MAX_BUFFER_COUNT,   // initial count
436         TUN_MAX_BUFFER_COUNT,   // maximum count
437         NULL);  // unnamed semaphore
438 
439     if(!overlapped->free_list_semaphore)  {
440         fprintf(stderr, "error creating free list semaphore!\n");
441     }
442 
443     overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL;
444 
445     {
446         unsigned index;
447         for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) {
448             tun_buffer_t* element = &overlapped->buffers[index];
449             element->next = overlapped->free_list;
450             overlapped->free_list = element;
451         }
452     }
453     /* To count buffers, initially no-signal. */
454     overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL);
455     if(!overlapped->tap_semaphore)
456         fprintf(stderr, "error creating tap_semaphore.\n");
457 }
458 
459 static int tap_win32_write(tap_win32_overlapped_t *overlapped,
460                            const void *buffer, unsigned long size)
461 {
462     unsigned long write_size;
463     BOOL result;
464     DWORD error;
465 
466 #ifdef TUN_ASYNCHRONOUS_WRITES
467     result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped,
468                                   &write_size, FALSE);
469 
470     if (!result && GetLastError() == ERROR_IO_INCOMPLETE)
471         WaitForSingleObject(overlapped->write_event, INFINITE);
472 #endif
473 
474     result = WriteFile(overlapped->handle, buffer, size,
475                        &write_size, &overlapped->write_overlapped);
476 
477 #ifdef TUN_ASYNCHRONOUS_WRITES
478     /* FIXME: we can't sensibly set write_size here, without waiting
479      * for the IO to complete! Moreover, we can't return zero,
480      * because that will disable receive on this interface, and we
481      * also can't assume it will succeed and return the full size,
482      * because that will result in the buffer being reclaimed while
483      * the IO is in progress. */
484 #error Async writes are broken. Please disable TUN_ASYNCHRONOUS_WRITES.
485 #else /* !TUN_ASYNCHRONOUS_WRITES */
486     if (!result) {
487         error = GetLastError();
488         if (error == ERROR_IO_PENDING) {
489             result = GetOverlappedResult(overlapped->handle,
490                                          &overlapped->write_overlapped,
491                                          &write_size, TRUE);
492         }
493     }
494 #endif
495 
496     if (!result) {
497 #ifdef DEBUG_TAP_WIN32
498         LPTSTR msgbuf;
499         error = GetLastError();
500         FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
501                       NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
502                       &msgbuf, 0, NULL);
503         fprintf(stderr, "Tap-Win32: Error WriteFile %d - %s\n", error, msgbuf);
504         LocalFree(msgbuf);
505 #endif
506         return 0;
507     }
508 
509     return write_size;
510 }
511 
512 static DWORD WINAPI tap_win32_thread_entry(LPVOID param)
513 {
514     tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param;
515     unsigned long read_size;
516     BOOL result;
517     DWORD dwError;
518     tun_buffer_t* buffer = get_buffer_from_free_list(overlapped);
519 
520 
521     for (;;) {
522         result = ReadFile(overlapped->handle,
523                           buffer->buffer,
524                           sizeof(buffer->buffer),
525                           &read_size,
526                           &overlapped->read_overlapped);
527         if (!result) {
528             dwError = GetLastError();
529             if (dwError == ERROR_IO_PENDING) {
530                 WaitForSingleObject(overlapped->read_event, INFINITE);
531                 result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped,
532                                               &read_size, FALSE);
533                 if (!result) {
534 #ifdef DEBUG_TAP_WIN32
535                     LPVOID lpBuffer;
536                     dwError = GetLastError();
537                     FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
538                                    NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
539                                    (LPTSTR) & lpBuffer, 0, NULL );
540                     fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer);
541                     LocalFree( lpBuffer );
542 #endif
543                 }
544             } else {
545 #ifdef DEBUG_TAP_WIN32
546                 LPVOID lpBuffer;
547                 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
548                                NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
549                                (LPTSTR) & lpBuffer, 0, NULL );
550                 fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer);
551                 LocalFree( lpBuffer );
552 #endif
553             }
554         }
555 
556         if(read_size > 0) {
557             buffer->read_size = read_size;
558             put_buffer_on_output_queue(overlapped, buffer);
559             ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL);
560             buffer = get_buffer_from_free_list(overlapped);
561         }
562     }
563 
564     return 0;
565 }
566 
567 static int tap_win32_read(tap_win32_overlapped_t *overlapped,
568                           uint8_t **pbuf, int max_size)
569 {
570     int size = 0;
571 
572     tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped);
573 
574     if(buffer != NULL) {
575         *pbuf = buffer->buffer;
576         size = (int)buffer->read_size;
577         if(size > max_size) {
578             size = max_size;
579         }
580     }
581 
582     return size;
583 }
584 
585 static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
586                                   uint8_t *pbuf)
587 {
588     tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
589     put_buffer_on_free_list(overlapped, buffer);
590 }
591 
592 static int tap_win32_open(tap_win32_overlapped_t **phandle,
593                           const char *preferred_name)
594 {
595     g_autofree char *device_path = NULL;
596     char device_guid[0x100];
597     int rc;
598     HANDLE handle;
599     BOOL bret;
600     char name_buffer[0x100] = {0, };
601     struct {
602         unsigned long major;
603         unsigned long minor;
604         unsigned long debug;
605     } version;
606     DWORD version_len;
607     DWORD idThread;
608 
609     if (preferred_name != NULL) {
610         snprintf(name_buffer, sizeof(name_buffer), "%s", preferred_name);
611     }
612 
613     rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));
614     if (rc)
615         return -1;
616 
617     device_path = g_strdup_printf("%s%s%s",
618               USERMODEDEVICEDIR,
619               device_guid,
620               TAPSUFFIX);
621 
622     handle = CreateFile (
623         device_path,
624         GENERIC_READ | GENERIC_WRITE,
625         0,
626         0,
627         OPEN_EXISTING,
628         FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
629         0 );
630 
631     if (handle == INVALID_HANDLE_VALUE) {
632         return -1;
633     }
634 
635     bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
636                            &version, sizeof (version),
637                            &version, sizeof (version), &version_len, NULL);
638 
639     if (bret == FALSE) {
640         CloseHandle(handle);
641         return -1;
642     }
643 
644     if (!tap_win32_set_status(handle, TRUE)) {
645         return -1;
646     }
647 
648     tap_win32_overlapped_init(&tap_overlapped, handle);
649 
650     *phandle = &tap_overlapped;
651 
652     CreateThread(NULL, 0, tap_win32_thread_entry,
653                  (LPVOID)&tap_overlapped, 0, &idThread);
654     return 0;
655 }
656 
657 /********************************************/
658 
659  typedef struct TAPState {
660      NetClientState nc;
661      tap_win32_overlapped_t *handle;
662  } TAPState;
663 
664 static void tap_cleanup(NetClientState *nc)
665 {
666     TAPState *s = DO_UPCAST(TAPState, nc, nc);
667 
668     qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL);
669 
670     /* FIXME: need to kill thread and close file handle:
671        tap_win32_close(s);
672     */
673 }
674 
675 static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size)
676 {
677     TAPState *s = DO_UPCAST(TAPState, nc, nc);
678 
679     return tap_win32_write(s->handle, buf, size);
680 }
681 
682 static void tap_win32_send(void *opaque)
683 {
684     TAPState *s = opaque;
685     uint8_t *buf, *orig_buf;
686     int max_size = 4096;
687     int size;
688     uint8_t min_pkt[ETH_ZLEN];
689     size_t min_pktsz = sizeof(min_pkt);
690 
691     size = tap_win32_read(s->handle, &buf, max_size);
692     if (size > 0) {
693         orig_buf = buf;
694 
695         if (net_peer_needs_padding(&s->nc)) {
696             if (eth_pad_short_frame(min_pkt, &min_pktsz, buf, size)) {
697                 buf = min_pkt;
698                 size = min_pktsz;
699             }
700         }
701 
702         qemu_send_packet(&s->nc, buf, size);
703         tap_win32_free_buffer(s->handle, orig_buf);
704     }
705 }
706 
707 struct vhost_net *tap_get_vhost_net(NetClientState *nc)
708 {
709     return NULL;
710 }
711 
712 static NetClientInfo net_tap_win32_info = {
713     .type = NET_CLIENT_DRIVER_TAP,
714     .size = sizeof(TAPState),
715     .receive = tap_receive,
716     .cleanup = tap_cleanup,
717 };
718 
719 static int tap_win32_init(NetClientState *peer, const char *model,
720                           const char *name, const char *ifname)
721 {
722     NetClientState *nc;
723     TAPState *s;
724     tap_win32_overlapped_t *handle;
725 
726     if (tap_win32_open(&handle, ifname) < 0) {
727         printf("tap: Could not open '%s'\n", ifname);
728         return -1;
729     }
730 
731     nc = qemu_new_net_client(&net_tap_win32_info, peer, model, name);
732 
733     s = DO_UPCAST(TAPState, nc, nc);
734 
735     qemu_set_info_str(&s->nc, "tap: ifname=%s", ifname);
736 
737     s->handle = handle;
738 
739     qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s);
740 
741     return 0;
742 }
743 
744 int net_init_tap(const Netdev *netdev, const char *name,
745                  NetClientState *peer, Error **errp)
746 {
747     /* FIXME error_setg(errp, ...) on failure */
748     const NetdevTapOptions *tap;
749 
750     assert(netdev->type == NET_CLIENT_DRIVER_TAP);
751     tap = &netdev->u.tap;
752 
753     if (!tap->ifname) {
754         error_report("tap: no interface name");
755         return -1;
756     }
757 
758     if (tap_win32_init(peer, "tap", name, tap->ifname) == -1) {
759         return -1;
760     }
761 
762     return 0;
763 }
764 
765 int tap_enable(NetClientState *nc)
766 {
767     abort();
768 }
769 
770 int tap_disable(NetClientState *nc)
771 {
772     abort();
773 }
774