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);
124 static int TcSetNonBlock(pcap_t *p, int nonblock);
125 static void TcCleanup(pcap_t *p);
126 static int TcInject(pcap_t *p, const void *buf, int size);
127 static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user);
128 static int TcStats(pcap_t *p, struct pcap_stat *ps);
129 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 *lenp);
137 static int TcOidSetRequest(pcap_t *p, bpf_u_int32 oid, const void *data, size_t *lenp);
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_list_t *devlist, char *errbuf)
438 TC_API_LOAD_STATUS loadStatus;
440 PTC_PORT pPorts = NULL;
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]);
475 add_dev(devlist, dev->name, dev->flags, dev->description, errbuf);
481 * ignore the result here
483 status = g_TcFunctions.FreePortList(pPorts);
491 static pcap_if_t* TcCreatePcapIfFromPort(TC_PORT port)
495 pcap_if_t *newIf = NULL;
497 newIf = (pcap_if_t*)malloc(sizeof(*newIf));
503 memset(newIf, 0, sizeof(*newIf));
505 name = g_TcFunctions.PortGetName(port);
506 description = g_TcFunctions.PortGetDescription(port);
508 newIf->name = (char*)malloc(strlen(name) + 1);
509 if (newIf->name == NULL)
515 newIf->description = (char*)malloc(strlen(description) + 1);
516 if (newIf->description == NULL)
523 strcpy(newIf->name, name);
524 strcpy(newIf->description, description);
526 newIf->addresses = NULL;
535 TcActivate(pcap_t *p)
537 struct pcap_tc *pt = p->priv;
540 PPPI_HEADER pPpiHeader;
545 * No monitor mode on Tc cards; they're Ethernet
548 return PCAP_ERROR_RFMON_NOTSUP;
551 pt->PpiPacket = malloc(sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE);
553 if (pt->PpiPacket == NULL)
555 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error allocating memory");
560 * Turn a negative snapshot value (invalid), a snapshot value of
561 * 0 (unspecified), or a value bigger than the normal maximum
562 * value, into the maximum allowed value.
564 * If some application really *needs* a bigger snapshot
565 * length, we should just increase MAXIMUM_SNAPLEN.
567 if (p->snapshot <= 0 || p->snapshot > MAXIMUM_SNAPLEN)
568 p->snapshot = MAXIMUM_SNAPLEN;
571 * Initialize the PPI fixed fields
573 pPpiHeader = (PPPI_HEADER)pt->PpiPacket;
574 pPpiHeader->PacketHeader.PphDlt = DLT_EN10MB;
575 pPpiHeader->PacketHeader.PphLength = sizeof(PPI_HEADER);
576 pPpiHeader->PacketHeader.PphFlags = 0;
577 pPpiHeader->PacketHeader.PphVersion = 0;
579 pPpiHeader->AggregationFieldHeader.PfhLength = sizeof(PPI_FIELD_AGGREGATION_EXTENSION);
580 pPpiHeader->AggregationFieldHeader.PfhType = PPI_FIELD_TYPE_AGGREGATION_EXTENSION;
582 pPpiHeader->Dot3FieldHeader.PfhLength = sizeof(PPI_FIELD_802_3_EXTENSION);
583 pPpiHeader->Dot3FieldHeader.PfhType = PPI_FIELD_TYPE_802_3_EXTENSION;
585 status = g_TcFunctions.InstanceOpenByName(p->opt.device, &pt->TcInstance);
587 if (status != TC_SUCCESS)
589 /* Adapter detected but we are not able to open it. Return failure. */
590 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Error opening TurboCap adapter: %s", g_TcFunctions.StatusGetString(status));
594 p->linktype = DLT_EN10MB;
595 p->dlt_list = (u_int *) malloc(sizeof(u_int) * 2);
597 * If that fails, just leave the list empty.
599 if (p->dlt_list != NULL) {
600 p->dlt_list[0] = DLT_EN10MB;
601 p->dlt_list[1] = DLT_PPI;
606 * ignore promiscuous mode
612 * ignore all the buffer sizes
618 status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_RX_STATUS, 1);
620 if (status != TC_SUCCESS)
622 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error enabling reception on a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
627 * enable transmission
629 status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_TX_STATUS, 1);
631 * Ignore the error here.
634 p->inject_op = TcInject;
636 * if the timeout is -1, it means immediate return, no timeout
637 * if the timeout is 0, it means INFINITE
640 if (p->opt.timeout == 0)
642 timeout = 0xFFFFFFFF;
645 if (p->opt.timeout < 0)
648 * we insert a minimal timeout here
654 timeout = p->opt.timeout;
657 status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_READ_TIMEOUT, timeout);
659 if (status != TC_SUCCESS)
661 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,"Error setting the read timeout a TurboCap instance: %s", g_TcFunctions.StatusGetString(status));
666 p->setfilter_op = TcSetFilter;
667 p->setdirection_op = NULL; /* Not implemented. */
668 p->set_datalink_op = TcSetDatalink;
669 p->getnonblock_op = TcGetNonBlock;
670 p->setnonblock_op = TcSetNonBlock;
671 p->stats_op = TcStats;
673 p->stats_ex_op = TcStatsEx;
674 p->setbuff_op = TcSetBuff;
675 p->setmode_op = TcSetMode;
676 p->setmintocopy_op = TcSetMinToCopy;
677 p->getevent_op = TcGetReceiveWaitHandle;
678 p->oid_get_request_op = TcOidGetRequest;
679 p->oid_set_request_op = TcOidSetRequest;
680 p->sendqueue_transmit_op = TcSendqueueTransmit;
681 p->setuserbuffer_op = TcSetUserBuffer;
682 p->live_dump_op = TcLiveDump;
683 p->live_dump_ended_op = TcLiveDumpEnded;
684 p->get_airpcap_handle_op = TcGetAirPcapHandle;
686 p->selectable_fd = -1;
689 p->cleanup_op = TcCleanup;
698 TcCreate(const char *device, char *ebuf, int *is_ours)
701 PTC_PORT pPorts = NULL;
707 if (LoadTcFunctions() != TC_API_LOADED)
710 * XXX - report this as an error rather than as
711 * "not a TurboCap device"?
718 * enumerate the ports, and add them to the list
720 status = g_TcFunctions.QueryPortList(&pPorts, &numPorts);
722 if (status != TC_SUCCESS)
725 * XXX - report this as an error rather than as
726 * "not a TurboCap device"?
733 for (i = 0; i < numPorts; i++)
735 if (strcmp(g_TcFunctions.PortGetName(pPorts[i]), device) == 0)
745 * ignore the result here
747 (void)g_TcFunctions.FreePortList(pPorts);
756 /* OK, it's probably ours. */
759 p = pcap_create_common(ebuf, sizeof (struct pcap_tc));
763 p->activate_op = TcActivate;
765 * Set these up front, so that, even if our client tries
766 * to set non-blocking mode before we're activated, or
767 * query the state of non-blocking mode, they get an error,
768 * rather than having the non-blocking mode option set
771 p->getnonblock_op = TcGetNonBlock;
772 p->setnonblock_op = TcSetNonBlock;
776 static int TcSetDatalink(pcap_t *p, int dlt)
779 * We don't have to do any work here; pcap_set_datalink() checks
780 * whether the value is in the list of DLT_ values we
781 * supplied, so we don't have to, and, if it is valid, sets
782 * p->linktype to the new value; we don't have to do anything
783 * in hardware, we just use what's in p->linktype.
785 * We do have to have a routine, however, so that pcap_set_datalink()
786 * doesn't think we don't support setting the link-layer header
792 static int TcGetNonBlock(pcap_t *p)
794 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
795 "Non-blocking mode isn't supported for TurboCap ports");
799 static int TcSetNonBlock(pcap_t *p, int nonblock)
801 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
802 "Non-blocking mode isn't supported for TurboCap ports");
806 static void TcCleanup(pcap_t *p)
808 struct pcap_tc *pt = p->priv;
810 if (pt->TcPacketsBuffer != NULL)
812 g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer);
813 pt->TcPacketsBuffer = NULL;
815 if (pt->TcInstance != NULL)
818 * here we do not check for the error values
820 g_TcFunctions.InstanceClose(pt->TcInstance);
821 pt->TcInstance = NULL;
824 if (pt->PpiPacket != NULL)
827 pt->PpiPacket = NULL;
830 pcap_cleanup_live_common(p);
833 /* Send a packet to the network */
834 static int TcInject(pcap_t *p, const void *buf, int size)
836 struct pcap_tc *pt = p->priv;
838 TC_PACKETS_BUFFER buffer;
839 TC_PACKET_HEADER header;
843 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: the TurboCap API does not support packets larger than 64k");
847 status = g_TcFunctions.PacketsBufferCreate(sizeof(TC_PACKET_HEADER) + TC_ALIGN_USHORT_TO_64BIT((USHORT)size), &buffer);
849 if (status != TC_SUCCESS)
851 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCreate failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
856 * we assume that the packet is without the checksum, as common with WinPcap
858 memset(&header, 0, sizeof(header));
860 header.Length = (USHORT)size;
861 header.CapturedLength = header.Length;
863 status = g_TcFunctions.PacketsBufferCommitNextPacket(buffer, &header, (PVOID)buf);
865 if (status == TC_SUCCESS)
867 status = g_TcFunctions.InstanceTransmitPackets(pt->TcInstance, buffer);
869 if (status != TC_SUCCESS)
871 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcInstanceTransmitPackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
876 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "send error: TcPacketsBufferCommitNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
879 g_TcFunctions.PacketsBufferDestroy(buffer);
881 if (status != TC_SUCCESS)
891 static int TcRead(pcap_t *p, int cnt, pcap_handler callback, u_char *user)
893 struct pcap_tc *pt = p->priv;
898 * Has "pcap_breakloop()" been called?
903 * Yes - clear the flag that indicates that it
904 * has, and return -2 to indicate that we were
905 * told to break out of the loop.
911 if (pt->TcPacketsBuffer == NULL)
913 status = g_TcFunctions.InstanceReceivePackets(pt->TcInstance, &pt->TcPacketsBuffer);
914 if (status != TC_SUCCESS)
916 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcInstanceReceivePackets failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
923 struct pcap_pkthdr hdr;
924 TC_PACKET_HEADER tcHeader;
929 * Has "pcap_breakloop()" been called?
930 * If so, return immediately - if we haven't read any
931 * packets, clear the flag and return -2 to indicate
932 * that we were told to break out of the loop, otherwise
933 * leave the flag set, so that the *next* call will break
934 * out of the loop without having read any packets, and
935 * return the number of packets we've processed so far.
950 if (pt->TcPacketsBuffer == NULL)
955 status = g_TcFunctions.PacketsBufferQueryNextPacket(pt->TcPacketsBuffer, &tcHeader, &data);
957 if (status == TC_ERROR_END_OF_BUFFER)
959 g_TcFunctions.PacketsBufferDestroy(pt->TcPacketsBuffer);
960 pt->TcPacketsBuffer = NULL;
964 if (status != TC_SUCCESS)
966 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "read error, TcPacketsBufferQueryNextPacket failure: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
970 /* No underlaying filtering system. We need to filter on our own */
971 if (p->fcode.bf_insns)
973 filterResult = bpf_filter(p->fcode.bf_insns, data, tcHeader.Length, tcHeader.CapturedLength);
975 if (filterResult == 0)
980 if (filterResult > tcHeader.CapturedLength)
982 filterResult = tcHeader.CapturedLength;
987 filterResult = tcHeader.CapturedLength;
990 pt->TcAcceptedCount ++;
992 hdr.ts.tv_sec = (bpf_u_int32)(tcHeader.Timestamp / (ULONGLONG)(1000 * 1000 * 1000));
993 hdr.ts.tv_usec = (bpf_u_int32)((tcHeader.Timestamp % (ULONGLONG)(1000 * 1000 * 1000)) / 1000);
995 if (p->linktype == DLT_EN10MB)
997 hdr.caplen = filterResult;
998 hdr.len = tcHeader.Length;
999 (*callback)(user, &hdr, data);
1003 PPPI_HEADER pPpiHeader = (PPPI_HEADER)pt->PpiPacket;
1004 PVOID data2 = pPpiHeader + 1;
1006 pPpiHeader->AggregationField.InterfaceId = TC_PH_FLAGS_RX_PORT_ID(tcHeader.Flags);
1007 pPpiHeader->Dot3Field.Errors = tcHeader.Errors;
1008 if (tcHeader.Flags & TC_PH_FLAGS_CHECKSUM)
1010 pPpiHeader->Dot3Field.Flags = PPI_FLD_802_3_EXT_FLAG_FCS_PRESENT;
1014 pPpiHeader->Dot3Field.Flags = 0;
1017 if (filterResult <= MAX_TC_PACKET_SIZE)
1019 memcpy(data2, data, filterResult);
1020 hdr.caplen = sizeof(PPI_HEADER) + filterResult;
1021 hdr.len = sizeof(PPI_HEADER) + tcHeader.Length;
1025 memcpy(data2, data, MAX_TC_PACKET_SIZE);
1026 hdr.caplen = sizeof(PPI_HEADER) + MAX_TC_PACKET_SIZE;
1027 hdr.len = sizeof(PPI_HEADER) + tcHeader.Length;
1030 (*callback)(user, &hdr, pt->PpiPacket);
1034 if (++n >= cnt && cnt > 0)
1044 TcStats(pcap_t *p, struct pcap_stat *ps)
1046 struct pcap_tc *pt = p->priv;
1047 TC_STATISTICS statistics;
1052 status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics);
1054 if (status != TC_SUCCESS)
1056 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1060 memset(&s, 0, sizeof(s));
1062 status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
1063 if (status != TC_SUCCESS)
1065 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1068 if (counter <= (ULONGLONG)0xFFFFFFFF)
1070 s.ps_recv = (ULONG)counter;
1074 s.ps_recv = 0xFFFFFFFF;
1077 status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
1078 if (status != TC_SUCCESS)
1080 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1083 if (counter <= (ULONGLONG)0xFFFFFFFF)
1085 s.ps_ifdrop = (ULONG)counter;
1086 s.ps_drop = (ULONG)counter;
1090 s.ps_ifdrop = 0xFFFFFFFF;
1091 s.ps_drop = 0xFFFFFFFF;
1094 #if defined(_WIN32) && defined(ENABLE_REMOTE)
1095 s.ps_capt = pt->TcAcceptedCount;
1104 * We filter at user level, since the kernel driver does't process the packets
1107 TcSetFilter(pcap_t *p, struct bpf_program *fp)
1111 strncpy(p->errbuf, "setfilter: No filter specified", sizeof(p->errbuf));
1115 /* Install a user level filter */
1116 if (install_bpf_program(p, fp) < 0)
1125 static struct pcap_stat *
1126 TcStatsEx(pcap_t *p, int *pcap_stat_size)
1128 struct pcap_tc *pt = p->priv;
1129 TC_STATISTICS statistics;
1133 *pcap_stat_size = sizeof (p->stat);
1135 status = g_TcFunctions.InstanceQueryStatistics(pt->TcInstance, &statistics);
1137 if (status != TC_SUCCESS)
1139 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcInstanceQueryStatistics: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1143 memset(&p->stat, 0, sizeof(p->stat));
1145 status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_TOTAL_RX_PACKETS, &counter);
1146 if (status != TC_SUCCESS)
1148 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1151 if (counter <= (ULONGLONG)0xFFFFFFFF)
1153 p->stat.ps_recv = (ULONG)counter;
1157 p->stat.ps_recv = 0xFFFFFFFF;
1160 status = g_TcFunctions.StatisticsQueryValue(statistics, TC_COUNTER_INSTANCE_RX_DROPPED_PACKETS, &counter);
1161 if (status != TC_SUCCESS)
1163 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error in TcStatisticsQueryValue: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1166 if (counter <= (ULONGLONG)0xFFFFFFFF)
1168 p->stat.ps_ifdrop = (ULONG)counter;
1169 p->stat.ps_drop = (ULONG)counter;
1173 p->stat.ps_ifdrop = 0xFFFFFFFF;
1174 p->stat.ps_drop = 0xFFFFFFFF;
1177 #if defined(_WIN32) && defined(ENABLE_REMOTE)
1178 p->stat.ps_capt = pt->TcAcceptedCount;
1184 /* Set the dimension of the kernel-level capture buffer */
1186 TcSetBuff(pcap_t *p, int dim)
1189 * XXX turbocap has an internal way of managing buffers.
1190 * And at the moment it's not configurable, so we just
1191 * silently ignore the request to set the buffer.
1197 TcSetMode(pcap_t *p, int mode)
1199 if (mode != MODE_CAPT)
1201 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mode %u not supported by TurboCap devices. TurboCap only supports capture.", mode);
1209 TcSetMinToCopy(pcap_t *p, int size)
1211 struct pcap_tc *pt = p->priv;
1216 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "Mintocopy cannot be less than 0.");
1220 status = g_TcFunctions.InstanceSetFeature(pt->TcInstance, TC_INST_FT_MINTOCOPY, (ULONG)size);
1222 if (status != TC_SUCCESS)
1224 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE, "TurboCap error setting the mintocopy: %s (%08x)", g_TcFunctions.StatusGetString(status), status);
1231 TcGetReceiveWaitHandle(pcap_t *p)
1233 struct pcap_tc *pt = p->priv;
1235 return g_TcFunctions.InstanceGetReceiveWaitHandle(pt->TcInstance);
1239 TcOidGetRequest(pcap_t *p, bpf_u_int32 oid _U_, void *data _U_, size_t *lenp _U_)
1241 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1242 "An OID get request cannot be performed on a TurboCap device");
1247 TcOidSetRequest(pcap_t *p, bpf_u_int32 oid _U_, const void *data _U_,
1250 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1251 "An OID set request cannot be performed on a TurboCap device");
1256 TcSendqueueTransmit(pcap_t *p, pcap_send_queue *queue _U_, int sync _U_)
1258 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1259 "Packets cannot be bulk transmitted on a TurboCap device");
1264 TcSetUserBuffer(pcap_t *p, int size _U_)
1266 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1267 "The user buffer cannot be set on a TurboCap device");
1272 TcLiveDump(pcap_t *p, char *filename _U_, int maxsize _U_, int maxpacks _U_)
1274 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1275 "Live packet dumping cannot be performed on a TurboCap device");
1280 TcLiveDumpEnded(pcap_t *p, int sync _U_)
1282 pcap_snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
1283 "Live packet dumping cannot be performed on a TurboCap device");
1287 static PAirpcapHandle
1288 TcGetAirPcapHandle(pcap_t *p _U_)