Statistics
| Branch: | Revision:

root / tap-win32.c @ 09d85fb8

History | View | Annotate | Download (20.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
#include "qemu-common.h"
29
#include "net.h"
30
#include "sysemu.h"
31
#include <stdio.h>
32
#include <windows.h>
33
#include <winioctl.h>
34

    
35
//=============
36
// TAP IOCTLs
37
//=============
38

    
39
#define TAP_CONTROL_CODE(request,method) \
40
  CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
41

    
42
#define TAP_IOCTL_GET_MAC               TAP_CONTROL_CODE (1, METHOD_BUFFERED)
43
#define TAP_IOCTL_GET_VERSION           TAP_CONTROL_CODE (2, METHOD_BUFFERED)
44
#define TAP_IOCTL_GET_MTU               TAP_CONTROL_CODE (3, METHOD_BUFFERED)
45
#define TAP_IOCTL_GET_INFO              TAP_CONTROL_CODE (4, METHOD_BUFFERED)
46
#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
47
#define TAP_IOCTL_SET_MEDIA_STATUS      TAP_CONTROL_CODE (6, METHOD_BUFFERED)
48
#define TAP_IOCTL_CONFIG_DHCP_MASQ      TAP_CONTROL_CODE (7, METHOD_BUFFERED)
49
#define TAP_IOCTL_GET_LOG_LINE          TAP_CONTROL_CODE (8, METHOD_BUFFERED)
50
#define TAP_IOCTL_CONFIG_DHCP_SET_OPT   TAP_CONTROL_CODE (9, METHOD_BUFFERED)
51

    
52
//=================
53
// Registry keys
54
//=================
55

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

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

    
60
//======================
61
// Filesystem prefixes
62
//======================
63

    
64
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
65
#define TAPSUFFIX         ".tap"
66

    
67

    
68
//======================
69
// Compile time configuration
70
//======================
71

    
72
//#define DEBUG_TAP_WIN32
73

    
74
#define TUN_ASYNCHRONOUS_WRITES 1
75

    
76
#define TUN_BUFFER_SIZE 1560
77
#define TUN_MAX_BUFFER_COUNT 32
78

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

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

    
106
static tap_win32_overlapped_t tap_overlapped;
107

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

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

    
130
static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block)
131
{
132
    tun_buffer_t* buffer = NULL;
133
    DWORD result, timeout = block ? INFINITE : 0L;
134

    
135
    // Non-blocking call
136
    result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout);
137

    
138
    switch (result)
139
    {
140
        // The semaphore object was signaled.
141
        case WAIT_OBJECT_0:
142
            EnterCriticalSection(&overlapped->output_queue_cs);
143

    
144
            buffer = overlapped->output_queue_front;
145
            overlapped->output_queue_front = buffer->next;
146

    
147
            if(overlapped->output_queue_front == NULL) {
148
                overlapped->output_queue_back = NULL;
149
            }
150

    
151
            LeaveCriticalSection(&overlapped->output_queue_cs);
152
            break;
153

    
154
        // Semaphore was nonsignaled, so a time-out occurred.
155
        case WAIT_TIMEOUT:
156
            // Cannot open another window.
157
            break;
158
    }
159

    
160
    return buffer;
161
}
162

    
163
static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped)
164
{
165
    return get_buffer_from_output_queue(overlapped, 0);
166
}
167

    
168
static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
169
{
170
    EnterCriticalSection(&overlapped->output_queue_cs);
171

    
172
    if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) {
173
        overlapped->output_queue_front = overlapped->output_queue_back = buffer;
174
    } else {
175
        buffer->next = NULL;
176
        overlapped->output_queue_back->next = buffer;
177
        overlapped->output_queue_back = buffer;
178
    }
179

    
180
    LeaveCriticalSection(&overlapped->output_queue_cs);
181

    
182
    ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL);
183
}
184

    
185

    
186
static int is_tap_win32_dev(const char *guid)
187
{
188
    HKEY netcard_key;
189
    LONG status;
190
    DWORD len;
191
    int i = 0;
192

    
193
    status = RegOpenKeyEx(
194
        HKEY_LOCAL_MACHINE,
195
        ADAPTER_KEY,
196
        0,
197
        KEY_READ,
198
        &netcard_key);
199

    
200
    if (status != ERROR_SUCCESS) {
201
        return FALSE;
202
    }
203

    
204
    for (;;) {
205
        char enum_name[256];
206
        char unit_string[256];
207
        HKEY unit_key;
208
        char component_id_string[] = "ComponentId";
209
        char component_id[256];
210
        char net_cfg_instance_id_string[] = "NetCfgInstanceId";
211
        char net_cfg_instance_id[256];
212
        DWORD data_type;
213

    
214
        len = sizeof (enum_name);
215
        status = RegEnumKeyEx(
216
            netcard_key,
217
            i,
218
            enum_name,
219
            &len,
220
            NULL,
221
            NULL,
222
            NULL,
223
            NULL);
224

    
225
        if (status == ERROR_NO_MORE_ITEMS)
226
            break;
227
        else if (status != ERROR_SUCCESS) {
228
            return FALSE;
229
        }
230

    
231
        snprintf (unit_string, sizeof(unit_string), "%s\\%s",
232
                  ADAPTER_KEY, enum_name);
233

    
234
        status = RegOpenKeyEx(
235
            HKEY_LOCAL_MACHINE,
236
            unit_string,
237
            0,
238
            KEY_READ,
239
            &unit_key);
240

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

    
253
            if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
254
                len = sizeof (net_cfg_instance_id);
255
                status = RegQueryValueEx(
256
                    unit_key,
257
                    net_cfg_instance_id_string,
258
                    NULL,
259
                    &data_type,
260
                    (LPBYTE)net_cfg_instance_id,
261
                    &len);
262

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

    
277
    RegCloseKey (netcard_key);
278
    return FALSE;
279
}
280

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

    
293
    status = RegOpenKeyEx(
294
        HKEY_LOCAL_MACHINE,
295
        NETWORK_CONNECTIONS_KEY,
296
        0,
297
        KEY_READ,
298
        &control_net_key);
299

    
300
    if (status != ERROR_SUCCESS) {
301
        return -1;
302
    }
303

    
304
    while (!stop)
305
    {
306
        char enum_name[256];
307
        char connection_string[256];
308
        HKEY connection_key;
309
        char name_data[256];
310
        DWORD name_type;
311
        const char name_string[] = "Name";
312

    
313
        len = sizeof (enum_name);
314
        status = RegEnumKeyEx(
315
            control_net_key,
316
            i,
317
            enum_name,
318
            &len,
319
            NULL,
320
            NULL,
321
            NULL,
322
            NULL);
323

    
324
        if (status == ERROR_NO_MORE_ITEMS)
325
            break;
326
        else if (status != ERROR_SUCCESS) {
327
            return -1;
328
        }
329

    
330
        snprintf(connection_string,
331
             sizeof(connection_string),
332
             "%s\\%s\\Connection",
333
             NETWORK_CONNECTIONS_KEY, enum_name);
334

    
335
        status = RegOpenKeyEx(
336
            HKEY_LOCAL_MACHINE,
337
            connection_string,
338
            0,
339
            KEY_READ,
340
            &connection_key);
341

    
342
        if (status == ERROR_SUCCESS) {
343
            len = sizeof (name_data);
344
            status = RegQueryValueEx(
345
                connection_key,
346
                name_string,
347
                NULL,
348
                &name_type,
349
                (LPBYTE)name_data,
350
                &len);
351

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

    
374
            RegCloseKey (connection_key);
375
        }
376
        ++i;
377
    }
378

    
379
    RegCloseKey (control_net_key);
380

    
381
    if (stop == 0)
382
        return -1;
383

    
384
    return 0;
385
}
386

    
387
static int tap_win32_set_status(HANDLE handle, int status)
388
{
389
    unsigned long len = 0;
390

    
391
    return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
392
                &status, sizeof (status),
393
                &status, sizeof (status), &len, NULL);
394
}
395

    
396
static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle)
397
{
398
    overlapped->handle = handle;
399

    
400
    overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL);
401
    overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
402

    
403
    overlapped->read_overlapped.Offset = 0;
404
    overlapped->read_overlapped.OffsetHigh = 0;
405
    overlapped->read_overlapped.hEvent = overlapped->read_event;
406

    
407
    overlapped->write_overlapped.Offset = 0;
408
    overlapped->write_overlapped.OffsetHigh = 0;
409
    overlapped->write_overlapped.hEvent = overlapped->write_event;
410

    
411
    InitializeCriticalSection(&overlapped->output_queue_cs);
412
    InitializeCriticalSection(&overlapped->free_list_cs);
413

    
414
    overlapped->output_queue_semaphore = CreateSemaphore(
415
        NULL,   // default security attributes
416
        0,   // initial count
417
        TUN_MAX_BUFFER_COUNT,   // maximum count
418
        NULL);  // unnamed semaphore
419

    
420
    if(!overlapped->output_queue_semaphore)  {
421
        fprintf(stderr, "error creating output queue semaphore!\n");
422
    }
423

    
424
    overlapped->free_list_semaphore = CreateSemaphore(
425
        NULL,   // default security attributes
426
        TUN_MAX_BUFFER_COUNT,   // initial count
427
        TUN_MAX_BUFFER_COUNT,   // maximum count
428
        NULL);  // unnamed semaphore
429

    
430
    if(!overlapped->free_list_semaphore)  {
431
        fprintf(stderr, "error creating free list semaphore!\n");
432
    }
433

    
434
    overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL;
435

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

    
450
static int tap_win32_write(tap_win32_overlapped_t *overlapped,
451
                           const void *buffer, unsigned long size)
452
{
453
    unsigned long write_size;
454
    BOOL result;
455
    DWORD error;
456

    
457
    result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped,
458
                                  &write_size, FALSE);
459

    
460
    if (!result && GetLastError() == ERROR_IO_INCOMPLETE)
461
        WaitForSingleObject(overlapped->write_event, INFINITE);
462

    
463
    result = WriteFile(overlapped->handle, buffer, size,
464
                       &write_size, &overlapped->write_overlapped);
465

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

    
479
    return 0;
480
}
481

    
482
static DWORD WINAPI tap_win32_thread_entry(LPVOID param)
483
{
484
    tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param;
485
    unsigned long read_size;
486
    BOOL result;
487
    DWORD dwError;
488
    tun_buffer_t* buffer = get_buffer_from_free_list(overlapped);
489

    
490

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

    
526
        if(read_size > 0) {
527
            buffer->read_size = read_size;
528
            put_buffer_on_output_queue(overlapped, buffer);
529
            ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL);
530
            buffer = get_buffer_from_free_list(overlapped);
531
        }
532
    }
533

    
534
    return 0;
535
}
536

    
537
static int tap_win32_read(tap_win32_overlapped_t *overlapped,
538
                          uint8_t **pbuf, int max_size)
539
{
540
    int size = 0;
541

    
542
    tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped);
543

    
544
    if(buffer != NULL) {
545
        *pbuf = buffer->buffer;
546
        size = (int)buffer->read_size;
547
        if(size > max_size) {
548
            size = max_size;
549
        }
550
    }
551

    
552
    return size;
553
}
554

    
555
static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
556
                                  uint8_t *pbuf)
557
{
558
    tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
559
    put_buffer_on_free_list(overlapped, buffer);
560
}
561

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

    
580
    if (prefered_name != NULL)
581
        snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name);
582

    
583
    rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));
584
    if (rc)
585
        return -1;
586

    
587
    snprintf (device_path, sizeof(device_path), "%s%s%s",
588
              USERMODEDEVICEDIR,
589
              device_guid,
590
              TAPSUFFIX);
591

    
592
    handle = CreateFile (
593
        device_path,
594
        GENERIC_READ | GENERIC_WRITE,
595
        0,
596
        0,
597
        OPEN_EXISTING,
598
        FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
599
        0 );
600

    
601
    if (handle == INVALID_HANDLE_VALUE) {
602
        return -1;
603
    }
604

    
605
    bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
606
                           &version, sizeof (version),
607
                           &version, sizeof (version), &version_len, NULL);
608

    
609
    if (bret == FALSE) {
610
        CloseHandle(handle);
611
        return -1;
612
    }
613

    
614
    if (!tap_win32_set_status(handle, TRUE)) {
615
        return -1;
616
    }
617

    
618
    tap_win32_overlapped_init(&tap_overlapped, handle);
619

    
620
    *phandle = &tap_overlapped;
621

    
622
    hThread = CreateThread(NULL, 0, tap_win32_thread_entry,
623
                           (LPVOID)&tap_overlapped, 0, &idThread);
624
    return 0;
625
}
626

    
627
/********************************************/
628

    
629
 typedef struct TAPState {
630
     VLANClientState *vc;
631
     tap_win32_overlapped_t *handle;
632
 } TAPState;
633

    
634
static void tap_cleanup(VLANClientState *vc)
635
{
636
    TAPState *s = vc->opaque;
637

    
638
    qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL);
639

    
640
    /* FIXME: need to kill thread and close file handle:
641
       tap_win32_close(s);
642
    */
643
    qemu_free(s);
644
}
645

    
646
static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
647
{
648
    TAPState *s = vc->opaque;
649

    
650
    return tap_win32_write(s->handle, buf, size);
651
}
652

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

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

    
667
int tap_win32_init(VLANState *vlan, const char *model,
668
                   const char *name, const char *ifname)
669
{
670
    TAPState *s;
671

    
672
    s = qemu_mallocz(sizeof(TAPState));
673
    if (!s)
674
        return -1;
675
    if (tap_win32_open(&s->handle, ifname) < 0) {
676
        printf("tap: Could not open '%s'\n", ifname);
677
        return -1;
678
    }
679

    
680
    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive,
681
                                 NULL, tap_cleanup, s);
682

    
683
    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
684
             "tap: ifname=%s", ifname);
685

    
686
    qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s);
687
    return 0;
688
}