xref: /qemu/net/tap-win32.c (revision ee0428e3)
133ad161aSMark McLoughlin /*
233ad161aSMark McLoughlin  *  TAP-Win32 -- A kernel driver to provide virtual tap device functionality
333ad161aSMark McLoughlin  *               on Windows.  Originally derived from the CIPE-Win32
433ad161aSMark McLoughlin  *               project by Damion K. Wilson, with extensive modifications by
533ad161aSMark McLoughlin  *               James Yonan.
633ad161aSMark McLoughlin  *
733ad161aSMark McLoughlin  *  All source code which derives from the CIPE-Win32 project is
833ad161aSMark McLoughlin  *  Copyright (C) Damion K. Wilson, 2003, and is released under the
933ad161aSMark McLoughlin  *  GPL version 2 (see below).
1033ad161aSMark McLoughlin  *
1133ad161aSMark McLoughlin  *  All other source code is Copyright (C) James Yonan, 2003-2004,
1233ad161aSMark McLoughlin  *  and is released under the GPL version 2 (see below).
1333ad161aSMark McLoughlin  *
1433ad161aSMark McLoughlin  *  This program is free software; you can redistribute it and/or modify
1533ad161aSMark McLoughlin  *  it under the terms of the GNU General Public License as published by
1633ad161aSMark McLoughlin  *  the Free Software Foundation; either version 2 of the License, or
1733ad161aSMark McLoughlin  *  (at your option) any later version.
1833ad161aSMark McLoughlin  *
1933ad161aSMark McLoughlin  *  This program is distributed in the hope that it will be useful,
2033ad161aSMark McLoughlin  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
2133ad161aSMark McLoughlin  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
2233ad161aSMark McLoughlin  *  GNU General Public License for more details.
2333ad161aSMark McLoughlin  *
2433ad161aSMark McLoughlin  *  You should have received a copy of the GNU General Public License
2533ad161aSMark McLoughlin  *  along with this program (see the file COPYING included with this
2633ad161aSMark McLoughlin  *  distribution); if not, see <http://www.gnu.org/licenses/>.
2733ad161aSMark McLoughlin  */
28a8ed73f7SMark McLoughlin 
291422e32dSPaolo Bonzini #include "tap_int.h"
30a8ed73f7SMark McLoughlin 
3133ad161aSMark McLoughlin #include "qemu-common.h"
3208778b39SStefan Weil #include "clients.h"            /* net_init_tap */
331422e32dSPaolo Bonzini #include "net/net.h"
34b2136140SStefan Weil #include "net/tap.h"            /* tap_has_ufo, ... */
359c17d615SPaolo Bonzini #include "sysemu/sysemu.h"
361de7afc9SPaolo Bonzini #include "qemu/error-report.h"
3733ad161aSMark McLoughlin #include <stdio.h>
3833ad161aSMark McLoughlin #include <windows.h>
3933ad161aSMark McLoughlin #include <winioctl.h>
4033ad161aSMark McLoughlin 
4133ad161aSMark McLoughlin //=============
4233ad161aSMark McLoughlin // TAP IOCTLs
4333ad161aSMark McLoughlin //=============
4433ad161aSMark McLoughlin 
4533ad161aSMark McLoughlin #define TAP_CONTROL_CODE(request,method) \
4633ad161aSMark McLoughlin   CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
4733ad161aSMark McLoughlin 
4833ad161aSMark McLoughlin #define TAP_IOCTL_GET_MAC               TAP_CONTROL_CODE (1, METHOD_BUFFERED)
4933ad161aSMark McLoughlin #define TAP_IOCTL_GET_VERSION           TAP_CONTROL_CODE (2, METHOD_BUFFERED)
5033ad161aSMark McLoughlin #define TAP_IOCTL_GET_MTU               TAP_CONTROL_CODE (3, METHOD_BUFFERED)
5133ad161aSMark McLoughlin #define TAP_IOCTL_GET_INFO              TAP_CONTROL_CODE (4, METHOD_BUFFERED)
5233ad161aSMark McLoughlin #define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
5333ad161aSMark McLoughlin #define TAP_IOCTL_SET_MEDIA_STATUS      TAP_CONTROL_CODE (6, METHOD_BUFFERED)
5433ad161aSMark McLoughlin #define TAP_IOCTL_CONFIG_DHCP_MASQ      TAP_CONTROL_CODE (7, METHOD_BUFFERED)
5533ad161aSMark McLoughlin #define TAP_IOCTL_GET_LOG_LINE          TAP_CONTROL_CODE (8, METHOD_BUFFERED)
5633ad161aSMark McLoughlin #define TAP_IOCTL_CONFIG_DHCP_SET_OPT   TAP_CONTROL_CODE (9, METHOD_BUFFERED)
5733ad161aSMark McLoughlin 
5833ad161aSMark McLoughlin //=================
5933ad161aSMark McLoughlin // Registry keys
6033ad161aSMark McLoughlin //=================
6133ad161aSMark McLoughlin 
6233ad161aSMark McLoughlin #define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
6333ad161aSMark McLoughlin 
6433ad161aSMark McLoughlin #define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
6533ad161aSMark McLoughlin 
6633ad161aSMark McLoughlin //======================
6733ad161aSMark McLoughlin // Filesystem prefixes
6833ad161aSMark McLoughlin //======================
6933ad161aSMark McLoughlin 
7033ad161aSMark McLoughlin #define USERMODEDEVICEDIR "\\\\.\\Global\\"
7133ad161aSMark McLoughlin #define TAPSUFFIX         ".tap"
7233ad161aSMark McLoughlin 
7333ad161aSMark McLoughlin 
7433ad161aSMark McLoughlin //======================
7533ad161aSMark McLoughlin // Compile time configuration
7633ad161aSMark McLoughlin //======================
7733ad161aSMark McLoughlin 
7833ad161aSMark McLoughlin //#define DEBUG_TAP_WIN32
7933ad161aSMark McLoughlin 
8033ad161aSMark McLoughlin #define TUN_ASYNCHRONOUS_WRITES 1
8133ad161aSMark McLoughlin 
8233ad161aSMark McLoughlin #define TUN_BUFFER_SIZE 1560
8333ad161aSMark McLoughlin #define TUN_MAX_BUFFER_COUNT 32
8433ad161aSMark McLoughlin 
8533ad161aSMark McLoughlin /*
8633ad161aSMark McLoughlin  * The data member "buffer" must be the first element in the tun_buffer
8733ad161aSMark McLoughlin  * structure. See the function, tap_win32_free_buffer.
8833ad161aSMark McLoughlin  */
8933ad161aSMark McLoughlin typedef struct tun_buffer_s {
9033ad161aSMark McLoughlin     unsigned char buffer [TUN_BUFFER_SIZE];
9133ad161aSMark McLoughlin     unsigned long read_size;
9233ad161aSMark McLoughlin     struct tun_buffer_s* next;
9333ad161aSMark McLoughlin } tun_buffer_t;
9433ad161aSMark McLoughlin 
9533ad161aSMark McLoughlin typedef struct tap_win32_overlapped {
9633ad161aSMark McLoughlin     HANDLE handle;
9733ad161aSMark McLoughlin     HANDLE read_event;
9833ad161aSMark McLoughlin     HANDLE write_event;
9933ad161aSMark McLoughlin     HANDLE output_queue_semaphore;
10033ad161aSMark McLoughlin     HANDLE free_list_semaphore;
10133ad161aSMark McLoughlin     HANDLE tap_semaphore;
10233ad161aSMark McLoughlin     CRITICAL_SECTION output_queue_cs;
10333ad161aSMark McLoughlin     CRITICAL_SECTION free_list_cs;
10433ad161aSMark McLoughlin     OVERLAPPED read_overlapped;
10533ad161aSMark McLoughlin     OVERLAPPED write_overlapped;
10633ad161aSMark McLoughlin     tun_buffer_t buffers[TUN_MAX_BUFFER_COUNT];
10733ad161aSMark McLoughlin     tun_buffer_t* free_list;
10833ad161aSMark McLoughlin     tun_buffer_t* output_queue_front;
10933ad161aSMark McLoughlin     tun_buffer_t* output_queue_back;
11033ad161aSMark McLoughlin } tap_win32_overlapped_t;
11133ad161aSMark McLoughlin 
11233ad161aSMark McLoughlin static tap_win32_overlapped_t tap_overlapped;
11333ad161aSMark McLoughlin 
11433ad161aSMark McLoughlin static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped)
11533ad161aSMark McLoughlin {
11633ad161aSMark McLoughlin     tun_buffer_t* buffer = NULL;
11733ad161aSMark McLoughlin     WaitForSingleObject(overlapped->free_list_semaphore, INFINITE);
11833ad161aSMark McLoughlin     EnterCriticalSection(&overlapped->free_list_cs);
11933ad161aSMark McLoughlin     buffer = overlapped->free_list;
12033ad161aSMark McLoughlin //    assert(buffer != NULL);
12133ad161aSMark McLoughlin     overlapped->free_list = buffer->next;
12233ad161aSMark McLoughlin     LeaveCriticalSection(&overlapped->free_list_cs);
12333ad161aSMark McLoughlin     buffer->next = NULL;
12433ad161aSMark McLoughlin     return buffer;
12533ad161aSMark McLoughlin }
12633ad161aSMark McLoughlin 
12733ad161aSMark McLoughlin static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
12833ad161aSMark McLoughlin {
12933ad161aSMark McLoughlin     EnterCriticalSection(&overlapped->free_list_cs);
13033ad161aSMark McLoughlin     buffer->next = overlapped->free_list;
13133ad161aSMark McLoughlin     overlapped->free_list = buffer;
13233ad161aSMark McLoughlin     LeaveCriticalSection(&overlapped->free_list_cs);
13333ad161aSMark McLoughlin     ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL);
13433ad161aSMark McLoughlin }
13533ad161aSMark McLoughlin 
13633ad161aSMark McLoughlin static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block)
13733ad161aSMark McLoughlin {
13833ad161aSMark McLoughlin     tun_buffer_t* buffer = NULL;
13933ad161aSMark McLoughlin     DWORD result, timeout = block ? INFINITE : 0L;
14033ad161aSMark McLoughlin 
14133ad161aSMark McLoughlin     // Non-blocking call
14233ad161aSMark McLoughlin     result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout);
14333ad161aSMark McLoughlin 
14433ad161aSMark McLoughlin     switch (result)
14533ad161aSMark McLoughlin     {
14633ad161aSMark McLoughlin         // The semaphore object was signaled.
14733ad161aSMark McLoughlin         case WAIT_OBJECT_0:
14833ad161aSMark McLoughlin             EnterCriticalSection(&overlapped->output_queue_cs);
14933ad161aSMark McLoughlin 
15033ad161aSMark McLoughlin             buffer = overlapped->output_queue_front;
15133ad161aSMark McLoughlin             overlapped->output_queue_front = buffer->next;
15233ad161aSMark McLoughlin 
15333ad161aSMark McLoughlin             if(overlapped->output_queue_front == NULL) {
15433ad161aSMark McLoughlin                 overlapped->output_queue_back = NULL;
15533ad161aSMark McLoughlin             }
15633ad161aSMark McLoughlin 
15733ad161aSMark McLoughlin             LeaveCriticalSection(&overlapped->output_queue_cs);
15833ad161aSMark McLoughlin             break;
15933ad161aSMark McLoughlin 
16033ad161aSMark McLoughlin         // Semaphore was nonsignaled, so a time-out occurred.
16133ad161aSMark McLoughlin         case WAIT_TIMEOUT:
16233ad161aSMark McLoughlin             // Cannot open another window.
16333ad161aSMark McLoughlin             break;
16433ad161aSMark McLoughlin     }
16533ad161aSMark McLoughlin 
16633ad161aSMark McLoughlin     return buffer;
16733ad161aSMark McLoughlin }
16833ad161aSMark McLoughlin 
16933ad161aSMark McLoughlin static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped)
17033ad161aSMark McLoughlin {
17133ad161aSMark McLoughlin     return get_buffer_from_output_queue(overlapped, 0);
17233ad161aSMark McLoughlin }
17333ad161aSMark McLoughlin 
17433ad161aSMark McLoughlin static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
17533ad161aSMark McLoughlin {
17633ad161aSMark McLoughlin     EnterCriticalSection(&overlapped->output_queue_cs);
17733ad161aSMark McLoughlin 
17833ad161aSMark McLoughlin     if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) {
17933ad161aSMark McLoughlin         overlapped->output_queue_front = overlapped->output_queue_back = buffer;
18033ad161aSMark McLoughlin     } else {
18133ad161aSMark McLoughlin         buffer->next = NULL;
18233ad161aSMark McLoughlin         overlapped->output_queue_back->next = buffer;
18333ad161aSMark McLoughlin         overlapped->output_queue_back = buffer;
18433ad161aSMark McLoughlin     }
18533ad161aSMark McLoughlin 
18633ad161aSMark McLoughlin     LeaveCriticalSection(&overlapped->output_queue_cs);
18733ad161aSMark McLoughlin 
18833ad161aSMark McLoughlin     ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL);
18933ad161aSMark McLoughlin }
19033ad161aSMark McLoughlin 
19133ad161aSMark McLoughlin 
19233ad161aSMark McLoughlin static int is_tap_win32_dev(const char *guid)
19333ad161aSMark McLoughlin {
19433ad161aSMark McLoughlin     HKEY netcard_key;
19533ad161aSMark McLoughlin     LONG status;
19633ad161aSMark McLoughlin     DWORD len;
19733ad161aSMark McLoughlin     int i = 0;
19833ad161aSMark McLoughlin 
19933ad161aSMark McLoughlin     status = RegOpenKeyEx(
20033ad161aSMark McLoughlin         HKEY_LOCAL_MACHINE,
20133ad161aSMark McLoughlin         ADAPTER_KEY,
20233ad161aSMark McLoughlin         0,
20333ad161aSMark McLoughlin         KEY_READ,
20433ad161aSMark McLoughlin         &netcard_key);
20533ad161aSMark McLoughlin 
20633ad161aSMark McLoughlin     if (status != ERROR_SUCCESS) {
20733ad161aSMark McLoughlin         return FALSE;
20833ad161aSMark McLoughlin     }
20933ad161aSMark McLoughlin 
21033ad161aSMark McLoughlin     for (;;) {
21133ad161aSMark McLoughlin         char enum_name[256];
21233ad161aSMark McLoughlin         char unit_string[256];
21333ad161aSMark McLoughlin         HKEY unit_key;
21433ad161aSMark McLoughlin         char component_id_string[] = "ComponentId";
21533ad161aSMark McLoughlin         char component_id[256];
21633ad161aSMark McLoughlin         char net_cfg_instance_id_string[] = "NetCfgInstanceId";
21733ad161aSMark McLoughlin         char net_cfg_instance_id[256];
21833ad161aSMark McLoughlin         DWORD data_type;
21933ad161aSMark McLoughlin 
22033ad161aSMark McLoughlin         len = sizeof (enum_name);
22133ad161aSMark McLoughlin         status = RegEnumKeyEx(
22233ad161aSMark McLoughlin             netcard_key,
22333ad161aSMark McLoughlin             i,
22433ad161aSMark McLoughlin             enum_name,
22533ad161aSMark McLoughlin             &len,
22633ad161aSMark McLoughlin             NULL,
22733ad161aSMark McLoughlin             NULL,
22833ad161aSMark McLoughlin             NULL,
22933ad161aSMark McLoughlin             NULL);
23033ad161aSMark McLoughlin 
23133ad161aSMark McLoughlin         if (status == ERROR_NO_MORE_ITEMS)
23233ad161aSMark McLoughlin             break;
23333ad161aSMark McLoughlin         else if (status != ERROR_SUCCESS) {
23433ad161aSMark McLoughlin             return FALSE;
23533ad161aSMark McLoughlin         }
23633ad161aSMark McLoughlin 
23733ad161aSMark McLoughlin         snprintf (unit_string, sizeof(unit_string), "%s\\%s",
23833ad161aSMark McLoughlin                   ADAPTER_KEY, enum_name);
23933ad161aSMark McLoughlin 
24033ad161aSMark McLoughlin         status = RegOpenKeyEx(
24133ad161aSMark McLoughlin             HKEY_LOCAL_MACHINE,
24233ad161aSMark McLoughlin             unit_string,
24333ad161aSMark McLoughlin             0,
24433ad161aSMark McLoughlin             KEY_READ,
24533ad161aSMark McLoughlin             &unit_key);
24633ad161aSMark McLoughlin 
24733ad161aSMark McLoughlin         if (status != ERROR_SUCCESS) {
24833ad161aSMark McLoughlin             return FALSE;
24933ad161aSMark McLoughlin         } else {
25033ad161aSMark McLoughlin             len = sizeof (component_id);
25133ad161aSMark McLoughlin             status = RegQueryValueEx(
25233ad161aSMark McLoughlin                 unit_key,
25333ad161aSMark McLoughlin                 component_id_string,
25433ad161aSMark McLoughlin                 NULL,
25533ad161aSMark McLoughlin                 &data_type,
25633ad161aSMark McLoughlin                 (LPBYTE)component_id,
25733ad161aSMark McLoughlin                 &len);
25833ad161aSMark McLoughlin 
25933ad161aSMark McLoughlin             if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
26033ad161aSMark McLoughlin                 len = sizeof (net_cfg_instance_id);
26133ad161aSMark McLoughlin                 status = RegQueryValueEx(
26233ad161aSMark McLoughlin                     unit_key,
26333ad161aSMark McLoughlin                     net_cfg_instance_id_string,
26433ad161aSMark McLoughlin                     NULL,
26533ad161aSMark McLoughlin                     &data_type,
26633ad161aSMark McLoughlin                     (LPBYTE)net_cfg_instance_id,
26733ad161aSMark McLoughlin                     &len);
26833ad161aSMark McLoughlin 
26933ad161aSMark McLoughlin                 if (status == ERROR_SUCCESS && data_type == REG_SZ) {
27033ad161aSMark McLoughlin                     if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/
27133ad161aSMark McLoughlin                         !strcmp (net_cfg_instance_id, guid)) {
27233ad161aSMark McLoughlin                         RegCloseKey (unit_key);
27333ad161aSMark McLoughlin                         RegCloseKey (netcard_key);
27433ad161aSMark McLoughlin                         return TRUE;
27533ad161aSMark McLoughlin                     }
27633ad161aSMark McLoughlin                 }
27733ad161aSMark McLoughlin             }
27833ad161aSMark McLoughlin             RegCloseKey (unit_key);
27933ad161aSMark McLoughlin         }
28033ad161aSMark McLoughlin         ++i;
28133ad161aSMark McLoughlin     }
28233ad161aSMark McLoughlin 
28333ad161aSMark McLoughlin     RegCloseKey (netcard_key);
28433ad161aSMark McLoughlin     return FALSE;
28533ad161aSMark McLoughlin }
28633ad161aSMark McLoughlin 
28733ad161aSMark McLoughlin static int get_device_guid(
28833ad161aSMark McLoughlin     char *name,
28933ad161aSMark McLoughlin     int name_size,
29033ad161aSMark McLoughlin     char *actual_name,
29133ad161aSMark McLoughlin     int actual_name_size)
29233ad161aSMark McLoughlin {
29333ad161aSMark McLoughlin     LONG status;
29433ad161aSMark McLoughlin     HKEY control_net_key;
29533ad161aSMark McLoughlin     DWORD len;
29633ad161aSMark McLoughlin     int i = 0;
29733ad161aSMark McLoughlin     int stop = 0;
29833ad161aSMark McLoughlin 
29933ad161aSMark McLoughlin     status = RegOpenKeyEx(
30033ad161aSMark McLoughlin         HKEY_LOCAL_MACHINE,
30133ad161aSMark McLoughlin         NETWORK_CONNECTIONS_KEY,
30233ad161aSMark McLoughlin         0,
30333ad161aSMark McLoughlin         KEY_READ,
30433ad161aSMark McLoughlin         &control_net_key);
30533ad161aSMark McLoughlin 
30633ad161aSMark McLoughlin     if (status != ERROR_SUCCESS) {
30733ad161aSMark McLoughlin         return -1;
30833ad161aSMark McLoughlin     }
30933ad161aSMark McLoughlin 
31033ad161aSMark McLoughlin     while (!stop)
31133ad161aSMark McLoughlin     {
31233ad161aSMark McLoughlin         char enum_name[256];
31333ad161aSMark McLoughlin         char connection_string[256];
31433ad161aSMark McLoughlin         HKEY connection_key;
31533ad161aSMark McLoughlin         char name_data[256];
31633ad161aSMark McLoughlin         DWORD name_type;
31733ad161aSMark McLoughlin         const char name_string[] = "Name";
31833ad161aSMark McLoughlin 
31933ad161aSMark McLoughlin         len = sizeof (enum_name);
32033ad161aSMark McLoughlin         status = RegEnumKeyEx(
32133ad161aSMark McLoughlin             control_net_key,
32233ad161aSMark McLoughlin             i,
32333ad161aSMark McLoughlin             enum_name,
32433ad161aSMark McLoughlin             &len,
32533ad161aSMark McLoughlin             NULL,
32633ad161aSMark McLoughlin             NULL,
32733ad161aSMark McLoughlin             NULL,
32833ad161aSMark McLoughlin             NULL);
32933ad161aSMark McLoughlin 
33033ad161aSMark McLoughlin         if (status == ERROR_NO_MORE_ITEMS)
33133ad161aSMark McLoughlin             break;
33233ad161aSMark McLoughlin         else if (status != ERROR_SUCCESS) {
33333ad161aSMark McLoughlin             return -1;
33433ad161aSMark McLoughlin         }
33533ad161aSMark McLoughlin 
33633ad161aSMark McLoughlin         snprintf(connection_string,
33733ad161aSMark McLoughlin              sizeof(connection_string),
33833ad161aSMark McLoughlin              "%s\\%s\\Connection",
33933ad161aSMark McLoughlin              NETWORK_CONNECTIONS_KEY, enum_name);
34033ad161aSMark McLoughlin 
34133ad161aSMark McLoughlin         status = RegOpenKeyEx(
34233ad161aSMark McLoughlin             HKEY_LOCAL_MACHINE,
34333ad161aSMark McLoughlin             connection_string,
34433ad161aSMark McLoughlin             0,
34533ad161aSMark McLoughlin             KEY_READ,
34633ad161aSMark McLoughlin             &connection_key);
34733ad161aSMark McLoughlin 
34833ad161aSMark McLoughlin         if (status == ERROR_SUCCESS) {
34933ad161aSMark McLoughlin             len = sizeof (name_data);
35033ad161aSMark McLoughlin             status = RegQueryValueEx(
35133ad161aSMark McLoughlin                 connection_key,
35233ad161aSMark McLoughlin                 name_string,
35333ad161aSMark McLoughlin                 NULL,
35433ad161aSMark McLoughlin                 &name_type,
35533ad161aSMark McLoughlin                 (LPBYTE)name_data,
35633ad161aSMark McLoughlin                 &len);
35733ad161aSMark McLoughlin 
35833ad161aSMark McLoughlin             if (status != ERROR_SUCCESS || name_type != REG_SZ) {
359*ee0428e3SAndrew Baumann                 ++i;
360*ee0428e3SAndrew Baumann                 continue;
36133ad161aSMark McLoughlin             }
36233ad161aSMark McLoughlin             else {
36333ad161aSMark McLoughlin                 if (is_tap_win32_dev(enum_name)) {
36433ad161aSMark McLoughlin                     snprintf(name, name_size, "%s", enum_name);
36533ad161aSMark McLoughlin                     if (actual_name) {
36633ad161aSMark McLoughlin                         if (strcmp(actual_name, "") != 0) {
36733ad161aSMark McLoughlin                             if (strcmp(name_data, actual_name) != 0) {
36833ad161aSMark McLoughlin                                 RegCloseKey (connection_key);
36933ad161aSMark McLoughlin                                 ++i;
37033ad161aSMark McLoughlin                                 continue;
37133ad161aSMark McLoughlin                             }
37233ad161aSMark McLoughlin                         }
37333ad161aSMark McLoughlin                         else {
37433ad161aSMark McLoughlin                             snprintf(actual_name, actual_name_size, "%s", name_data);
37533ad161aSMark McLoughlin                         }
37633ad161aSMark McLoughlin                     }
37733ad161aSMark McLoughlin                     stop = 1;
37833ad161aSMark McLoughlin                 }
37933ad161aSMark McLoughlin             }
38033ad161aSMark McLoughlin 
38133ad161aSMark McLoughlin             RegCloseKey (connection_key);
38233ad161aSMark McLoughlin         }
38333ad161aSMark McLoughlin         ++i;
38433ad161aSMark McLoughlin     }
38533ad161aSMark McLoughlin 
38633ad161aSMark McLoughlin     RegCloseKey (control_net_key);
38733ad161aSMark McLoughlin 
38833ad161aSMark McLoughlin     if (stop == 0)
38933ad161aSMark McLoughlin         return -1;
39033ad161aSMark McLoughlin 
39133ad161aSMark McLoughlin     return 0;
39233ad161aSMark McLoughlin }
39333ad161aSMark McLoughlin 
39433ad161aSMark McLoughlin static int tap_win32_set_status(HANDLE handle, int status)
39533ad161aSMark McLoughlin {
39633ad161aSMark McLoughlin     unsigned long len = 0;
39733ad161aSMark McLoughlin 
39833ad161aSMark McLoughlin     return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
39933ad161aSMark McLoughlin                 &status, sizeof (status),
40033ad161aSMark McLoughlin                 &status, sizeof (status), &len, NULL);
40133ad161aSMark McLoughlin }
40233ad161aSMark McLoughlin 
40333ad161aSMark McLoughlin static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle)
40433ad161aSMark McLoughlin {
40533ad161aSMark McLoughlin     overlapped->handle = handle;
40633ad161aSMark McLoughlin 
40733ad161aSMark McLoughlin     overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL);
40833ad161aSMark McLoughlin     overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
40933ad161aSMark McLoughlin 
41033ad161aSMark McLoughlin     overlapped->read_overlapped.Offset = 0;
41133ad161aSMark McLoughlin     overlapped->read_overlapped.OffsetHigh = 0;
41233ad161aSMark McLoughlin     overlapped->read_overlapped.hEvent = overlapped->read_event;
41333ad161aSMark McLoughlin 
41433ad161aSMark McLoughlin     overlapped->write_overlapped.Offset = 0;
41533ad161aSMark McLoughlin     overlapped->write_overlapped.OffsetHigh = 0;
41633ad161aSMark McLoughlin     overlapped->write_overlapped.hEvent = overlapped->write_event;
41733ad161aSMark McLoughlin 
41833ad161aSMark McLoughlin     InitializeCriticalSection(&overlapped->output_queue_cs);
41933ad161aSMark McLoughlin     InitializeCriticalSection(&overlapped->free_list_cs);
42033ad161aSMark McLoughlin 
42133ad161aSMark McLoughlin     overlapped->output_queue_semaphore = CreateSemaphore(
42233ad161aSMark McLoughlin         NULL,   // default security attributes
42333ad161aSMark McLoughlin         0,   // initial count
42433ad161aSMark McLoughlin         TUN_MAX_BUFFER_COUNT,   // maximum count
42533ad161aSMark McLoughlin         NULL);  // unnamed semaphore
42633ad161aSMark McLoughlin 
42733ad161aSMark McLoughlin     if(!overlapped->output_queue_semaphore)  {
42833ad161aSMark McLoughlin         fprintf(stderr, "error creating output queue semaphore!\n");
42933ad161aSMark McLoughlin     }
43033ad161aSMark McLoughlin 
43133ad161aSMark McLoughlin     overlapped->free_list_semaphore = CreateSemaphore(
43233ad161aSMark McLoughlin         NULL,   // default security attributes
43333ad161aSMark McLoughlin         TUN_MAX_BUFFER_COUNT,   // initial count
43433ad161aSMark McLoughlin         TUN_MAX_BUFFER_COUNT,   // maximum count
43533ad161aSMark McLoughlin         NULL);  // unnamed semaphore
43633ad161aSMark McLoughlin 
43733ad161aSMark McLoughlin     if(!overlapped->free_list_semaphore)  {
43833ad161aSMark McLoughlin         fprintf(stderr, "error creating free list semaphore!\n");
43933ad161aSMark McLoughlin     }
44033ad161aSMark McLoughlin 
44133ad161aSMark McLoughlin     overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL;
44233ad161aSMark McLoughlin 
44333ad161aSMark McLoughlin     {
44433ad161aSMark McLoughlin         unsigned index;
44533ad161aSMark McLoughlin         for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) {
44633ad161aSMark McLoughlin             tun_buffer_t* element = &overlapped->buffers[index];
44733ad161aSMark McLoughlin             element->next = overlapped->free_list;
44833ad161aSMark McLoughlin             overlapped->free_list = element;
44933ad161aSMark McLoughlin         }
45033ad161aSMark McLoughlin     }
45133ad161aSMark McLoughlin     /* To count buffers, initially no-signal. */
45233ad161aSMark McLoughlin     overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL);
45333ad161aSMark McLoughlin     if(!overlapped->tap_semaphore)
45433ad161aSMark McLoughlin         fprintf(stderr, "error creating tap_semaphore.\n");
45533ad161aSMark McLoughlin }
45633ad161aSMark McLoughlin 
45733ad161aSMark McLoughlin static int tap_win32_write(tap_win32_overlapped_t *overlapped,
45833ad161aSMark McLoughlin                            const void *buffer, unsigned long size)
45933ad161aSMark McLoughlin {
46033ad161aSMark McLoughlin     unsigned long write_size;
46133ad161aSMark McLoughlin     BOOL result;
46233ad161aSMark McLoughlin     DWORD error;
46333ad161aSMark McLoughlin 
46433ad161aSMark McLoughlin     result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped,
46533ad161aSMark McLoughlin                                   &write_size, FALSE);
46633ad161aSMark McLoughlin 
46733ad161aSMark McLoughlin     if (!result && GetLastError() == ERROR_IO_INCOMPLETE)
46833ad161aSMark McLoughlin         WaitForSingleObject(overlapped->write_event, INFINITE);
46933ad161aSMark McLoughlin 
47033ad161aSMark McLoughlin     result = WriteFile(overlapped->handle, buffer, size,
47133ad161aSMark McLoughlin                        &write_size, &overlapped->write_overlapped);
47233ad161aSMark McLoughlin 
47333ad161aSMark McLoughlin     if (!result) {
47433ad161aSMark McLoughlin         switch (error = GetLastError())
47533ad161aSMark McLoughlin         {
47633ad161aSMark McLoughlin         case ERROR_IO_PENDING:
47733ad161aSMark McLoughlin #ifndef TUN_ASYNCHRONOUS_WRITES
47833ad161aSMark McLoughlin             WaitForSingleObject(overlapped->write_event, INFINITE);
47933ad161aSMark McLoughlin #endif
48033ad161aSMark McLoughlin             break;
48133ad161aSMark McLoughlin         default:
48233ad161aSMark McLoughlin             return -1;
48333ad161aSMark McLoughlin         }
48433ad161aSMark McLoughlin     }
48533ad161aSMark McLoughlin 
486c3febae6SPavel Dovgaluk     return write_size;
48733ad161aSMark McLoughlin }
48833ad161aSMark McLoughlin 
48933ad161aSMark McLoughlin static DWORD WINAPI tap_win32_thread_entry(LPVOID param)
49033ad161aSMark McLoughlin {
49133ad161aSMark McLoughlin     tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param;
49233ad161aSMark McLoughlin     unsigned long read_size;
49333ad161aSMark McLoughlin     BOOL result;
49433ad161aSMark McLoughlin     DWORD dwError;
49533ad161aSMark McLoughlin     tun_buffer_t* buffer = get_buffer_from_free_list(overlapped);
49633ad161aSMark McLoughlin 
49733ad161aSMark McLoughlin 
49833ad161aSMark McLoughlin     for (;;) {
49933ad161aSMark McLoughlin         result = ReadFile(overlapped->handle,
50033ad161aSMark McLoughlin                           buffer->buffer,
50133ad161aSMark McLoughlin                           sizeof(buffer->buffer),
50233ad161aSMark McLoughlin                           &read_size,
50333ad161aSMark McLoughlin                           &overlapped->read_overlapped);
50433ad161aSMark McLoughlin         if (!result) {
50533ad161aSMark McLoughlin             dwError = GetLastError();
50633ad161aSMark McLoughlin             if (dwError == ERROR_IO_PENDING) {
50733ad161aSMark McLoughlin                 WaitForSingleObject(overlapped->read_event, INFINITE);
50833ad161aSMark McLoughlin                 result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped,
50933ad161aSMark McLoughlin                                               &read_size, FALSE);
51033ad161aSMark McLoughlin                 if (!result) {
51133ad161aSMark McLoughlin #ifdef DEBUG_TAP_WIN32
51233ad161aSMark McLoughlin                     LPVOID lpBuffer;
51333ad161aSMark McLoughlin                     dwError = GetLastError();
51433ad161aSMark McLoughlin                     FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
51533ad161aSMark McLoughlin                                    NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
51633ad161aSMark McLoughlin                                    (LPTSTR) & lpBuffer, 0, NULL );
51733ad161aSMark McLoughlin                     fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer);
51833ad161aSMark McLoughlin                     LocalFree( lpBuffer );
51933ad161aSMark McLoughlin #endif
52033ad161aSMark McLoughlin                 }
52133ad161aSMark McLoughlin             } else {
52233ad161aSMark McLoughlin #ifdef DEBUG_TAP_WIN32
52333ad161aSMark McLoughlin                 LPVOID lpBuffer;
52433ad161aSMark McLoughlin                 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
52533ad161aSMark McLoughlin                                NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
52633ad161aSMark McLoughlin                                (LPTSTR) & lpBuffer, 0, NULL );
52733ad161aSMark McLoughlin                 fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer);
52833ad161aSMark McLoughlin                 LocalFree( lpBuffer );
52933ad161aSMark McLoughlin #endif
53033ad161aSMark McLoughlin             }
53133ad161aSMark McLoughlin         }
53233ad161aSMark McLoughlin 
53333ad161aSMark McLoughlin         if(read_size > 0) {
53433ad161aSMark McLoughlin             buffer->read_size = read_size;
53533ad161aSMark McLoughlin             put_buffer_on_output_queue(overlapped, buffer);
53633ad161aSMark McLoughlin             ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL);
53733ad161aSMark McLoughlin             buffer = get_buffer_from_free_list(overlapped);
53833ad161aSMark McLoughlin         }
53933ad161aSMark McLoughlin     }
54033ad161aSMark McLoughlin 
54133ad161aSMark McLoughlin     return 0;
54233ad161aSMark McLoughlin }
54333ad161aSMark McLoughlin 
54433ad161aSMark McLoughlin static int tap_win32_read(tap_win32_overlapped_t *overlapped,
54533ad161aSMark McLoughlin                           uint8_t **pbuf, int max_size)
54633ad161aSMark McLoughlin {
54733ad161aSMark McLoughlin     int size = 0;
54833ad161aSMark McLoughlin 
54933ad161aSMark McLoughlin     tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped);
55033ad161aSMark McLoughlin 
55133ad161aSMark McLoughlin     if(buffer != NULL) {
55233ad161aSMark McLoughlin         *pbuf = buffer->buffer;
55333ad161aSMark McLoughlin         size = (int)buffer->read_size;
55433ad161aSMark McLoughlin         if(size > max_size) {
55533ad161aSMark McLoughlin             size = max_size;
55633ad161aSMark McLoughlin         }
55733ad161aSMark McLoughlin     }
55833ad161aSMark McLoughlin 
55933ad161aSMark McLoughlin     return size;
56033ad161aSMark McLoughlin }
56133ad161aSMark McLoughlin 
56233ad161aSMark McLoughlin static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
56333ad161aSMark McLoughlin                                   uint8_t *pbuf)
56433ad161aSMark McLoughlin {
56533ad161aSMark McLoughlin     tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
56633ad161aSMark McLoughlin     put_buffer_on_free_list(overlapped, buffer);
56733ad161aSMark McLoughlin }
56833ad161aSMark McLoughlin 
56933ad161aSMark McLoughlin static int tap_win32_open(tap_win32_overlapped_t **phandle,
570eac29d87SStefan Weil                           const char *preferred_name)
57133ad161aSMark McLoughlin {
57233ad161aSMark McLoughlin     char device_path[256];
57333ad161aSMark McLoughlin     char device_guid[0x100];
57433ad161aSMark McLoughlin     int rc;
57533ad161aSMark McLoughlin     HANDLE handle;
57633ad161aSMark McLoughlin     BOOL bret;
57733ad161aSMark McLoughlin     char name_buffer[0x100] = {0, };
57833ad161aSMark McLoughlin     struct {
57933ad161aSMark McLoughlin         unsigned long major;
58033ad161aSMark McLoughlin         unsigned long minor;
58133ad161aSMark McLoughlin         unsigned long debug;
58233ad161aSMark McLoughlin     } version;
58333ad161aSMark McLoughlin     DWORD version_len;
58433ad161aSMark McLoughlin     DWORD idThread;
58533ad161aSMark McLoughlin 
586eac29d87SStefan Weil     if (preferred_name != NULL) {
587eac29d87SStefan Weil         snprintf(name_buffer, sizeof(name_buffer), "%s", preferred_name);
588eac29d87SStefan Weil     }
58933ad161aSMark McLoughlin 
59033ad161aSMark McLoughlin     rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));
59133ad161aSMark McLoughlin     if (rc)
59233ad161aSMark McLoughlin         return -1;
59333ad161aSMark McLoughlin 
59433ad161aSMark McLoughlin     snprintf (device_path, sizeof(device_path), "%s%s%s",
59533ad161aSMark McLoughlin               USERMODEDEVICEDIR,
59633ad161aSMark McLoughlin               device_guid,
59733ad161aSMark McLoughlin               TAPSUFFIX);
59833ad161aSMark McLoughlin 
59933ad161aSMark McLoughlin     handle = CreateFile (
60033ad161aSMark McLoughlin         device_path,
60133ad161aSMark McLoughlin         GENERIC_READ | GENERIC_WRITE,
60233ad161aSMark McLoughlin         0,
60333ad161aSMark McLoughlin         0,
60433ad161aSMark McLoughlin         OPEN_EXISTING,
60533ad161aSMark McLoughlin         FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
60633ad161aSMark McLoughlin         0 );
60733ad161aSMark McLoughlin 
60833ad161aSMark McLoughlin     if (handle == INVALID_HANDLE_VALUE) {
60933ad161aSMark McLoughlin         return -1;
61033ad161aSMark McLoughlin     }
61133ad161aSMark McLoughlin 
61233ad161aSMark McLoughlin     bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
61333ad161aSMark McLoughlin                            &version, sizeof (version),
61433ad161aSMark McLoughlin                            &version, sizeof (version), &version_len, NULL);
61533ad161aSMark McLoughlin 
61633ad161aSMark McLoughlin     if (bret == FALSE) {
61733ad161aSMark McLoughlin         CloseHandle(handle);
61833ad161aSMark McLoughlin         return -1;
61933ad161aSMark McLoughlin     }
62033ad161aSMark McLoughlin 
62133ad161aSMark McLoughlin     if (!tap_win32_set_status(handle, TRUE)) {
62233ad161aSMark McLoughlin         return -1;
62333ad161aSMark McLoughlin     }
62433ad161aSMark McLoughlin 
62533ad161aSMark McLoughlin     tap_win32_overlapped_init(&tap_overlapped, handle);
62633ad161aSMark McLoughlin 
62733ad161aSMark McLoughlin     *phandle = &tap_overlapped;
62833ad161aSMark McLoughlin 
62949a2942dSBlue Swirl     CreateThread(NULL, 0, tap_win32_thread_entry,
63033ad161aSMark McLoughlin                  (LPVOID)&tap_overlapped, 0, &idThread);
63133ad161aSMark McLoughlin     return 0;
63233ad161aSMark McLoughlin }
63333ad161aSMark McLoughlin 
63433ad161aSMark McLoughlin /********************************************/
63533ad161aSMark McLoughlin 
63633ad161aSMark McLoughlin  typedef struct TAPState {
6374e68f7a0SStefan Hajnoczi      NetClientState nc;
63833ad161aSMark McLoughlin      tap_win32_overlapped_t *handle;
63933ad161aSMark McLoughlin  } TAPState;
64033ad161aSMark McLoughlin 
6414e68f7a0SStefan Hajnoczi static void tap_cleanup(NetClientState *nc)
64233ad161aSMark McLoughlin {
643dca91811SMark McLoughlin     TAPState *s = DO_UPCAST(TAPState, nc, nc);
64433ad161aSMark McLoughlin 
64533ad161aSMark McLoughlin     qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL);
64633ad161aSMark McLoughlin 
64733ad161aSMark McLoughlin     /* FIXME: need to kill thread and close file handle:
64833ad161aSMark McLoughlin        tap_win32_close(s);
64933ad161aSMark McLoughlin     */
65033ad161aSMark McLoughlin }
65133ad161aSMark McLoughlin 
6524e68f7a0SStefan Hajnoczi static ssize_t tap_receive(NetClientState *nc, const uint8_t *buf, size_t size)
65333ad161aSMark McLoughlin {
654dca91811SMark McLoughlin     TAPState *s = DO_UPCAST(TAPState, nc, nc);
65533ad161aSMark McLoughlin 
65633ad161aSMark McLoughlin     return tap_win32_write(s->handle, buf, size);
65733ad161aSMark McLoughlin }
65833ad161aSMark McLoughlin 
65933ad161aSMark McLoughlin static void tap_win32_send(void *opaque)
66033ad161aSMark McLoughlin {
66133ad161aSMark McLoughlin     TAPState *s = opaque;
66233ad161aSMark McLoughlin     uint8_t *buf;
66333ad161aSMark McLoughlin     int max_size = 4096;
66433ad161aSMark McLoughlin     int size;
66533ad161aSMark McLoughlin 
66633ad161aSMark McLoughlin     size = tap_win32_read(s->handle, &buf, max_size);
66733ad161aSMark McLoughlin     if (size > 0) {
668dca91811SMark McLoughlin         qemu_send_packet(&s->nc, buf, size);
66933ad161aSMark McLoughlin         tap_win32_free_buffer(s->handle, buf);
67033ad161aSMark McLoughlin     }
67133ad161aSMark McLoughlin }
67233ad161aSMark McLoughlin 
6733bac80d3SVincenzo Maffione static bool tap_has_ufo(NetClientState *nc)
6742e753bccSVincenzo Maffione {
6752e753bccSVincenzo Maffione     return false;
6762e753bccSVincenzo Maffione }
6772e753bccSVincenzo Maffione 
6783bac80d3SVincenzo Maffione static bool tap_has_vnet_hdr(NetClientState *nc)
6792e753bccSVincenzo Maffione {
6802e753bccSVincenzo Maffione     return false;
6812e753bccSVincenzo Maffione }
6822e753bccSVincenzo Maffione 
6832e753bccSVincenzo Maffione int tap_probe_vnet_hdr_len(int fd, int len)
6842e753bccSVincenzo Maffione {
6852e753bccSVincenzo Maffione     return 0;
6862e753bccSVincenzo Maffione }
6872e753bccSVincenzo Maffione 
6882e753bccSVincenzo Maffione void tap_fd_set_vnet_hdr_len(int fd, int len)
6892e753bccSVincenzo Maffione {
6902e753bccSVincenzo Maffione }
6912e753bccSVincenzo Maffione 
6924ee9b43bSMichael S. Tsirkin int tap_fd_set_vnet_le(int fd, int is_le)
6934ee9b43bSMichael S. Tsirkin {
6944ee9b43bSMichael S. Tsirkin     return -EINVAL;
6954ee9b43bSMichael S. Tsirkin }
6964ee9b43bSMichael S. Tsirkin 
6974ee9b43bSMichael S. Tsirkin int tap_fd_set_vnet_be(int fd, int is_be)
6984ee9b43bSMichael S. Tsirkin {
6994ee9b43bSMichael S. Tsirkin     return -EINVAL;
7004ee9b43bSMichael S. Tsirkin }
7014ee9b43bSMichael S. Tsirkin 
7023bac80d3SVincenzo Maffione static void tap_using_vnet_hdr(NetClientState *nc, bool using_vnet_hdr)
7032e753bccSVincenzo Maffione {
7042e753bccSVincenzo Maffione }
7052e753bccSVincenzo Maffione 
7063bac80d3SVincenzo Maffione static void tap_set_offload(NetClientState *nc, int csum, int tso4,
7072e753bccSVincenzo Maffione                      int tso6, int ecn, int ufo)
7082e753bccSVincenzo Maffione {
7092e753bccSVincenzo Maffione }
7102e753bccSVincenzo Maffione 
7112e753bccSVincenzo Maffione struct vhost_net *tap_get_vhost_net(NetClientState *nc)
7122e753bccSVincenzo Maffione {
7132e753bccSVincenzo Maffione     return NULL;
7142e753bccSVincenzo Maffione }
7152e753bccSVincenzo Maffione 
7163bac80d3SVincenzo Maffione static bool tap_has_vnet_hdr_len(NetClientState *nc, int len)
7172e753bccSVincenzo Maffione {
7182e753bccSVincenzo Maffione     return false;
7192e753bccSVincenzo Maffione }
7202e753bccSVincenzo Maffione 
7213bac80d3SVincenzo Maffione static void tap_set_vnet_hdr_len(NetClientState *nc, int len)
7222e753bccSVincenzo Maffione {
7232e753bccSVincenzo Maffione     abort();
7242e753bccSVincenzo Maffione }
7252e753bccSVincenzo Maffione 
726dca91811SMark McLoughlin static NetClientInfo net_tap_win32_info = {
7272be64a68SLaszlo Ersek     .type = NET_CLIENT_OPTIONS_KIND_TAP,
728dca91811SMark McLoughlin     .size = sizeof(TAPState),
729dca91811SMark McLoughlin     .receive = tap_receive,
730dca91811SMark McLoughlin     .cleanup = tap_cleanup,
7312e753bccSVincenzo Maffione     .has_ufo = tap_has_ufo,
7322e753bccSVincenzo Maffione     .has_vnet_hdr = tap_has_vnet_hdr,
7332e753bccSVincenzo Maffione     .has_vnet_hdr_len = tap_has_vnet_hdr_len,
7342e753bccSVincenzo Maffione     .using_vnet_hdr = tap_using_vnet_hdr,
7352e753bccSVincenzo Maffione     .set_offload = tap_set_offload,
7362e753bccSVincenzo Maffione     .set_vnet_hdr_len = tap_set_vnet_hdr_len,
737dca91811SMark McLoughlin };
738dca91811SMark McLoughlin 
7394e68f7a0SStefan Hajnoczi static int tap_win32_init(NetClientState *peer, const char *model,
74033ad161aSMark McLoughlin                           const char *name, const char *ifname)
74133ad161aSMark McLoughlin {
7424e68f7a0SStefan Hajnoczi     NetClientState *nc;
74333ad161aSMark McLoughlin     TAPState *s;
744dca91811SMark McLoughlin     tap_win32_overlapped_t *handle;
74533ad161aSMark McLoughlin 
746dca91811SMark McLoughlin     if (tap_win32_open(&handle, ifname) < 0) {
74733ad161aSMark McLoughlin         printf("tap: Could not open '%s'\n", ifname);
74833ad161aSMark McLoughlin         return -1;
74933ad161aSMark McLoughlin     }
75033ad161aSMark McLoughlin 
751ab5f3f84SStefan Hajnoczi     nc = qemu_new_net_client(&net_tap_win32_info, peer, model, name);
75233ad161aSMark McLoughlin 
75308fd0fa9SBlue Swirl     s = DO_UPCAST(TAPState, nc, nc);
75408fd0fa9SBlue Swirl 
755dca91811SMark McLoughlin     snprintf(s->nc.info_str, sizeof(s->nc.info_str),
75633ad161aSMark McLoughlin              "tap: ifname=%s", ifname);
75733ad161aSMark McLoughlin 
758dca91811SMark McLoughlin     s->handle = handle;
759dca91811SMark McLoughlin 
76033ad161aSMark McLoughlin     qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s);
761dca91811SMark McLoughlin 
76233ad161aSMark McLoughlin     return 0;
76333ad161aSMark McLoughlin }
764a8ed73f7SMark McLoughlin 
7651a0c0958SLaszlo Ersek int net_init_tap(const NetClientOptions *opts, const char *name,
766a30ecde6SMarkus Armbruster                  NetClientState *peer, Error **errp)
767a8ed73f7SMark McLoughlin {
768a30ecde6SMarkus Armbruster     /* FIXME error_setg(errp, ...) on failure */
76908c573a8SLaszlo Ersek     const NetdevTapOptions *tap;
770a8ed73f7SMark McLoughlin 
7718d0bcba8SEric Blake     assert(opts->type == NET_CLIENT_OPTIONS_KIND_TAP);
7728d0bcba8SEric Blake     tap = opts->u.tap;
773a8ed73f7SMark McLoughlin 
77408c573a8SLaszlo Ersek     if (!tap->has_ifname) {
7751ecda02bSMarkus Armbruster         error_report("tap: no interface name");
776a8ed73f7SMark McLoughlin         return -1;
777a8ed73f7SMark McLoughlin     }
778a8ed73f7SMark McLoughlin 
779d33d93b2SStefan Hajnoczi     if (tap_win32_init(peer, "tap", name, tap->ifname) == -1) {
780a8ed73f7SMark McLoughlin         return -1;
781a8ed73f7SMark McLoughlin     }
782a8ed73f7SMark McLoughlin 
783a8ed73f7SMark McLoughlin     return 0;
784a8ed73f7SMark McLoughlin }
785a8ed73f7SMark McLoughlin 
78616dbaf90SJason Wang int tap_enable(NetClientState *nc)
78716dbaf90SJason Wang {
78816dbaf90SJason Wang     abort();
78916dbaf90SJason Wang }
79016dbaf90SJason Wang 
79116dbaf90SJason Wang int tap_disable(NetClientState *nc)
79216dbaf90SJason Wang {
79316dbaf90SJason Wang     abort();
79416dbaf90SJason Wang }
795