Statistics
| Branch: | Revision:

root / net / tap-win32.c @ c3febae6

History | View | Annotate | Download (21.1 kB)

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 "net/tap.h"
30

    
31
#include "qemu-common.h"
32
#include "net.h"
33
#include "sysemu.h"
34
#include "qemu-error.h"
35
#include <stdio.h>
36
#include <windows.h>
37
#include <winioctl.h>
38

    
39
//=============
40
// TAP IOCTLs
41
//=============
42

    
43
#define TAP_CONTROL_CODE(request,method) \
44
  CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
45

    
46
#define TAP_IOCTL_GET_MAC               TAP_CONTROL_CODE (1, METHOD_BUFFERED)
47
#define TAP_IOCTL_GET_VERSION           TAP_CONTROL_CODE (2, METHOD_BUFFERED)
48
#define TAP_IOCTL_GET_MTU               TAP_CONTROL_CODE (3, METHOD_BUFFERED)
49
#define TAP_IOCTL_GET_INFO              TAP_CONTROL_CODE (4, METHOD_BUFFERED)
50
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
51
#define TAP_IOCTL_SET_MEDIA_STATUS      TAP_CONTROL_CODE (6, METHOD_BUFFERED)
52
#define TAP_IOCTL_CONFIG_DHCP_MASQ      TAP_CONTROL_CODE (7, METHOD_BUFFERED)
53
#define TAP_IOCTL_GET_LOG_LINE          TAP_CONTROL_CODE (8, METHOD_BUFFERED)
54
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT   TAP_CONTROL_CODE (9, METHOD_BUFFERED)
55

    
56
//=================
57
// Registry keys
58
//=================
59

    
60
#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
61

    
62
#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
63

    
64
//======================
65
// Filesystem prefixes
66
//======================
67

    
68
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
69
#define TAPSUFFIX         ".tap"
70

    
71

    
72
//======================
73
// Compile time configuration
74
//======================
75

    
76
//#define DEBUG_TAP_WIN32
77

    
78
#define TUN_ASYNCHRONOUS_WRITES 1
79

    
80
#define TUN_BUFFER_SIZE 1560
81
#define TUN_MAX_BUFFER_COUNT 32
82

    
83
/*
84
 * The data member "buffer" must be the first element in the tun_buffer
85
 * structure. See the function, tap_win32_free_buffer.
86
 */
87
typedef struct tun_buffer_s {
88
    unsigned char buffer [TUN_BUFFER_SIZE];
89
    unsigned long read_size;
90
    struct tun_buffer_s* next;
91
} tun_buffer_t;
92

    
93
typedef struct tap_win32_overlapped {
94
    HANDLE handle;
95
    HANDLE read_event;
96
    HANDLE write_event;
97
    HANDLE output_queue_semaphore;
98
    HANDLE free_list_semaphore;
99
    HANDLE tap_semaphore;
100
    CRITICAL_SECTION output_queue_cs;
101
    CRITICAL_SECTION free_list_cs;
102
    OVERLAPPED read_overlapped;
103
    OVERLAPPED write_overlapped;
104
    tun_buffer_t buffers[TUN_MAX_BUFFER_COUNT];
105
    tun_buffer_t* free_list;
106
    tun_buffer_t* output_queue_front;
107
    tun_buffer_t* output_queue_back;
108
} tap_win32_overlapped_t;
109

    
110
static tap_win32_overlapped_t tap_overlapped;
111

    
112
static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped)
113
{
114
    tun_buffer_t* buffer = NULL;
115
    WaitForSingleObject(overlapped->free_list_semaphore, INFINITE);
116
    EnterCriticalSection(&overlapped->free_list_cs);
117
    buffer = overlapped->free_list;
118
//    assert(buffer != NULL);
119
    overlapped->free_list = buffer->next;
120
    LeaveCriticalSection(&overlapped->free_list_cs);
121
    buffer->next = NULL;
122
    return buffer;
123
}
124

    
125
static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
126
{
127
    EnterCriticalSection(&overlapped->free_list_cs);
128
    buffer->next = overlapped->free_list;
129
    overlapped->free_list = buffer;
130
    LeaveCriticalSection(&overlapped->free_list_cs);
131
    ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL);
132
}
133

    
134
static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block)
135
{
136
    tun_buffer_t* buffer = NULL;
137
    DWORD result, timeout = block ? INFINITE : 0L;
138

    
139
    // Non-blocking call
140
    result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout);
141

    
142
    switch (result)
143
    {
144
        // The semaphore object was signaled.
145
        case WAIT_OBJECT_0:
146
            EnterCriticalSection(&overlapped->output_queue_cs);
147

    
148
            buffer = overlapped->output_queue_front;
149
            overlapped->output_queue_front = buffer->next;
150

    
151
            if(overlapped->output_queue_front == NULL) {
152
                overlapped->output_queue_back = NULL;
153
            }
154

    
155
            LeaveCriticalSection(&overlapped->output_queue_cs);
156
            break;
157

    
158
        // Semaphore was nonsignaled, so a time-out occurred.
159
        case WAIT_TIMEOUT:
160
            // Cannot open another window.
161
            break;
162
    }
163

    
164
    return buffer;
165
}
166

    
167
static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped)
168
{
169
    return get_buffer_from_output_queue(overlapped, 0);
170
}
171

    
172
static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
173
{
174
    EnterCriticalSection(&overlapped->output_queue_cs);
175

    
176
    if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) {
177
        overlapped->output_queue_front = overlapped->output_queue_back = buffer;
178
    } else {
179
        buffer->next = NULL;
180
        overlapped->output_queue_back->next = buffer;
181
        overlapped->output_queue_back = buffer;
182
    }
183

    
184
    LeaveCriticalSection(&overlapped->output_queue_cs);
185

    
186
    ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL);
187
}
188

    
189

    
190
static int is_tap_win32_dev(const char *guid)
191
{
192
    HKEY netcard_key;
193
    LONG status;
194
    DWORD len;
195
    int i = 0;
196

    
197
    status = RegOpenKeyEx(
198
        HKEY_LOCAL_MACHINE,
199
        ADAPTER_KEY,
200
        0,
201
        KEY_READ,
202
        &netcard_key);
203

    
204
    if (status != ERROR_SUCCESS) {
205
        return FALSE;
206
    }
207

    
208
    for (;;) {
209
        char enum_name[256];
210
        char unit_string[256];
211
        HKEY unit_key;
212
        char component_id_string[] = "ComponentId";
213
        char component_id[256];
214
        char net_cfg_instance_id_string[] = "NetCfgInstanceId";
215
        char net_cfg_instance_id[256];
216
        DWORD data_type;
217

    
218
        len = sizeof (enum_name);
219
        status = RegEnumKeyEx(
220
            netcard_key,
221
            i,
222
            enum_name,
223
            &len,
224
            NULL,
225
            NULL,
226
            NULL,
227
            NULL);
228

    
229
        if (status == ERROR_NO_MORE_ITEMS)
230
            break;
231
        else if (status != ERROR_SUCCESS) {
232
            return FALSE;
233
        }
234

    
235
        snprintf (unit_string, sizeof(unit_string), "%s\\%s",
236
                  ADAPTER_KEY, enum_name);
237

    
238
        status = RegOpenKeyEx(
239
            HKEY_LOCAL_MACHINE,
240
            unit_string,
241
            0,
242
            KEY_READ,
243
            &unit_key);
244

    
245
        if (status != ERROR_SUCCESS) {
246
            return FALSE;
247
        } else {
248
            len = sizeof (component_id);
249
            status = RegQueryValueEx(
250
                unit_key,
251
                component_id_string,
252
                NULL,
253
                &data_type,
254
                (LPBYTE)component_id,
255
                &len);
256

    
257
            if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
258
                len = sizeof (net_cfg_instance_id);
259
                status = RegQueryValueEx(
260
                    unit_key,
261
                    net_cfg_instance_id_string,
262
                    NULL,
263
                    &data_type,
264
                    (LPBYTE)net_cfg_instance_id,
265
                    &len);
266

    
267
                if (status == ERROR_SUCCESS && data_type == REG_SZ) {
268
                    if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/
269
                        !strcmp (net_cfg_instance_id, guid)) {
270
                        RegCloseKey (unit_key);
271
                        RegCloseKey (netcard_key);
272
                        return TRUE;
273
                    }
274
                }
275
            }
276
            RegCloseKey (unit_key);
277
        }
278
        ++i;
279
    }
280

    
281
    RegCloseKey (netcard_key);
282
    return FALSE;
283
}
284

    
285
static int get_device_guid(
286
    char *name,
287
    int name_size,
288
    char *actual_name,
289
    int actual_name_size)
290
{
291
    LONG status;
292
    HKEY control_net_key;
293
    DWORD len;
294
    int i = 0;
295
    int stop = 0;
296

    
297
    status = RegOpenKeyEx(
298
        HKEY_LOCAL_MACHINE,
299
        NETWORK_CONNECTIONS_KEY,
300
        0,
301
        KEY_READ,
302
        &control_net_key);
303

    
304
    if (status != ERROR_SUCCESS) {
305
        return -1;
306
    }
307

    
308
    while (!stop)
309
    {
310
        char enum_name[256];
311
        char connection_string[256];
312
        HKEY connection_key;
313
        char name_data[256];
314
        DWORD name_type;
315
        const char name_string[] = "Name";
316

    
317
        len = sizeof (enum_name);
318
        status = RegEnumKeyEx(
319
            control_net_key,
320
            i,
321
            enum_name,
322
            &len,
323
            NULL,
324
            NULL,
325
            NULL,
326
            NULL);
327

    
328
        if (status == ERROR_NO_MORE_ITEMS)
329
            break;
330
        else if (status != ERROR_SUCCESS) {
331
            return -1;
332
        }
333

    
334
        snprintf(connection_string,
335
             sizeof(connection_string),
336
             "%s\\%s\\Connection",
337
             NETWORK_CONNECTIONS_KEY, enum_name);
338

    
339
        status = RegOpenKeyEx(
340
            HKEY_LOCAL_MACHINE,
341
            connection_string,
342
            0,
343
            KEY_READ,
344
            &connection_key);
345

    
346
        if (status == ERROR_SUCCESS) {
347
            len = sizeof (name_data);
348
            status = RegQueryValueEx(
349
                connection_key,
350
                name_string,
351
                NULL,
352
                &name_type,
353
                (LPBYTE)name_data,
354
                &len);
355

    
356
            if (status != ERROR_SUCCESS || name_type != REG_SZ) {
357
                    return -1;
358
            }
359
            else {
360
                if (is_tap_win32_dev(enum_name)) {
361
                    snprintf(name, name_size, "%s", enum_name);
362
                    if (actual_name) {
363
                        if (strcmp(actual_name, "") != 0) {
364
                            if (strcmp(name_data, actual_name) != 0) {
365
                                RegCloseKey (connection_key);
366
                                ++i;
367
                                continue;
368
                            }
369
                        }
370
                        else {
371
                            snprintf(actual_name, actual_name_size, "%s", name_data);
372
                        }
373
                    }
374
                    stop = 1;
375
                }
376
            }
377

    
378
            RegCloseKey (connection_key);
379
        }
380
        ++i;
381
    }
382

    
383
    RegCloseKey (control_net_key);
384

    
385
    if (stop == 0)
386
        return -1;
387

    
388
    return 0;
389
}
390

    
391
static int tap_win32_set_status(HANDLE handle, int status)
392
{
393
    unsigned long len = 0;
394

    
395
    return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
396
                &status, sizeof (status),
397
                &status, sizeof (status), &len, NULL);
398
}
399

    
400
static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle)
401
{
402
    overlapped->handle = handle;
403

    
404
    overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL);
405
    overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
406

    
407
    overlapped->read_overlapped.Offset = 0;
408
    overlapped->read_overlapped.OffsetHigh = 0;
409
    overlapped->read_overlapped.hEvent = overlapped->read_event;
410

    
411
    overlapped->write_overlapped.Offset = 0;
412
    overlapped->write_overlapped.OffsetHigh = 0;
413
    overlapped->write_overlapped.hEvent = overlapped->write_event;
414

    
415
    InitializeCriticalSection(&overlapped->output_queue_cs);
416
    InitializeCriticalSection(&overlapped->free_list_cs);
417

    
418
    overlapped->output_queue_semaphore = CreateSemaphore(
419
        NULL,   // default security attributes
420
        0,   // initial count
421
        TUN_MAX_BUFFER_COUNT,   // maximum count
422
        NULL);  // unnamed semaphore
423

    
424
    if(!overlapped->output_queue_semaphore)  {
425
        fprintf(stderr, "error creating output queue semaphore!\n");
426
    }
427

    
428
    overlapped->free_list_semaphore = CreateSemaphore(
429
        NULL,   // default security attributes
430
        TUN_MAX_BUFFER_COUNT,   // initial count
431
        TUN_MAX_BUFFER_COUNT,   // maximum count
432
        NULL);  // unnamed semaphore
433

    
434
    if(!overlapped->free_list_semaphore)  {
435
        fprintf(stderr, "error creating free list semaphore!\n");
436
    }
437

    
438
    overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL;
439

    
440
    {
441
        unsigned index;
442
        for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) {
443
            tun_buffer_t* element = &overlapped->buffers[index];
444
            element->next = overlapped->free_list;
445
            overlapped->free_list = element;
446
        }
447
    }
448
    /* To count buffers, initially no-signal. */
449
    overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL);
450
    if(!overlapped->tap_semaphore)
451
        fprintf(stderr, "error creating tap_semaphore.\n");
452
}
453

    
454
static int tap_win32_write(tap_win32_overlapped_t *overlapped,
455
                           const void *buffer, unsigned long size)
456
{
457
    unsigned long write_size;
458
    BOOL result;
459
    DWORD error;
460

    
461
    result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped,
462
                                  &write_size, FALSE);
463

    
464
    if (!result && GetLastError() == ERROR_IO_INCOMPLETE)
465
        WaitForSingleObject(overlapped->write_event, INFINITE);
466

    
467
    result = WriteFile(overlapped->handle, buffer, size,
468
                       &write_size, &overlapped->write_overlapped);
469

    
470
    if (!result) {
471
        switch (error = GetLastError())
472
        {
473
        case ERROR_IO_PENDING:
474
#ifndef TUN_ASYNCHRONOUS_WRITES
475
            WaitForSingleObject(overlapped->write_event, INFINITE);
476
#endif
477
            break;
478
        default:
479
            return -1;
480
        }
481
    }
482

    
483
    return write_size;
484
}
485

    
486
static DWORD WINAPI tap_win32_thread_entry(LPVOID param)
487
{
488
    tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param;
489
    unsigned long read_size;
490
    BOOL result;
491
    DWORD dwError;
492
    tun_buffer_t* buffer = get_buffer_from_free_list(overlapped);
493

    
494

    
495
    for (;;) {
496
        result = ReadFile(overlapped->handle,
497
                          buffer->buffer,
498
                          sizeof(buffer->buffer),
499
                          &read_size,
500
                          &overlapped->read_overlapped);
501
        if (!result) {
502
            dwError = GetLastError();
503
            if (dwError == ERROR_IO_PENDING) {
504
                WaitForSingleObject(overlapped->read_event, INFINITE);
505
                result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped,
506
                                              &read_size, FALSE);
507
                if (!result) {
508
#ifdef DEBUG_TAP_WIN32
509
                    LPVOID lpBuffer;
510
                    dwError = GetLastError();
511
                    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
512
                                   NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
513
                                   (LPTSTR) & lpBuffer, 0, NULL );
514
                    fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer);
515
                    LocalFree( lpBuffer );
516
#endif
517
                }
518
            } else {
519
#ifdef DEBUG_TAP_WIN32
520
                LPVOID lpBuffer;
521
                FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
522
                               NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
523
                               (LPTSTR) & lpBuffer, 0, NULL );
524
                fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer);
525
                LocalFree( lpBuffer );
526
#endif
527
            }
528
        }
529

    
530
        if(read_size > 0) {
531
            buffer->read_size = read_size;
532
            put_buffer_on_output_queue(overlapped, buffer);
533
            ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL);
534
            buffer = get_buffer_from_free_list(overlapped);
535
        }
536
    }
537

    
538
    return 0;
539
}
540

    
541
static int tap_win32_read(tap_win32_overlapped_t *overlapped,
542
                          uint8_t **pbuf, int max_size)
543
{
544
    int size = 0;
545

    
546
    tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped);
547

    
548
    if(buffer != NULL) {
549
        *pbuf = buffer->buffer;
550
        size = (int)buffer->read_size;
551
        if(size > max_size) {
552
            size = max_size;
553
        }
554
    }
555

    
556
    return size;
557
}
558

    
559
static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
560
                                  uint8_t *pbuf)
561
{
562
    tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
563
    put_buffer_on_free_list(overlapped, buffer);
564
}
565

    
566
static int tap_win32_open(tap_win32_overlapped_t **phandle,
567
                          const char *prefered_name)
568
{
569
    char device_path[256];
570
    char device_guid[0x100];
571
    int rc;
572
    HANDLE handle;
573
    BOOL bret;
574
    char name_buffer[0x100] = {0, };
575
    struct {
576
        unsigned long major;
577
        unsigned long minor;
578
        unsigned long debug;
579
    } version;
580
    DWORD version_len;
581
    DWORD idThread;
582

    
583
    if (prefered_name != NULL)
584
        snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name);
585

    
586
    rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));
587
    if (rc)
588
        return -1;
589

    
590
    snprintf (device_path, sizeof(device_path), "%s%s%s",
591
              USERMODEDEVICEDIR,
592
              device_guid,
593
              TAPSUFFIX);
594

    
595
    handle = CreateFile (
596
        device_path,
597
        GENERIC_READ | GENERIC_WRITE,
598
        0,
599
        0,
600
        OPEN_EXISTING,
601
        FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
602
        0 );
603

    
604
    if (handle == INVALID_HANDLE_VALUE) {
605
        return -1;
606
    }
607

    
608
    bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
609
                           &version, sizeof (version),
610
                           &version, sizeof (version), &version_len, NULL);
611

    
612
    if (bret == FALSE) {
613
        CloseHandle(handle);
614
        return -1;
615
    }
616

    
617
    if (!tap_win32_set_status(handle, TRUE)) {
618
        return -1;
619
    }
620

    
621
    tap_win32_overlapped_init(&tap_overlapped, handle);
622

    
623
    *phandle = &tap_overlapped;
624

    
625
    CreateThread(NULL, 0, tap_win32_thread_entry,
626
                 (LPVOID)&tap_overlapped, 0, &idThread);
627
    return 0;
628
}
629

    
630
/********************************************/
631

    
632
 typedef struct TAPState {
633
     VLANClientState nc;
634
     tap_win32_overlapped_t *handle;
635
 } TAPState;
636

    
637
static void tap_cleanup(VLANClientState *nc)
638
{
639
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
640

    
641
    qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL);
642

    
643
    /* FIXME: need to kill thread and close file handle:
644
       tap_win32_close(s);
645
    */
646
}
647

    
648
static ssize_t tap_receive(VLANClientState *nc, const uint8_t *buf, size_t size)
649
{
650
    TAPState *s = DO_UPCAST(TAPState, nc, nc);
651

    
652
    return tap_win32_write(s->handle, buf, size);
653
}
654

    
655
static void tap_win32_send(void *opaque)
656
{
657
    TAPState *s = opaque;
658
    uint8_t *buf;
659
    int max_size = 4096;
660
    int size;
661

    
662
    size = tap_win32_read(s->handle, &buf, max_size);
663
    if (size > 0) {
664
        qemu_send_packet(&s->nc, buf, size);
665
        tap_win32_free_buffer(s->handle, buf);
666
    }
667
}
668

    
669
static NetClientInfo net_tap_win32_info = {
670
    .type = NET_CLIENT_TYPE_TAP,
671
    .size = sizeof(TAPState),
672
    .receive = tap_receive,
673
    .cleanup = tap_cleanup,
674
};
675

    
676
static int tap_win32_init(VLANState *vlan, const char *model,
677
                          const char *name, const char *ifname)
678
{
679
    VLANClientState *nc;
680
    TAPState *s;
681
    tap_win32_overlapped_t *handle;
682

    
683
    if (tap_win32_open(&handle, ifname) < 0) {
684
        printf("tap: Could not open '%s'\n", ifname);
685
        return -1;
686
    }
687

    
688
    nc = qemu_new_net_client(&net_tap_win32_info, vlan, NULL, model, name);
689

    
690
    s = DO_UPCAST(TAPState, nc, nc);
691

    
692
    snprintf(s->nc.info_str, sizeof(s->nc.info_str),
693
             "tap: ifname=%s", ifname);
694

    
695
    s->handle = handle;
696

    
697
    qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s);
698

    
699
    return 0;
700
}
701

    
702
int net_init_tap(QemuOpts *opts, Monitor *mon, const char *name, VLANState *vlan)
703
{
704
    const char *ifname;
705

    
706
    ifname = qemu_opt_get(opts, "ifname");
707

    
708
    if (!ifname) {
709
        error_report("tap: no interface name");
710
        return -1;
711
    }
712

    
713
    if (tap_win32_init(vlan, "tap", name, ifname) == -1) {
714
        return -1;
715
    }
716

    
717
    return 0;
718
}
719

    
720
int tap_has_ufo(VLANClientState *vc)
721
{
722
    return 0;
723
}
724

    
725
int tap_has_vnet_hdr(VLANClientState *vc)
726
{
727
    return 0;
728
}
729

    
730
int tap_probe_vnet_hdr_len(int fd, int len)
731
{
732
    return 0;
733
}
734

    
735
void tap_fd_set_vnet_hdr_len(int fd, int len)
736
{
737
}
738

    
739
void tap_using_vnet_hdr(VLANClientState *vc, int using_vnet_hdr)
740
{
741
}
742

    
743
void tap_set_offload(VLANClientState *vc, int csum, int tso4,
744
                     int tso6, int ecn, int ufo)
745
{
746
}
747

    
748
struct vhost_net *tap_get_vhost_net(VLANClientState *nc)
749
{
750
    return NULL;
751
}