2 * Copyright (c) 2008 CACE Technologies, Davis (California)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
50 typedef TC_STATUS (TC_CALLCONV
*TcFcnQueryPortList
) (PTC_PORT
*ppPorts
, PULONG pLength
);
51 typedef TC_STATUS (TC_CALLCONV
*TcFcnFreePortList
) (TC_PORT
*pPorts
);
53 typedef PCHAR (TC_CALLCONV
*TcFcnStatusGetString
) (TC_STATUS status
);
55 typedef PCHAR (TC_CALLCONV
*TcFcnPortGetName
) (TC_PORT port
);
56 typedef PCHAR (TC_CALLCONV
*TcFcnPortGetDescription
) (TC_PORT port
);
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
);
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
);
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
);
86 typedef struct _TC_FUNCTIONS
88 TC_API_LOAD_STATUS LoadStatus
;
90 HMODULE hTcApiDllHandle
;
92 TcFcnQueryPortList QueryPortList
;
93 TcFcnFreePortList FreePortList
;
94 TcFcnStatusGetString StatusGetString
;
96 TcFcnPortGetName PortGetName
;
97 TcFcnPortGetDescription PortGetDescription
;
99 TcFcnInstanceOpenByName InstanceOpenByName
;
100 TcFcnInstanceClose InstanceClose
;
101 TcFcnInstanceSetFeature InstanceSetFeature
;
102 TcFcnInstanceQueryFeature InstanceQueryFeature
;
103 TcFcnInstanceReceivePackets InstanceReceivePackets
;
105 TcFcnInstanceGetReceiveWaitHandle InstanceGetReceiveWaitHandle
;
107 TcFcnInstanceTransmitPackets InstanceTransmitPackets
;
108 TcFcnInstanceQueryStatistics InstanceQueryStatistics
;
110 TcFcnPacketsBufferCreate PacketsBufferCreate
;
111 TcFcnPacketsBufferDestroy PacketsBufferDestroy
;
112 TcFcnPacketsBufferQueryNextPacket PacketsBufferQueryNextPacket
;
113 TcFcnPacketsBufferCommitNextPacket PacketsBufferCommitNextPacket
;
115 TcFcnStatisticsDestroy StatisticsDestroy
;
116 TcFcnStatisticsUpdate StatisticsUpdate
;
117 TcFcnStatisticsQueryValue StatisticsQueryValue
;
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
);
131 static struct pcap_stat
*TcStatsEx(pcap_t
*p
, int *pcap_stat_size
);
132 static int TcSetBuff(pcap_t
*p
, int dim
);
133 static int TcSetMode(pcap_t
*p
, int mode
);
134 static int TcSetMinToCopy(pcap_t
*p
, int size
);
135 static HANDLE
TcGetReceiveWaitHandle(pcap_t
*p
);
136 static int TcOidGetRequest(pcap_t
*p
, bpf_u_int32 oid
, void *data
, size_t len
);
137 static int TcOidSetRequest(pcap_t
*p
, bpf_u_int32 oid
, const void *data
, size_t len
);
138 static u_int
TcSendqueueTransmit(pcap_t
*p
, pcap_send_queue
*queue
, int sync
);
139 static int TcSetUserBuffer(pcap_t
*p
, int size
);
140 static int TcLiveDump(pcap_t
*p
, char *filename
, int maxsize
, int maxpacks
);
141 static int TcLiveDumpEnded(pcap_t
*p
, int sync
);
142 static PAirpcapHandle
TcGetAirPcapHandle(pcap_t
*p
);
146 TC_FUNCTIONS g_TcFunctions
=
148 TC_API_UNLOADED
, /* LoadStatus */
149 NULL
, /* hTcApiDllHandle */
150 NULL
, /* QueryPortList */
151 NULL
, /* FreePortList */
152 NULL
, /* StatusGetString */
153 NULL
, /* PortGetName */
154 NULL
, /* PortGetDescription */
155 NULL
, /* InstanceOpenByName */
156 NULL
, /* InstanceClose */
157 NULL
, /* InstanceSetFeature */
158 NULL
, /* InstanceQueryFeature */
159 NULL
, /* InstanceReceivePackets */
160 NULL
, /* InstanceGetReceiveWaitHandle */
161 NULL
, /* InstanceTransmitPackets */
162 NULL
, /* InstanceQueryStatistics */
163 NULL
, /* PacketsBufferCreate */
164 NULL
, /* PacketsBufferDestroy */
165 NULL
, /* PacketsBufferQueryNextPacket */
166 NULL
, /* PacketsBufferCommitNextPacket */
167 NULL
, /* StatisticsDestroy */
168 NULL
, /* StatisticsUpdate */
169 NULL
/* StatisticsQueryValue */
172 TC_FUNCTIONS g_TcFunctions
=
174 TC_API_LOADED
, /* LoadStatus */
179 TcPortGetDescription
,
180 TcInstanceOpenByName
,
182 TcInstanceSetFeature
,
183 TcInstanceQueryFeature
,
184 TcInstanceReceivePackets
,
186 TcInstanceGetReceiveWaitHandle
,
188 TcInstanceTransmitPackets
,
189 TcInstanceQueryStatistics
,
190 TcPacketsBufferCreate
,
191 TcPacketsBufferDestroy
,
192 TcPacketsBufferQueryNextPacket
,
193 TcPacketsBufferCommitNextPacket
,
196 TcStatisticsQueryValue
,
200 #define MAX_TC_PACKET_SIZE 9500
202 #pragma pack(push, 1)
204 #define PPH_PH_FLAG_PADDING ((UCHAR)0x01)
205 #define PPH_PH_VERSION ((UCHAR)0x00)
207 typedef struct _PPI_PACKET_HEADER
214 PPI_PACKET_HEADER
, *PPPI_PACKET_HEADER
;
216 typedef struct _PPI_FIELD_HEADER
221 PPI_FIELD_HEADER
, *PPPI_FIELD_HEADER
;
224 #define PPI_FIELD_TYPE_AGGREGATION_EXTENSION ((UCHAR)0x08)
226 typedef struct _PPI_FIELD_AGGREGATION_EXTENSION
230 PPI_FIELD_AGGREGATION_EXTENSION
, *PPPI_FIELD_AGGREGATION_EXTENSION
;
233 #define PPI_FIELD_TYPE_802_3_EXTENSION ((UCHAR)0x09)
235 #define PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT ((ULONG)0x00000001)
237 typedef struct _PPI_FIELD_802_3_EXTENSION
242 PPI_FIELD_802_3_EXTENSION
, *PPPI_FIELD_802_3_EXTENSION
;
244 typedef struct _PPI_HEADER
246 PPI_PACKET_HEADER PacketHeader
;
247 PPI_FIELD_HEADER AggregationFieldHeader
;
248 PPI_FIELD_AGGREGATION_EXTENSION AggregationField
;
249 PPI_FIELD_HEADER Dot3FieldHeader
;
250 PPI_FIELD_802_3_EXTENSION Dot3Field
;
252 PPI_HEADER
, *PPPI_HEADER
;
257 // This wrapper around loadlibrary appends the system folder (usually c:\windows\system32)
258 // to the relative path of the DLL, so that the DLL is always loaded from an absolute path
259 // (It's no longer possible to load airpcap.dll from the application folder).
260 // This solves the DLL Hijacking issue discovered in August 2010
261 // http://blog.metasploit.com/2010/08/exploiting-dll-hijacking-flaws.html
263 HMODULE
LoadLibrarySafe(LPCTSTR lpFileName
)
265 TCHAR path
[MAX_PATH
];
266 TCHAR fullFileName
[MAX_PATH
];
268 HMODULE hModule
= NULL
;
271 res
= GetSystemDirectory(path
, MAX_PATH
);
276 // some bad failure occurred;
284 // the buffer was not big enough
286 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
290 if (res
+ 1 + _tcslen(lpFileName
) + 1 < MAX_PATH
)
292 memcpy(fullFileName
, path
, res
* sizeof(TCHAR
));
293 fullFileName
[res
] = _T('\\');
294 memcpy(&fullFileName
[res
+ 1], lpFileName
, (_tcslen(lpFileName
) + 1) * sizeof(TCHAR
));
296 hModule
= LoadLibrary(fullFileName
);
300 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
309 * NOTE: this function should be called by the pcap functions that can theoretically
310 * deal with the Tc library for the first time, namely listing the adapters and
311 * opening one. All the other ones (close, read, write, set parameters) work
312 * on an open instance of TC, so we do not care to call this function
314 TC_API_LOAD_STATUS
LoadTcFunctions(void)
316 TC_API_LOAD_STATUS currentStatus
;
320 currentStatus
= InterlockedCompareExchange((LONG
*)&g_TcFunctions
.LoadStatus
, TC_API_LOADING
, TC_API_UNLOADED
);
322 while(currentStatus
== TC_API_LOADING
)
324 currentStatus
= InterlockedCompareExchange((LONG
*)&g_TcFunctions
.LoadStatus
, TC_API_LOADING
, TC_API_LOADING
);
329 * at this point we are either in the LOADED state, unloaded state (i.e. we are the ones loading everything)
332 if(currentStatus
== TC_API_LOADED
)
334 return TC_API_LOADED
;
337 if (currentStatus
== TC_API_CANNOT_LOAD
)
339 return TC_API_CANNOT_LOAD
;
342 currentStatus
= TC_API_CANNOT_LOAD
;
344 g_TcFunctions
.hTcApiDllHandle
= LoadLibrarySafe("TcApi.dll");
345 if (g_TcFunctions
.hTcApiDllHandle
== NULL
) break;
347 g_TcFunctions
.QueryPortList
= (TcFcnQueryPortList
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcQueryPortList");
348 g_TcFunctions
.FreePortList
= (TcFcnFreePortList
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcFreePortList");
350 g_TcFunctions
.StatusGetString
= (TcFcnStatusGetString
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcStatusGetString");
352 g_TcFunctions
.PortGetName
= (TcFcnPortGetName
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcPortGetName");
353 g_TcFunctions
.PortGetDescription
= (TcFcnPortGetDescription
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcPortGetDescription");
355 g_TcFunctions
.InstanceOpenByName
= (TcFcnInstanceOpenByName
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceOpenByName");
356 g_TcFunctions
.InstanceClose
= (TcFcnInstanceClose
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceClose");
357 g_TcFunctions
.InstanceSetFeature
= (TcFcnInstanceSetFeature
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceSetFeature");
358 g_TcFunctions
.InstanceQueryFeature
= (TcFcnInstanceQueryFeature
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceQueryFeature");
359 g_TcFunctions
.InstanceReceivePackets
= (TcFcnInstanceReceivePackets
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceReceivePackets");
360 g_TcFunctions
.InstanceGetReceiveWaitHandle
= (TcFcnInstanceGetReceiveWaitHandle
)GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceGetReceiveWaitHandle");
361 g_TcFunctions
.InstanceTransmitPackets
= (TcFcnInstanceTransmitPackets
)GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceTransmitPackets");
362 g_TcFunctions
.InstanceQueryStatistics
= (TcFcnInstanceQueryStatistics
)GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceQueryStatistics");
364 g_TcFunctions
.PacketsBufferCreate
= (TcFcnPacketsBufferCreate
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcPacketsBufferCreate");
365 g_TcFunctions
.PacketsBufferDestroy
= (TcFcnPacketsBufferDestroy
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcPacketsBufferDestroy");
366 g_TcFunctions
.PacketsBufferQueryNextPacket
= (TcFcnPacketsBufferQueryNextPacket
)GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcPacketsBufferQueryNextPacket");
367 g_TcFunctions
.PacketsBufferCommitNextPacket
= (TcFcnPacketsBufferCommitNextPacket
)GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcPacketsBufferCommitNextPacket");
369 g_TcFunctions
.StatisticsDestroy
= (TcFcnStatisticsDestroy
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcStatisticsDestroy");
370 g_TcFunctions
.StatisticsUpdate
= (TcFcnStatisticsUpdate
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcStatisticsUpdate");
371 g_TcFunctions
.StatisticsQueryValue
= (TcFcnStatisticsQueryValue
) GetProcAddress(g_TcFunctions
.hTcApiDllHandle
, "TcStatisticsQueryValue");
373 if ( g_TcFunctions
.QueryPortList
== NULL
374 || g_TcFunctions
.FreePortList
== NULL
375 || g_TcFunctions
.StatusGetString
== NULL
376 || g_TcFunctions
.PortGetName
== NULL
377 || g_TcFunctions
.PortGetDescription
== NULL
378 || g_TcFunctions
.InstanceOpenByName
== NULL
379 || g_TcFunctions
.InstanceClose
== NULL
380 || g_TcFunctions
.InstanceSetFeature
== NULL
381 || g_TcFunctions
.InstanceQueryFeature
== NULL
382 || g_TcFunctions
.InstanceReceivePackets
== NULL
383 || g_TcFunctions
.InstanceGetReceiveWaitHandle
== NULL
384 || g_TcFunctions
.InstanceTransmitPackets
== NULL
385 || g_TcFunctions
.InstanceQueryStatistics
== NULL
386 || g_TcFunctions
.PacketsBufferCreate
== NULL
387 || g_TcFunctions
.PacketsBufferDestroy
== NULL
388 || g_TcFunctions
.PacketsBufferQueryNextPacket
== NULL
389 || g_TcFunctions
.PacketsBufferCommitNextPacket
== NULL
390 || g_TcFunctions
.StatisticsDestroy
== NULL
391 || g_TcFunctions
.StatisticsUpdate
== NULL
392 || g_TcFunctions
.StatisticsQueryValue
== NULL
399 * everything got loaded, yay!!
401 currentStatus
= TC_API_LOADED
;
404 if (currentStatus
!= TC_API_LOADED
)
406 if (g_TcFunctions
.hTcApiDllHandle
!= NULL
)
408 FreeLibrary(g_TcFunctions
.hTcApiDllHandle
);
409 g_TcFunctions
.hTcApiDllHandle
= NULL
;
413 InterlockedExchange((LONG
*)&g_TcFunctions
.LoadStatus
, currentStatus
);
415 return currentStatus
;
419 TC_API_LOAD_STATUS
LoadTcFunctions(void)
421 return TC_API_LOADED
;
426 * Private data for capturing on TurboCap devices.
429 TC_INSTANCE TcInstance
;
430 TC_PACKETS_BUFFER TcPacketsBuffer
;
431 ULONG TcAcceptedCount
;
436 TcFindAllDevs(pcap_if_t
**alldevsp
, char *errbuf
)
438 TC_API_LOAD_STATUS loadStatus
;
440 PTC_PORT pPorts
= NULL
;
443 pcap_if_t
*dev
, *cursor
;
448 loadStatus
= LoadTcFunctions();
450 if (loadStatus
!= TC_API_LOADED
)
457 * enumerate the ports, and add them to the list
459 status
= g_TcFunctions
.QueryPortList(&pPorts
, &numPorts
);
461 if (status
!= TC_SUCCESS
)
467 for (i
= 0; i
< numPorts
; i
++)
470 * transform the port into an entry in the list
472 dev
= TcCreatePcapIfFromPort(pPorts
[i
]);
477 * append it at the end
479 if (*alldevsp
== NULL
)
485 for(cursor
= *alldevsp
; cursor
->next
!= NULL
; cursor
= cursor
->next
);
494 * ignore the result here
496 status
= g_TcFunctions
.FreePortList(pPorts
);
504 static pcap_if_t
* TcCreatePcapIfFromPort(TC_PORT port
)
508 pcap_if_t
*newIf
= NULL
;
510 newIf
= (pcap_if_t
*)malloc(sizeof(*newIf
));
516 memset(newIf
, 0, sizeof(*newIf
));
518 name
= g_TcFunctions
.PortGetName(port
);
519 description
= g_TcFunctions
.PortGetDescription(port
);
521 newIf
->name
= (char*)malloc(strlen(name
) + 1);
522 if (newIf
->name
== NULL
)
528 newIf
->description
= (char*)malloc(strlen(description
) + 1);
529 if (newIf
->description
== NULL
)
536 strcpy(newIf
->name
, name
);
537 strcpy(newIf
->description
, description
);
539 newIf
->addresses
= NULL
;
548 TcActivate(pcap_t
*p
)
550 struct pcap_tc
*pt
= p
->priv
;
553 PPPI_HEADER pPpiHeader
;
558 * No monitor mode on Tc cards; they're Ethernet
561 return PCAP_ERROR_RFMON_NOTSUP
;
564 pt
->PpiPacket
= (PCHAR
)malloc(sizeof(PPI_HEADER
) + MAX_TC_PACKET_SIZE
);
566 if (pt
->PpiPacket
== NULL
)
568 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Error allocating memory");
573 * Initialize the PPI fixed fields
575 pPpiHeader
= (PPPI_HEADER
)pt
->PpiPacket
;
576 pPpiHeader
->PacketHeader
.PphDlt
= DLT_EN10MB
;
577 pPpiHeader
->PacketHeader
.PphLength
= sizeof(PPI_HEADER
);
578 pPpiHeader
->PacketHeader
.PphFlags
= 0;
579 pPpiHeader
->PacketHeader
.PphVersion
= 0;
581 pPpiHeader
->AggregationFieldHeader
.PfhLength
= sizeof(PPI_FIELD_AGGREGATION_EXTENSION
);
582 pPpiHeader
->AggregationFieldHeader
.PfhType
= PPI_FIELD_TYPE_AGGREGATION_EXTENSION
;
584 pPpiHeader
->Dot3FieldHeader
.PfhLength
= sizeof(PPI_FIELD_802_3_EXTENSION
);
585 pPpiHeader
->Dot3FieldHeader
.PfhType
= PPI_FIELD_TYPE_802_3_EXTENSION
;
587 status
= g_TcFunctions
.InstanceOpenByName(p
->opt
.source
, &pt
->TcInstance
);
589 if (status
!= TC_SUCCESS
)
591 /* Adapter detected but we are not able to open it. Return failure. */
592 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Error opening TurboCap adapter: %s", g_TcFunctions
.StatusGetString(status
));
596 p
->linktype
= DLT_EN10MB
;
597 p
->dlt_list
= (u_int
*) malloc(sizeof(u_int
) * 2);
599 * If that fails, just leave the list empty.
601 if (p
->dlt_list
!= NULL
) {
602 p
->dlt_list
[0] = DLT_EN10MB
;
603 p
->dlt_list
[1] = DLT_PPI
;
608 * ignore promiscuous mode
614 * ignore all the buffer sizes
620 status
= g_TcFunctions
.InstanceSetFeature(pt
->TcInstance
, TC_INST_FT_RX_STATUS
, 1);
622 if (status
!= TC_SUCCESS
)
624 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions
.StatusGetString(status
));
629 * enable transmission
631 status
= g_TcFunctions
.InstanceSetFeature(pt
->TcInstance
, TC_INST_FT_TX_STATUS
, 1);
633 * Ignore the error here.
636 p
->inject_op
= TcInject
;
638 * if the timeout is -1, it means immediate return, no timeout
639 * if the timeout is 0, it means INFINITE
642 if (p
->opt
.timeout
== 0)
644 timeout
= 0xFFFFFFFF;
647 if (p
->opt
.timeout
< 0)
650 * we insert a minimal timeout here
656 timeout
= p
->opt
.timeout
;
659 status
= g_TcFunctions
.InstanceSetFeature(pt
->TcInstance
, TC_INST_FT_READ_TIMEOUT
, timeout
);
661 if (status
!= TC_SUCCESS
)
663 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions
.StatusGetString(status
));
668 p
->setfilter_op
= TcSetFilter
;
669 p
->setdirection_op
= NULL
; /* Not implemented. */
670 p
->set_datalink_op
= TcSetDatalink
;
671 p
->getnonblock_op
= TcGetNonBlock
;
672 p
->setnonblock_op
= TcSetNonBlock
;
673 p
->stats_op
= TcStats
;
675 p
->stats_ex_op
= TcStatsEx
;
676 p
->setbuff_op
= TcSetBuff
;
677 p
->setmode_op
= TcSetMode
;
678 p
->setmintocopy_op
= TcSetMinToCopy
;
679 p
->getevent_op
= TcGetReceiveWaitHandle
;
680 p
->oid_get_request_op
= TcOidGetRequest
;
681 p
->oid_set_request_op
= TcOidSetRequest
;
682 p
->sendqueue_transmit_op
= TcSendqueueTransmit
;
683 p
->setuserbuffer_op
= TcSetUserBuffer
;
684 p
->live_dump_op
= TcLiveDump
;
685 p
->live_dump_ended_op
= TcLiveDumpEnded
;
686 p
->get_airpcap_handle_op
= TcGetAirPcapHandle
;
688 p
->selectable_fd
= -1;
691 p
->cleanup_op
= TcCleanup
;
700 TcCreate(const char *device
, char *ebuf
, int *is_ours
)
703 PTC_PORT pPorts
= NULL
;
709 if (LoadTcFunctions() != TC_API_LOADED
)
712 * XXX - report this as an error rather than as
713 * "not a TurboCap device"?
720 * enumerate the ports, and add them to the list
722 status
= g_TcFunctions
.QueryPortList(&pPorts
, &numPorts
);
724 if (status
!= TC_SUCCESS
)
727 * XXX - report this as an error rather than as
728 * "not a TurboCap device"?
735 for (i
= 0; i
< numPorts
; i
++)
737 if (strcmp(g_TcFunctions
.PortGetName(pPorts
[i
]), device
) == 0)
747 * ignore the result here
749 (void)g_TcFunctions
.FreePortList(pPorts
);
758 /* OK, it's probably ours. */
761 p
= pcap_create_common(device
, ebuf
, sizeof (struct pcap_tc
));
765 p
->activate_op
= TcActivate
;
769 static int TcSetDatalink(pcap_t
*p
, int dlt
)
772 * always return 0, as the check is done by pcap_set_datalink
777 static int TcGetNonBlock(pcap_t
*p
, char *errbuf
)
779 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
780 "Getting the non blocking status is not available for TurboCap ports");
781 snprintf(errbuf
, PCAP_ERRBUF_SIZE
,
782 "Getting the non blocking status is not available for TurboCap ports");
786 static int TcSetNonBlock(pcap_t
*p
, int nonblock
, char *errbuf
)
788 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
789 "Setting the non blocking status is not available for TurboCap ports");
790 snprintf(errbuf
, PCAP_ERRBUF_SIZE
,
791 "Setting the non blocking status is not available for TurboCap ports");
796 static void TcCleanup(pcap_t
*p
)
798 struct pcap_tc
*pt
= p
->priv
;
800 if (pt
->TcPacketsBuffer
!= NULL
)
802 g_TcFunctions
.PacketsBufferDestroy(pt
->TcPacketsBuffer
);
803 pt
->TcPacketsBuffer
= NULL
;
805 if (pt
->TcInstance
!= NULL
)
808 * here we do not check for the error values
810 g_TcFunctions
.InstanceClose(pt
->TcInstance
);
811 pt
->TcInstance
= NULL
;
814 if (pt
->PpiPacket
!= NULL
)
817 pt
->PpiPacket
= NULL
;
820 pcap_cleanup_live_common(p
);
823 /* Send a packet to the network */
824 static int TcInject(pcap_t
*p
, const void *buf
, size_t size
)
826 struct pcap_tc
*pt
= p
->priv
;
828 TC_PACKETS_BUFFER buffer
;
829 TC_PACKET_HEADER header
;
833 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "send error: the TurboCap API does not support packets larger than 64k");
837 status
= g_TcFunctions
.PacketsBufferCreate(sizeof(TC_PACKET_HEADER
) + TC_ALIGN_USHORT_TO_64BIT((USHORT
)size
), &buffer
);
839 if (status
!= TC_SUCCESS
)
841 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
846 * we assume that the packet is without the checksum, as common with WinPcap
848 memset(&header
, 0, sizeof(header
));
850 header
.Length
= (USHORT
)size
;
851 header
.CapturedLength
= header
.Length
;
853 status
= g_TcFunctions
.PacketsBufferCommitNextPacket(buffer
, &header
, (PVOID
)buf
);
855 if (status
== TC_SUCCESS
)
857 status
= g_TcFunctions
.InstanceTransmitPackets(pt
->TcInstance
, buffer
);
859 if (status
!= TC_SUCCESS
)
861 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
866 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
869 g_TcFunctions
.PacketsBufferDestroy(buffer
);
871 if (status
!= TC_SUCCESS
)
881 static int TcRead(pcap_t
*p
, int cnt
, pcap_handler callback
, u_char
*user
)
883 struct pcap_tc
*pt
= p
->priv
;
888 * Has "pcap_breakloop()" been called?
893 * Yes - clear the flag that indicates that it
894 * has, and return -2 to indicate that we were
895 * told to break out of the loop.
901 if (pt
->TcPacketsBuffer
== NULL
)
903 status
= g_TcFunctions
.InstanceReceivePackets(pt
->TcInstance
, &pt
->TcPacketsBuffer
);
904 if (status
!= TC_SUCCESS
)
906 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
913 struct pcap_pkthdr hdr
;
914 TC_PACKET_HEADER tcHeader
;
919 * Has "pcap_breakloop()" been called?
920 * If so, return immediately - if we haven't read any
921 * packets, clear the flag and return -2 to indicate
922 * that we were told to break out of the loop, otherwise
923 * leave the flag set, so that the *next* call will break
924 * out of the loop without having read any packets, and
925 * return the number of packets we've processed so far.
940 if (pt
->TcPacketsBuffer
== NULL
)
945 status
= g_TcFunctions
.PacketsBufferQueryNextPacket(pt
->TcPacketsBuffer
, &tcHeader
, &data
);
947 if (status
== TC_ERROR_END_OF_BUFFER
)
949 g_TcFunctions
.PacketsBufferDestroy(pt
->TcPacketsBuffer
);
950 pt
->TcPacketsBuffer
= NULL
;
954 if (status
!= TC_SUCCESS
)
956 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
960 /* No underlaying filtering system. We need to filter on our own */
961 if (p
->fcode
.bf_insns
)
963 filterResult
= bpf_filter(p
->fcode
.bf_insns
, data
, tcHeader
.Length
, tcHeader
.CapturedLength
);
965 if (filterResult
== 0)
970 if (filterResult
> tcHeader
.CapturedLength
)
972 filterResult
= tcHeader
.CapturedLength
;
977 filterResult
= tcHeader
.CapturedLength
;
980 pt
->TcAcceptedCount
++;
982 hdr
.ts
.tv_sec
= (bpf_u_int32
)(tcHeader
.Timestamp
/ (ULONGLONG
)(1000 * 1000 * 1000));
983 hdr
.ts
.tv_usec
= (bpf_u_int32
)((tcHeader
.Timestamp
% (ULONGLONG
)(1000 * 1000 * 1000)) / 1000);
985 if (p
->linktype
== DLT_EN10MB
)
987 hdr
.caplen
= filterResult
;
988 hdr
.len
= tcHeader
.Length
;
989 (*callback
)(user
, &hdr
, data
);
993 PPPI_HEADER pPpiHeader
= (PPPI_HEADER
)pt
->PpiPacket
;
994 PVOID data2
= pPpiHeader
+ 1;
996 pPpiHeader
->AggregationField
.InterfaceId
= TC_PH_FLAGS_RX_PORT_ID(tcHeader
.Flags
);
997 pPpiHeader
->Dot3Field
.Errors
= tcHeader
.Errors
;
998 if (tcHeader
.Flags
& TC_PH_FLAGS_CHECKSUM
)
1000 pPpiHeader
->Dot3Field
.Flags
= PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT
;
1004 pPpiHeader
->Dot3Field
.Flags
= 0;
1007 if (filterResult
<= MAX_TC_PACKET_SIZE
)
1009 memcpy(data2
, data
, filterResult
);
1010 hdr
.caplen
= sizeof(PPI_HEADER
) + filterResult
;
1011 hdr
.len
= sizeof(PPI_HEADER
) + tcHeader
.Length
;
1015 memcpy(data2
, data
, MAX_TC_PACKET_SIZE
);
1016 hdr
.caplen
= sizeof(PPI_HEADER
) + MAX_TC_PACKET_SIZE
;
1017 hdr
.len
= sizeof(PPI_HEADER
) + tcHeader
.Length
;
1020 (*callback
)(user
, &hdr
, pt
->PpiPacket
);
1024 if (++n
>= cnt
&& cnt
> 0)
1034 TcStats(pcap_t
*p
, struct pcap_stat
*ps
)
1036 struct pcap_tc
*pt
= p
->priv
;
1037 TC_STATISTICS statistics
;
1042 status
= g_TcFunctions
.InstanceQueryStatistics(pt
->TcInstance
, &statistics
);
1044 if (status
!= TC_SUCCESS
)
1046 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1050 memset(&s
, 0, sizeof(s
));
1052 status
= g_TcFunctions
.StatisticsQueryValue(statistics
, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS
, &counter
);
1053 if (status
!= TC_SUCCESS
)
1055 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1058 if (counter
<= (ULONGLONG
)0xFFFFFFFF)
1060 s
.ps_recv
= (ULONG
)counter
;
1064 s
.ps_recv
= 0xFFFFFFFF;
1067 status
= g_TcFunctions
.StatisticsQueryValue(statistics
, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS
, &counter
);
1068 if (status
!= TC_SUCCESS
)
1070 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1073 if (counter
<= (ULONGLONG
)0xFFFFFFFF)
1075 s
.ps_ifdrop
= (ULONG
)counter
;
1076 s
.ps_drop
= (ULONG
)counter
;
1080 s
.ps_ifdrop
= 0xFFFFFFFF;
1081 s
.ps_drop
= 0xFFFFFFFF;
1084 #if defined(_WIN32) && defined(HAVE_REMOTE)
1085 s
.ps_capt
= pt
->TcAcceptedCount
;
1094 * We filter at user level, since the kernel driver does't process the packets
1097 TcSetFilter(pcap_t
*p
, struct bpf_program
*fp
)
1101 strncpy(p
->errbuf
, "setfilter: No filter specified", sizeof(p
->errbuf
));
1105 /* Install a user level filter */
1106 if (install_bpf_program(p
, fp
) < 0)
1108 snprintf(p
->errbuf
, sizeof(p
->errbuf
),
1109 "setfilter, unable to install the filter: %s", pcap_strerror(errno
));
1117 static struct pcap_stat
*
1118 TcStatsEx(pcap_t
*p
, int *pcap_stat_size
)
1120 struct pcap_tc
*pt
= p
->priv
;
1121 TC_STATISTICS statistics
;
1125 *pcap_stat_size
= sizeof (p
->stat
);
1127 status
= g_TcFunctions
.InstanceQueryStatistics(pt
->TcInstance
, &statistics
);
1129 if (status
!= TC_SUCCESS
)
1131 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1135 memset(&p
->stat
, 0, sizeof(p
->stat
));
1137 status
= g_TcFunctions
.StatisticsQueryValue(statistics
, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS
, &counter
);
1138 if (status
!= TC_SUCCESS
)
1140 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1143 if (counter
<= (ULONGLONG
)0xFFFFFFFF)
1145 p
->stat
.ps_recv
= (ULONG
)counter
;
1149 p
->stat
.ps_recv
= 0xFFFFFFFF;
1152 status
= g_TcFunctions
.StatisticsQueryValue(statistics
, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS
, &counter
);
1153 if (status
!= TC_SUCCESS
)
1155 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1158 if (counter
<= (ULONGLONG
)0xFFFFFFFF)
1160 p
->stat
.ps_ifdrop
= (ULONG
)counter
;
1161 p
->stat
.ps_drop
= (ULONG
)counter
;
1165 p
->stat
.ps_ifdrop
= 0xFFFFFFFF;
1166 p
->stat
.ps_drop
= 0xFFFFFFFF;
1170 p
->stat
.ps_capt
= pt
->TcAcceptedCount
;
1176 /* Set the dimension of the kernel-level capture buffer */
1178 TcSetBuff(pcap_t
*p
, int dim
)
1181 * XXX turbocap has an internal way of managing buffers.
1182 * And at the moment it's not configurable, so we just
1183 * silently ignore the request to set the buffer.
1189 TcSetMode(pcap_t
*p
, int mode
)
1191 if (mode
!= MODE_CAPT
)
1193 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode
);
1201 TcSetMinToCopy(pcap_t
*p
, int size
)
1203 struct pcap_tc
*pt
= p
->priv
;
1208 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Mintocopy cannot be less than 0.");
1212 status
= g_TcFunctions
.InstanceSetFeature(pt
->TcInstance
, TC_INST_FT_MINTOCOPY
, (ULONG
)size
);
1214 if (status
!= TC_SUCCESS
)
1216 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1223 TcGetReceiveWaitHandle(pcap_t
*p
)
1225 struct pcap_tc
*pt
= p
->priv
;
1227 return g_TcFunctions
.InstanceGetReceiveWaitHandle(pt
->TcInstance
);
1231 TcOidGetRequest(pcap_t
*p
, bpf_u_int32 oid _U_
, void *data _U_
, size_t len _U_
1233 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1234 "An OID get request cannot be performed on a TurboCap device");
1239 TcOidSetRequest(pcap_t
*p
, bpf_u_int32 oid _U_
, const void *data _U_
,
1242 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1243 "An OID set request cannot be performed on a TurboCap device");
1248 TcSendqueueTransmit(pcap_t
*p
, pcap_send_queue
*queue _U_
, int sync _U_
)
1250 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1251 "Packets cannot be bulk transmitted on a TurboCap device");
1256 TcSetUserBuffer(pcap_t
*p
, int size _U_
)
1258 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1259 "The user buffer cannot be set on a TurboCap device");
1264 TcLiveDump(pcap_t
*p
, char *filename _U_
, int maxsize _U_
, int maxpacks _U_
)
1266 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1267 "Live packet dumping cannot be performed on a TurboCap device");
1272 TcLiveDumpEnded(pcap_t
*p
, int sync _U_
)
1274 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1275 "Live packet dumping cannot be performed on a TurboCap device");
1279 static PAirpcapHandle
1280 TcGetAirPcapHandle(pcap_t
*p _U_
)