tap-win32.c 20 KB

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