1
0

TAPInterface.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #include "exception/Except.h"
  16. #include "exception/WinFail.h"
  17. #include "memory/Allocator.h"
  18. #include "interface/tuntap/windows/TAPDevice.h"
  19. #include "interface/tuntap/windows/TAPInterface.h"
  20. #include "interface/FramingInterface.h"
  21. #include "util/events/EventBase.h"
  22. #include "util/events/Pipe.h"
  23. #include "util/platform/netdev/NetDev.h"
  24. /*
  25. * Portions of this code are copied from QEMU project which is licensed
  26. * under GPLv2 or greater, further contributions are licensed under GPLv3
  27. * or greater.
  28. */
  29. /*
  30. * TAP-Win32 -- A kernel driver to provide virtual tap device functionality
  31. * on win32. Originally derived from the CIPE-Win32
  32. * project by Damion K. Wilson, with extensive modifications by
  33. * James Yonan.
  34. *
  35. * All source code which derives from the CIPE-Win32 project is
  36. * Copyright (C) Damion K. Wilson, 2003, and is released under the
  37. * GPL version 2 (see below).
  38. *
  39. * All other source code is Copyright (C) James Yonan, 2003-2004,
  40. * and is released under the GPL version 2 (see below).
  41. *
  42. * This program is free software; you can redistribute it and/or modify
  43. * it under the terms of the GNU General Public License as published by
  44. * the Free Software Foundation; either version 2 of the License, or
  45. * (at your option) any later version.
  46. *
  47. * This program is distributed in the hope that it will be useful,
  48. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  49. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  50. * GNU General Public License for more details.
  51. *
  52. * You should have received a copy of the GNU General Public License
  53. * along with this program (see the file COPYING included with this
  54. * distribution); if not, write to the Free Software Foundation, Inc.,
  55. * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  56. */
  57. #include <stdio.h>
  58. #include <windows.h>
  59. #include <io.h>
  60. //=============
  61. // TAP IOCTLs
  62. //=============
  63. #define TAP_CONTROL_CODE(request,method) \
  64. CTL_CODE (FILE_DEVICE_UNKNOWN, request, method, FILE_ANY_ACCESS)
  65. #define TAP_IOCTL_GET_MAC TAP_CONTROL_CODE (1, METHOD_BUFFERED)
  66. #define TAP_IOCTL_GET_VERSION TAP_CONTROL_CODE (2, METHOD_BUFFERED)
  67. #define TAP_IOCTL_GET_MTU TAP_CONTROL_CODE (3, METHOD_BUFFERED)
  68. #define TAP_IOCTL_GET_INFO TAP_CONTROL_CODE (4, METHOD_BUFFERED)
  69. #define TAP_IOCTL_CONFIG_POINT_TO_POINT TAP_CONTROL_CODE (5, METHOD_BUFFERED)
  70. #define TAP_IOCTL_SET_MEDIA_STATUS TAP_CONTROL_CODE (6, METHOD_BUFFERED)
  71. #define TAP_IOCTL_CONFIG_DHCP_MASQ TAP_CONTROL_CODE (7, METHOD_BUFFERED)
  72. #define TAP_IOCTL_GET_LOG_LINE TAP_CONTROL_CODE (8, METHOD_BUFFERED)
  73. #define TAP_IOCTL_CONFIG_DHCP_SET_OPT TAP_CONTROL_CODE (9, METHOD_BUFFERED)
  74. struct TAPInterface_Version_pvt {
  75. unsigned long major;
  76. unsigned long minor;
  77. unsigned long debug;
  78. };
  79. static void getVersion(HANDLE tap, struct TAPInterface_Version_pvt* version, struct Except* eh)
  80. {
  81. ULONG version_len;
  82. BOOL bret = DeviceIoControl(tap,
  83. TAP_IOCTL_GET_VERSION,
  84. version,
  85. sizeof(struct TAPInterface_Version_pvt),
  86. version,
  87. sizeof(struct TAPInterface_Version_pvt),
  88. &version_len,
  89. NULL);
  90. if (!bret) {
  91. DWORD err = GetLastError();
  92. CloseHandle(tap);
  93. WinFail_fail(eh, "DeviceIoControl(TAP_IOCTL_GET_VERSION)", err);
  94. }
  95. if (version_len != sizeof(struct TAPInterface_Version_pvt)) {
  96. CloseHandle(tap);
  97. Except_throw(eh, "DeviceIoControl(TAP_IOCTL_GET_VERSION) out size [%d] expected [%d]",
  98. (int)version_len, (int)sizeof(struct TAPInterface_Version_pvt));
  99. }
  100. }
  101. static void setEnabled(HANDLE tap, int status, struct Except* eh)
  102. {
  103. unsigned long len = 0;
  104. BOOL bret = DeviceIoControl(tap, TAP_IOCTL_SET_MEDIA_STATUS,
  105. &status, sizeof (status),
  106. &status, sizeof (status), &len, NULL);
  107. if (!bret) {
  108. DWORD err = GetLastError();
  109. CloseHandle(tap);
  110. WinFail_fail(eh, "DeviceIoControl(TAP_IOCTL_SET_MEDIA_STATUS)", err);
  111. }
  112. }
  113. union TAPInterface_buffer {
  114. struct {
  115. uint32_t length_be;
  116. // account for ethernet misallignment
  117. uint16_t pad;
  118. uint8_t data[2042];
  119. } components;
  120. uint8_t bytes[2048];
  121. };
  122. #define TAPInterface_FdAndOl_state_AWAITING_READ 1
  123. #define TAPInterface_FdAndOl_state_AWAITING_WRITE 2
  124. struct TAPInterface_FdAndOl
  125. {
  126. HANDLE fd;
  127. OVERLAPPED ol;
  128. union TAPInterface_buffer buff;
  129. int state;
  130. DWORD bytes;
  131. DWORD offset;
  132. char* name;
  133. };
  134. struct TAPInterface_ThreadContext
  135. {
  136. struct TAPInterface_FdAndOl tap;
  137. struct TAPInterface_FdAndOl pipe;
  138. };
  139. #include "util/Hex.h"
  140. /**
  141. * Copy data from one file handle to another.
  142. * @return the handle which has blocked.
  143. */
  144. #define thread_copy_ADD_FRAMING 1
  145. #define thread_copy_REMOVE_FRAMING 2
  146. static HANDLE thread_copy(struct TAPInterface_FdAndOl* from,
  147. struct TAPInterface_FdAndOl* to,
  148. int framing)
  149. {
  150. for (;;) {
  151. uint8_t* readTo = (framing == thread_copy_ADD_FRAMING)
  152. ? from->buff.components.data : from->buff.bytes;
  153. uint8_t* writeFrom = (framing == thread_copy_REMOVE_FRAMING)
  154. ? from->buff.components.data : from->buff.bytes;
  155. DWORD bytesToRead = 2042;
  156. if (framing == thread_copy_REMOVE_FRAMING) {
  157. if (!from->bytes) {
  158. bytesToRead = 4;
  159. } else {
  160. bytesToRead = from->bytes;
  161. }
  162. }
  163. DWORD bytesRead = 0;
  164. if (from->state == TAPInterface_FdAndOl_state_AWAITING_READ) {
  165. if (!GetOverlappedResult(from->fd, &from->ol, &bytesRead, FALSE)) {
  166. switch (GetLastError()) {
  167. case ERROR_IO_PENDING: return from->fd;
  168. default:;
  169. }
  170. printf("GetOverlappedResult(read, %s): %s\n",
  171. from->name, WinFail_strerror(GetLastError()));
  172. Assert_true(0);
  173. }
  174. printf("read completed from %s with %d bytes\n", from->name, (int)bytesRead);
  175. from->state = 0;
  176. } else if (from->state == TAPInterface_FdAndOl_state_AWAITING_WRITE) {
  177. DWORD bytesWritten;
  178. if (!GetOverlappedResult(to->fd, &from->ol, &bytesWritten, FALSE)) {
  179. switch (GetLastError()) {
  180. case ERROR_IO_PENDING: return to->fd;
  181. default:;
  182. }
  183. printf("GetOverlappedResult(write, %s): %s\n",
  184. to->name, WinFail_strerror(GetLastError()));
  185. Assert_true(0);
  186. }
  187. from->state = 0;
  188. if (bytesWritten < from->bytes) {
  189. from->bytes -= bytesWritten;
  190. from->offset += bytesWritten;
  191. goto writeMore;
  192. } else {
  193. Assert_true(bytesWritten == from->bytes);
  194. from->bytes = 0;
  195. from->offset = 0;
  196. printf("write to %s with %d bytes completed\n", to->name, (int)bytesWritten);
  197. // successfully finished a write, loop back and try again.
  198. continue;
  199. }
  200. } else if (!ReadFile(from->fd, &readTo[from->offset], bytesToRead, &bytesRead, &from->ol)) {
  201. switch (GetLastError()) {
  202. case ERROR_IO_PENDING: {
  203. from->state = TAPInterface_FdAndOl_state_AWAITING_READ;
  204. printf("read pending from %s\n", from->name);
  205. return from->fd;
  206. }
  207. default: {
  208. printf("ReadFile(%s): %s\n", from->name, WinFail_strerror(GetLastError()));
  209. Assert_true(0);
  210. }
  211. }
  212. } else {
  213. printf("read completed immedietly from %s with %d bytes\n",
  214. from->name, (int)bytesRead);
  215. }
  216. if (framing == thread_copy_REMOVE_FRAMING) {
  217. if (!from->bytes) {
  218. if (bytesRead < 4) {
  219. from->offset += bytesRead;
  220. continue;
  221. }
  222. from->bytes = Endian_bigEndianToHost32(from->buff.components.length_be) + 4;
  223. Assert_true(from->bytes <= 2042);
  224. }
  225. if (bytesRead < from->bytes) {
  226. from->offset += bytesRead;
  227. from->bytes -= bytesRead;
  228. continue;
  229. }
  230. } else {
  231. from->bytes = bytesRead;
  232. from->bytes += 2;
  233. from->buff.components.length_be = Endian_hostToBigEndian32(((uint32_t)from->bytes));
  234. from->bytes += 4;
  235. }
  236. from->offset = 0;
  237. writeMore:
  238. for (;;) {
  239. DWORD bytes;
  240. if (!WriteFile(to->fd,
  241. &writeFrom[from->offset],
  242. from->bytes - (writeFrom - from->buff.bytes),
  243. &bytes,
  244. &from->ol))
  245. {
  246. switch (GetLastError()) {
  247. case ERROR_IO_PENDING: {
  248. from->state = TAPInterface_FdAndOl_state_AWAITING_WRITE;
  249. return to->fd;
  250. }
  251. default:;
  252. }
  253. printf("WriteFile(%s): %s\n", to->name, WinFail_strerror(GetLastError()));
  254. Assert_true(0);
  255. } else {
  256. if (bytes < from->bytes) {
  257. from->bytes += bytes;
  258. from->offset += bytes;
  259. continue;
  260. }
  261. Assert_true(bytes == from->bytes);
  262. printf("write to %s with %d bytes completed immedietly\n", to->name, (int)bytes);
  263. from->bytes = 0;
  264. from->offset = 0;
  265. break;
  266. }
  267. }
  268. }
  269. }
  270. static DWORD WINAPI thread_main(LPVOID param)
  271. {
  272. struct TAPInterface_ThreadContext* tc = (struct TAPInterface_ThreadContext*)param;
  273. for (;;) {
  274. HANDLE handles[2];
  275. handles[0] = thread_copy(&tc->tap, &tc->pipe, thread_copy_ADD_FRAMING);
  276. handles[1] = thread_copy(&tc->pipe, &tc->tap, thread_copy_REMOVE_FRAMING);
  277. if (WaitForMultipleObjects(2, handles, FALSE, 3000) == WAIT_FAILED) {
  278. printf("WaitForMultipleObjects(): %s\n", WinFail_strerror(GetLastError()));
  279. }
  280. }
  281. return 0;
  282. }
  283. struct Interface* TAPInterface_new(const char* preferredName,
  284. char** assignedName,
  285. struct Except* eh,
  286. struct Log* logger,
  287. struct EventBase* base,
  288. struct Allocator* alloc)
  289. {
  290. Log_debug(logger, "Getting TAP-Windows device name");
  291. struct TAPDevice* dev = TAPDevice_find(preferredName, eh, alloc);
  292. *assignedName = dev->name;
  293. NetDev_flushAddresses(dev->name, eh);
  294. Log_debug(logger, "Opening TAP-Windows device [%s] at location [%s]", dev->name, dev->path);
  295. struct TAPInterface_ThreadContext* tc =
  296. Allocator_calloc(alloc, sizeof(struct TAPInterface_ThreadContext), 1);
  297. WinFail_assert(eh, (tc->tap.ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL);
  298. WinFail_assert(eh, (tc->pipe.ol.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL)) != NULL);
  299. tc->tap.name = "tap";
  300. tc->pipe.name = "pipe";
  301. tc->tap.fd = CreateFile(dev->path,
  302. GENERIC_READ | GENERIC_WRITE,
  303. 0,
  304. 0,
  305. OPEN_EXISTING,
  306. FILE_ATTRIBUTE_SYSTEM | FILE_FLAG_OVERLAPPED,
  307. 0);
  308. if (tc->tap.fd == INVALID_HANDLE_VALUE) {
  309. WinFail_fail(eh, "CreateFile(tapDevice)", GetLastError());
  310. }
  311. struct TAPInterface_Version_pvt ver = { .major = 0 };
  312. getVersion(tc->tap.fd, &ver, eh);
  313. setEnabled(tc->tap.fd, 1, eh);
  314. tc->pipe.fd =
  315. CreateNamedPipeA("\\\\.\\pipe\\cjdns_pipe_abcdefg",
  316. PIPE_ACCESS_DUPLEX | FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_OVERLAPPED,
  317. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
  318. PIPE_UNLIMITED_INSTANCES,
  319. 65536,
  320. 65536,
  321. 0,
  322. NULL);
  323. struct Pipe* p = Pipe_named("abcdefg", base, eh, alloc);
  324. p->logger = logger;
  325. // CreateThread(NULL, 0, piper, (LPVOID)&fh[1], 0, NULL);
  326. CreateThread(NULL, 0, thread_main, (LPVOID)tc, 0, NULL);
  327. Log_info(logger, "Opened TAP-Windows device [%s] version [%lu.%lu.%lu] at location [%s]",
  328. dev->name, ver.major, ver.minor, ver.debug, dev->path);
  329. return FramingInterface_new(2048, &p->iface, alloc);
  330. }