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