xref: /freebsd/contrib/libpcap/pcap-tc.c (revision e0c4386e)
1 /*
2  * Copyright (c) 2008 CACE Technologies, Davis (California)
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of CACE Technologies nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  */
31 
32 #ifdef HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include <pcap.h>
37 #include <pcap-int.h>
38 
39 #include "pcap-tc.h"
40 
41 #include <malloc.h>
42 #include <memory.h>
43 #include <string.h>
44 #include <errno.h>
45 
46 #ifdef _WIN32
47 #include <tchar.h>
48 #endif
49 
50 typedef TC_STATUS	(TC_CALLCONV *TcFcnQueryPortList)			(PTC_PORT *ppPorts, PULONG pLength);
51 typedef TC_STATUS	(TC_CALLCONV *TcFcnFreePortList)			(TC_PORT *pPorts);
52 
53 typedef PCHAR		(TC_CALLCONV *TcFcnStatusGetString)			(TC_STATUS status);
54 
55 typedef PCHAR		(TC_CALLCONV *TcFcnPortGetName)				(TC_PORT port);
56 typedef PCHAR		(TC_CALLCONV *TcFcnPortGetDescription)		(TC_PORT port);
57 
58 typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceOpenByName)		(PCHAR name, PTC_INSTANCE pInstance);
59 typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceClose)			(TC_INSTANCE instance);
60 typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceSetFeature)		(TC_INSTANCE instance, ULONG feature, ULONG value);
61 typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceQueryFeature)	(TC_INSTANCE instance, ULONG feature, PULONG pValue);
62 typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceReceivePackets)	(TC_INSTANCE instance, PTC_PACKETS_BUFFER pBuffer);
63 typedef HANDLE		(TC_CALLCONV *TcFcnInstanceGetReceiveWaitHandle) (TC_INSTANCE instance);
64 typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceTransmitPackets)	(TC_INSTANCE instance, TC_PACKETS_BUFFER pBuffer);
65 typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceQueryStatistics)	(TC_INSTANCE instance, PTC_STATISTICS pStatistics);
66 
67 typedef TC_STATUS	(TC_CALLCONV *TcFcnPacketsBufferCreate)		(ULONG size, PTC_PACKETS_BUFFER pBuffer);
68 typedef VOID		(TC_CALLCONV *TcFcnPacketsBufferDestroy)	(TC_PACKETS_BUFFER buffer);
69 typedef TC_STATUS	(TC_CALLCONV *TcFcnPacketsBufferQueryNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID *ppData);
70 typedef TC_STATUS	(TC_CALLCONV *TcFcnPacketsBufferCommitNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID pData);
71 
72 typedef VOID		(TC_CALLCONV *TcFcnStatisticsDestroy)		(TC_STATISTICS statistics);
73 typedef TC_STATUS	(TC_CALLCONV *TcFcnStatisticsUpdate)		(TC_STATISTICS statistics);
74 typedef TC_STATUS	(TC_CALLCONV *TcFcnStatisticsQueryValue)	(TC_STATISTICS statistics, ULONG counterId, PULONGLONG pValue);
75 
76 typedef enum LONG
77 {
78 	TC_API_UNLOADED = 0,
79 	TC_API_LOADED,
80 	TC_API_CANNOT_LOAD,
81 	TC_API_LOADING
82 }
83 	TC_API_LOAD_STATUS;
84 
85 
86 typedef struct _TC_FUNCTIONS
87 {
88 	TC_API_LOAD_STATUS			LoadStatus;
89 #ifdef _WIN32
90 	HMODULE						hTcApiDllHandle;
91 #endif
92 	TcFcnQueryPortList			QueryPortList;
93 	TcFcnFreePortList			FreePortList;
94 	TcFcnStatusGetString		StatusGetString;
95 
96 	TcFcnPortGetName			PortGetName;
97 	TcFcnPortGetDescription		PortGetDescription;
98 
99 	TcFcnInstanceOpenByName		InstanceOpenByName;
100 	TcFcnInstanceClose			InstanceClose;
101 	TcFcnInstanceSetFeature		InstanceSetFeature;
102 	TcFcnInstanceQueryFeature	InstanceQueryFeature;
103 	TcFcnInstanceReceivePackets	InstanceReceivePackets;
104 #ifdef _WIN32
105 	TcFcnInstanceGetReceiveWaitHandle InstanceGetReceiveWaitHandle;
106 #endif
107 	TcFcnInstanceTransmitPackets InstanceTransmitPackets;
108 	TcFcnInstanceQueryStatistics InstanceQueryStatistics;
109 
110 	TcFcnPacketsBufferCreate	PacketsBufferCreate;
111 	TcFcnPacketsBufferDestroy	PacketsBufferDestroy;
112 	TcFcnPacketsBufferQueryNextPacket	PacketsBufferQueryNextPacket;
113 	TcFcnPacketsBufferCommitNextPacket  PacketsBufferCommitNextPacket;
114 
115 	TcFcnStatisticsDestroy		StatisticsDestroy;
116 	TcFcnStatisticsUpdate		StatisticsUpdate;
117 	TcFcnStatisticsQueryValue	StatisticsQueryValue;
118 }
119 	TC_FUNCTIONS;
120 
121 static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port);
122 static int TcSetDatalink(pcap_t *p, int dlt);
123 static int TcGetNonBlock(pcap_t *p);
124 static int TcSetNonBlock(pcap_t *p, int nonblock);
125 static void TcCleanup(pcap_t *p);
126 static int TcInject(pcap_t *p, const void *buf, int size);
127 static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
128 static int TcStats(pcap_t *p, struct pcap_stat *ps);
129 #ifdef _WIN32
130 static struct pcap_stat *TcStatsEx(pcap_t *p, int *pcap_stat_size);
131 static int TcSetBuff(pcap_t *p, int dim);
132 static int TcSetMode(pcap_t *p, int mode);
133 static int TcSetMinToCopy(pcap_t *p, int size);
134 static HANDLE TcGetReceiveWaitHandle(pcap_t *p);
135 static int TcOidGetRequest(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp);
136 static int TcOidSetRequest(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp);
137 static u_int TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue, int sync);
138 static int TcSetUserBuffer(pcap_t *p, int size);
139 static int TcLiveDump(pcap_t *p, char *filename, int maxsize, int maxpacks);
140 static int TcLiveDumpEnded(pcap_t *p, int sync);
141 static PAirpcapHandle TcGetAirPcapHandle(pcap_t *p);
142 #endif
143 
144 #ifdef _WIN32
145 TC_FUNCTIONS g_TcFunctions =
146 {
147 	TC_API_UNLOADED, /* LoadStatus */
148 	NULL,  /* hTcApiDllHandle */
149 	NULL,  /* QueryPortList */
150 	NULL,  /* FreePortList */
151 	NULL,  /* StatusGetString */
152 	NULL,  /* PortGetName */
153 	NULL,  /* PortGetDescription */
154 	NULL,  /* InstanceOpenByName */
155 	NULL,  /* InstanceClose */
156 	NULL,  /* InstanceSetFeature */
157 	NULL,  /* InstanceQueryFeature */
158 	NULL,  /* InstanceReceivePackets */
159 	NULL,  /* InstanceGetReceiveWaitHandle */
160 	NULL,  /* InstanceTransmitPackets */
161 	NULL,  /* InstanceQueryStatistics */
162 	NULL,  /* PacketsBufferCreate */
163 	NULL,  /* PacketsBufferDestroy */
164 	NULL,  /* PacketsBufferQueryNextPacket */
165 	NULL,  /* PacketsBufferCommitNextPacket */
166 	NULL,  /* StatisticsDestroy */
167 	NULL,  /* StatisticsUpdate */
168 	NULL  /* StatisticsQueryValue */
169 };
170 #else
171 TC_FUNCTIONS g_TcFunctions =
172 {
173 	TC_API_LOADED, /* LoadStatus */
174 	TcQueryPortList,
175 	TcFreePortList,
176 	TcStatusGetString,
177 	TcPortGetName,
178 	TcPortGetDescription,
179 	TcInstanceOpenByName,
180 	TcInstanceClose,
181 	TcInstanceSetFeature,
182 	TcInstanceQueryFeature,
183 	TcInstanceReceivePackets,
184 #ifdef _WIN32
185 	TcInstanceGetReceiveWaitHandle,
186 #endif
187 	TcInstanceTransmitPackets,
188 	TcInstanceQueryStatistics,
189 	TcPacketsBufferCreate,
190 	TcPacketsBufferDestroy,
191 	TcPacketsBufferQueryNextPacket,
192 	TcPacketsBufferCommitNextPacket,
193 	TcStatisticsDestroy,
194 	TcStatisticsUpdate,
195 	TcStatisticsQueryValue,
196 };
197 #endif
198 
199 #define MAX_TC_PACKET_SIZE	9500
200 
201 #pragma pack(push, 1)
202 
203 #define PPH_PH_FLAG_PADDING	((UCHAR)0x01)
204 #define PPH_PH_VERSION		((UCHAR)0x00)
205 
206 typedef struct _PPI_PACKET_HEADER
207 {
208 	UCHAR	PphVersion;
209 	UCHAR	PphFlags;
210 	USHORT	PphLength;
211 	ULONG	PphDlt;
212 }
213 	PPI_PACKET_HEADER, *PPPI_PACKET_HEADER;
214 
215 typedef struct _PPI_FIELD_HEADER
216 {
217 	USHORT PfhType;
218 	USHORT PfhLength;
219 }
220 	PPI_FIELD_HEADER, *PPPI_FIELD_HEADER;
221 
222 
223 #define		PPI_FIELD_TYPE_AGGREGATION_EXTENSION	((UCHAR)0x08)
224 
225 typedef struct _PPI_FIELD_AGGREGATION_EXTENSION
226 {
227 	ULONG		InterfaceId;
228 }
229 	PPI_FIELD_AGGREGATION_EXTENSION, *PPPI_FIELD_AGGREGATION_EXTENSION;
230 
231 
232 #define		PPI_FIELD_TYPE_802_3_EXTENSION			((UCHAR)0x09)
233 
234 #define PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT			((ULONG)0x00000001)
235 
236 typedef struct _PPI_FIELD_802_3_EXTENSION
237 {
238 	ULONG		Flags;
239 	ULONG		Errors;
240 }
241 	PPI_FIELD_802_3_EXTENSION, *PPPI_FIELD_802_3_EXTENSION;
242 
243 typedef struct _PPI_HEADER
244 {
245 	PPI_PACKET_HEADER PacketHeader;
246 	PPI_FIELD_HEADER  AggregationFieldHeader;
247 	PPI_FIELD_AGGREGATION_EXTENSION AggregationField;
248 	PPI_FIELD_HEADER  Dot3FieldHeader;
249 	PPI_FIELD_802_3_EXTENSION Dot3Field;
250 }
251 	PPI_HEADER, *PPPI_HEADER;
252 #pragma pack(pop)
253 
254 #ifdef _WIN32
255 /*
256  * NOTE: this function should be called by the pcap functions that can theoretically
257  *       deal with the Tc library for the first time, namely listing the adapters and
258  *       opening one. All the other ones (close, read, write, set parameters) work
259  *       on an open instance of TC, so we do not care to call this function
260  */
261 TC_API_LOAD_STATUS LoadTcFunctions(void)
262 {
263 	TC_API_LOAD_STATUS currentStatus;
264 
265 	do
266 	{
267 		currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_UNLOADED);
268 
269 		while(currentStatus == TC_API_LOADING)
270 		{
271 			currentStatus = InterlockedCompareExchange((LONG*)&g_TcFunctions.LoadStatus, TC_API_LOADING, TC_API_LOADING);
272 			Sleep(10);
273 		}
274 
275 		/*
276 		 * at this point we are either in the LOADED state, unloaded state (i.e. we are the ones loading everything)
277 		 * or in cannot load
278 		 */
279 		if(currentStatus  == TC_API_LOADED)
280 		{
281 			return TC_API_LOADED;
282 		}
283 
284 		if (currentStatus == TC_API_CANNOT_LOAD)
285 		{
286 			return TC_API_CANNOT_LOAD;
287 		}
288 
289 		currentStatus = TC_API_CANNOT_LOAD;
290 
291 		g_TcFunctions.hTcApiDllHandle = pcap_load_code("TcApi.dll");
292 		if (g_TcFunctions.hTcApiDllHandle == NULL)	break;
293 
294 		g_TcFunctions.QueryPortList			= (TcFcnQueryPortList)			pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcQueryPortList");
295 		g_TcFunctions.FreePortList			= (TcFcnFreePortList)			pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcFreePortList");
296 
297 		g_TcFunctions.StatusGetString			= (TcFcnStatusGetString)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatusGetString");
298 
299 		g_TcFunctions.PortGetName			= (TcFcnPortGetName)			pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetName");
300 		g_TcFunctions.PortGetDescription		= (TcFcnPortGetDescription)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPortGetDescription");
301 
302 		g_TcFunctions.InstanceOpenByName		= (TcFcnInstanceOpenByName)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceOpenByName");
303 		g_TcFunctions.InstanceClose			= (TcFcnInstanceClose)			pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceClose");
304 		g_TcFunctions.InstanceSetFeature		= (TcFcnInstanceSetFeature)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceSetFeature");
305 		g_TcFunctions.InstanceQueryFeature		= (TcFcnInstanceQueryFeature)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryFeature");
306 		g_TcFunctions.InstanceReceivePackets		= (TcFcnInstanceReceivePackets)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceReceivePackets");
307 		g_TcFunctions.InstanceGetReceiveWaitHandle	= (TcFcnInstanceGetReceiveWaitHandle)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceGetReceiveWaitHandle");
308 		g_TcFunctions.InstanceTransmitPackets		= (TcFcnInstanceTransmitPackets)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceTransmitPackets");
309 		g_TcFunctions.InstanceQueryStatistics		= (TcFcnInstanceQueryStatistics)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcInstanceQueryStatistics");
310 
311 		g_TcFunctions.PacketsBufferCreate		= (TcFcnPacketsBufferCreate)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCreate");
312 		g_TcFunctions.PacketsBufferDestroy		= (TcFcnPacketsBufferDestroy)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferDestroy");
313 		g_TcFunctions.PacketsBufferQueryNextPacket	= (TcFcnPacketsBufferQueryNextPacket)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferQueryNextPacket");
314 		g_TcFunctions.PacketsBufferCommitNextPacket	= (TcFcnPacketsBufferCommitNextPacket)pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcPacketsBufferCommitNextPacket");
315 
316 		g_TcFunctions.StatisticsDestroy			= (TcFcnStatisticsDestroy)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsDestroy");
317 		g_TcFunctions.StatisticsUpdate			= (TcFcnStatisticsUpdate)		pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsUpdate");
318 		g_TcFunctions.StatisticsQueryValue		= (TcFcnStatisticsQueryValue)	pcap_find_function(g_TcFunctions.hTcApiDllHandle, "TcStatisticsQueryValue");
319 
320 		if (   g_TcFunctions.QueryPortList == NULL
321 			|| g_TcFunctions.FreePortList == NULL
322 			|| g_TcFunctions.StatusGetString == NULL
323 			|| g_TcFunctions.PortGetName == NULL
324 			|| g_TcFunctions.PortGetDescription == NULL
325 			|| g_TcFunctions.InstanceOpenByName == NULL
326 			|| g_TcFunctions.InstanceClose == NULL
327 			|| g_TcFunctions.InstanceSetFeature	 == NULL
328 			|| g_TcFunctions.InstanceQueryFeature == NULL
329 			|| g_TcFunctions.InstanceReceivePackets == NULL
330 			|| g_TcFunctions.InstanceGetReceiveWaitHandle == NULL
331 			|| g_TcFunctions.InstanceTransmitPackets == NULL
332 			|| g_TcFunctions.InstanceQueryStatistics == NULL
333 			|| g_TcFunctions.PacketsBufferCreate == NULL
334 			|| g_TcFunctions.PacketsBufferDestroy == NULL
335 			|| g_TcFunctions.PacketsBufferQueryNextPacket == NULL
336 			|| g_TcFunctions.PacketsBufferCommitNextPacket == NULL
337 			|| g_TcFunctions.StatisticsDestroy == NULL
338 			|| g_TcFunctions.StatisticsUpdate == NULL
339 			|| g_TcFunctions.StatisticsQueryValue == NULL
340 		)
341 		{
342 			break;
343 		}
344 
345 		/*
346 		 * everything got loaded, yay!!
347 		 */
348 		currentStatus = TC_API_LOADED;
349 	}while(FALSE);
350 
351 	if (currentStatus != TC_API_LOADED)
352 	{
353 		if (g_TcFunctions.hTcApiDllHandle != NULL)
354 		{
355 			FreeLibrary(g_TcFunctions.hTcApiDllHandle);
356 			g_TcFunctions.hTcApiDllHandle = NULL;
357 		}
358 	}
359 
360 	InterlockedExchange((LONG*)&g_TcFunctions.LoadStatus, currentStatus);
361 
362 	return currentStatus;
363 }
364 #else
365 // static linking
366 TC_API_LOAD_STATUS LoadTcFunctions(void)
367 {
368 	return TC_API_LOADED;
369 }
370 #endif
371 
372 /*
373  * Private data for capturing on TurboCap devices.
374  */
375 struct pcap_tc {
376 	TC_INSTANCE TcInstance;
377 	TC_PACKETS_BUFFER TcPacketsBuffer;
378 	ULONG TcAcceptedCount;
379 	u_char *PpiPacket;
380 };
381 
382 int
383 TcFindAllDevs(pcap_if_list_t *devlist, char *errbuf)
384 {
385 	TC_API_LOAD_STATUS loadStatus;
386 	ULONG numPorts;
387 	PTC_PORT pPorts = NULL;
388 	TC_STATUS status;
389 	int result = 0;
390 	pcap_if_t *dev;
391 	ULONG i;
392 
393 	do
394 	{
395 		loadStatus = LoadTcFunctions();
396 
397 		if (loadStatus != TC_API_LOADED)
398 		{
399 			result = 0;
400 			break;
401 		}
402 
403 		/*
404 		 * enumerate the ports, and add them to the list
405 		 */
406 		status = g_TcFunctions.QueryPortList(&pPorts, &numPorts);
407 
408 		if (status != TC_SUCCESS)
409 		{
410 			result = 0;
411 			break;
412 		}
413 
414 		for (i = 0; i < numPorts; i++)
415 		{
416 			/*
417 			 * transform the port into an entry in the list
418 			 */
419 			dev = TcCreatePcapIfFromPort(pPorts[i]);
420 
421 			if (dev != NULL)
422 				add_dev(devlist, dev->name, dev->flags, dev->description, errbuf);
423 		}
424 
425 		if (numPorts > 0)
426 		{
427 			/*
428 			 * ignore the result here
429 			 */
430 			status = g_TcFunctions.FreePortList(pPorts);
431 		}
432 
433 	}while(FALSE);
434 
435 	return result;
436 }
437 
438 static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port)
439 {
440 	CHAR *name;
441 	CHAR *description;
442 	pcap_if_t *newIf = NULL;
443 
444 	newIf = (pcap_if_t*)malloc(sizeof(*newIf));
445 	if (newIf == NULL)
446 	{
447 		return NULL;
448 	}
449 
450 	memset(newIf, 0, sizeof(*newIf));
451 
452 	name = g_TcFunctions.PortGetName(port);
453 	description = g_TcFunctions.PortGetDescription(port);
454 
455 	newIf->name = (char*)malloc(strlen(name) + 1);
456 	if (newIf->name == NULL)
457 	{
458 		free(newIf);
459 		return NULL;
460 	}
461 
462 	newIf->description = (char*)malloc(strlen(description) + 1);
463 	if (newIf->description == NULL)
464 	{
465 		free(newIf->name);
466 		free(newIf);
467 		return NULL;
468 	}
469 
470 	strcpy(newIf->name, name);
471 	strcpy(newIf->description, description);
472 
473 	newIf->addresses = NULL;
474 	newIf->next = NULL;
475 	newIf->flags = 0;
476 
477 	return newIf;
478 
479 }
480 
481 static int
482 TcActivate(pcap_t *p)
483 {
484 	struct pcap_tc *pt = p->priv;
485 	TC_STATUS status;
486 	ULONG timeout;
487 	PPPI_HEADER pPpiHeader;
488 
489 	if (p->opt.rfmon)
490 	{
491 		/*
492 		 * No monitor mode on Tc cards; they're Ethernet
493 		 * capture adapters.
494 		 */
495 		return PCAP_ERROR_RFMON_NOTSUP;
496 	}
497 
498 	pt->PpiPacket = malloc(sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE);
499 
500 	if (pt->PpiPacket == NULL)
501 	{
502 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory");
503 		return PCAP_ERROR;
504 	}
505 
506 	/*
507 	 * Turn a negative snapshot value (invalid), a snapshot value of
508 	 * 0 (unspecified), or a value bigger than the normal maximum
509 	 * value, into the maximum allowed value.
510 	 *
511 	 * If some application really *needs* a bigger snapshot
512 	 * length, we should just increase MAXIMUM_SNAPLEN.
513 	 */
514 	if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
515 		p->snapshot = MAXIMUM_SNAPLEN;
516 
517 	/*
518 	 * Initialize the PPI fixed fields
519 	 */
520 	pPpiHeader = (PPPI_HEADER)pt->PpiPacket;
521 	pPpiHeader->PacketHeader.PphDlt = DLT_EN10MB;
522 	pPpiHeader->PacketHeader.PphLength = sizeof(PPI_HEADER);
523 	pPpiHeader->PacketHeader.PphFlags = 0;
524 	pPpiHeader->PacketHeader.PphVersion = 0;
525 
526 	pPpiHeader->AggregationFieldHeader.PfhLength = sizeof(PPI_FIELD_AGGREGATION_EXTENSION);
527 	pPpiHeader->AggregationFieldHeader.PfhType = PPI_FIELD_TYPE_AGGREGATION_EXTENSION;
528 
529 	pPpiHeader->Dot3FieldHeader.PfhLength = sizeof(PPI_FIELD_802_3_EXTENSION);
530 	pPpiHeader->Dot3FieldHeader.PfhType = PPI_FIELD_TYPE_802_3_EXTENSION;
531 
532 	status = g_TcFunctions.InstanceOpenByName(p->opt.device, &pt->TcInstance);
533 
534 	if (status != TC_SUCCESS)
535 	{
536 		/* Adapter detected but we are not able to open it. Return failure. */
537 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status));
538 		return PCAP_ERROR;
539 	}
540 
541 	p->linktype = DLT_EN10MB;
542 	p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
543 	/*
544 	 * If that fails, just leave the list empty.
545 	 */
546 	if (p->dlt_list != NULL) {
547 		p->dlt_list[0] = DLT_EN10MB;
548 		p->dlt_list[1] = DLT_PPI;
549 		p->dlt_count = 2;
550 	}
551 
552 	/*
553 	 * ignore promiscuous mode
554 	 * p->opt.promisc
555 	 */
556 
557 
558 	/*
559 	 * ignore all the buffer sizes
560 	 */
561 
562 	/*
563 	 * enable reception
564 	 */
565 	status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_RX_STATUS, 1);
566 
567 	if (status != TC_SUCCESS)
568 	{
569 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
570 		goto bad;
571 	}
572 
573 	/*
574 	 * enable transmission
575 	 */
576 	status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_TX_STATUS, 1);
577 	/*
578 	 * Ignore the error here.
579 	 */
580 
581 	p->inject_op = TcInject;
582 	/*
583 	 * if the timeout is -1, it means immediate return, no timeout
584 	 * if the timeout is 0, it means INFINITE
585 	 */
586 
587 	if (p->opt.timeout == 0)
588 	{
589 		timeout = 0xFFFFFFFF;
590 	}
591 	else
592 	if (p->opt.timeout < 0)
593 	{
594 		/*
595 		 *  we insert a minimal timeout here
596 		 */
597 		timeout = 10;
598 	}
599 	else
600 	{
601 		timeout = p->opt.timeout;
602 	}
603 
604 	status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_READ_TIMEOUT, timeout);
605 
606 	if (status != TC_SUCCESS)
607 	{
608 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
609 		goto bad;
610 	}
611 
612 	p->read_op = TcRead;
613 	p->setfilter_op = install_bpf_program;
614 	p->setdirection_op = NULL;	/* Not implemented. */
615 	p->set_datalink_op = TcSetDatalink;
616 	p->getnonblock_op = TcGetNonBlock;
617 	p->setnonblock_op = TcSetNonBlock;
618 	p->stats_op = TcStats;
619 #ifdef _WIN32
620 	p->stats_ex_op = TcStatsEx;
621 	p->setbuff_op = TcSetBuff;
622 	p->setmode_op = TcSetMode;
623 	p->setmintocopy_op = TcSetMinToCopy;
624 	p->getevent_op = TcGetReceiveWaitHandle;
625 	p->oid_get_request_op = TcOidGetRequest;
626 	p->oid_set_request_op = TcOidSetRequest;
627 	p->sendqueue_transmit_op = TcSendqueueTransmit;
628 	p->setuserbuffer_op = TcSetUserBuffer;
629 	p->live_dump_op = TcLiveDump;
630 	p->live_dump_ended_op = TcLiveDumpEnded;
631 	p->get_airpcap_handle_op = TcGetAirPcapHandle;
632 #else
633 	p->selectable_fd = -1;
634 #endif
635 
636 	p->cleanup_op = TcCleanup;
637 
638 	return 0;
639 bad:
640 	TcCleanup(p);
641 	return PCAP_ERROR;
642 }
643 
644 pcap_t *
645 TcCreate(const char *device, char *ebuf, int *is_ours)
646 {
647 	ULONG numPorts;
648 	PTC_PORT pPorts = NULL;
649 	TC_STATUS status;
650 	int is_tc;
651 	ULONG i;
652 	pcap_t *p;
653 
654 	if (LoadTcFunctions() != TC_API_LOADED)
655 	{
656 		/*
657 		 * XXX - report this as an error rather than as
658 		 * "not a TurboCap device"?
659 		 */
660 		*is_ours = 0;
661 		return NULL;
662 	}
663 
664 	/*
665 	 * enumerate the ports, and add them to the list
666 	 */
667 	status = g_TcFunctions.QueryPortList(&pPorts, &numPorts);
668 
669 	if (status != TC_SUCCESS)
670 	{
671 		/*
672 		 * XXX - report this as an error rather than as
673 		 * "not a TurboCap device"?
674 		 */
675 		*is_ours = 0;
676 		return NULL;
677 	}
678 
679 	is_tc = FALSE;
680 	for (i = 0; i < numPorts; i++)
681 	{
682 		if (strcmp(g_TcFunctions.PortGetName(pPorts[i]), device) == 0)
683 		{
684 			is_tc = TRUE;
685 			break;
686 		}
687 	}
688 
689 	if (numPorts > 0)
690 	{
691 		/*
692 		 * ignore the result here
693 		 */
694 		(void)g_TcFunctions.FreePortList(pPorts);
695 	}
696 
697 	if (!is_tc)
698 	{
699 		*is_ours = 0;
700 		return NULL;
701 	}
702 
703 	/* OK, it's probably ours. */
704 	*is_ours = 1;
705 
706 	p = PCAP_CREATE_COMMON(ebuf, struct pcap_tc);
707 	if (p == NULL)
708 		return NULL;
709 
710 	p->activate_op = TcActivate;
711 	/*
712 	 * Set these up front, so that, even if our client tries
713 	 * to set non-blocking mode before we're activated, or
714 	 * query the state of non-blocking mode, they get an error,
715 	 * rather than having the non-blocking mode option set
716 	 * for use later.
717 	 */
718 	p->getnonblock_op = TcGetNonBlock;
719 	p->setnonblock_op = TcSetNonBlock;
720 	return p;
721 }
722 
723 static int TcSetDatalink(pcap_t *p, int dlt)
724 {
725 	/*
726 	 * We don't have to do any work here; pcap_set_datalink() checks
727 	 * whether the value is in the list of DLT_ values we
728 	 * supplied, so we don't have to, and, if it is valid, sets
729 	 * p->linktype to the new value; we don't have to do anything
730 	 * in hardware, we just use what's in p->linktype.
731 	 *
732 	 * We do have to have a routine, however, so that pcap_set_datalink()
733 	 * doesn't think we don't support setting the link-layer header
734 	 * type at all.
735 	 */
736 	return 0;
737 }
738 
739 static int TcGetNonBlock(pcap_t *p)
740 {
741 	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
742 	    "Non-blocking mode isn't supported for TurboCap ports");
743 	return -1;
744 }
745 
746 static int TcSetNonBlock(pcap_t *p, int nonblock)
747 {
748 	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
749 	    "Non-blocking mode isn't supported for TurboCap ports");
750 	return -1;
751 }
752 
753 static void TcCleanup(pcap_t *p)
754 {
755 	struct pcap_tc *pt = p->priv;
756 
757 	if (pt->TcPacketsBuffer != NULL)
758 	{
759 		g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer);
760 		pt->TcPacketsBuffer = NULL;
761 	}
762 	if (pt->TcInstance != NULL)
763 	{
764 		/*
765 		 * here we do not check for the error values
766 		 */
767 		g_TcFunctions.InstanceClose(pt->TcInstance);
768 		pt->TcInstance = NULL;
769 	}
770 
771 	if (pt->PpiPacket != NULL)
772 	{
773 		free(pt->PpiPacket);
774 		pt->PpiPacket = NULL;
775 	}
776 
777 	pcap_cleanup_live_common(p);
778 }
779 
780 /* Send a packet to the network */
781 static int TcInject(pcap_t *p, const void *buf, int size)
782 {
783 	struct pcap_tc *pt = p->priv;
784 	TC_STATUS status;
785 	TC_PACKETS_BUFFER buffer;
786 	TC_PACKET_HEADER header;
787 
788 	if (size >= 0xFFFF)
789 	{
790 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k");
791 		return -1;
792 	}
793 
794 	status = g_TcFunctions.PacketsBufferCreate(sizeof(TC_PACKET_HEADER) + TC_ALIGN_USHORT_TO_64BIT((USHORT)size), &buffer);
795 
796 	if (status != TC_SUCCESS)
797 	{
798 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
799 		return -1;
800 	}
801 
802 	/*
803 	 * we assume that the packet is without the checksum, as common with WinPcap
804 	 */
805 	memset(&header, 0, sizeof(header));
806 
807 	header.Length = (USHORT)size;
808 	header.CapturedLength = header.Length;
809 
810 	status = g_TcFunctions.PacketsBufferCommitNextPacket(buffer, &header, (PVOID)buf);
811 
812 	if (status == TC_SUCCESS)
813 	{
814 		status = g_TcFunctions.InstanceTransmitPackets(pt->TcInstance, buffer);
815 
816 		if (status != TC_SUCCESS)
817 		{
818 			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
819 		}
820 	}
821 	else
822 	{
823 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
824 	}
825 
826 	g_TcFunctions.PacketsBufferDestroy(buffer);
827 
828 	if (status != TC_SUCCESS)
829 	{
830 		return -1;
831 	}
832 	else
833 	{
834 		return 0;
835 	}
836 }
837 
838 static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
839 {
840 	struct pcap_tc *pt = p->priv;
841 	TC_STATUS status;
842 	int n = 0;
843 
844 	/*
845 	 * Has "pcap_breakloop()" been called?
846 	 */
847 	if (p->break_loop)
848 	{
849 		/*
850 		 * Yes - clear the flag that indicates that it
851 		 * has, and return -2 to indicate that we were
852 		 * told to break out of the loop.
853 		 */
854 		p->break_loop = 0;
855 		return -2;
856 	}
857 
858 	if (pt->TcPacketsBuffer == NULL)
859 	{
860 		status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer);
861 		if (status != TC_SUCCESS)
862 		{
863 			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
864 			return -1;
865 		}
866 	}
867 
868 	while (TRUE)
869 	{
870 		struct pcap_pkthdr hdr;
871 		TC_PACKET_HEADER tcHeader;
872 		PVOID data;
873 		ULONG filterResult;
874 
875 		/*
876 		 * Has "pcap_breakloop()" been called?
877 		 * If so, return immediately - if we haven't read any
878 		 * packets, clear the flag and return -2 to indicate
879 		 * that we were told to break out of the loop, otherwise
880 		 * leave the flag set, so that the *next* call will break
881 		 * out of the loop without having read any packets, and
882 		 * return the number of packets we've processed so far.
883 		 */
884 		if (p->break_loop)
885 		{
886 			if (n == 0)
887 			{
888 				p->break_loop = 0;
889 				return -2;
890 			}
891 			else
892 			{
893 				return n;
894 			}
895 		}
896 
897 		if (pt->TcPacketsBuffer == NULL)
898 		{
899 			break;
900 		}
901 
902 		status = g_TcFunctions.PacketsBufferQueryNextPacket(pt->TcPacketsBuffer, &tcHeader, &data);
903 
904 		if (status == TC_ERROR_END_OF_BUFFER)
905 		{
906 			g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer);
907 			pt->TcPacketsBuffer = NULL;
908 			break;
909 		}
910 
911 		if (status != TC_SUCCESS)
912 		{
913 			snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
914 			return -1;
915 		}
916 
917 		/* No underlying filtering system. We need to filter on our own */
918 		if (p->fcode.bf_insns)
919 		{
920 			filterResult = pcap_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength);
921 
922 			if (filterResult == 0)
923 			{
924 				continue;
925 			}
926 
927 			if (filterResult > tcHeader.CapturedLength)
928 			{
929 				filterResult = tcHeader.CapturedLength;
930 			}
931 		}
932 		else
933 		{
934 			filterResult = tcHeader.CapturedLength;
935 		}
936 
937 		pt->TcAcceptedCount ++;
938 
939 		hdr.ts.tv_sec = (bpf_u_int32)(tcHeader.Timestamp / (ULONGLONG)(1000  * 1000 * 1000));
940 		hdr.ts.tv_usec = (bpf_u_int32)((tcHeader.Timestamp % (ULONGLONG)(1000  * 1000 * 1000)) / 1000);
941 
942 		if (p->linktype == DLT_EN10MB)
943 		{
944 			hdr.caplen = filterResult;
945 			hdr.len = tcHeader.Length;
946 			(*callback)(user, &hdr, data);
947 		}
948 		else
949 		{
950 			PPPI_HEADER pPpiHeader = (PPPI_HEADER)pt->PpiPacket;
951 			PVOID data2 = pPpiHeader + 1;
952 
953 			pPpiHeader->AggregationField.InterfaceId = TC_PH_FLAGS_RX_PORT_ID(tcHeader.Flags);
954 			pPpiHeader->Dot3Field.Errors = tcHeader.Errors;
955 			if (tcHeader.Flags & TC_PH_FLAGS_CHECKSUM)
956 			{
957 				pPpiHeader->Dot3Field.Flags = PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT;
958 			}
959 			else
960 			{
961 				pPpiHeader->Dot3Field.Flags = 0;
962 			}
963 
964 			if (filterResult <= MAX_TC_PACKET_SIZE)
965 			{
966 				memcpy(data2, data, filterResult);
967 				hdr.caplen = sizeof(PPI_HEADER) + filterResult;
968 				hdr.len = sizeof(PPI_HEADER) + tcHeader.Length;
969 			}
970 			else
971 			{
972 				memcpy(data2, data, MAX_TC_PACKET_SIZE);
973 				hdr.caplen = sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE;
974 				hdr.len = sizeof(PPI_HEADER) + tcHeader.Length;
975 			}
976 
977 			(*callback)(user, &hdr, pt->PpiPacket);
978 
979 		}
980 
981 		if (++n >= cnt && cnt > 0)
982 		{
983 			return n;
984 		}
985 	}
986 
987 	return n;
988 }
989 
990 static int
991 TcStats(pcap_t *p, struct pcap_stat *ps)
992 {
993 	struct pcap_tc *pt = p->priv;
994 	TC_STATISTICS statistics;
995 	TC_STATUS status;
996 	ULONGLONG counter;
997 	struct pcap_stat s;
998 
999 	status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics);
1000 
1001 	if (status != TC_SUCCESS)
1002 	{
1003 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1004 		return -1;
1005 	}
1006 
1007 	memset(&s, 0, sizeof(s));
1008 
1009 	status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
1010 	if (status != TC_SUCCESS)
1011 	{
1012 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1013 		return -1;
1014 	}
1015 	if (counter <= (ULONGLONG)0xFFFFFFFF)
1016 	{
1017 		s.ps_recv = (ULONG)counter;
1018 	}
1019 	else
1020 	{
1021 		s.ps_recv = 0xFFFFFFFF;
1022 	}
1023 
1024 	status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
1025 	if (status != TC_SUCCESS)
1026 	{
1027 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1028 		return -1;
1029 	}
1030 	if (counter <= (ULONGLONG)0xFFFFFFFF)
1031 	{
1032 		s.ps_ifdrop = (ULONG)counter;
1033 		s.ps_drop = (ULONG)counter;
1034 	}
1035 	else
1036 	{
1037 		s.ps_ifdrop = 0xFFFFFFFF;
1038 		s.ps_drop = 0xFFFFFFFF;
1039 	}
1040 
1041 #if defined(_WIN32) && defined(ENABLE_REMOTE)
1042 	s.ps_capt = pt->TcAcceptedCount;
1043 #endif
1044 	*ps = s;
1045 
1046 	return 0;
1047 }
1048 
1049 
1050 #ifdef _WIN32
1051 static struct pcap_stat *
1052 TcStatsEx(pcap_t *p, int *pcap_stat_size)
1053 {
1054 	struct pcap_tc *pt = p->priv;
1055 	TC_STATISTICS statistics;
1056 	TC_STATUS status;
1057 	ULONGLONG counter;
1058 
1059 	*pcap_stat_size = sizeof (p->stat);
1060 
1061 	status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics);
1062 
1063 	if (status != TC_SUCCESS)
1064 	{
1065 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1066 		return NULL;
1067 	}
1068 
1069 	memset(&p->stat, 0, sizeof(p->stat));
1070 
1071 	status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
1072 	if (status != TC_SUCCESS)
1073 	{
1074 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1075 		return NULL;
1076 	}
1077 	if (counter <= (ULONGLONG)0xFFFFFFFF)
1078 	{
1079 		p->stat.ps_recv = (ULONG)counter;
1080 	}
1081 	else
1082 	{
1083 		p->stat.ps_recv = 0xFFFFFFFF;
1084 	}
1085 
1086 	status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
1087 	if (status != TC_SUCCESS)
1088 	{
1089 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1090 		return NULL;
1091 	}
1092 	if (counter <= (ULONGLONG)0xFFFFFFFF)
1093 	{
1094 		p->stat.ps_ifdrop = (ULONG)counter;
1095 		p->stat.ps_drop = (ULONG)counter;
1096 	}
1097 	else
1098 	{
1099 		p->stat.ps_ifdrop = 0xFFFFFFFF;
1100 		p->stat.ps_drop = 0xFFFFFFFF;
1101 	}
1102 
1103 #if defined(_WIN32) && defined(ENABLE_REMOTE)
1104 	p->stat.ps_capt = pt->TcAcceptedCount;
1105 #endif
1106 
1107 	return &p->stat;
1108 }
1109 
1110 /* Set the dimension of the kernel-level capture buffer */
1111 static int
1112 TcSetBuff(pcap_t *p, int dim)
1113 {
1114 	/*
1115 	 * XXX turbocap has an internal way of managing buffers.
1116 	 * And at the moment it's not configurable, so we just
1117 	 * silently ignore the request to set the buffer.
1118 	 */
1119 	return 0;
1120 }
1121 
1122 static int
1123 TcSetMode(pcap_t *p, int mode)
1124 {
1125 	if (mode != MODE_CAPT)
1126 	{
1127 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %d not supported by TurboCap devices. TurboCap only supports capture.", mode);
1128 		return -1;
1129 	}
1130 
1131 	return 0;
1132 }
1133 
1134 static int
1135 TcSetMinToCopy(pcap_t *p, int size)
1136 {
1137 	struct pcap_tc *pt = p->priv;
1138 	TC_STATUS status;
1139 
1140 	if (size < 0)
1141 	{
1142 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0.");
1143 		return -1;
1144 	}
1145 
1146 	status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_MINTOCOPY, (ULONG)size);
1147 
1148 	if (status != TC_SUCCESS)
1149 	{
1150 		snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1151 	}
1152 
1153 	return 0;
1154 }
1155 
1156 static HANDLE
1157 TcGetReceiveWaitHandle(pcap_t *p)
1158 {
1159 	struct pcap_tc *pt = p->priv;
1160 
1161 	return g_TcFunctions.InstanceGetReceiveWaitHandle(pt->TcInstance);
1162 }
1163 
1164 static int
1165 TcOidGetRequest(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_)
1166 {
1167 	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1168 	    "An OID get request cannot be performed on a TurboCap device");
1169 	return PCAP_ERROR;
1170 }
1171 
1172 static int
1173 TcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
1174     size_t *lenp _U_)
1175 {
1176 	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1177 	    "An OID set request cannot be performed on a TurboCap device");
1178 	return PCAP_ERROR;
1179 }
1180 
1181 static u_int
1182 TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
1183 {
1184 	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1185 	    "Packets cannot be bulk transmitted on a TurboCap device");
1186 	return 0;
1187 }
1188 
1189 static int
1190 TcSetUserBuffer(pcap_t *p, int size _U_)
1191 {
1192 	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1193 	    "The user buffer cannot be set on a TurboCap device");
1194 	return -1;
1195 }
1196 
1197 static int
1198 TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
1199 {
1200 	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1201 	    "Live packet dumping cannot be performed on a TurboCap device");
1202 	return -1;
1203 }
1204 
1205 static int
1206 TcLiveDumpEnded(pcap_t *p, int sync _U_)
1207 {
1208 	snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1209 	    "Live packet dumping cannot be performed on a TurboCap device");
1210 	return -1;
1211 }
1212 
1213 static PAirpcapHandle
1214 TcGetAirPcapHandle(pcap_t *p _U_)
1215 {
1216 	return NULL;
1217 }
1218 #endif
1219