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