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