--- gvpe/src/device-cygwin.C 2003/03/01 15:53:03 1.1 +++ gvpe/src/device-cygwin.C 2003/10/15 01:35:45 1.4 @@ -1,6 +1,8 @@ /* device-cygwin.C -- Stub for Cygwin environment Copyright (C) 2003 Marc Lehmann + Copyright (C) 2002-2003 Ivo Timmermans , + 2002-2003 Guus Sliepen This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -23,6 +25,8 @@ // this is probably not very fast, but neither is cygwin nor poll. // // http://cipe-win32.sourceforge.net/ +// a newer driver is available as part of the openvpn package: +// http://openvpn.sf.net/ #include "config.h" @@ -38,11 +42,153 @@ #include "conf.h" #include "util.h" +#include +#include + +#define REG_CONTROL_NET "SYSTEM\\CurrentControlSet\\Control\\Network\\{4D36E972-E325-11CE-BFC1-08002BE10318}" + +#define USERMODEDEVICEDIR "\\\\.\\" +#define USERDEVICEDIR "\\??\\" +#define TAPSUFFIX ".tap" + +#define TAP_CONTROL_CODE(request,method) CTL_CODE(FILE_DEVICE_PHYSICAL_NETCARD | 8000, request, method, FILE_ANY_ACCESS) + +#define TAP_IOCTL_GET_LASTMAC TAP_CONTROL_CODE(0, METHOD_BUFFERED) +#define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE(1, METHOD_BUFFERED) +#define TAP_IOCTL_SET_STATISTICS TAP_CONTROL_CODE(2, METHOD_BUFFERED) + +static HANDLE device_handle = INVALID_HANDLE_VALUE; +static mac my_mac; + +static const char * +wstrerror (int err) +{ + static char buf[1024]; + + if (!FormatMessage + (FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, + MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), buf, sizeof (buf), NULL)) + { + strncpy (buf, _("(unable to format errormessage)"), sizeof (buf)); + }; + + if ((char *newline = strchr (buf, '\r'))) + *newline = '\0'; + + return buf; +} + +const char * +tap_device::info () +{ + return _("cygwin cipe/openvpn tap device"); +} + tap_device::tap_device () { - if ((fd = open (conf.ifname, O_RDWR)) < 0) + HKEY key, key2; + int i; + + char regpath[1024]; + char adapterid[1024]; + char adaptername[1024]; + char tapname[1024]; + long len; + + bool found = false; + + int sock, err; + + /* Open registry and look for network adapters */ + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, REG_CONTROL_NET, 0, KEY_READ, &key)) + { + slog (L_ERR, _("Unable to read registry: %s"), + wstrerror (GetLastError ())); + return false; + } + + for (i = 0;; i++) + { + len = sizeof (adapterid); + if (RegEnumKeyEx (key, i, adapterid, &len, 0, 0, 0, NULL)) + break; + + /* Find out more about this adapter */ + + snprintf (regpath, sizeof (regpath), "%s\\%s\\Connection", + REG_CONTROL_NET, adapterid); + + if (RegOpenKeyEx (HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &key2)) + continue; + + len = sizeof (adaptername); + err = RegQueryValueEx (key2, "Name", 0, 0, adaptername, &len); + + RegCloseKey (key2); + + if (err) + continue; + + if (conf.ifname) + { + if (strcmp (conf.ifname, adapterid)) + continue; + } + else + { + found = true; + break; + } + + snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, adapterid); + device_handle = CreateFile(tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, + OPEN_EXISTING, FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + if (device_handle != INVALID_HANDLE_VALUE) + { + found = true; + break; + } + } + + RegCloseKey (key); + + if (!found) + { + slog (L_ERR, _("No Windows tap device found!")); + exit (1); + } + + strcpy (ifrname, adaptername); + + /* Try to open the corresponding tap device */ + + if (device_handle == INVALID_HANDLE_VALUE) + { + snprintf (tapname, sizeof (tapname), USERMODEDEVICEDIR "%s" TAPSUFFIX, device); + device_handle = + CreateFile (tapname, GENERIC_WRITE | GENERIC_READ, 0, 0, + OPEN_EXISTING, + FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED, 0); + } + + if (device_handle == INVALID_HANDLE_VALUE) { - slog (L_CRIT, _("could not open %s: %s"), conf.ifname, strerror (errno)); + slog (L_ERR, _("%s (%s) is not a usable Windows tap device: %s"), + device, iface, wstrerror (GetLastError ())); + exit (1); + } + + fd = cygwin_attach_handle_to_fd (tapname, -1, device_handle, 1, GENERIC_WRITE | GENERIC_READ); + + /* Get MAC address from tap device */ + + if (!DeviceIoControl + (device_handle, TAP_IOCTL_GET_MAC, &mac, sizeof (mac), &mac, sizeof (mac), &len, 0)) + { + slog (L_ERR, + _("Could not get MAC address from Windows tap device %s (%s): %s"), + device, iface, wstrerror (GetLastError ())); exit (1); } } @@ -62,7 +208,7 @@ if (pkt->len <= 0) { slog (L_ERR, _("error while reading from %s %s: %s"), - info (), conf.ifname, strerror (errno)); + info (), conf.ifname, strerror (errno)); free (pkt); return 0; } @@ -71,29 +217,142 @@ if (pkt->is_arp ()) { - if ((*pkt)[22] == 0x08) id2mac (THISNODE->id, &((*pkt)[22])); - if ((*pkt)[32] == 0x08) id2mac (THISNODE->id, &((*pkt)[32])); + if ((*pkt)[22] == 0x08) + id2mac (THISNODE->id, &((*pkt)[22])); + if ((*pkt)[32] == 0x08) + id2mac (THISNODE->id, &((*pkt)[32])); } return pkt; } void -tap_device::send (tap_packet *pkt) +tap_device::send (tap_packet * pkt) { - (*pkt)[ 6] = 0x08; (*pkt)[ 7] = 0x00; (*pkt)[ 8] = 0x58; - (*pkt)[ 9] = 0x00; (*pkt)[10] = 0x00; (*pkt)[11] = 0x01; + (*pkt)[6] = 0x08; + (*pkt)[7] = 0x00; + (*pkt)[8] = 0x58; + (*pkt)[9] = 0x00; + (*pkt)[10] = 0x00; + (*pkt)[11] = 0x01; if (pkt->is_arp ()) { - if ((*pkt)[22] == 0xfe && (*pkt)[27] == THISNODE->id) - memcpy (&(*pkt)[22], &(*pkt)[6], sizeof (mac)); + if ((*pkt)[22] == 0xfe && (*pkt)[27] == THISNODE->id) + memcpy (&(*pkt)[22], &(*pkt)[6], sizeof (mac)); - if ((*pkt)[32] == 0xfe && (*pkt)[37] == THISNODE->id) - memcpy (&(*pkt)[32], &(*pkt)[6], sizeof (mac)); + if ((*pkt)[32] == 0xfe && (*pkt)[37] == THISNODE->id) + memcpy (&(*pkt)[32], &(*pkt)[6], sizeof (mac)); } if (write (fd, &((*pkt)[0]), pkt->len) < 0) slog (L_ERR, _("can't write to %s %s: %s"), info (), conf.ifname, - strerror (errno)); + strerror (errno)); +} + +#if 0 + +slog (L_DEBUG, _indent: Standard input:377: Error:Stmt nesting error. +("Tap reader running")); + + /* Read from tap device and send to parent */ + +overlapped.hEvent = CreateEvent (NULL, TRUE, FALSE, NULL); + +for indent +: Standard input: 320: Error:Stmt nesting error.(;; + ) +{ + overlapped.Offset = 0; + overlapped.OffsetHigh = 0; + ResetEvent (overlapped.hEvent); + + status = ReadFile (device_handle, buf, sizeof (buf), &len, &overlapped); + + if (!status) + { + if (GetLastError () == ERROR_IO_PENDING) + { + WaitForSingleObject (overlapped.hEvent, INFINITE); + if (!GetOverlappedResult (device_handle, &overlapped, &len, FALSE)) + continue; + } + else + { + slog (L_ERR, _("Error while reading from %s %s: %s"), + device_info, device, strerror (errno)); + return -1; + } + } + + if (send (sock, buf, len, 0) <= 0) + return -1; +} +} + +void +close_device (void) +{ + cp (); + + CloseHandle (device_handle); +} + +bool +read_packet (vpn_packet_t * packet) +{ + int lenin; + + cp (); + + if ((lenin = recv (device_fd, packet->data, MTU, 0)) <= 0) + { + slog (L_ERR, _("Error while reading from %s %s: %s"), device_info, + device, strerror (errno)); + return false; + } + + packet->len = lenin; + + device_total_in += packet->len; + + ifdebug (TRAFFIC) slog (L_DEBUG, _("Read packet of %d bytes from %s"), + packet->len, device_info); + + return true; +} + +bool +write_packet (vpn_packet_t * packet) +{ + long lenout; + OVERLAPPED overlapped = { 0 }; + + cp (); + + ifdebug (TRAFFIC) slog (L_DEBUG, _("Writing packet of %d bytes to %s"), + packet->len, device_info); + + if (!WriteFile + (device_handle, packet->data, packet->len, &lenout, &overlapped)) + { + slog (L_ERR, _("Error while writing to %s %s: %s"), device_info, + device, wstrerror (GetLastError ())); + return false; + } + + device_total_out += packet->len; + + return true; +} + +void +dump_device_stats (void) +{ + cp (); + + slog (L_DEBUG, _("Statistics for %s %s:"), device_info, device); + slog (L_DEBUG, _(" total bytes in: %10d"), device_total_in); + slog (L_DEBUG, _(" total bytes out: %10d"), device_total_out); } +#endif