]> The Tcpdump Group git mirrors - libpcap/blob - pcap-tc.c
Set setuserbuffer_op in WinPcap.
[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, char *errbuf);
124 static int TcSetNonBlock(pcap_t *p, int nonblock, char *errbuf);
125 static void TcCleanup(pcap_t *p);
126 static int TcInject(pcap_t *p, const void *buf, size_t 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 int TcOidGetRequest(pcap_t *p, pcap_oid_data_t *data);
136 static int TcOidSetRequest(pcap_t *p, pcap_oid_data_t *data);
137 static u_int TcOidSendqueueTransmit(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 PCHAR PpiPacket;
432 };
433
434 int
435 TcFindAllDevs(pcap_if_t **alldevsp, 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, *cursor;
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 {
475 /*
476 * append it at the end
477 */
478 if (*alldevsp == NULL)
479 {
480 *alldevsp = dev;
481 }
482 else
483 {
484 for(cursor = *alldevsp; cursor->next != NULL; cursor = cursor->next);
485 cursor->next = dev;
486 }
487 }
488 }
489
490 if (numPorts > 0)
491 {
492 /*
493 * ignore the result here
494 */
495 status = g_TcFunctions.FreePortList(pPorts);
496 }
497
498 }while(FALSE);
499
500 return result;
501 }
502
503 static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port)
504 {
505 CHAR *name;
506 CHAR *description;
507 pcap_if_t *newIf = NULL;
508
509 newIf = (pcap_if_t*)malloc(sizeof(*newIf));
510 if (newIf == NULL)
511 {
512 return NULL;
513 }
514
515 memset(newIf, 0, sizeof(*newIf));
516
517 name = g_TcFunctions.PortGetName(port);
518 description = g_TcFunctions.PortGetDescription(port);
519
520 newIf->name = (char*)malloc(strlen(name) + 1);
521 if (newIf->name == NULL)
522 {
523 free(newIf);
524 return NULL;
525 }
526
527 newIf->description = (char*)malloc(strlen(description) + 1);
528 if (newIf->description == NULL)
529 {
530 free(newIf->name);
531 free(newIf);
532 return NULL;
533 }
534
535 strcpy(newIf->name, name);
536 strcpy(newIf->description, description);
537
538 newIf->addresses = NULL;
539 newIf->next = NULL;
540 newIf->flags = 0;
541
542 return newIf;
543
544 }
545
546 static int
547 TcActivate(pcap_t *p)
548 {
549 struct pcap_tc *pt = p->priv;
550 TC_STATUS status;
551 ULONG timeout;
552 PPPI_HEADER pPpiHeader;
553
554 if (p->opt.rfmon)
555 {
556 /*
557 * No monitor mode on Tc cards; they're Ethernet
558 * capture adapters.
559 */
560 return (PCAP_ERROR_RFMON_NOTSUP);
561 }
562
563 pt->PpiPacket = (PCHAR)malloc(sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE);
564
565 if (pt->PpiPacket == NULL)
566 {
567 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory");
568 return PCAP_ERROR;
569 }
570
571 /*
572 * Initialize the PPI fixed fields
573 */
574 pPpiHeader = (PPPI_HEADER)pt->PpiPacket;
575 pPpiHeader->PacketHeader.PphDlt = DLT_EN10MB;
576 pPpiHeader->PacketHeader.PphLength = sizeof(PPI_HEADER);
577 pPpiHeader->PacketHeader.PphFlags = 0;
578 pPpiHeader->PacketHeader.PphVersion = 0;
579
580 pPpiHeader->AggregationFieldHeader.PfhLength = sizeof(PPI_FIELD_AGGREGATION_EXTENSION);
581 pPpiHeader->AggregationFieldHeader.PfhType = PPI_FIELD_TYPE_AGGREGATION_EXTENSION;
582
583 pPpiHeader->Dot3FieldHeader.PfhLength = sizeof(PPI_FIELD_802_3_EXTENSION);
584 pPpiHeader->Dot3FieldHeader.PfhType = PPI_FIELD_TYPE_802_3_EXTENSION;
585
586 status = g_TcFunctions.InstanceOpenByName(p->opt.source, &pt->TcInstance);
587
588 if (status != TC_SUCCESS)
589 {
590 /* Adapter detected but we are not able to open it. Return failure. */
591 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status));
592 return PCAP_ERROR;
593 }
594
595 p->linktype = DLT_EN10MB;
596 p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
597 /*
598 * If that fails, just leave the list empty.
599 */
600 if (p->dlt_list != NULL) {
601 p->dlt_list[0] = DLT_EN10MB;
602 p->dlt_list[1] = DLT_PPI;
603 p->dlt_count = 2;
604 }
605
606 /*
607 * ignore promiscuous mode
608 * p->opt.promisc
609 */
610
611
612 /*
613 * ignore all the buffer sizes
614 */
615
616 /*
617 * enable reception
618 */
619 status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_RX_STATUS, 1);
620
621 if (status != TC_SUCCESS)
622 {
623 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
624 goto bad;
625 }
626
627 /*
628 * enable transmission
629 */
630 status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_TX_STATUS, 1);
631 /*
632 * Ignore the error here.
633 */
634
635 p->inject_op = TcInject;
636 /*
637 * if the timeout is -1, it means immediate return, no timeout
638 * if the timeout is 0, it means INFINITE
639 */
640
641 if (p->opt.timeout == 0)
642 {
643 timeout = 0xFFFFFFFF;
644 }
645 else
646 if (p->opt.timeout < 0)
647 {
648 /*
649 * we insert a minimal timeout here
650 */
651 timeout = 10;
652 }
653 else
654 {
655 timeout = p->opt.timeout;
656 }
657
658 status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_READ_TIMEOUT, timeout);
659
660 if (status != TC_SUCCESS)
661 {
662 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
663 goto bad;
664 }
665
666 p->read_op = TcRead;
667 p->setfilter_op = TcSetFilter;
668 p->setdirection_op = NULL; /* Not implemented. */
669 p->set_datalink_op = TcSetDatalink;
670 p->getnonblock_op = TcGetNonBlock;
671 p->setnonblock_op = TcSetNonBlock;
672 p->stats_op = TcStats;
673 #ifdef _WIN32
674 p->stats_ex_op = TcStatsEx;
675 p->setbuff_op = TcSetBuff;
676 p->setmode_op = TcSetMode;
677 p->setmintocopy_op = TcSetMinToCopy;
678 p->getevent_op = TcGetReceiveWaitHandle;
679 p->oid_get_request_op = TcOidGetRequest;
680 p->oid_set_request_op = TcOidSetRequest;
681 p->sendqueue_transmit_op = TcOidSendqueueTransmit;
682 p->setuserbuffer_op = TcSetUserBuffer;
683 p->live_dump_op = TcLiveDump;
684 p->live_dump_ended_op = TcLiveDumpEnded;
685 p->get_airpcap_handle_op = TcGetAirPcapHandle;
686 #else
687 p->selectable_fd = -1;
688 #endif
689
690 p->cleanup_op = TcCleanup;
691
692 return (0);
693 bad:
694 TcCleanup(p);
695 return (PCAP_ERROR);
696 }
697
698 pcap_t *
699 TcCreate(const char *device, char *ebuf, int *is_ours)
700 {
701 ULONG numPorts;
702 PTC_PORT pPorts = NULL;
703 TC_STATUS status;
704 int is_tc;
705 ULONG i;
706 pcap_t *p;
707
708 if (LoadTcFunctions() != TC_API_LOADED)
709 {
710 /*
711 * XXX - report this as an error rather than as
712 * "not a TurboCap device"?
713 */
714 *is_ours = 0;
715 return NULL;
716 }
717
718 /*
719 * enumerate the ports, and add them to the list
720 */
721 status = g_TcFunctions.QueryPortList(&pPorts, &numPorts);
722
723 if (status != TC_SUCCESS)
724 {
725 /*
726 * XXX - report this as an error rather than as
727 * "not a TurboCap device"?
728 */
729 *is_ours = 0;
730 return NULL;
731 }
732
733 is_tc = FALSE;
734 for (i = 0; i < numPorts; i++)
735 {
736 if (strcmp(g_TcFunctions.PortGetName(pPorts[i]), device) == 0)
737 {
738 is_tc = TRUE;
739 break;
740 }
741 }
742
743 if (numPorts > 0)
744 {
745 /*
746 * ignore the result here
747 */
748 (void)g_TcFunctions.FreePortList(pPorts);
749 }
750
751 if (!is_tc)
752 {
753 *is_ours = 0;
754 return NULL;
755 }
756
757 /* OK, it's probably ours. */
758 *is_ours = 1;
759
760 p = pcap_create_common(device, ebuf, sizeof (struct pcap_tc));
761 if (p == NULL)
762 return NULL;
763
764 p->activate_op = TcActivate;
765 return p;
766 }
767
768 static int TcSetDatalink(pcap_t *p, int dlt)
769 {
770 /*
771 * always return 0, as the check is done by pcap_set_datalink
772 */
773 return 0;
774 }
775
776 static int TcGetNonBlock(pcap_t *p, char *errbuf)
777 {
778 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
779 "Getting the non blocking status is not available for TurboCap ports");
780 snprintf(errbuf, PCAP_ERRBUF_SIZE,
781 "Getting the non blocking status is not available for TurboCap ports");
782 return -1;
783
784 }
785 static int TcSetNonBlock(pcap_t *p, int nonblock, char *errbuf)
786 {
787 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
788 "Setting the non blocking status is not available for TurboCap ports");
789 snprintf(errbuf, PCAP_ERRBUF_SIZE,
790 "Setting the non blocking status is not available for TurboCap ports");
791 return -1;
792 }
793
794
795 static void TcCleanup(pcap_t *p)
796 {
797 struct pcap_tc *pt = p->priv;
798
799 if (pt->TcPacketsBuffer != NULL)
800 {
801 g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer);
802 pt->TcPacketsBuffer = NULL;
803 }
804 if (pt->TcInstance != NULL)
805 {
806 /*
807 * here we do not check for the error values
808 */
809 g_TcFunctions.InstanceClose(pt->TcInstance);
810 pt->TcInstance = NULL;
811 }
812
813 if (pt->PpiPacket != NULL)
814 {
815 free(pt->PpiPacket);
816 pt->PpiPacket = NULL;
817 }
818
819 pcap_cleanup_live_common(p);
820 }
821
822 /* Send a packet to the network */
823 static int TcInject(pcap_t *p, const void *buf, size_t size)
824 {
825 struct pcap_tc *pt = p->priv;
826 TC_STATUS status;
827 TC_PACKETS_BUFFER buffer;
828 TC_PACKET_HEADER header;
829
830 if (size >= 0xFFFF)
831 {
832 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k");
833 return -1;
834 }
835
836 status = g_TcFunctions.PacketsBufferCreate(sizeof(TC_PACKET_HEADER) + TC_ALIGN_USHORT_TO_64BIT((USHORT)size), &buffer);
837
838 if (status != TC_SUCCESS)
839 {
840 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
841 return -1;
842 }
843
844 /*
845 * we assume that the packet is without the checksum, as common with WinPcap
846 */
847 memset(&header, 0, sizeof(header));
848
849 header.Length = (USHORT)size;
850 header.CapturedLength = header.Length;
851
852 status = g_TcFunctions.PacketsBufferCommitNextPacket(buffer, &header, (PVOID)buf);
853
854 if (status == TC_SUCCESS)
855 {
856 status = g_TcFunctions.InstanceTransmitPackets(pt->TcInstance, buffer);
857
858 if (status != TC_SUCCESS)
859 {
860 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
861 }
862 }
863 else
864 {
865 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
866 }
867
868 g_TcFunctions.PacketsBufferDestroy(buffer);
869
870 if (status != TC_SUCCESS)
871 {
872 return -1;
873 }
874 else
875 {
876 return 0;
877 }
878 }
879
880 static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
881 {
882 struct pcap_tc *pt = p->priv;
883 TC_STATUS status;
884 int n = 0;
885
886 /*
887 * Has "pcap_breakloop()" been called?
888 */
889 if (p->break_loop)
890 {
891 /*
892 * Yes - clear the flag that indicates that it
893 * has, and return -2 to indicate that we were
894 * told to break out of the loop.
895 */
896 p->break_loop = 0;
897 return (-2);
898 }
899
900 if (pt->TcPacketsBuffer == NULL)
901 {
902 status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer);
903 if (status != TC_SUCCESS)
904 {
905 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
906 return (-1);
907 }
908 }
909
910 while (TRUE)
911 {
912 struct pcap_pkthdr hdr;
913 TC_PACKET_HEADER tcHeader;
914 PVOID data;
915 ULONG filterResult;
916
917 /*
918 * Has "pcap_breakloop()" been called?
919 * If so, return immediately - if we haven't read any
920 * packets, clear the flag and return -2 to indicate
921 * that we were told to break out of the loop, otherwise
922 * leave the flag set, so that the *next* call will break
923 * out of the loop without having read any packets, and
924 * return the number of packets we've processed so far.
925 */
926 if (p->break_loop)
927 {
928 if (n == 0)
929 {
930 p->break_loop = 0;
931 return (-2);
932 }
933 else
934 {
935 return (n);
936 }
937 }
938
939 if (pt->TcPacketsBuffer == NULL)
940 {
941 break;
942 }
943
944 status = g_TcFunctions.PacketsBufferQueryNextPacket(pt->TcPacketsBuffer, &tcHeader, &data);
945
946 if (status == TC_ERROR_END_OF_BUFFER)
947 {
948 g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer);
949 pt->TcPacketsBuffer = NULL;
950 break;
951 }
952
953 if (status != TC_SUCCESS)
954 {
955 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
956 return (-1);
957 }
958
959 /* No underlaying filtering system. We need to filter on our own */
960 if (p->fcode.bf_insns)
961 {
962 filterResult = bpf_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength);
963
964 if (filterResult == 0)
965 {
966 continue;
967 }
968
969 if (filterResult > tcHeader.CapturedLength)
970 {
971 filterResult = tcHeader.CapturedLength;
972 }
973 }
974 else
975 {
976 filterResult = tcHeader.CapturedLength;
977 }
978
979 pt->TcAcceptedCount ++;
980
981 hdr.ts.tv_sec = (bpf_u_int32)(tcHeader.Timestamp / (ULONGLONG)(1000 * 1000 * 1000));
982 hdr.ts.tv_usec = (bpf_u_int32)((tcHeader.Timestamp % (ULONGLONG)(1000 * 1000 * 1000)) / 1000);
983
984 if (p->linktype == DLT_EN10MB)
985 {
986 hdr.caplen = filterResult;
987 hdr.len = tcHeader.Length;
988 (*callback)(user, &hdr, data);
989 }
990 else
991 {
992 PPPI_HEADER pPpiHeader = (PPPI_HEADER)pt->PpiPacket;
993 PVOID data2 = pPpiHeader + 1;
994
995 pPpiHeader->AggregationField.InterfaceId = TC_PH_FLAGS_RX_PORT_ID(tcHeader.Flags);
996 pPpiHeader->Dot3Field.Errors = tcHeader.Errors;
997 if (tcHeader.Flags & TC_PH_FLAGS_CHECKSUM)
998 {
999 pPpiHeader->Dot3Field.Flags = PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT;
1000 }
1001 else
1002 {
1003 pPpiHeader->Dot3Field.Flags = 0;
1004 }
1005
1006 if (filterResult <= MAX_TC_PACKET_SIZE)
1007 {
1008 memcpy(data2, data, filterResult);
1009 hdr.caplen = sizeof(PPI_HEADER) + filterResult;
1010 hdr.len = sizeof(PPI_HEADER) + tcHeader.Length;
1011 }
1012 else
1013 {
1014 memcpy(data2, data, MAX_TC_PACKET_SIZE);
1015 hdr.caplen = sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE;
1016 hdr.len = sizeof(PPI_HEADER) + tcHeader.Length;
1017 }
1018
1019 (*callback)(user, &hdr, pt->PpiPacket);
1020
1021 }
1022
1023 if (++n >= cnt && cnt > 0)
1024 {
1025 return (n);
1026 }
1027 }
1028
1029 return (n);
1030 }
1031
1032 static int
1033 TcStats(pcap_t *p, struct pcap_stat *ps)
1034 {
1035 struct pcap_tc *pt = p->priv;
1036 TC_STATISTICS statistics;
1037 TC_STATUS status;
1038 ULONGLONG counter;
1039 struct pcap_stat s;
1040
1041 status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics);
1042
1043 if (status != TC_SUCCESS)
1044 {
1045 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1046 return -1;
1047 }
1048
1049 memset(&s, 0, sizeof(s));
1050
1051 status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
1052 if (status != TC_SUCCESS)
1053 {
1054 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1055 return -1;
1056 }
1057 if (counter <= (ULONGLONG)0xFFFFFFFF)
1058 {
1059 s.ps_recv = (ULONG)counter;
1060 }
1061 else
1062 {
1063 s.ps_recv = 0xFFFFFFFF;
1064 }
1065
1066 status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
1067 if (status != TC_SUCCESS)
1068 {
1069 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1070 return -1;
1071 }
1072 if (counter <= (ULONGLONG)0xFFFFFFFF)
1073 {
1074 s.ps_ifdrop = (ULONG)counter;
1075 s.ps_drop = (ULONG)counter;
1076 }
1077 else
1078 {
1079 s.ps_ifdrop = 0xFFFFFFFF;
1080 s.ps_drop = 0xFFFFFFFF;
1081 }
1082
1083 #if defined(_WIN32) && defined(HAVE_REMOTE)
1084 s.ps_capt = pt->TcAcceptedCount;
1085 #endif
1086 *ps = s;
1087
1088 return 0;
1089 }
1090
1091
1092 /*
1093 * We filter at user level, since the kernel driver does't process the packets
1094 */
1095 static int
1096 TcSetFilter(pcap_t *p, struct bpf_program *fp)
1097 {
1098 if(!fp)
1099 {
1100 strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf));
1101 return -1;
1102 }
1103
1104 /* Install a user level filter */
1105 if (install_bpf_program(p, fp) < 0)
1106 {
1107 snprintf(p->errbuf, sizeof(p->errbuf),
1108 "setfilter, unable to install the filter: %s", pcap_strerror(errno));
1109 return -1;
1110 }
1111
1112 return (0);
1113 }
1114
1115 #ifdef _WIN32
1116 static struct pcap_stat *
1117 TcStatsEx(pcap_t *p, int *pcap_stat_size)
1118 {
1119 struct pcap_tc *pt = p->priv;
1120 TC_STATISTICS statistics;
1121 TC_STATUS status;
1122 ULONGLONG counter;
1123
1124 *pcap_stat_size = sizeof (p->stat);
1125
1126 status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics);
1127
1128 if (status != TC_SUCCESS)
1129 {
1130 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1131 return (NULL);
1132 }
1133
1134 memset(&p->stat, 0, sizeof(p->stat));
1135
1136 status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
1137 if (status != TC_SUCCESS)
1138 {
1139 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1140 return (NULL);
1141 }
1142 if (counter <= (ULONGLONG)0xFFFFFFFF)
1143 {
1144 p->stat.ps_recv = (ULONG)counter;
1145 }
1146 else
1147 {
1148 p->stat.ps_recv = 0xFFFFFFFF;
1149 }
1150
1151 status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
1152 if (status != TC_SUCCESS)
1153 {
1154 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1155 return (NULL);
1156 }
1157 if (counter <= (ULONGLONG)0xFFFFFFFF)
1158 {
1159 p->stat.ps_ifdrop = (ULONG)counter;
1160 p->stat.ps_drop = (ULONG)counter;
1161 }
1162 else
1163 {
1164 p->stat.ps_ifdrop = 0xFFFFFFFF;
1165 p->stat.ps_drop = 0xFFFFFFFF;
1166 }
1167
1168 #ifdef HAVE_REMOTE
1169 p->stat.ps_capt = pt->TcAcceptedCount;
1170 #endif
1171
1172 return &p->stat;
1173 }
1174
1175 /* Set the dimension of the kernel-level capture buffer */
1176 static int
1177 TcSetBuff(pcap_t *p, int dim)
1178 {
1179 /*
1180 * XXX turbocap has an internal way of managing buffers.
1181 * And at the moment it's not configurable, so we just
1182 * silently ignore the request to set the buffer.
1183 */
1184 return 0;
1185 }
1186
1187 static int
1188 TcSetMode(pcap_t *p, int mode)
1189 {
1190 if (mode != MODE_CAPT)
1191 {
1192 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode);
1193 return -1;
1194 }
1195
1196 return 0;
1197 }
1198
1199 static int
1200 TcSetMinToCopy(pcap_t *p, int size)
1201 {
1202 struct pcap_tc *pt = p->priv;
1203 TC_STATUS status;
1204
1205 if (size < 0)
1206 {
1207 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0.");
1208 return -1;
1209 }
1210
1211 status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_MINTOCOPY, (ULONG)size);
1212
1213 if (status != TC_SUCCESS)
1214 {
1215 snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1216 }
1217
1218 return 0;
1219 }
1220
1221 HANDLE
1222 TcGetReceiveWaitHandle(pcap_t *p)
1223 {
1224 struct pcap_tc *pt = p->priv;
1225
1226 return g_TcFunctions.InstanceGetReceiveWaitHandle(pt->TcInstance);
1227 }
1228
1229 static int
1230 TcOidGetRequest(pcap_t *p, pcap_oid_data_t *data _U_)
1231 {
1232 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1233 "An OID get request cannot be performed on a TurboCap device");
1234 return (PCAP_ERROR);
1235 }
1236
1237 static int
1238 TcOidSetRequest(pcap_t *p, pcap_oid_data_t *data _U_)
1239 {
1240 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1241 "An OID set request cannot be performed on a TurboCap device");
1242 return (PCAP_ERROR);
1243 }
1244
1245 static u_int
1246 TcOidSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
1247 {
1248 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1249 "Packets cannot be bulk transmitted on a TurboCap device");
1250 return (0);
1251 }
1252
1253 static int
1254 TcSetUserBuffer(pcap_t *p, int size _U_)
1255 {
1256 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1257 "The user buffer cannot be set on a TurboCap device");
1258 return (-1);
1259 }
1260
1261 static int
1262 TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
1263 {
1264 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1265 "Live packet dumping cannot be performed on a TurboCap device");
1266 return (-1);
1267 }
1268
1269 static int
1270 TcLiveDumpEnded(pcap_t *p, int sync _U_)
1271 {
1272 snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1273 "Live packet dumping cannot be performed on a TurboCap device");
1274 return (-1);
1275 }
1276
1277 static PAirpcapHandle
1278 TcGetAirPcapHandle(pcap_t *p _U_)
1279 {
1280 return (NULL);
1281 }
1282 #endif