1/*********************************************************************
2   PicoTCP. Copyright (c) 2014-2017 Altran Intelligent Systems. Some rights reserved.
3   See COPYING, LICENSE.GPLv2 and LICENSE.GPLv3 for usage.
4
5   Authors: Maxime Vincent
6            Based on the OpenVPN tun.c driver, under GPL
7
8   NOTES: This is the Windows-only driver, a Linux-equivalent is available, too
9          You need to have an OpenVPN TUN/TAP network adapter installed, first
10          This driver is barely working:
11 * Only TAP-mode is supported (TUN is not)
12 * it will simply open the first TAP device it can find
13 * there is memory being allocated that's never freed
14 * there is no destroy function, yet
15 * it has only been tested on a Windows 7 machine
16 *********************************************************************/
17
18#include "pico_device.h"
19#include "pico_dev_null.h"
20#include "pico_stack.h"
21#include "pico_dev_tap_windows.h"
22
23#include <Windows.h>
24#include <Winreg.h>
25#include <winioctl.h>
26#include "pico_dev_tap_windows_private.h"
27
28/*
29 * Debugging info
30 */
31#ifdef DEBUG_TAP_GENERAL
32#define dbg_tap                dbg    /* first level debug */
33#else
34#define dbg_tap(...)           do{} while(0)
35#endif
36
37#ifdef DEBUG_TAP_INFO
38#define dbg_tap_info           dbg    /* tap info messages */
39#else
40#define dbg_tap_info(...)      do{} while(0)
41#endif
42
43#ifdef DEBUG_TAP_WIN
44#define dbg_tap_win32          dbg    /* second level detailed win32 debug */
45#else
46#define dbg_tap_win32(...)     do{} while(0)
47#endif
48
49#ifdef DEBUG_TAP_REG
50#define dbg_tap_reg            dbg    /* third level: registry debug */
51#else
52#define dbg_tap_reg(...)       do{} while(0)
53#endif
54
55/*
56 * Tunnel types
57 */
58#define DEV_TYPE_UNDEF 0
59#define DEV_TYPE_NULL  1
60#define DEV_TYPE_TUN   2    /* point-to-point IP tunnel */
61#define DEV_TYPE_TAP   3    /* ethernet (802.3) tunnel */
62
63
64/*
65 * We try to do all Win32 I/O using overlapped
66 * (i.e. asynchronous) I/O for a performance win.
67 */
68struct overlapped_io {
69# define IOSTATE_INITIAL          0
70# define IOSTATE_QUEUED           1 /* overlapped I/O has been queued */
71# define IOSTATE_IMMEDIATE_RETURN 2 /* I/O function returned immediately without queueing */
72    int iostate;
73    OVERLAPPED overlapped;
74    DWORD size;
75    DWORD flags;
76    int status;
77    int addr_defined;
78    uint8_t *buf_init;
79    uint32_t buf_init_len;
80    uint8_t *buf;
81    uint32_t buf_len;
82};
83
84struct rw_handle {
85    HANDLE read;
86    HANDLE write;
87};
88
89struct tuntap
90{
91    int type; /* DEV_TYPE_x as defined in proto.h */
92    int ipv6;
93    int persistent_if;      /* if existed before, keep on program end */
94    char *actual_name; /* actual name of TUN/TAP dev, usually including unit number */
95    int post_open_mtu;
96    uint8_t mac[6];
97
98    /* Windows stuff */
99    DWORD adapter_index; /*adapter index for TAP-Windows adapter, ~0 if undefined */
100    HANDLE hand;
101    struct overlapped_io reads; /* for overlapped IO */
102    struct overlapped_io writes;
103    struct rw_handle rw_handle;
104
105};
106
107
108struct pico_device_tap {
109    struct pico_device dev;
110    int statistics_frames_out;
111    struct tuntap *tt;
112};
113
114
115/*
116 * Private function prototypes
117 */
118const struct tap_reg *get_tap_reg (void);
119const struct panel_reg *get_panel_reg (void);
120
121
122/*
123 * Private functions
124 */
125
126/* Get TAP info from Windows registry */
127const struct tap_reg *get_tap_reg (void)
128{
129    HKEY adapter_key;
130    LONG status;
131    DWORD len;
132    struct tap_reg *first = NULL;
133    struct tap_reg *last = NULL;
134    int i = 0;
135
136    status = RegOpenKeyEx(
137        HKEY_LOCAL_MACHINE,
138        ADAPTER_KEY,
139        0,
140        KEY_READ,
141        &adapter_key);
142
143    if (status != ERROR_SUCCESS)
144    {
145        dbg_tap_reg("Error opening registry key: %s\n", ADAPTER_KEY);
146        return NULL;
147    }
148
149    while (1)
150    {
151        char enum_name[256];
152        char unit_string[256];
153        HKEY unit_key;
154        char component_id_string[] = "ComponentId";
155        char component_id[256];
156        char net_cfg_instance_id_string[] = "NetCfgInstanceId";
157        char net_cfg_instance_id[256];
158        DWORD data_type;
159
160        len = sizeof (enum_name);
161        status = RegEnumKeyEx(
162            adapter_key,
163            i,
164            enum_name,
165            &len,
166            NULL,
167            NULL,
168            NULL,
169            NULL);
170        if (status == ERROR_NO_MORE_ITEMS)
171            break;
172        else if (status != ERROR_SUCCESS)
173            dbg_tap_reg("Error enumerating registry subkeys of key: %s.\n", ADAPTER_KEY);
174
175        snprintf (unit_string, sizeof(unit_string), "%s\\%s",
176                  ADAPTER_KEY, enum_name);
177
178        status = RegOpenKeyEx(
179            HKEY_LOCAL_MACHINE,
180            unit_string,
181            0,
182            KEY_READ,
183            &unit_key);
184
185        if (status != ERROR_SUCCESS)
186        {
187            dbg_tap_reg("Error opening registry key: %s\n", unit_string);
188        }
189        else
190        {
191            len = sizeof (component_id);
192            status = RegQueryValueEx(
193                unit_key,
194                component_id_string,
195                NULL,
196                &data_type,
197                (LPBYTE)component_id,
198                &len);
199
200            if (status != ERROR_SUCCESS || data_type != REG_SZ)
201            {
202                dbg_tap_reg("Error opening registry key: %s\\%s\n", unit_string, component_id_string);
203            }
204            else
205            {
206                len = sizeof (net_cfg_instance_id);
207                status = RegQueryValueEx(
208                    unit_key,
209                    net_cfg_instance_id_string,
210                    NULL,
211                    &data_type,
212                    (LPBYTE)net_cfg_instance_id,
213                    &len);
214
215                if (status == ERROR_SUCCESS && data_type == REG_SZ)
216                {
217                    if (!strcmp (component_id, TAP_WIN_COMPONENT_ID))
218                    {
219                        struct tap_reg *reg;
220                        reg = PICO_ZALLOC(sizeof(struct tap_reg), 1);
221                        /* ALLOC_OBJ_CLEAR_GC (reg, struct tap_reg, gc); */
222                        if (!reg)
223                            return NULL;
224
225                        /* reg->guid = string_alloc (net_cfg_instance_id, gc); */
226                        reg->guid = PICO_ZALLOC (strlen(net_cfg_instance_id) + 1, 1);
227                        if (!(reg->guid))
228                        {
229                            PICO_FREE(reg);
230                            return NULL;
231                        }
232
233                        strcpy((char *)reg->guid, net_cfg_instance_id);
234                        /* link into return list */
235                        if (!first)
236                            first = reg;
237
238                        if (last)
239                            last->next = reg;
240
241                        last = reg;
242                    }
243                }
244            }
245
246            RegCloseKey (unit_key);
247        }
248
249        ++i;
250    }
251    RegCloseKey (adapter_key);
252    return first;
253}
254
255/* Get Panel info from Windows registry */
256const struct panel_reg *get_panel_reg (void)
257{
258    LONG status;
259    HKEY network_connections_key;
260    DWORD len;
261    struct panel_reg *first = NULL;
262    struct panel_reg *last = NULL;
263    int i = 0;
264
265    status = RegOpenKeyEx(
266        HKEY_LOCAL_MACHINE,
267        NETWORK_CONNECTIONS_KEY,
268        0,
269        KEY_READ,
270        &network_connections_key);
271
272    if (status != ERROR_SUCCESS)
273    {
274        dbg_tap_reg("Error opening registry key: %s\n", NETWORK_CONNECTIONS_KEY);
275        return NULL;
276    }
277
278    while (1)
279    {
280        char enum_name[256];
281        char connection_string[256];
282        HKEY connection_key;
283        WCHAR name_data[256];
284        DWORD name_type;
285        const WCHAR name_string[] = L"Name";
286
287        len = sizeof (enum_name);
288        status = RegEnumKeyEx(
289            network_connections_key,
290            i,
291            enum_name,
292            &len,
293            NULL,
294            NULL,
295            NULL,
296            NULL);
297        if (status == ERROR_NO_MORE_ITEMS)
298            break;
299        else if (status != ERROR_SUCCESS)
300            dbg_tap_reg("Error enumerating registry subkeys of key: %s.\n", NETWORK_CONNECTIONS_KEY);
301
302        snprintf (connection_string, sizeof(connection_string), "%s\\%s\\Connection", NETWORK_CONNECTIONS_KEY, enum_name);
303
304        status = RegOpenKeyEx(
305            HKEY_LOCAL_MACHINE,
306            connection_string,
307            0,
308            KEY_READ,
309            &connection_key);
310        if (status != ERROR_SUCCESS)
311            dbg_tap_reg("Error opening registry key: %s\n", connection_string);
312        else
313        {
314            len = sizeof (name_data);
315            status = RegQueryValueExW(
316                connection_key,
317                name_string,
318                NULL,
319                &name_type,
320                (LPBYTE) name_data,
321                &len);
322
323            if (status != ERROR_SUCCESS || name_type != REG_SZ)
324                dbg_tap_reg("Error opening registry key: %s\\%s\\%S\n", NETWORK_CONNECTIONS_KEY, connection_string, name_string);
325            else
326            {
327                int n;
328                LPSTR name;
329                struct panel_reg *reg;
330
331                /* ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc); */
332                reg = PICO_ZALLOC(sizeof(struct panel_reg), 1);
333                if (!reg)
334                    return NULL;
335
336                n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL);
337                /* name = gc_malloc (n, false, gc); */
338                name = PICO_ZALLOC(n, 1);
339                if (!name)
340                {
341                    PICO_FREE(reg);
342                    return NULL;
343                }
344
345                WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL);
346                reg->name = name;
347                /* reg->guid = string_alloc (enum_name, gc); */
348                reg->guid = PICO_ZALLOC(strlen(enum_name) + 1, 1);
349                if (!reg->guid)
350                {
351                    PICO_FREE((void *)reg->name);
352                    PICO_FREE((void *)reg);
353                    return NULL;
354                }
355
356                strcpy((char *)reg->guid, enum_name);
357
358                /* link into return list */
359                if (!first)
360                    first = reg;
361
362                if (last)
363                    last->next = reg;
364
365                last = reg;
366            }
367
368            RegCloseKey (connection_key);
369        }
370
371        ++i;
372    }
373    RegCloseKey (network_connections_key);
374
375    return first;
376}
377
378
379void show_tap_win_adapters (void)
380{
381    int warn_panel_null = 0;
382    int warn_panel_dup = 0;
383    int warn_tap_dup = 0;
384
385    int links;
386
387    const struct tap_reg *tr;
388    const struct tap_reg *tr1;
389    const struct panel_reg *pr;
390
391    const struct tap_reg *tap_reg = get_tap_reg ();
392    const struct panel_reg *panel_reg = get_panel_reg ();
393
394    if (!(tap_reg && panel_reg))
395        return;
396
397    dbg_tap_info("Available TAP-WIN32 adapters [name, GUID]:\n");
398
399    /* loop through each TAP-Windows adapter registry entry */
400    for (tr = tap_reg; tr != NULL; tr = tr->next)
401    {
402        links = 0;
403
404        /* loop through each network connections entry in the control panel */
405        for (pr = panel_reg; pr != NULL; pr = pr->next)
406        {
407            if (!strcmp (tr->guid, pr->guid))
408            {
409                dbg_tap_info("\t>> '%s' %s\n", pr->name, tr->guid);
410                ++links;
411            }
412        }
413        if (links > 1)
414        {
415            warn_panel_dup = 1;
416        }
417        else if (links == 0)
418        {
419            /* a TAP adapter exists without a link from the network
420               connections control panel */
421            warn_panel_null = 1;
422            dbg_tap_info("\t>> [NULL] %s\n", tr->guid);
423        }
424    }
425    /* check for TAP-Windows adapter duplicated GUIDs */
426    for (tr = tap_reg; tr != NULL; tr = tr->next)
427    {
428        for (tr1 = tap_reg; tr1 != NULL; tr1 = tr1->next)
429        {
430            if (tr != tr1 && !strcmp (tr->guid, tr1->guid))
431                warn_tap_dup = 1;
432        }
433    }
434    /* warn on registry inconsistencies */
435    if (warn_tap_dup)
436        dbg_tap_info("WARNING: Some TAP-Windows adapters have duplicate GUIDs\n");
437
438    if (warn_panel_dup)
439        dbg_tap_info("WARNING: Some TAP-Windows adapters have duplicate links from the Network Connections control panel\n");
440
441    if (warn_panel_null)
442        dbg_tap_info("WARNING: Some TAP-Windows adapters have no link from the Network Connections control panel\n");
443}
444
445
446/* Get the GUID of the first TAP device found */
447const char *get_first_device_guid(const struct tap_reg *tap_reg, const struct panel_reg *panel_reg, char *name)
448{
449    const struct tap_reg *tr;
450    const struct panel_reg *pr;
451    /* loop through each TAP-Windows adapter registry entry */
452    for (tr = tap_reg; tr != NULL; tr = tr->next)
453    {
454        /* loop through each network connections entry in the control panel */
455        for (pr = panel_reg; pr != NULL; pr = pr->next)
456        {
457            if (!strcmp (tr->guid, pr->guid))
458            {
459                dbg_tap_info("Using first TAP device: '%s' %s\n", pr->name, tr->guid);
460                if (name)
461                    strcpy(name, pr->name);
462
463                return tr->guid;
464            }
465        }
466    }
467    return NULL;
468}
469
470
471
472int open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
473{
474    char device_path[256];
475    const char *device_guid = NULL;
476    DWORD len;
477
478    dbg_tap_info("open_tun, tt->ipv6=%d\n", tt->ipv6 );
479
480    if (!(tt->type == DEV_TYPE_TAP || tt->type == DEV_TYPE_TUN))
481    {
482        dbg_tap_info("Unknown virtual device type: '%s'\n", dev);
483        return -1;
484    }
485
486    /*
487     * Lookup the device name in the registry, using the --dev-node high level name.
488     */
489    {
490        const struct tap_reg *tap_reg = get_tap_reg();
491        const struct panel_reg *panel_reg = get_panel_reg();
492        char name[256];
493
494        if (!(tap_reg && panel_reg))
495        {
496            dbg_tap_info("No TUN/TAP devices found\n");
497            return -1;
498        }
499
500        /* Get the device GUID for the device specified with --dev-node. */
501        device_guid = get_first_device_guid (tap_reg, panel_reg, name);
502
503        if (!device_guid)
504            dbg_tap_info("TAP-Windows adapter '%s' not found\n", dev_node);
505
506        /* Open Windows TAP-Windows adapter */
507        snprintf (device_path, sizeof(device_path), "%s%s%s",
508                  USERMODEDEVICEDIR,
509                  device_guid,
510                  TAP_WIN_SUFFIX);
511
512        tt->hand = CreateFile (
513            device_path,
514            GENERIC_READ | GENERIC_WRITE,
515            0,     /* was: FILE_SHARE_READ */
516            0,
517            OPEN_EXISTING,
518            FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
519            0
520            );
521
522        if (tt->hand == INVALID_HANDLE_VALUE)
523            dbg_tap_info("CreateFile failed on TAP device: %s\n", device_path);
524
525        /* translate high-level device name into a device instance
526           GUID using the registry */
527        tt->actual_name = PICO_ZALLOC(strlen(name) + 1);
528        if (tt->actual_name)
529            strcpy(tt->actual_name, name);
530    }
531
532    dbg_tap_info("TAP-WIN32 device [%s] opened: %s\n", tt->actual_name, device_path);
533    /* TODO TODO TODO */
534    /* tt->adapter_index = get_adapter_index (device_guid); */
535
536    /* get driver version info */
537    {
538        ULONG info[3];
539        /* TODO TODO TODO */
540        /* CLEAR (info); */
541        if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_VERSION, &info, sizeof (info), &info, sizeof (info), &len, NULL))
542        {
543            dbg_tap_info ("TAP-Windows Driver Version %d.%d %s\n",
544                          (int) info[0],
545                          (int) info[1],
546                          (info[2] ? "(DEBUG)" : ""));
547
548        }
549
550        if (!(info[0] == TAP_WIN_MIN_MAJOR && info[1] >= TAP_WIN_MIN_MINOR))
551            dbg_tap_info ("ERROR:  This version of " PACKAGE_NAME " requires a TAP-Windows driver that is at least version %d.%d  \
552                    -- If you recently upgraded your " PACKAGE_NAME " distribution,                             \
553                    a reboot is probably required at this point to get Windows to see the new driver.\n",
554                          TAP_WIN_MIN_MAJOR,
555                          TAP_WIN_MIN_MINOR);
556
557        /* usage of numeric constants is ugly, but this is really tied to
558         * *this* version of the driver
559         */
560        if ( tt->ipv6 && tt->type == DEV_TYPE_TUN && info[0] == 9 && info[1] < 8)
561        {
562            dbg_tap_info("WARNING:  Tap-Win32 driver version %d.%d does not support IPv6 in TUN mode.  IPv6 will be disabled. \
563                    Upgrade to Tap-Win32 9.8 (2.2-beta3 release or later) or use TAP mode to get IPv6\n", (int) info[0], (int) info[1] );
564            tt->ipv6 = 0;
565        }
566
567        /* tap driver 9.8 (2.2.0 and 2.2.1 release) is buggy
568         */
569        if ( tt->type == DEV_TYPE_TUN && info[0] == 9 && info[1] == 8)
570        {
571            dbg_tap_info("ERROR:  Tap-Win32 driver version %d.%d is buggy regarding small IPv4 packets in TUN mode.  Upgrade to Tap-Win32 9.9 (2.2.2 release or later) or use TAP mode\n", (int) info[0], (int) info[1] );
572        }
573    }
574
575    /* get driver MTU */
576    {
577        ULONG mtu;
578        if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_MTU,
579                             &mtu, sizeof (mtu),
580                             &mtu, sizeof (mtu), &len, NULL))
581        {
582            tt->post_open_mtu = (int) mtu;
583            dbg_tap_info("TAP-Windows MTU=%d\n", (int) mtu);
584        }
585    }
586
587
588    /* get driver MAC */
589    {
590        uint8_t mac[6] = {
591            0, 0, 0, 0, 0, 0
592        };
593        if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_MAC,
594                             mac, sizeof (mac),
595                             mac, sizeof (mac), &len, NULL))
596        {
597            dbg_tap_info("TAP-Windows MAC=[%x,%x,%x,%x,%x,%x]\n", mac[0], mac[1], mac[2],
598                         mac[2], mac[4], mac[5]);
599            memcpy(tt->mac, mac, sizeof(mac));
600        }
601    }
602
603    /* set point-to-point mode if TUN device */
604
605    if (tt->type == DEV_TYPE_TUN)
606    {
607        dbg_tap_info("TUN type not supported for now...\n");
608        return -1;
609    }
610    else if (tt->type == DEV_TYPE_TAP)
611    { /* TAP DEVICE */
612        dbg_tap_info("TODO: Set Point-to-point through DeviceIoControl\n");
613    }
614
615    /* set driver media status to 'connected' */
616    {
617        ULONG status = TRUE;
618        if (!DeviceIoControl (tt->hand, TAP_WIN_IOCTL_SET_MEDIA_STATUS,
619                              &status, sizeof (status),
620                              &status, sizeof (status), &len, NULL))
621            dbg_tap_info("WARNING: The TAP-Windows driver rejected a TAP_WIN_IOCTL_SET_MEDIA_STATUS DeviceIoControl call.");
622    }
623
624    return 0;
625}
626
627
628
629
630/* TODO: Closing a TUN device is currently not implemented */
631/*
632   void close_tun (struct tuntap *tt)
633   {
634    (void)tt;
635   }
636 */
637
638
639int tap_win_getinfo (const struct tuntap *tt, char *buf, int bufsize)
640{
641    if (tt && tt->hand != NULL && buf != NULL)
642    {
643        DWORD len;
644        if (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_INFO,
645                             buf, bufsize,
646                             buf, bufsize,
647                             &len, NULL))
648        {
649            return 0;
650        }
651    }
652
653    return -1;
654}
655
656void tun_show_debug (struct tuntap *tt, char *buf, int bufsize)
657{
658    if (tt && tt->hand != NULL && buf != NULL)
659    {
660        DWORD len;
661        while (DeviceIoControl (tt->hand, TAP_WIN_IOCTL_GET_LOG_LINE,
662                                buf, bufsize,
663                                buf, bufsize,
664                                &len, NULL))
665        {
666            dbg_tap_info("TAP-Windows: %s\n", buf);
667        }
668    }
669}
670
671
672/* returns the state */
673int tun_read_queue (struct tuntap *tt, uint8_t *buffer, int maxsize)
674{
675    if (tt->reads.iostate == IOSTATE_INITIAL)
676    {
677        DWORD len = 1500;
678        BOOL status;
679        int err;
680
681        /* reset buf to its initial state */
682        tt->reads.buf = tt->reads.buf_init;
683        tt->reads.buf_len = tt->reads.buf_init_len;
684
685        len = maxsize ? maxsize : (tt->reads.buf_len);
686        if (len > (tt->reads.buf_len)) /* clip to buffer len */
687            len = tt->reads.buf_len;
688
689        /* the overlapped read will signal this event on I/O completion */
690        if (!ResetEvent (tt->reads.overlapped.hEvent))
691            dbg_tap("ResetEvent failed\n");
692
693        status = ReadFile(
694            tt->hand,
695            buffer,
696            len,
697            &tt->reads.size,
698            &tt->reads.overlapped
699            );
700
701        if (status) /* operation completed immediately? */
702        {
703            /* since we got an immediate return, we must signal the event object ourselves */
704            /* ASSERT (SetEvent (tt->reads.overlapped.hEvent)); */
705            if (!SetEvent (tt->reads.overlapped.hEvent))
706                dbg_tap("SetEvent failed\n");
707
708            tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
709            tt->reads.status = 0;
710
711            dbg_tap_win32 ("WIN32 I/O: TAP Read immediate return [%d,%d]\n",
712                       (int) len,
713                       (int) tt->reads.size);
714        }
715        else
716        {
717            err = GetLastError ();
718            if (err == ERROR_IO_PENDING) /* operation queued? */
719            {
720                tt->reads.iostate = IOSTATE_QUEUED;
721                tt->reads.status = err;
722                dbg_tap_win32 ("WIN32 I/O: TAP Read queued [%d]\n", (int) len);
723            }
724            else /* error occurred */
725            {
726                if (!SetEvent (tt->reads.overlapped.hEvent))
727                    dbg_tap("SetEvent failed\n");
728
729                tt->reads.iostate = IOSTATE_IMMEDIATE_RETURN;
730                tt->reads.status = err;
731                dbg_tap ("WIN32 I/O: TAP Read error [%d] : %d\n", (int) len, (int) err);
732            }
733        }
734    }
735
736    return tt->reads.iostate;
737}
738
739/* Finalize any pending overlapped IO's */
740int tun_finalize(HANDLE h, struct overlapped_io *io, uint8_t **buf, uint32_t *buf_len)
741{
742    int ret = -1;
743    BOOL status;
744
745    switch (io->iostate)
746    {
747    case IOSTATE_QUEUED:
748        status = GetOverlappedResult(
749            h,
750            &io->overlapped,
751            &io->size,
752            0u
753            );
754        if (status)
755        {
756            /* successful return for a queued operation */
757            if (buf)
758            {
759                *buf = io->buf;
760                *buf_len = io->buf_len;
761            }
762
763            ret = io->size;
764            io->iostate = IOSTATE_INITIAL;
765
766            if (!ResetEvent (io->overlapped.hEvent))
767                dbg_tap("ResetEvent in finalize failed!\n");
768
769            dbg_tap_win32 ("WIN32 I/O: TAP Completion success: QUEUED! [%d]\n", ret);
770        }
771        else
772        {
773            /* error during a queued operation */
774            /* error, or just not completed? */
775            ret = 0;
776            if (GetLastError() != ERROR_IO_INCOMPLETE)
777            {
778                /* if no error (i.e. just not finished yet),
779                   then DON'T execute this code */
780                io->iostate = IOSTATE_INITIAL;
781                if (!ResetEvent (io->overlapped.hEvent))
782                    dbg_tap("ResetEvent in finalize failed!\n");
783
784                dbg_tap("WIN32 I/O: TAP Completion error\n");
785                ret = -1;     /* There actually was an error */
786            }
787        }
788
789        break;
790
791    case IOSTATE_IMMEDIATE_RETURN:
792        io->iostate = IOSTATE_INITIAL;
793        if (!ResetEvent (io->overlapped.hEvent))
794            dbg_tap("ResetEvent in finalize failed!\n");
795
796        if (io->status)
797        {
798            /* error return for a non-queued operation */
799            SetLastError (io->status);
800            ret = -1;
801            dbg_tap("WIN32 I/O: TAP Completion non-queued error\n");
802        }
803        else
804        {
805            /* successful return for a non-queued operation */
806            if (buf)
807                *buf = io->buf;
808
809            ret = io->size;
810            dbg_tap_win32 ("WIN32 I/O: TAP Completion non-queued success [%d]\n", ret);
811        }
812
813        break;
814
815    case IOSTATE_INITIAL:     /* were we called without proper queueing? */
816        SetLastError (ERROR_INVALID_FUNCTION);
817        ret = -1;
818        dbg_tap ("WIN32 I/O: TAP Completion BAD STATE\n");
819        break;
820
821    default:
822        dbg_tap ("Some weird case happened..\n");
823    }
824
825    if (buf)
826        *buf_len = ret;
827
828    return ret;
829}
830
831
832
833/* returns the amount of bytes written */
834int tun_write_queue (struct tuntap *tt, uint8_t *buf, uint32_t buf_len)
835{
836    if (tt->writes.iostate == IOSTATE_INITIAL)
837    {
838        BOOL status;
839        int err;
840
841        /* make a private copy of buf */
842        tt->writes.buf = tt->writes.buf_init;
843        tt->writes.buf_len = buf_len;
844        memcpy(tt->writes.buf, buf, buf_len);
845
846        /* the overlapped write will signal this event on I/O completion */
847        if (!ResetEvent (tt->writes.overlapped.hEvent))
848            dbg_tap("ResetEvent in write_queue failed!\n");
849
850        status = WriteFile(
851            tt->hand,
852            tt->writes.buf,
853            tt->writes.buf_len,
854            &tt->writes.size,
855            &tt->writes.overlapped
856            );
857
858        if (status) /* operation completed immediately? */
859        {
860            tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
861
862            /* since we got an immediate return, we must signal the event object ourselves */
863            if (!SetEvent (tt->writes.overlapped.hEvent))
864                dbg_tap("SetEvent in write_queue failed!\n");
865
866            tt->writes.status = 0;
867
868            dbg_tap_win32 ("WIN32 I/O: TAP Write immediate return [%d,%d]\n",
869                       (int)(tt->writes.buf_len),
870                       (int)tt->writes.size);
871        }
872        else
873        {
874            err = GetLastError ();
875            if (err == ERROR_IO_PENDING) /* operation queued? */
876            {
877                tt->writes.iostate = IOSTATE_QUEUED;
878                tt->writes.status = err;
879                dbg_tap_win32("WIN32 I/O: TAP Write queued [%d]\n",
880                          (tt->writes.buf_len));
881            }
882            else /* error occurred */
883            {
884                if (!SetEvent (tt->writes.overlapped.hEvent))
885                    dbg_tap("SetEvent in write_queue failed!\n");
886
887                tt->writes.iostate = IOSTATE_IMMEDIATE_RETURN;
888                tt->writes.status = err;
889                dbg_tap ("WIN32 I/O: TAP Write error [%d] : %d\n", (int) &tt->writes.buf_len, (int) err);
890            }
891        }
892    }
893
894    return tt->writes.iostate;
895}
896
897static inline int overlapped_io_active (struct overlapped_io *o)
898{
899    return o->iostate == IOSTATE_QUEUED || o->iostate == IOSTATE_IMMEDIATE_RETURN;
900}
901
902/* if >= 0: returns the amount of bytes read, otherwise error! */
903static int tun_write_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len)
904{
905    int err = 0;
906    int status = 0;
907    if (overlapped_io_active (&tt->writes))
908    {
909        status = tun_finalize (tt->hand, &tt->writes, NULL, 0);
910        if (status == 0)
911        {
912            /* busy, just wait, do not schedule a new write */
913            return 0;
914        }
915
916        if (status < 0)
917            err = GetLastError ();
918    }
919
920    /* the overlapped IO is done, now we can schedule a new write */
921    tun_write_queue (tt, buf, buf_len);
922    if (status < 0)
923    {
924        SetLastError (err);
925        return status;
926    }
927    else
928        return buf_len;
929}
930
931
932/* if >= 0: returns the amount of bytes read, otherwise error! */
933static int tun_read_win32 (struct tuntap *tt, uint8_t *buf, uint32_t buf_len)
934{
935    int err = 0;
936    int status = 0;
937
938
939    /* First, finish possible pending IOs */
940    if (overlapped_io_active (&tt->reads))
941    {
942        status = tun_finalize (tt->hand, &tt->reads, &buf, &buf_len);
943        if (status == 0)
944        {
945            /* busy, just wait, do not schedule a new read */
946            return 0;
947        }
948
949        if (status < 0)
950        {
951            dbg_tap ("tun_finalize status < 0: %d\n", status);
952            err = GetLastError ();
953        }
954
955        if (status > 0)
956        {
957            return buf_len;
958        }
959    }
960
961    /* If no pending IOs, schedule a new read */
962    /* queue, or immediate return */
963    if (IOSTATE_IMMEDIATE_RETURN == tun_read_queue(tt, buf, buf_len))
964    {
965        return tt->reads.size;
966    }
967
968    /* If the pending IOs gave an error, report it */
969    if (status < 0)
970    {
971        SetLastError (err);
972        return status;
973    }
974    else
975    {
976        /* no errors, but the newly scheduled read is now pending */
977        return 0;
978    }
979}
980
981
982static int read_tun_buffered(struct tuntap *tt, uint8_t *buf, uint32_t buf_len)
983{
984    return tun_read_win32 (tt, buf, buf_len);
985}
986
987static int write_tun_buffered(struct tuntap *tt, uint8_t *buf, uint32_t buf_len)
988{
989    return tun_write_win32 (tt, buf, buf_len);
990}
991
992
993static int pico_tap_send(struct pico_device *dev, void *buf, int len)
994{
995    uint32_t bytes_sent = 0;
996    struct pico_device_tap *tap = (struct pico_device_tap *) dev;
997
998    /* Increase the statistic count */
999    tap->statistics_frames_out++;
1000
1001    bytes_sent = write_tun_buffered (tap->tt, buf, len);
1002    dbg_tap("TX> sent %d bytes\n", bytes_sent);
1003
1004    /* Discard the frame content silently. */
1005    return bytes_sent;
1006}
1007
1008uint8_t recv_buffer[1500];
1009
1010static int pico_tap_poll(struct pico_device *dev, int loop_score)
1011{
1012    struct pico_device_tap *tap = (struct pico_device_tap *) dev;
1013    while (loop_score)
1014    {
1015        int bytes_read = read_tun_buffered(tap->tt, recv_buffer, 1500);
1016        loop_score--;
1017        if (bytes_read > 0)
1018        {
1019            dbg_tap("RX< recvd: %d bytes\n", bytes_read);
1020            pico_stack_recv(dev, recv_buffer, bytes_read);
1021            /* break; */
1022        }
1023        else
1024            break;
1025    }
1026    return loop_score;
1027}
1028
1029
1030
1031#define CLEAR(x) memset(&(x), 0, sizeof(x))
1032
1033void overlapped_io_init (struct overlapped_io *o, int event_state)
1034{
1035    CLEAR (*o);
1036
1037    /* manual reset event, initially set according to event_state */
1038    o->overlapped.hEvent = CreateEvent (NULL, TRUE, event_state, NULL);
1039    if (o->overlapped.hEvent == NULL)
1040        dbg_tap ("Error: overlapped_io_init: CreateEvent failed\n");
1041
1042    /* allocate buffer for overlapped I/O */
1043    o->buf_init = PICO_ZALLOC(1500); /* XXX: MTU */
1044    o->buf_init_len = 1500; /* XXX: MTU */
1045    if (!(o->buf_init))
1046        dbg_tap("buffer alloc failed!\n"); /* XXX: return -1 or so? */
1047    else
1048        dbg_tap("overlapped_io_init buffer allocated!\n");
1049}
1050
1051void init_tun_post (struct tuntap *tt)
1052{
1053    dbg_tap("TUN post init (for overlapped io)\n");
1054    overlapped_io_init (&tt->reads, FALSE);
1055    overlapped_io_init (&tt->writes, TRUE);
1056    tt->rw_handle.read = tt->reads.overlapped.hEvent;
1057    tt->rw_handle.write = tt->writes.overlapped.hEvent;
1058}
1059
1060
1061/*
1062 * Public interface: pico_tap_create
1063 * TODO: pico_tap_destroy
1064 */
1065
1066struct pico_device *pico_tap_create(char *name, uint8_t *mac)
1067{
1068    struct pico_device_tap *tap = PICO_ZALLOC(sizeof(struct pico_device_tap));
1069    struct tuntap *tt = PICO_ZALLOC(sizeof(struct tuntap), 1);
1070
1071    if (!(tap) || !(tt))
1072        return NULL;
1073
1074    tap->dev.overhead = 0;
1075    tap->statistics_frames_out = 0;
1076    tap->dev.send = pico_tap_send;
1077    tap->dev.poll = pico_tap_poll;
1078
1079    show_tap_win_adapters();
1080
1081    tt->type = DEV_TYPE_TAP;
1082    if (open_tun(NULL, NULL, "tap0", tt))
1083    {
1084        dbg_tap("Failed to create TAP device!\n");
1085        PICO_FREE(tt);
1086        PICO_FREE(tap);
1087        return NULL;
1088    }
1089
1090    tap->tt = tt;
1091
1092    if( 0 != pico_device_init((struct pico_device *)tap, name, mac)) {
1093        return NULL;
1094    }
1095
1096    init_tun_post(tt); /* init overlapped io */
1097
1098    dbg_tap("Device %s created.\n", tap->dev.name);
1099
1100    return (struct pico_device *)tap;
1101}
1102