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
50typedef TC_STATUS	(TC_CALLCONV *TcFcnQueryPortList)			(PTC_PORT *ppPorts, PULONG pLength);
51typedef TC_STATUS	(TC_CALLCONV *TcFcnFreePortList)			(TC_PORT *pPorts);
52
53typedef PCHAR		(TC_CALLCONV *TcFcnStatusGetString)			(TC_STATUS status);
54
55typedef PCHAR		(TC_CALLCONV *TcFcnPortGetName)				(TC_PORT port);
56typedef PCHAR		(TC_CALLCONV *TcFcnPortGetDescription)		(TC_PORT port);
57
58typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceOpenByName)		(PCHAR name, PTC_INSTANCE pInstance);
59typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceClose)			(TC_INSTANCE instance);
60typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceSetFeature)		(TC_INSTANCE instance, ULONG feature, ULONG value);
61typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceQueryFeature)	(TC_INSTANCE instance, ULONG feature, PULONG pValue);
62typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceReceivePackets)	(TC_INSTANCE instance, PTC_PACKETS_BUFFER pBuffer);
63typedef HANDLE		(TC_CALLCONV *TcFcnInstanceGetReceiveWaitHandle) (TC_INSTANCE instance);
64typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceTransmitPackets)	(TC_INSTANCE instance, TC_PACKETS_BUFFER pBuffer);
65typedef TC_STATUS	(TC_CALLCONV *TcFcnInstanceQueryStatistics)	(TC_INSTANCE instance, PTC_STATISTICS pStatistics);
66
67typedef TC_STATUS	(TC_CALLCONV *TcFcnPacketsBufferCreate)		(ULONG size, PTC_PACKETS_BUFFER pBuffer);
68typedef VOID		(TC_CALLCONV *TcFcnPacketsBufferDestroy)	(TC_PACKETS_BUFFER buffer);
69typedef TC_STATUS	(TC_CALLCONV *TcFcnPacketsBufferQueryNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID *ppData);
70typedef TC_STATUS	(TC_CALLCONV *TcFcnPacketsBufferCommitNextPacket)(TC_PACKETS_BUFFER buffer, PTC_PACKET_HEADER pHeader, PVOID pData);
71
72typedef VOID		(TC_CALLCONV *TcFcnStatisticsDestroy)		(TC_STATISTICS statistics);
73typedef TC_STATUS	(TC_CALLCONV *TcFcnStatisticsUpdate)		(TC_STATISTICS statistics);
74typedef TC_STATUS	(TC_CALLCONV *TcFcnStatisticsQueryValue)	(TC_STATISTICS statistics, ULONG counterId, PULONGLONG pValue);
75
76typedef 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
86typedef 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
121static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port);
122static int TcSetDatalink(pcap_t *p, int dlt);
123static int TcGetNonBlock(pcap_t *p);
124static int TcSetNonBlock(pcap_t *p, int nonblock);
125static void TcCleanup(pcap_t *p);
126static int TcInject(pcap_t *p, const void *buf, int size);
127static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
128static int TcStats(pcap_t *p, struct pcap_stat *ps);
129#ifdef _WIN32
130static struct pcap_stat *TcStatsEx(pcap_t *p, int *pcap_stat_size);
131static int TcSetBuff(pcap_t *p, int dim);
132static int TcSetMode(pcap_t *p, int mode);
133static int TcSetMinToCopy(pcap_t *p, int size);
134static HANDLE TcGetReceiveWaitHandle(pcap_t *p);
135static int TcOidGetRequest(pcap_t *p, bpf_u_int32 oid, void *data, size_t *lenp);
136static int TcOidSetRequest(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp);
137static u_int TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue, int sync);
138static int TcSetUserBuffer(pcap_t *p, int size);
139static int TcLiveDump(pcap_t *p, char *filename, int maxsize, int maxpacks);
140static int TcLiveDumpEnded(pcap_t *p, int sync);
141static PAirpcapHandle TcGetAirPcapHandle(pcap_t *p);
142#endif
143
144#ifdef _WIN32
145TC_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
171TC_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
206typedef 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
215typedef 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
225typedef 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
236typedef 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
243typedef 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 */
261TC_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
366TC_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 */
375struct pcap_tc {
376	TC_INSTANCE TcInstance;
377	TC_PACKETS_BUFFER TcPacketsBuffer;
378	ULONG TcAcceptedCount;
379	u_char *PpiPacket;
380};
381
382int
383TcFindAllDevs(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
438static 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
481static int
482TcActivate(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;
639bad:
640	TcCleanup(p);
641	return PCAP_ERROR;
642}
643
644pcap_t *
645TcCreate(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
723static 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
739static 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
746static 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
753static 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 */
781static 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
838static 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
990static int
991TcStats(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
1051static struct pcap_stat *
1052TcStatsEx(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 */
1111static int
1112TcSetBuff(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
1122static int
1123TcSetMode(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
1134static int
1135TcSetMinToCopy(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
1156static HANDLE
1157TcGetReceiveWaitHandle(pcap_t *p)
1158{
1159	struct pcap_tc *pt = p->priv;
1160
1161	return g_TcFunctions.InstanceGetReceiveWaitHandle(pt->TcInstance);
1162}
1163
1164static int
1165TcOidGetRequest(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
1172static int
1173TcOidSetRequest(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
1181static u_int
1182TcSendqueueTransmit(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
1189static int
1190TcSetUserBuffer(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
1197static int
1198TcLiveDump(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
1205static int
1206TcLiveDumpEnded(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
1213static PAirpcapHandle
1214TcGetAirPcapHandle(pcap_t *p _U_)
1215{
1216	return NULL;
1217}
1218#endif
1219