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.
48 typedef TC_STATUS (TC_CALLCONV
*TcFcnQueryPortList
) (PTC_PORT
*ppPorts
, PULONG pLength
);
49 typedef TC_STATUS (TC_CALLCONV
*TcFcnFreePortList
) (TC_PORT
*pPorts
);
51 typedef PCHAR (TC_CALLCONV
*TcFcnStatusGetString
) (TC_STATUS status
);
53 typedef PCHAR (TC_CALLCONV
*TcFcnPortGetName
) (TC_PORT port
);
54 typedef PCHAR (TC_CALLCONV
*TcFcnPortGetDescription
) (TC_PORT port
);
56 typedef TC_STATUS (TC_CALLCONV
*TcFcnInstanceOpenByName
) (PCHAR name
, PTC_INSTANCE pInstance
);
57 typedef TC_STATUS (TC_CALLCONV
*TcFcnInstanceClose
) (TC_INSTANCE instance
);
58 typedef TC_STATUS (TC_CALLCONV
*TcFcnInstanceSetFeature
) (TC_INSTANCE instance
, ULONG feature
, ULONG value
);
59 typedef TC_STATUS (TC_CALLCONV
*TcFcnInstanceQueryFeature
) (TC_INSTANCE instance
, ULONG feature
, PULONG pValue
);
60 typedef TC_STATUS (TC_CALLCONV
*TcFcnInstanceReceivePackets
) (TC_INSTANCE instance
, PTC_PACKETS_BUFFER pBuffer
);
61 typedef HANDLE (TC_CALLCONV
*TcFcnInstanceGetReceiveWaitHandle
) (TC_INSTANCE instance
);
62 typedef TC_STATUS (TC_CALLCONV
*TcFcnInstanceTransmitPackets
) (TC_INSTANCE instance
, TC_PACKETS_BUFFER pBuffer
);
63 typedef TC_STATUS (TC_CALLCONV
*TcFcnInstanceQueryStatistics
) (TC_INSTANCE instance
, PTC_STATISTICS pStatistics
);
65 typedef TC_STATUS (TC_CALLCONV
*TcFcnPacketsBufferCreate
) (ULONG size
, PTC_PACKETS_BUFFER pBuffer
);
66 typedef VOID (TC_CALLCONV
*TcFcnPacketsBufferDestroy
) (TC_PACKETS_BUFFER buffer
);
67 typedef TC_STATUS (TC_CALLCONV
*TcFcnPacketsBufferQueryNextPacket
)(TC_PACKETS_BUFFER buffer
, PTC_PACKET_HEADER pHeader
, PVOID
*ppData
);
68 typedef TC_STATUS (TC_CALLCONV
*TcFcnPacketsBufferCommitNextPacket
)(TC_PACKETS_BUFFER buffer
, PTC_PACKET_HEADER pHeader
, PVOID pData
);
70 typedef VOID (TC_CALLCONV
*TcFcnStatisticsDestroy
) (TC_STATISTICS statistics
);
71 typedef TC_STATUS (TC_CALLCONV
*TcFcnStatisticsUpdate
) (TC_STATISTICS statistics
);
72 typedef TC_STATUS (TC_CALLCONV
*TcFcnStatisticsQueryValue
) (TC_STATISTICS statistics
, ULONG counterId
, PULONGLONG pValue
);
84 typedef struct _TC_FUNCTIONS
86 TC_API_LOAD_STATUS LoadStatus
;
88 HMODULE hTcApiDllHandle
;
90 TcFcnQueryPortList QueryPortList
;
91 TcFcnFreePortList FreePortList
;
92 TcFcnStatusGetString StatusGetString
;
94 TcFcnPortGetName PortGetName
;
95 TcFcnPortGetDescription PortGetDescription
;
97 TcFcnInstanceOpenByName InstanceOpenByName
;
98 TcFcnInstanceClose InstanceClose
;
99 TcFcnInstanceSetFeature InstanceSetFeature
;
100 TcFcnInstanceQueryFeature InstanceQueryFeature
;
101 TcFcnInstanceReceivePackets InstanceReceivePackets
;
103 TcFcnInstanceGetReceiveWaitHandle InstanceGetReceiveWaitHandle
;
105 TcFcnInstanceTransmitPackets InstanceTransmitPackets
;
106 TcFcnInstanceQueryStatistics InstanceQueryStatistics
;
108 TcFcnPacketsBufferCreate PacketsBufferCreate
;
109 TcFcnPacketsBufferDestroy PacketsBufferDestroy
;
110 TcFcnPacketsBufferQueryNextPacket PacketsBufferQueryNextPacket
;
111 TcFcnPacketsBufferCommitNextPacket PacketsBufferCommitNextPacket
;
113 TcFcnStatisticsDestroy StatisticsDestroy
;
114 TcFcnStatisticsUpdate StatisticsUpdate
;
115 TcFcnStatisticsQueryValue StatisticsQueryValue
;
119 static pcap_if_t
* TcCreatePcapIfFromPort(TC_PORT port
);
120 static int TcSetDatalink(pcap_t
*p
, int dlt
);
121 static int TcGetNonBlock(pcap_t
*p
);
122 static int TcSetNonBlock(pcap_t
*p
, int nonblock
);
123 static void TcCleanup(pcap_t
*p
);
124 static int TcInject(pcap_t
*p
, const void *buf
, int size
);
125 static int TcRead(pcap_t
*p
, int cnt
, pcap_handler callback
, u_char
*user
);
126 static int TcStats(pcap_t
*p
, struct pcap_stat
*ps
);
128 static struct pcap_stat
*TcStatsEx(pcap_t
*p
, int *pcap_stat_size
);
129 static int TcSetBuff(pcap_t
*p
, int dim
);
130 static int TcSetMode(pcap_t
*p
, int mode
);
131 static int TcSetMinToCopy(pcap_t
*p
, int size
);
132 static HANDLE
TcGetReceiveWaitHandle(pcap_t
*p
);
133 static int TcOidGetRequest(pcap_t
*p
, bpf_u_int32 oid
, void *data
, size_t *lenp
);
134 static int TcOidSetRequest(pcap_t
*p
, bpf_u_int32 oid
, const void *data
, size_t *lenp
);
135 static u_int
TcSendqueueTransmit(pcap_t
*p
, pcap_send_queue
*queue
, int sync
);
136 static int TcSetUserBuffer(pcap_t
*p
, int size
);
137 static int TcLiveDump(pcap_t
*p
, char *filename
, int maxsize
, int maxpacks
);
138 static int TcLiveDumpEnded(pcap_t
*p
, int sync
);
139 static PAirpcapHandle
TcGetAirPcapHandle(pcap_t
*p
);
143 TC_FUNCTIONS g_TcFunctions
=
145 TC_API_UNLOADED
, /* LoadStatus */
146 NULL
, /* hTcApiDllHandle */
147 NULL
, /* QueryPortList */
148 NULL
, /* FreePortList */
149 NULL
, /* StatusGetString */
150 NULL
, /* PortGetName */
151 NULL
, /* PortGetDescription */
152 NULL
, /* InstanceOpenByName */
153 NULL
, /* InstanceClose */
154 NULL
, /* InstanceSetFeature */
155 NULL
, /* InstanceQueryFeature */
156 NULL
, /* InstanceReceivePackets */
157 NULL
, /* InstanceGetReceiveWaitHandle */
158 NULL
, /* InstanceTransmitPackets */
159 NULL
, /* InstanceQueryStatistics */
160 NULL
, /* PacketsBufferCreate */
161 NULL
, /* PacketsBufferDestroy */
162 NULL
, /* PacketsBufferQueryNextPacket */
163 NULL
, /* PacketsBufferCommitNextPacket */
164 NULL
, /* StatisticsDestroy */
165 NULL
, /* StatisticsUpdate */
166 NULL
/* StatisticsQueryValue */
169 TC_FUNCTIONS g_TcFunctions
=
171 TC_API_LOADED
, /* LoadStatus */
176 TcPortGetDescription
,
177 TcInstanceOpenByName
,
179 TcInstanceSetFeature
,
180 TcInstanceQueryFeature
,
181 TcInstanceReceivePackets
,
183 TcInstanceGetReceiveWaitHandle
,
185 TcInstanceTransmitPackets
,
186 TcInstanceQueryStatistics
,
187 TcPacketsBufferCreate
,
188 TcPacketsBufferDestroy
,
189 TcPacketsBufferQueryNextPacket
,
190 TcPacketsBufferCommitNextPacket
,
193 TcStatisticsQueryValue
,
197 #define MAX_TC_PACKET_SIZE 9500
199 #pragma pack(push, 1)
201 #define PPH_PH_FLAG_PADDING ((UCHAR)0x01)
202 #define PPH_PH_VERSION ((UCHAR)0x00)
204 typedef struct _PPI_PACKET_HEADER
211 PPI_PACKET_HEADER
, *PPPI_PACKET_HEADER
;
213 typedef struct _PPI_FIELD_HEADER
218 PPI_FIELD_HEADER
, *PPPI_FIELD_HEADER
;
221 #define PPI_FIELD_TYPE_AGGREGATION_EXTENSION ((UCHAR)0x08)
223 typedef struct _PPI_FIELD_AGGREGATION_EXTENSION
227 PPI_FIELD_AGGREGATION_EXTENSION
, *PPPI_FIELD_AGGREGATION_EXTENSION
;
230 #define PPI_FIELD_TYPE_802_3_EXTENSION ((UCHAR)0x09)
232 #define PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT ((ULONG)0x00000001)
234 typedef struct _PPI_FIELD_802_3_EXTENSION
239 PPI_FIELD_802_3_EXTENSION
, *PPPI_FIELD_802_3_EXTENSION
;
241 typedef struct _PPI_HEADER
243 PPI_PACKET_HEADER PacketHeader
;
244 PPI_FIELD_HEADER AggregationFieldHeader
;
245 PPI_FIELD_AGGREGATION_EXTENSION AggregationField
;
246 PPI_FIELD_HEADER Dot3FieldHeader
;
247 PPI_FIELD_802_3_EXTENSION Dot3Field
;
249 PPI_HEADER
, *PPPI_HEADER
;
254 * NOTE: this function should be called by the pcap functions that can theoretically
255 * deal with the Tc library for the first time, namely listing the adapters and
256 * opening one. All the other ones (close, read, write, set parameters) work
257 * on an open instance of TC, so we do not care to call this function
259 TC_API_LOAD_STATUS
LoadTcFunctions(void)
261 TC_API_LOAD_STATUS currentStatus
;
265 currentStatus
= InterlockedCompareExchange((LONG
*)&g_TcFunctions
.LoadStatus
, TC_API_LOADING
, TC_API_UNLOADED
);
267 while(currentStatus
== TC_API_LOADING
)
269 currentStatus
= InterlockedCompareExchange((LONG
*)&g_TcFunctions
.LoadStatus
, TC_API_LOADING
, TC_API_LOADING
);
274 * at this point we are either in the LOADED state, unloaded state (i.e. we are the ones loading everything)
277 if(currentStatus
== TC_API_LOADED
)
279 return TC_API_LOADED
;
282 if (currentStatus
== TC_API_CANNOT_LOAD
)
284 return TC_API_CANNOT_LOAD
;
287 currentStatus
= TC_API_CANNOT_LOAD
;
289 g_TcFunctions
.hTcApiDllHandle
= pcapint_load_code("TcApi.dll");
290 if (g_TcFunctions
.hTcApiDllHandle
== NULL
) break;
292 g_TcFunctions
.QueryPortList
= (TcFcnQueryPortList
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcQueryPortList");
293 g_TcFunctions
.FreePortList
= (TcFcnFreePortList
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcFreePortList");
295 g_TcFunctions
.StatusGetString
= (TcFcnStatusGetString
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcStatusGetString");
297 g_TcFunctions
.PortGetName
= (TcFcnPortGetName
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcPortGetName");
298 g_TcFunctions
.PortGetDescription
= (TcFcnPortGetDescription
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcPortGetDescription");
300 g_TcFunctions
.InstanceOpenByName
= (TcFcnInstanceOpenByName
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceOpenByName");
301 g_TcFunctions
.InstanceClose
= (TcFcnInstanceClose
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceClose");
302 g_TcFunctions
.InstanceSetFeature
= (TcFcnInstanceSetFeature
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceSetFeature");
303 g_TcFunctions
.InstanceQueryFeature
= (TcFcnInstanceQueryFeature
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceQueryFeature");
304 g_TcFunctions
.InstanceReceivePackets
= (TcFcnInstanceReceivePackets
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceReceivePackets");
305 g_TcFunctions
.InstanceGetReceiveWaitHandle
= (TcFcnInstanceGetReceiveWaitHandle
)pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceGetReceiveWaitHandle");
306 g_TcFunctions
.InstanceTransmitPackets
= (TcFcnInstanceTransmitPackets
)pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceTransmitPackets");
307 g_TcFunctions
.InstanceQueryStatistics
= (TcFcnInstanceQueryStatistics
)pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcInstanceQueryStatistics");
309 g_TcFunctions
.PacketsBufferCreate
= (TcFcnPacketsBufferCreate
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcPacketsBufferCreate");
310 g_TcFunctions
.PacketsBufferDestroy
= (TcFcnPacketsBufferDestroy
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcPacketsBufferDestroy");
311 g_TcFunctions
.PacketsBufferQueryNextPacket
= (TcFcnPacketsBufferQueryNextPacket
)pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcPacketsBufferQueryNextPacket");
312 g_TcFunctions
.PacketsBufferCommitNextPacket
= (TcFcnPacketsBufferCommitNextPacket
)pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcPacketsBufferCommitNextPacket");
314 g_TcFunctions
.StatisticsDestroy
= (TcFcnStatisticsDestroy
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcStatisticsDestroy");
315 g_TcFunctions
.StatisticsUpdate
= (TcFcnStatisticsUpdate
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcStatisticsUpdate");
316 g_TcFunctions
.StatisticsQueryValue
= (TcFcnStatisticsQueryValue
) pcapint_find_function(g_TcFunctions
.hTcApiDllHandle
, "TcStatisticsQueryValue");
318 if ( g_TcFunctions
.QueryPortList
== NULL
319 || g_TcFunctions
.FreePortList
== NULL
320 || g_TcFunctions
.StatusGetString
== NULL
321 || g_TcFunctions
.PortGetName
== NULL
322 || g_TcFunctions
.PortGetDescription
== NULL
323 || g_TcFunctions
.InstanceOpenByName
== NULL
324 || g_TcFunctions
.InstanceClose
== NULL
325 || g_TcFunctions
.InstanceSetFeature
== NULL
326 || g_TcFunctions
.InstanceQueryFeature
== NULL
327 || g_TcFunctions
.InstanceReceivePackets
== NULL
328 || g_TcFunctions
.InstanceGetReceiveWaitHandle
== NULL
329 || g_TcFunctions
.InstanceTransmitPackets
== NULL
330 || g_TcFunctions
.InstanceQueryStatistics
== NULL
331 || g_TcFunctions
.PacketsBufferCreate
== NULL
332 || g_TcFunctions
.PacketsBufferDestroy
== NULL
333 || g_TcFunctions
.PacketsBufferQueryNextPacket
== NULL
334 || g_TcFunctions
.PacketsBufferCommitNextPacket
== NULL
335 || g_TcFunctions
.StatisticsDestroy
== NULL
336 || g_TcFunctions
.StatisticsUpdate
== NULL
337 || g_TcFunctions
.StatisticsQueryValue
== NULL
344 * everything got loaded, yay!!
346 currentStatus
= TC_API_LOADED
;
349 if (currentStatus
!= TC_API_LOADED
)
351 if (g_TcFunctions
.hTcApiDllHandle
!= NULL
)
353 FreeLibrary(g_TcFunctions
.hTcApiDllHandle
);
354 g_TcFunctions
.hTcApiDllHandle
= NULL
;
358 InterlockedExchange((LONG
*)&g_TcFunctions
.LoadStatus
, currentStatus
);
360 return currentStatus
;
364 TC_API_LOAD_STATUS
LoadTcFunctions(void)
366 return TC_API_LOADED
;
371 * Private data for capturing on TurboCap devices.
374 TC_INSTANCE TcInstance
;
375 TC_PACKETS_BUFFER TcPacketsBuffer
;
376 ULONG TcAcceptedCount
;
381 TcFindAllDevs(pcap_if_list_t
*devlist
, char *errbuf
)
383 TC_API_LOAD_STATUS loadStatus
;
385 PTC_PORT pPorts
= NULL
;
393 loadStatus
= LoadTcFunctions();
395 if (loadStatus
!= TC_API_LOADED
)
402 * enumerate the ports, and add them to the list
404 status
= g_TcFunctions
.QueryPortList(&pPorts
, &numPorts
);
406 if (status
!= TC_SUCCESS
)
412 for (i
= 0; i
< numPorts
; i
++)
415 * transform the port into an entry in the list
417 dev
= TcCreatePcapIfFromPort(pPorts
[i
]);
420 pcapint_add_dev(devlist
, dev
->name
, dev
->flags
, dev
->description
, errbuf
);
426 * ignore the result here
428 status
= g_TcFunctions
.FreePortList(pPorts
);
436 static pcap_if_t
* TcCreatePcapIfFromPort(TC_PORT port
)
440 pcap_if_t
*newIf
= NULL
;
442 newIf
= (pcap_if_t
*)malloc(sizeof(*newIf
));
448 memset(newIf
, 0, sizeof(*newIf
));
450 name
= g_TcFunctions
.PortGetName(port
);
451 description
= g_TcFunctions
.PortGetDescription(port
);
453 newIf
->name
= (char*)malloc(strlen(name
) + 1);
454 if (newIf
->name
== NULL
)
460 newIf
->description
= (char*)malloc(strlen(description
) + 1);
461 if (newIf
->description
== NULL
)
468 strcpy(newIf
->name
, name
);
469 strcpy(newIf
->description
, description
);
471 newIf
->addresses
= NULL
;
480 TcActivate(pcap_t
*p
)
482 struct pcap_tc
*pt
= p
->priv
;
485 PPPI_HEADER pPpiHeader
;
490 * No monitor mode on Tc cards; they're Ethernet
493 return PCAP_ERROR_RFMON_NOTSUP
;
496 pt
->PpiPacket
= malloc(sizeof(PPI_HEADER
) + MAX_TC_PACKET_SIZE
);
498 if (pt
->PpiPacket
== NULL
)
500 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Error allocating memory");
505 * Turn a negative snapshot value (invalid), a snapshot value of
506 * 0 (unspecified), or a value bigger than the normal maximum
507 * value, into the maximum allowed value.
509 * If some application really *needs* a bigger snapshot
510 * length, we should just increase MAXIMUM_SNAPLEN.
512 if (p
->snapshot
<= 0 || p
->snapshot
> MAXIMUM_SNAPLEN
)
513 p
->snapshot
= MAXIMUM_SNAPLEN
;
516 * Initialize the PPI fixed fields
518 pPpiHeader
= (PPPI_HEADER
)pt
->PpiPacket
;
519 pPpiHeader
->PacketHeader
.PphDlt
= DLT_EN10MB
;
520 pPpiHeader
->PacketHeader
.PphLength
= sizeof(PPI_HEADER
);
521 pPpiHeader
->PacketHeader
.PphFlags
= 0;
522 pPpiHeader
->PacketHeader
.PphVersion
= 0;
524 pPpiHeader
->AggregationFieldHeader
.PfhLength
= sizeof(PPI_FIELD_AGGREGATION_EXTENSION
);
525 pPpiHeader
->AggregationFieldHeader
.PfhType
= PPI_FIELD_TYPE_AGGREGATION_EXTENSION
;
527 pPpiHeader
->Dot3FieldHeader
.PfhLength
= sizeof(PPI_FIELD_802_3_EXTENSION
);
528 pPpiHeader
->Dot3FieldHeader
.PfhType
= PPI_FIELD_TYPE_802_3_EXTENSION
;
530 status
= g_TcFunctions
.InstanceOpenByName(p
->opt
.device
, &pt
->TcInstance
);
532 if (status
!= TC_SUCCESS
)
534 /* Adapter detected but we are not able to open it. Return failure. */
535 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Error opening TurboCap adapter: %s", g_TcFunctions
.StatusGetString(status
));
539 p
->linktype
= DLT_EN10MB
;
540 p
->dlt_list
= (u_int
*) malloc(sizeof(u_int
) * 2);
541 if (p
->dlt_list
== NULL
)
543 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Error allocating memory");
546 p
->dlt_list
[0] = DLT_EN10MB
;
547 p
->dlt_list
[1] = DLT_PPI
;
551 * ignore promiscuous mode
557 * ignore all the buffer sizes
563 status
= g_TcFunctions
.InstanceSetFeature(pt
->TcInstance
, TC_INST_FT_RX_STATUS
, 1);
565 if (status
!= TC_SUCCESS
)
567 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions
.StatusGetString(status
));
572 * enable transmission
574 status
= g_TcFunctions
.InstanceSetFeature(pt
->TcInstance
, TC_INST_FT_TX_STATUS
, 1);
576 * Ignore the error here.
579 p
->inject_op
= TcInject
;
581 * if the timeout is -1, it means immediate return, no timeout
582 * if the timeout is 0, it means INFINITE
585 if (p
->opt
.timeout
== 0)
587 timeout
= 0xFFFFFFFF;
590 if (p
->opt
.timeout
< 0)
593 * we insert a minimal timeout here
599 timeout
= p
->opt
.timeout
;
602 status
= g_TcFunctions
.InstanceSetFeature(pt
->TcInstance
, TC_INST_FT_READ_TIMEOUT
, timeout
);
604 if (status
!= TC_SUCCESS
)
606 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions
.StatusGetString(status
));
611 p
->setfilter_op
= pcapint_install_bpf_program
;
612 p
->setdirection_op
= NULL
; /* Not implemented. */
613 p
->set_datalink_op
= TcSetDatalink
;
614 p
->getnonblock_op
= TcGetNonBlock
;
615 p
->setnonblock_op
= TcSetNonBlock
;
616 p
->stats_op
= TcStats
;
618 p
->stats_ex_op
= TcStatsEx
;
619 p
->setbuff_op
= TcSetBuff
;
620 p
->setmode_op
= TcSetMode
;
621 p
->setmintocopy_op
= TcSetMinToCopy
;
622 p
->getevent_op
= TcGetReceiveWaitHandle
;
623 p
->oid_get_request_op
= TcOidGetRequest
;
624 p
->oid_set_request_op
= TcOidSetRequest
;
625 p
->sendqueue_transmit_op
= TcSendqueueTransmit
;
626 p
->setuserbuffer_op
= TcSetUserBuffer
;
627 p
->live_dump_op
= TcLiveDump
;
628 p
->live_dump_ended_op
= TcLiveDumpEnded
;
629 p
->get_airpcap_handle_op
= TcGetAirPcapHandle
;
631 p
->selectable_fd
= -1;
634 p
->cleanup_op
= TcCleanup
;
643 TcCreate(const char *device
, char *ebuf
, int *is_ours
)
646 PTC_PORT pPorts
= NULL
;
652 if (LoadTcFunctions() != TC_API_LOADED
)
655 * XXX - report this as an error rather than as
656 * "not a TurboCap device"?
663 * enumerate the ports, and add them to the list
665 status
= g_TcFunctions
.QueryPortList(&pPorts
, &numPorts
);
667 if (status
!= TC_SUCCESS
)
670 * XXX - report this as an error rather than as
671 * "not a TurboCap device"?
678 for (i
= 0; i
< numPorts
; i
++)
680 if (strcmp(g_TcFunctions
.PortGetName(pPorts
[i
]), device
) == 0)
690 * ignore the result here
692 (void)g_TcFunctions
.FreePortList(pPorts
);
701 /* OK, it's probably ours. */
704 p
= PCAP_CREATE_COMMON(ebuf
, struct pcap_tc
);
708 p
->activate_op
= TcActivate
;
710 * Set these up front, so that, even if our client tries
711 * to set non-blocking mode before we're activated, or
712 * query the state of non-blocking mode, they get an error,
713 * rather than having the non-blocking mode option set
716 p
->getnonblock_op
= TcGetNonBlock
;
717 p
->setnonblock_op
= TcSetNonBlock
;
721 static int TcSetDatalink(pcap_t
*p
, int dlt
)
724 * We don't have to do any work here; pcap_set_datalink() checks
725 * whether the value is in the list of DLT_ values we
726 * supplied, so we don't have to, and, if it is valid, sets
727 * p->linktype to the new value; we don't have to do anything
728 * in hardware, we just use what's in p->linktype.
730 * We do have to have a routine, however, so that pcap_set_datalink()
731 * doesn't think we don't support setting the link-layer header
737 static int TcGetNonBlock(pcap_t
*p
)
739 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
740 "Non-blocking mode isn't supported for TurboCap ports");
744 static int TcSetNonBlock(pcap_t
*p
, int nonblock
)
746 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
747 "Non-blocking mode isn't supported for TurboCap ports");
751 static void TcCleanup(pcap_t
*p
)
753 struct pcap_tc
*pt
= p
->priv
;
755 if (pt
->TcPacketsBuffer
!= NULL
)
757 g_TcFunctions
.PacketsBufferDestroy(pt
->TcPacketsBuffer
);
758 pt
->TcPacketsBuffer
= NULL
;
760 if (pt
->TcInstance
!= NULL
)
763 * here we do not check for the error values
765 g_TcFunctions
.InstanceClose(pt
->TcInstance
);
766 pt
->TcInstance
= NULL
;
769 if (pt
->PpiPacket
!= NULL
)
772 pt
->PpiPacket
= NULL
;
775 pcapint_cleanup_live_common(p
);
778 /* Send a packet to the network */
779 static int TcInject(pcap_t
*p
, const void *buf
, int size
)
781 struct pcap_tc
*pt
= p
->priv
;
783 TC_PACKETS_BUFFER buffer
;
784 TC_PACKET_HEADER header
;
788 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "send error: the TurboCap API does not support packets larger than 64k");
792 status
= g_TcFunctions
.PacketsBufferCreate(sizeof(TC_PACKET_HEADER
) + TC_ALIGN_USHORT_TO_64BIT((USHORT
)size
), &buffer
);
794 if (status
!= TC_SUCCESS
)
796 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
801 * we assume that the packet is without the checksum, as common with WinPcap
803 memset(&header
, 0, sizeof(header
));
805 header
.Length
= (USHORT
)size
;
806 header
.CapturedLength
= header
.Length
;
808 status
= g_TcFunctions
.PacketsBufferCommitNextPacket(buffer
, &header
, (PVOID
)buf
);
810 if (status
== TC_SUCCESS
)
812 status
= g_TcFunctions
.InstanceTransmitPackets(pt
->TcInstance
, buffer
);
814 if (status
!= TC_SUCCESS
)
816 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
821 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
824 g_TcFunctions
.PacketsBufferDestroy(buffer
);
826 if (status
!= TC_SUCCESS
)
836 static int TcRead(pcap_t
*p
, int cnt
, pcap_handler callback
, u_char
*user
)
838 struct pcap_tc
*pt
= p
->priv
;
843 * Has "pcap_breakloop()" been called?
848 * Yes - clear the flag that indicates that it
849 * has, and return -2 to indicate that we were
850 * told to break out of the loop.
856 if (pt
->TcPacketsBuffer
== NULL
)
858 status
= g_TcFunctions
.InstanceReceivePackets(pt
->TcInstance
, &pt
->TcPacketsBuffer
);
859 if (status
!= TC_SUCCESS
)
861 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
868 struct pcap_pkthdr hdr
;
869 TC_PACKET_HEADER tcHeader
;
874 * Has "pcap_breakloop()" been called?
875 * If so, return immediately - if we haven't read any
876 * packets, clear the flag and return -2 to indicate
877 * that we were told to break out of the loop, otherwise
878 * leave the flag set, so that the *next* call will break
879 * out of the loop without having read any packets, and
880 * return the number of packets we've processed so far.
895 if (pt
->TcPacketsBuffer
== NULL
)
900 status
= g_TcFunctions
.PacketsBufferQueryNextPacket(pt
->TcPacketsBuffer
, &tcHeader
, &data
);
902 if (status
== TC_ERROR_END_OF_BUFFER
)
904 g_TcFunctions
.PacketsBufferDestroy(pt
->TcPacketsBuffer
);
905 pt
->TcPacketsBuffer
= NULL
;
909 if (status
!= TC_SUCCESS
)
911 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
915 /* No underlying filtering system. We need to filter on our own */
916 if (p
->fcode
.bf_insns
)
918 filterResult
= pcapint_filter(p
->fcode
.bf_insns
, data
, tcHeader
.Length
, tcHeader
.CapturedLength
);
920 if (filterResult
== 0)
925 if (filterResult
> tcHeader
.CapturedLength
)
927 filterResult
= tcHeader
.CapturedLength
;
932 filterResult
= tcHeader
.CapturedLength
;
935 pt
->TcAcceptedCount
++;
937 hdr
.ts
.tv_sec
= (bpf_u_int32
)(tcHeader
.Timestamp
/ (ULONGLONG
)(1000 * 1000 * 1000));
938 hdr
.ts
.tv_usec
= (bpf_u_int32
)((tcHeader
.Timestamp
% (ULONGLONG
)(1000 * 1000 * 1000)) / 1000);
940 if (p
->linktype
== DLT_EN10MB
)
942 hdr
.caplen
= filterResult
;
943 hdr
.len
= tcHeader
.Length
;
944 (*callback
)(user
, &hdr
, data
);
948 PPPI_HEADER pPpiHeader
= (PPPI_HEADER
)pt
->PpiPacket
;
949 PVOID data2
= pPpiHeader
+ 1;
951 pPpiHeader
->AggregationField
.InterfaceId
= TC_PH_FLAGS_RX_PORT_ID(tcHeader
.Flags
);
952 pPpiHeader
->Dot3Field
.Errors
= tcHeader
.Errors
;
953 if (tcHeader
.Flags
& TC_PH_FLAGS_CHECKSUM
)
955 pPpiHeader
->Dot3Field
.Flags
= PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT
;
959 pPpiHeader
->Dot3Field
.Flags
= 0;
962 if (filterResult
<= MAX_TC_PACKET_SIZE
)
964 memcpy(data2
, data
, filterResult
);
965 hdr
.caplen
= sizeof(PPI_HEADER
) + filterResult
;
966 hdr
.len
= sizeof(PPI_HEADER
) + tcHeader
.Length
;
970 memcpy(data2
, data
, MAX_TC_PACKET_SIZE
);
971 hdr
.caplen
= sizeof(PPI_HEADER
) + MAX_TC_PACKET_SIZE
;
972 hdr
.len
= sizeof(PPI_HEADER
) + tcHeader
.Length
;
975 (*callback
)(user
, &hdr
, pt
->PpiPacket
);
979 if (++n
>= cnt
&& cnt
> 0)
989 TcStats(pcap_t
*p
, struct pcap_stat
*ps
)
991 struct pcap_tc
*pt
= p
->priv
;
992 TC_STATISTICS statistics
;
997 status
= g_TcFunctions
.InstanceQueryStatistics(pt
->TcInstance
, &statistics
);
999 if (status
!= TC_SUCCESS
)
1001 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1005 memset(&s
, 0, sizeof(s
));
1007 status
= g_TcFunctions
.StatisticsQueryValue(statistics
, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS
, &counter
);
1008 if (status
!= TC_SUCCESS
)
1010 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1013 if (counter
<= (ULONGLONG
)0xFFFFFFFF)
1015 s
.ps_recv
= (ULONG
)counter
;
1019 s
.ps_recv
= 0xFFFFFFFF;
1022 status
= g_TcFunctions
.StatisticsQueryValue(statistics
, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS
, &counter
);
1023 if (status
!= TC_SUCCESS
)
1025 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1028 if (counter
<= (ULONGLONG
)0xFFFFFFFF)
1030 s
.ps_ifdrop
= (ULONG
)counter
;
1031 s
.ps_drop
= (ULONG
)counter
;
1035 s
.ps_ifdrop
= 0xFFFFFFFF;
1036 s
.ps_drop
= 0xFFFFFFFF;
1039 #if defined(_WIN32) && defined(ENABLE_REMOTE)
1040 s
.ps_capt
= pt
->TcAcceptedCount
;
1049 static struct pcap_stat
*
1050 TcStatsEx(pcap_t
*p
, int *pcap_stat_size
)
1052 struct pcap_tc
*pt
= p
->priv
;
1053 TC_STATISTICS statistics
;
1057 *pcap_stat_size
= sizeof (p
->stat
);
1059 status
= g_TcFunctions
.InstanceQueryStatistics(pt
->TcInstance
, &statistics
);
1061 if (status
!= TC_SUCCESS
)
1063 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1067 memset(&p
->stat
, 0, sizeof(p
->stat
));
1069 status
= g_TcFunctions
.StatisticsQueryValue(statistics
, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS
, &counter
);
1070 if (status
!= TC_SUCCESS
)
1072 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1075 if (counter
<= (ULONGLONG
)0xFFFFFFFF)
1077 p
->stat
.ps_recv
= (ULONG
)counter
;
1081 p
->stat
.ps_recv
= 0xFFFFFFFF;
1084 status
= g_TcFunctions
.StatisticsQueryValue(statistics
, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS
, &counter
);
1085 if (status
!= TC_SUCCESS
)
1087 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1090 if (counter
<= (ULONGLONG
)0xFFFFFFFF)
1092 p
->stat
.ps_ifdrop
= (ULONG
)counter
;
1093 p
->stat
.ps_drop
= (ULONG
)counter
;
1097 p
->stat
.ps_ifdrop
= 0xFFFFFFFF;
1098 p
->stat
.ps_drop
= 0xFFFFFFFF;
1101 #if defined(_WIN32) && defined(ENABLE_REMOTE)
1102 p
->stat
.ps_capt
= pt
->TcAcceptedCount
;
1108 /* Set the dimension of the kernel-level capture buffer */
1110 TcSetBuff(pcap_t
*p
, int dim
)
1113 * XXX turbocap has an internal way of managing buffers.
1114 * And at the moment it's not configurable, so we just
1115 * silently ignore the request to set the buffer.
1121 TcSetMode(pcap_t
*p
, int mode
)
1123 if (mode
!= MODE_CAPT
)
1125 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Mode %d not supported by TurboCap devices. TurboCap only supports capture.", mode
);
1133 TcSetMinToCopy(pcap_t
*p
, int size
)
1135 struct pcap_tc
*pt
= p
->priv
;
1140 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "Mintocopy cannot be less than 0.");
1144 status
= g_TcFunctions
.InstanceSetFeature(pt
->TcInstance
, TC_INST_FT_MINTOCOPY
, (ULONG
)size
);
1146 if (status
!= TC_SUCCESS
)
1148 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions
.StatusGetString(status
), status
);
1155 TcGetReceiveWaitHandle(pcap_t
*p
)
1157 struct pcap_tc
*pt
= p
->priv
;
1159 return g_TcFunctions
.InstanceGetReceiveWaitHandle(pt
->TcInstance
);
1163 TcOidGetRequest(pcap_t
*p
, bpf_u_int32 oid _U_
, void *data _U_
, size_t *lenp _U_
)
1165 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1166 "An OID get request cannot be performed on a TurboCap device");
1171 TcOidSetRequest(pcap_t
*p
, bpf_u_int32 oid _U_
, const void *data _U_
,
1174 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1175 "An OID set request cannot be performed on a TurboCap device");
1180 TcSendqueueTransmit(pcap_t
*p
, pcap_send_queue
*queue _U_
, int sync _U_
)
1182 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1183 "Packets cannot be bulk transmitted on a TurboCap device");
1188 TcSetUserBuffer(pcap_t
*p
, int size _U_
)
1190 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1191 "The user buffer cannot be set on a TurboCap device");
1196 TcLiveDump(pcap_t
*p
, char *filename _U_
, int maxsize _U_
, int maxpacks _U_
)
1198 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1199 "Live packet dumping cannot be performed on a TurboCap device");
1204 TcLiveDumpEnded(pcap_t
*p
, int sync _U_
)
1206 snprintf(p
->errbuf
, PCAP_ERRBUF_SIZE
,
1207 "Live packet dumping cannot be performed on a TurboCap device");
1211 static PAirpcapHandle
1212 TcGetAirPcapHandle(pcap_t
*p _U_
)