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