1 /*============================================================================*
2 * FILE: winpcap_stress.c
3 *============================================================================*
5 * COPYRIGHT (C) 2006 BY
6 * CACE TECHNOLOGIES, INC., DAVIS, CALIFORNIA
9 * THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND
10 * COPIED ONLY IN ACCORDANCE WITH THE TERMS OF SUCH LICENSE AND WITH
11 * THE INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY
12 * OTHER COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE
13 * AVAILABLE TO ANY OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE
14 * SOFTWARE IS HEREBY TRANSFERRED.
16 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT
17 * NOTICE AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY CACE TECNOLOGIES
19 *===========================================================================*
21 * This program is a generic "stress test" for winpcap. It creates several threads
22 * each of which opens an adapter, captures some packets and then closes it.
23 * The user can specify:
25 * - the number of threads
26 * - the number of read operations that every thread performs before exiting
28 * The program prints statistics before exiting.
30 *===========================================================================*/
32 /////////////////////////////////////////////////////////////////////
34 /////////////////////////////////////////////////////////////////////
35 #undef STRESS_AIRPCAP_TRANSMISSION
36 #define NUM_THREADS 16
37 #define MAX_NUM_READS 500
38 #define MAX_NUM_WRITES 10000
40 #define WRITES_FREQUENCY 2 // This constant specifies how often a thread will transmit instead of receiving
42 // - 0 means no Tx threads
43 // - 1 means all threads are Tx
44 // - 2 means that 1 thread every 2 is Tx
45 // - 3 means that 1 thread every 3 is Tx
50 /////////////////////////////////////////////////////////////////////
58 #ifdef STRESS_AIRPCAP_TRANSMISSION
65 #define FILTER "ether[80:1] < 128 || ether[81:1] > 127 || ether[82:1] < 180 || ether[83:1] > 181" \
66 "|| ether[84:1] < 128 || ether[85:1] > 127 || ether[86:1] < 180 || ether[87:1] > 181" \
67 "|| ether[88:1] < 128 || ether[89:1] > 127 || ether[90:1] < 180 || ether[91:1] > 181" \
68 "|| ether[92:1] < 128 || ether[93:1] > 127 || ether[94:1] < 180 || ether[95:1] > 181" \
69 "|| ether[96:1] < 128 || ether[97:1] > 127 || ether[98:1] < 180 || ether[99:1] > 181" \
70 "|| ether[100:1] < 128 || ether[101:1] > 127 || ether[102:1] < 180 || ether[103:1] > 181" \
71 "|| ether[104:1] < 128 || ether[105:1] > 127 || ether[106:1] < 180 || ether[107:1] > 181" \
72 "|| ether[108:1] < 128 || ether[109:1] > 127 || ether[110:1] < 180 || ether[111:1] > 181" \
75 u_int n_iterations = 0;
78 u_int n_open_errors
= 0;
79 u_int n_read_errors
= 0;
80 u_int n_write_errors
= 0;
81 u_int n_findalldevs_errors
= 0;
82 u_int n_setfilters
= 0;
85 CRITICAL_SECTION print_cs
;
87 #define MAX_TX_PACKET_SIZE 1604
88 u_char pkt_to_send
[MAX_TX_PACKET_SIZE
];
91 /////////////////////////////////////////////////////////////////////
92 // Radiotap header. Used for 802.11 transmission
93 /////////////////////////////////////////////////////////////////////
99 typedef struct _tx_ieee80211_radiotap_header
104 u_int32_t it_present
;
108 __attribute__((__packed__
))
109 #endif // __MINGW32__
110 tx_ieee80211_radiotap_header
;
113 #endif // __MINGW32__
115 /////////////////////////////////////////////////////////////////////
116 // Table of legal radiotap Tx rates
117 /////////////////////////////////////////////////////////////////////
118 UCHAR TxRateInfoTable
[] =
134 /////////////////////////////////////////////////////////////////////
138 printf("winpcap_stress: utility that stresses winpcap by opening and capturing from multiple adapters at the same time.\n");
139 printf(" Usage: winpcap_stress <nthreads> <adapter_substring_to_match>\n\n"
142 " winpcap_stress 10\n\n"
143 " winpcap_stress 10 \\Device\\NPF_{ \n");
146 /////////////////////////////////////////////////////////////////////
150 EnterCriticalSection(&print_cs
);
152 printf("\nNumber of iterations:\t\t%u\n", n_iterations
);
153 printf("Number of packets captured:\t\t%u\n", n_packets
);
154 printf("Number of read timeouts:\t\t%u\n", n_timeouts
);
155 printf("Number of open errors:\t\t%u\n", n_open_errors
);
156 printf("Number of read errors:\t\t%u\n", n_read_errors
);
157 printf("Number of setfilters:\t\t%u\n", n_setfilters
);
160 // Note: we don't release the critical section on purpose, so the user doesn't
161 // get crappy input when he presses CTRL+C
168 /////////////////////////////////////////////////////////////////////
170 DWORD WINAPI
pcap_thread(LPVOID arg
)
173 char* AdName
= (char*)arg
;
174 char errbuf
[PCAP_ERRBUF_SIZE
];
176 struct pcap_pkthdr
*header
;
177 const u_char
*pkt_data
;
179 u_int n_reads
, n_writes
;
180 #ifdef INJECT_FILTERS
181 struct bpf_program fcode
;
184 #ifdef STRESS_AIRPCAP_TRANSMISSION
185 PAirpcapHandle airpcap_handle
;
186 tx_ieee80211_radiotap_header
*radio_header
;
190 srand( (unsigned)time( NULL
) );
195 if((fp
= pcap_open_live(AdName
,
197 0, // promiscuous mode
201 EnterCriticalSection(&print_cs
);
202 fprintf(stderr
,"\nError opening adapter (%s)\n", errbuf
);
203 LeaveCriticalSection(&print_cs
);
209 // Decide if this is going to be a read or write thread
212 if((WRITES_FREQUENCY
!= 0) && ((thread_id
++) % WRITES_FREQUENCY
== 0))
219 n_writes
= rand() % MAX_NUM_READS
;
227 // Get the airpcap handle so we can change wireless-specific settings
229 #ifdef STRESS_AIRPCAP_TRANSMISSION
230 airpcap_handle
= pcap_get_airpcap_handle(fp
);
232 if(airpcap_handle
!= NULL
)
235 // Configure the AirPcap adapter
238 // Tell the adapter that the packets we'll send don't include the FCS
239 if(!AirpcapSetFcsPresence(airpcap_handle
, FALSE
))
241 printf("Error setting the Fcs presence: %s\n", AirpcapGetLastError(airpcap_handle
));
247 // Set the link layer to 802.11 + radiotap
249 if(!AirpcapSetLinkType(airpcap_handle
, AIRPCAP_LT_802_11_PLUS_RADIO
))
251 printf("Error setting the link layer: %s\n", AirpcapGetLastError(airpcap_handle
));
257 // Create the radiotap header
259 radio_header
= (tx_ieee80211_radiotap_header
*)pkt_to_send
;
260 radio_header
->it_version
= 0;
261 radio_header
->it_pad
= 0;
262 radio_header
->it_len
= sizeof(tx_ieee80211_radiotap_header
);
263 radio_header
->it_present
= 1 << 2; // bit 2 is the rate
264 rate_index
= 18/*rand() % (sizeof(TxRateInfoTable) / sizeof(TxRateInfoTable[0]))*/;
265 radio_header
->it_rate
= 18/*TxRateInfoTable[rate_index]*/;
268 for(i
= 0; i
< n_writes
; i
++)
270 if(pcap_sendpacket(fp
, pkt_to_send
, (rand() % MAX_TX_PACKET_SIZE
) + 10) != 0)
272 // EnterCriticalSection(&print_cs);
273 // printf("Write Error: %s\n", pcap_geterr(fp));
274 // LeaveCriticalSection(&print_cs);
287 n_reads
= rand() % MAX_NUM_READS
;
294 for(i
= 0; i
< n_reads
; i
++)
296 res
= pcap_next_ex(fp
, &header
, &pkt_data
);
303 #ifdef INJECT_FILTERS
305 EnterCriticalSection(&print_cs
);
306 compile_result
= pcap_compile(fp
, &fcode
, FILTER
, 1, 0xFFFFFFFF);
307 LeaveCriticalSection(&print_cs
);
312 if( compile_result
< 0)
314 fprintf(stderr
,"Error compiling filter: wrong syntax.\n");
319 if(pcap_setfilter(fp
, &fcode
)<0)
321 fprintf(stderr
,"Error setting the filter\n");
325 InterlockedIncrement(&n_setfilters
);
327 pcap_freecode(&fcode
);
339 // print pkt timestamp and pkt len
345 EnterCriticalSection(&print_cs
);
346 printf("Read error: %s\n", pcap_geterr(fp
));
347 LeaveCriticalSection(&print_cs
);
357 /////////////////////////////////////////////////////////////////////
358 /////////////////////////////////////////////////////////////////////
360 int main(int argc
, char **argv
)
362 pcap_if_t
*alldevs
, *d
;
364 char errbuf
[PCAP_ERRBUF_SIZE
];
367 char* string_to_match
;
375 n_threads
= NUM_THREADS
;
376 string_to_match
= NULL
;
381 n_threads
= atoi(argv
[1]);
382 string_to_match
= NULL
;
387 n_threads
= atoi(argv
[1]);
388 string_to_match
= argv
[2];
397 // Init the Tx packet
399 for(i
= 0; i
< MAX_TX_PACKET_SIZE
; i
++)
401 pkt_to_send
[i
] = i
& 0xff;
405 // Allocate storage for the threads list
407 hThreads
= (HANDLE
*)malloc(n_threads
* sizeof(HANDLE
));
410 printf("Memeory allocation failure\n");
414 memset(hThreads
, 0, n_threads
* sizeof(HANDLE
));
416 signal(SIGINT
, sigh
);
417 InitializeCriticalSection(&print_cs
);
420 // Scan the device list
422 if(pcap_findalldevs(&alldevs
, errbuf
) == -1)
424 EnterCriticalSection(&print_cs
);
425 fprintf(stderr
,"Error in pcap_findalldevs_ex: %s\n", errbuf
);
426 LeaveCriticalSection(&print_cs
);
427 n_findalldevs_errors
++;
433 // Jump to the selected adapter
438 // Go through the list, feeding a thread with each adapter that contains our substring
440 for(d
= alldevs
; d
; d
= d
->next
)
444 if(!strstr(d
->name
, string_to_match
))
456 // Check if the thread is done
458 WaitRes
= WaitForSingleObject(hThreads
[i
], 1);
460 if(WaitRes
== WAIT_TIMEOUT
)
463 // In case of timeout, we switch to the following thread
470 // Create the child thread
472 printf("Thread %u, %s 0x%x\n", i
, d
->name
, WaitRes
);
475 // Close the thread handle
479 CloseHandle(hThreads
[i
]);
482 hThreads
[i
] = CreateThread(NULL
, 0, pcap_thread
, d
->name
, 0, NULL
);
484 if(hThreads
[i
] == NULL
)
486 printf("error creating thread. Quitting\n");