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