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, write to the Free Software Foundation, Inc.,
27 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 */
29#include "qemu-common.h"
30#include "net/net.h"
31#include "sysemu/sysemu.h"
32#include <stdio.h>
33#include <windows.h>
34#include <winioctl.h>
35
36//=============
37// TAP IOCTLs
38//=============
39
40#define TAP_CONTROL_CODE(request,method) \
41  CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
42
43#define TAP_IOCTL_GET_MAC               TAP_CONTROL_CODE (1, METHOD_BUFFERED)
44#define TAP_IOCTL_GET_VERSION           TAP_CONTROL_CODE (2, METHOD_BUFFERED)
45#define TAP_IOCTL_GET_MTU               TAP_CONTROL_CODE (3, METHOD_BUFFERED)
46#define TAP_IOCTL_GET_INFO              TAP_CONTROL_CODE (4, METHOD_BUFFERED)
47#define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
48#define TAP_IOCTL_SET_MEDIA_STATUS      TAP_CONTROL_CODE (6, METHOD_BUFFERED)
49#define TAP_IOCTL_CONFIG_DHCP_MASQ      TAP_CONTROL_CODE (7, METHOD_BUFFERED)
50#define TAP_IOCTL_GET_LOG_LINE          TAP_CONTROL_CODE (8, METHOD_BUFFERED)
51#define TAP_IOCTL_CONFIG_DHCP_SET_OPT   TAP_CONTROL_CODE (9, METHOD_BUFFERED)
52
53//=================
54// Registry keys
55//=================
56
57#define ADAPTER_KEY "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
58
59#define NETWORK_CONNECTIONS_KEY "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
60
61//======================
62// Filesystem prefixes
63//======================
64
65#define USERMODEDEVICEDIR "\\\\.\\Global\\"
66#define TAPSUFFIX         ".tap"
67
68
69//======================
70// Compile time configuration
71//======================
72
73//#define DEBUG_TAP_WIN32
74
75#define TUN_ASYNCHRONOUS_WRITES 1
76
77#define TUN_BUFFER_SIZE 1560
78#define TUN_MAX_BUFFER_COUNT 32
79
80/*
81 * The data member "buffer" must be the first element in the tun_buffer
82 * structure. See the function, tap_win32_free_buffer.
83 */
84typedef struct tun_buffer_s {
85    unsigned char buffer [TUN_BUFFER_SIZE];
86    unsigned long read_size;
87    struct tun_buffer_s* next;
88} tun_buffer_t;
89
90typedef struct tap_win32_overlapped {
91    HANDLE handle;
92    HANDLE read_event;
93    HANDLE write_event;
94    HANDLE output_queue_semaphore;
95    HANDLE free_list_semaphore;
96    HANDLE tap_semaphore;
97    CRITICAL_SECTION output_queue_cs;
98    CRITICAL_SECTION free_list_cs;
99    OVERLAPPED read_overlapped;
100    OVERLAPPED write_overlapped;
101    tun_buffer_t buffers[TUN_MAX_BUFFER_COUNT];
102    tun_buffer_t* free_list;
103    tun_buffer_t* output_queue_front;
104    tun_buffer_t* output_queue_back;
105} tap_win32_overlapped_t;
106
107static tap_win32_overlapped_t tap_overlapped;
108
109static tun_buffer_t* get_buffer_from_free_list(tap_win32_overlapped_t* const overlapped)
110{
111    tun_buffer_t* buffer = NULL;
112    WaitForSingleObject(overlapped->free_list_semaphore, INFINITE);
113    EnterCriticalSection(&overlapped->free_list_cs);
114    buffer = overlapped->free_list;
115//    assert(buffer != NULL);
116    overlapped->free_list = buffer->next;
117    LeaveCriticalSection(&overlapped->free_list_cs);
118    buffer->next = NULL;
119    return buffer;
120}
121
122static void put_buffer_on_free_list(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
123{
124    EnterCriticalSection(&overlapped->free_list_cs);
125    buffer->next = overlapped->free_list;
126    overlapped->free_list = buffer;
127    LeaveCriticalSection(&overlapped->free_list_cs);
128    ReleaseSemaphore(overlapped->free_list_semaphore, 1, NULL);
129}
130
131static tun_buffer_t* get_buffer_from_output_queue(tap_win32_overlapped_t* const overlapped, const int block)
132{
133    tun_buffer_t* buffer = NULL;
134    DWORD result, timeout = block ? INFINITE : 0L;
135
136    // Non-blocking call
137    result = WaitForSingleObject(overlapped->output_queue_semaphore, timeout);
138
139    switch (result)
140    {
141        // The semaphore object was signaled.
142        case WAIT_OBJECT_0:
143            EnterCriticalSection(&overlapped->output_queue_cs);
144
145            buffer = overlapped->output_queue_front;
146            overlapped->output_queue_front = buffer->next;
147
148            if(overlapped->output_queue_front == NULL) {
149                overlapped->output_queue_back = NULL;
150            }
151
152            LeaveCriticalSection(&overlapped->output_queue_cs);
153            break;
154
155        // Semaphore was nonsignaled, so a time-out occurred.
156        case WAIT_TIMEOUT:
157            // Cannot open another window.
158            break;
159    }
160
161    return buffer;
162}
163
164static tun_buffer_t* get_buffer_from_output_queue_immediate (tap_win32_overlapped_t* const overlapped)
165{
166    return get_buffer_from_output_queue(overlapped, 0);
167}
168
169static void put_buffer_on_output_queue(tap_win32_overlapped_t* const overlapped, tun_buffer_t* const buffer)
170{
171    EnterCriticalSection(&overlapped->output_queue_cs);
172
173    if(overlapped->output_queue_front == NULL && overlapped->output_queue_back == NULL) {
174        overlapped->output_queue_front = overlapped->output_queue_back = buffer;
175    } else {
176        buffer->next = NULL;
177        overlapped->output_queue_back->next = buffer;
178        overlapped->output_queue_back = buffer;
179    }
180
181    LeaveCriticalSection(&overlapped->output_queue_cs);
182
183    ReleaseSemaphore(overlapped->output_queue_semaphore, 1, NULL);
184}
185
186
187static int is_tap_win32_dev(const char *guid)
188{
189    HKEY netcard_key;
190    LONG status;
191    DWORD len;
192    int i = 0;
193
194    status = RegOpenKeyEx(
195        HKEY_LOCAL_MACHINE,
196        ADAPTER_KEY,
197        0,
198        KEY_READ,
199        &netcard_key);
200
201    if (status != ERROR_SUCCESS) {
202        return FALSE;
203    }
204
205    for (;;) {
206        char enum_name[256];
207        char unit_string[256];
208        HKEY unit_key;
209        char component_id_string[] = "ComponentId";
210        char component_id[256];
211        char net_cfg_instance_id_string[] = "NetCfgInstanceId";
212        char net_cfg_instance_id[256];
213        DWORD data_type;
214
215        len = sizeof (enum_name);
216        status = RegEnumKeyEx(
217            netcard_key,
218            i,
219            enum_name,
220            &len,
221            NULL,
222            NULL,
223            NULL,
224            NULL);
225
226        if (status == ERROR_NO_MORE_ITEMS)
227            break;
228        else if (status != ERROR_SUCCESS) {
229            return FALSE;
230        }
231
232        snprintf (unit_string, sizeof(unit_string), "%s\\%s",
233                  ADAPTER_KEY, enum_name);
234
235        status = RegOpenKeyEx(
236            HKEY_LOCAL_MACHINE,
237            unit_string,
238            0,
239            KEY_READ,
240            &unit_key);
241
242        if (status != ERROR_SUCCESS) {
243            return FALSE;
244        } else {
245            len = sizeof (component_id);
246            status = RegQueryValueEx(
247                unit_key,
248                component_id_string,
249                NULL,
250                &data_type,
251                (LPBYTE)component_id,
252                &len);
253
254            if (!(status != ERROR_SUCCESS || data_type != REG_SZ)) {
255                len = sizeof (net_cfg_instance_id);
256                status = RegQueryValueEx(
257                    unit_key,
258                    net_cfg_instance_id_string,
259                    NULL,
260                    &data_type,
261                    (LPBYTE)net_cfg_instance_id,
262                    &len);
263
264                if (status == ERROR_SUCCESS && data_type == REG_SZ) {
265                    if (/* !strcmp (component_id, TAP_COMPONENT_ID) &&*/
266                        !strcmp (net_cfg_instance_id, guid)) {
267                        RegCloseKey (unit_key);
268                        RegCloseKey (netcard_key);
269                        return TRUE;
270                    }
271                }
272            }
273            RegCloseKey (unit_key);
274        }
275        ++i;
276    }
277
278    RegCloseKey (netcard_key);
279    return FALSE;
280}
281
282static int get_device_guid(
283    char *name,
284    int name_size,
285    char *actual_name,
286    int actual_name_size)
287{
288    LONG status;
289    HKEY control_net_key;
290    DWORD len;
291    int i = 0;
292    int stop = 0;
293
294    status = RegOpenKeyEx(
295        HKEY_LOCAL_MACHINE,
296        NETWORK_CONNECTIONS_KEY,
297        0,
298        KEY_READ,
299        &control_net_key);
300
301    if (status != ERROR_SUCCESS) {
302        return -1;
303    }
304
305    while (!stop)
306    {
307        char enum_name[256];
308        char connection_string[256];
309        HKEY connection_key;
310        char name_data[256];
311        DWORD name_type;
312        const char name_string[] = "Name";
313
314        len = sizeof (enum_name);
315        status = RegEnumKeyEx(
316            control_net_key,
317            i,
318            enum_name,
319            &len,
320            NULL,
321            NULL,
322            NULL,
323            NULL);
324
325        if (status == ERROR_NO_MORE_ITEMS)
326            break;
327        else if (status != ERROR_SUCCESS) {
328            return -1;
329        }
330
331        snprintf(connection_string,
332             sizeof(connection_string),
333             "%s\\%s\\Connection",
334             NETWORK_CONNECTIONS_KEY, enum_name);
335
336        status = RegOpenKeyEx(
337            HKEY_LOCAL_MACHINE,
338            connection_string,
339            0,
340            KEY_READ,
341            &connection_key);
342
343        if (status == ERROR_SUCCESS) {
344            len = sizeof (name_data);
345            status = RegQueryValueEx(
346                connection_key,
347                name_string,
348                NULL,
349                &name_type,
350                (LPBYTE)name_data,
351                &len);
352
353            if (status != ERROR_SUCCESS || name_type != REG_SZ) {
354                    return -1;
355            }
356            else {
357                if (is_tap_win32_dev(enum_name)) {
358                    snprintf(name, name_size, "%s", enum_name);
359                    if (actual_name) {
360                        if (strcmp(actual_name, "") != 0) {
361                            if (strcmp(name_data, actual_name) != 0) {
362                                RegCloseKey (connection_key);
363                                ++i;
364                                continue;
365                            }
366                        }
367                        else {
368                            snprintf(actual_name, actual_name_size, "%s", name_data);
369                        }
370                    }
371                    stop = 1;
372                }
373            }
374
375            RegCloseKey (connection_key);
376        }
377        ++i;
378    }
379
380    RegCloseKey (control_net_key);
381
382    if (stop == 0)
383        return -1;
384
385    return 0;
386}
387
388static int tap_win32_set_status(HANDLE handle, int status)
389{
390    unsigned long len = 0;
391
392    return DeviceIoControl(handle, TAP_IOCTL_SET_MEDIA_STATUS,
393                &status, sizeof (status),
394                &status, sizeof (status), &len, NULL);
395}
396
397static void tap_win32_overlapped_init(tap_win32_overlapped_t* const overlapped, const HANDLE handle)
398{
399    overlapped->handle = handle;
400
401    overlapped->read_event = CreateEvent(NULL, FALSE, FALSE, NULL);
402    overlapped->write_event = CreateEvent(NULL, FALSE, FALSE, NULL);
403
404    overlapped->read_overlapped.Offset = 0;
405    overlapped->read_overlapped.OffsetHigh = 0;
406    overlapped->read_overlapped.hEvent = overlapped->read_event;
407
408    overlapped->write_overlapped.Offset = 0;
409    overlapped->write_overlapped.OffsetHigh = 0;
410    overlapped->write_overlapped.hEvent = overlapped->write_event;
411
412    InitializeCriticalSection(&overlapped->output_queue_cs);
413    InitializeCriticalSection(&overlapped->free_list_cs);
414
415    overlapped->output_queue_semaphore = CreateSemaphore(
416        NULL,   // default security attributes
417        0,   // initial count
418        TUN_MAX_BUFFER_COUNT,   // maximum count
419        NULL);  // unnamed semaphore
420
421    if(!overlapped->output_queue_semaphore)  {
422        fprintf(stderr, "error creating output queue semaphore!\n");
423    }
424
425    overlapped->free_list_semaphore = CreateSemaphore(
426        NULL,   // default security attributes
427        TUN_MAX_BUFFER_COUNT,   // initial count
428        TUN_MAX_BUFFER_COUNT,   // maximum count
429        NULL);  // unnamed semaphore
430
431    if(!overlapped->free_list_semaphore)  {
432        fprintf(stderr, "error creating free list semaphore!\n");
433    }
434
435    overlapped->free_list = overlapped->output_queue_front = overlapped->output_queue_back = NULL;
436
437    {
438        unsigned index;
439        for(index = 0; index < TUN_MAX_BUFFER_COUNT; index++) {
440            tun_buffer_t* element = &overlapped->buffers[index];
441            element->next = overlapped->free_list;
442            overlapped->free_list = element;
443        }
444    }
445    /* To count buffers, initially no-signal. */
446    overlapped->tap_semaphore = CreateSemaphore(NULL, 0, TUN_MAX_BUFFER_COUNT, NULL);
447    if(!overlapped->tap_semaphore)
448        fprintf(stderr, "error creating tap_semaphore.\n");
449}
450
451static int tap_win32_write(tap_win32_overlapped_t *overlapped,
452                           const void *buffer, unsigned long size)
453{
454    unsigned long write_size;
455    BOOL result;
456    DWORD error;
457
458    result = GetOverlappedResult( overlapped->handle, &overlapped->write_overlapped,
459                                  &write_size, FALSE);
460
461    if (!result && GetLastError() == ERROR_IO_INCOMPLETE)
462        WaitForSingleObject(overlapped->write_event, INFINITE);
463
464    result = WriteFile(overlapped->handle, buffer, size,
465                       &write_size, &overlapped->write_overlapped);
466
467    if (!result) {
468        switch (error = GetLastError())
469        {
470        case ERROR_IO_PENDING:
471#ifndef TUN_ASYNCHRONOUS_WRITES
472            WaitForSingleObject(overlapped->write_event, INFINITE);
473#endif
474            break;
475        default:
476            return -1;
477        }
478    }
479
480    return 0;
481}
482
483static DWORD WINAPI tap_win32_thread_entry(LPVOID param)
484{
485    tap_win32_overlapped_t *overlapped = (tap_win32_overlapped_t*)param;
486    unsigned long read_size;
487    BOOL result;
488    DWORD dwError;
489    tun_buffer_t* buffer = get_buffer_from_free_list(overlapped);
490
491
492    for (;;) {
493        result = ReadFile(overlapped->handle,
494                          buffer->buffer,
495                          sizeof(buffer->buffer),
496                          &read_size,
497                          &overlapped->read_overlapped);
498        if (!result) {
499            dwError = GetLastError();
500            if (dwError == ERROR_IO_PENDING) {
501                WaitForSingleObject(overlapped->read_event, INFINITE);
502                result = GetOverlappedResult( overlapped->handle, &overlapped->read_overlapped,
503                                              &read_size, FALSE);
504                if (!result) {
505#ifdef DEBUG_TAP_WIN32
506                    LPVOID lpBuffer;
507                    dwError = GetLastError();
508                    FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
509                                   NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
510                                   (LPTSTR) & lpBuffer, 0, NULL );
511                    fprintf(stderr, "Tap-Win32: Error GetOverlappedResult %d - %s\n", dwError, lpBuffer);
512                    LocalFree( lpBuffer );
513#endif
514                }
515            } else {
516#ifdef DEBUG_TAP_WIN32
517                LPVOID lpBuffer;
518                FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
519                               NULL, dwError, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
520                               (LPTSTR) & lpBuffer, 0, NULL );
521                fprintf(stderr, "Tap-Win32: Error ReadFile %d - %s\n", dwError, lpBuffer);
522                LocalFree( lpBuffer );
523#endif
524            }
525        }
526
527        if(read_size > 0) {
528            buffer->read_size = read_size;
529            put_buffer_on_output_queue(overlapped, buffer);
530            ReleaseSemaphore(overlapped->tap_semaphore, 1, NULL);
531            buffer = get_buffer_from_free_list(overlapped);
532        }
533    }
534
535    return 0;
536}
537
538static int tap_win32_read(tap_win32_overlapped_t *overlapped,
539                          uint8_t **pbuf, int max_size)
540{
541    int size = 0;
542
543    tun_buffer_t* buffer = get_buffer_from_output_queue_immediate(overlapped);
544
545    if(buffer != NULL) {
546        *pbuf = buffer->buffer;
547        size = (int)buffer->read_size;
548        if(size > max_size) {
549            size = max_size;
550        }
551    }
552
553    return size;
554}
555
556static void tap_win32_free_buffer(tap_win32_overlapped_t *overlapped,
557                                  uint8_t *pbuf)
558{
559    tun_buffer_t* buffer = (tun_buffer_t*)pbuf;
560    put_buffer_on_free_list(overlapped, buffer);
561}
562
563static int tap_win32_open(tap_win32_overlapped_t **phandle,
564                          const char *prefered_name)
565{
566    char device_path[256];
567    char device_guid[0x100];
568    int rc;
569    HANDLE handle;
570    BOOL bret;
571    char name_buffer[0x100] = {0, };
572    struct {
573        unsigned long major;
574        unsigned long minor;
575        unsigned long debug;
576    } version;
577    DWORD version_len;
578    DWORD idThread;
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    (void) 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
634static 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    g_free(s);
644}
645
646static 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
653static 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
667int tap_win32_init(VLANState *vlan, const char *model,
668                   const char *name, const char *ifname)
669{
670    TAPState *s;
671
672    s = g_malloc0(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}
689