Statistics
| Branch: | Revision:

root / tap-win32.c @ 3174ecd1

History | View | Annotate | Download (20.2 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

    
34
/* NOTE: PCIBus is redefined in winddk.h */
35
#define PCIBus _PCIBus
36
#include <ddk/ntapi.h>
37
#include <ddk/winddk.h>
38
#include <ddk/ntddk.h>
39
#undef PCIBus
40

    
41
//=============
42
// TAP IOCTLs
43
//=============
44

    
45
#define TAP_CONTROL_CODE(request,method) \
46
  CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
47

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

    
58
//=================
59
// Registry keys
60
//=================
61

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

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

    
66
//======================
67
// Filesystem prefixes
68
//======================
69

    
70
#define USERMODEDEVICEDIR "\\\\.\\Global\\"
71
#define TAPSUFFIX         ".tap"
72

    
73

    
74
//======================
75
// Compile time configuration
76
//======================
77

    
78
//#define DEBUG_TAP_WIN32
79

    
80
#define TUN_ASYNCHRONOUS_WRITES 1
81

    
82
#define TUN_BUFFER_SIZE 1560
83
#define TUN_MAX_BUFFER_COUNT 32
84

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

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

    
112
static tap_win32_overlapped_t tap_overlapped;
113

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

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

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

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

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

    
150
            buffer = overlapped->output_queue_front;
151
            overlapped->output_queue_front = buffer->next;
152

    
153
            if(overlapped->output_queue_front == NULL) {
154
                overlapped->output_queue_back = NULL;
155
            }
156

    
157
            LeaveCriticalSection(&overlapped->output_queue_cs);
158
            break;
159

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

    
166
    return buffer;
167
}
168

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

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

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

    
186
    LeaveCriticalSection(&overlapped->output_queue_cs);
187

    
188
    ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL);
189
}
190

    
191

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

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

    
206
    if (status != ERROR_SUCCESS) {
207
        return FALSE;
208
    }
209

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

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

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

    
237
        snprintf (unit_string, sizeof(unit_string), "%s\\%s",
238
                  ADAPTER_KEY, enum_name);
239

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

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

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

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

    
283
    RegCloseKey (netcard_key);
284
    return FALSE;
285
}
286

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

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

    
306
    if (status != ERROR_SUCCESS) {
307
        return -1;
308
    }
309

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

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

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

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

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

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

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

    
380
            RegCloseKey (connection_key);
381
        }
382
        ++i;
383
    }
384

    
385
    RegCloseKey (control_net_key);
386

    
387
    if (stop == 0)
388
        return -1;
389

    
390
    return 0;
391
}
392

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

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

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

    
406
    overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL);
407
    overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
408

    
409
    overlapped->read_overlapped.Offset = 0;
410
    overlapped->read_overlapped.OffsetHigh = 0;
411
    overlapped->read_overlapped.hEvent = overlapped->read_event;
412

    
413
    overlapped->write_overlapped.Offset = 0;
414
    overlapped->write_overlapped.OffsetHigh = 0;
415
    overlapped->write_overlapped.hEvent = overlapped->write_event;
416

    
417
    InitializeCriticalSection(&overlapped->output_queue_cs);
418
    InitializeCriticalSection(&overlapped->free_list_cs);
419

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

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

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

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

    
440
    overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL;
441

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

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

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

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

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

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

    
485
    return 0;
486
}
487

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

    
496

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

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

    
540
    return 0;
541
}
542

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

    
548
    tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped);
549

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

    
558
    return size;
559
}
560

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

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

    
586
    if (prefered_name != NULL)
587
        snprintf(name_buffer, sizeof(name_buffer), "%s", prefered_name);
588

    
589
    rc = get_device_guid(device_guid, sizeof(device_guid), name_buffer, sizeof(name_buffer));
590
    if (rc)
591
        return -1;
592

    
593
    snprintf (device_path, sizeof(device_path), "%s%s%s",
594
              USERMODEDEVICEDIR,
595
              device_guid,
596
              TAPSUFFIX);
597

    
598
    handle = CreateFile (
599
        device_path,
600
        GENERIC_READ | GENERIC_WRITE,
601
        0,
602
        0,
603
        OPEN_EXISTING,
604
        FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
605
        0 );
606

    
607
    if (handle == INVALID_HANDLE_VALUE) {
608
        return -1;
609
    }
610

    
611
    bret = DeviceIoControl(handle, TAP_IOCTL_GET_VERSION,
612
                           &version, sizeof (version),
613
                           &version, sizeof (version), &version_len, NULL);
614

    
615
    if (bret == FALSE) {
616
        CloseHandle(handle);
617
        return -1;
618
    }
619

    
620
    if (!tap_win32_set_status(handle, TRUE)) {
621
        return -1;
622
    }
623

    
624
    tap_win32_overlapped_init(&tap_overlapped, handle);
625

    
626
    *phandle = &tap_overlapped;
627

    
628
    hThread = CreateThread(NULL, 0, tap_win32_thread_entry,
629
                           (LPVOID)&tap_overlapped, 0, &idThread);
630
    return 0;
631
}
632

    
633
/********************************************/
634

    
635
 typedef struct TAPState {
636
     VLANClientState *vc;
637
     tap_win32_overlapped_t *handle;
638
 } TAPState;
639

    
640
static void tap_cleanup(VLANClientState *vc)
641
{
642
    TAPState *s = vc->opaque;
643

    
644
    qemu_del_wait_object(s->handle->tap_semaphore, NULL, NULL);
645

    
646
    /* FIXME: need to kill thread and close file handle:
647
       tap_win32_close(s);
648
    */
649
    qemu_free(s);
650
}
651

    
652
static ssize_t tap_receive(VLANClientState *vc, const uint8_t *buf, size_t size)
653
{
654
    TAPState *s = vc->opaque;
655

    
656
    return tap_win32_write(s->handle, buf, size);
657
}
658

    
659
static void tap_win32_send(void *opaque)
660
{
661
    TAPState *s = opaque;
662
    uint8_t *buf;
663
    int max_size = 4096;
664
    int size;
665

    
666
    size = tap_win32_read(s->handle, &buf, max_size);
667
    if (size > 0) {
668
        qemu_send_packet(s->vc, buf, size);
669
        tap_win32_free_buffer(s->handle, buf);
670
    }
671
}
672

    
673
int tap_win32_init(VLANState *vlan, const char *model,
674
                   const char *name, const char *ifname)
675
{
676
    TAPState *s;
677

    
678
    s = qemu_mallocz(sizeof(TAPState));
679
    if (!s)
680
        return -1;
681
    if (tap_win32_open(&s->handle, ifname) < 0) {
682
        printf("tap: Could not open '%s'\n", ifname);
683
        return -1;
684
    }
685

    
686
    s->vc = qemu_new_vlan_client(vlan, model, name, NULL, tap_receive,
687
                                 NULL, tap_cleanup, s);
688

    
689
    snprintf(s->vc->info_str, sizeof(s->vc->info_str),
690
             "tap: ifname=%s", ifname);
691

    
692
    qemu_add_wait_object(s->handle->tap_semaphore, tap_win32_send, s);
693
    return 0;
694
}