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