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