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