wlaninject.c revision 262007
1/*-
2 * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
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 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/10/tools/tools/net80211/wlaninject/wlaninject.c 262007 2014-02-17 01:36:53Z kevlo $
27 */
28#include <stdlib.h>
29#include <stdio.h>
30#include <errno.h>
31#include <err.h>
32#include <fcntl.h>
33#include <unistd.h>
34#include <sys/types.h>
35#include <sys/time.h>
36#include <sys/ioctl.h>
37#include <sys/uio.h>
38#include <net/bpf.h>
39#include <sys/socket.h>
40#include <net/if.h>
41#include <net/if_media.h>
42#include <string.h>
43#include <net80211/ieee80211.h>
44#include <net80211/ieee80211_ioctl.h>
45#include <net80211/ieee80211_freebsd.h>
46#include <net80211/ieee80211_radiotap.h>
47#include <sys/endian.h>
48#include <assert.h>
49
50void setup_if(char *dev, int chan) {
51	int s;
52	struct ifreq ifr;
53	unsigned int flags;
54	struct ifmediareq ifmr;
55	int *mwords;
56	struct ieee80211req ireq;
57
58	if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
59		err(1, "socket()");
60
61	/* chan */
62	memset(&ireq, 0, sizeof(ireq));
63	snprintf(ireq.i_name, sizeof(ireq.i_name), "%s", dev);
64	ireq.i_type = IEEE80211_IOC_CHANNEL;
65	ireq.i_val = chan;
66	if (ioctl(s, SIOCS80211, &ireq) == -1)
67		err(1, "ioctl(SIOCS80211)");
68
69	/* UP & PROMISC */
70	memset(&ifr, 0, sizeof(ifr));
71	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev);
72	if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1)
73		err(1, "ioctl(SIOCGIFFLAGS)");
74	flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
75	flags |= IFF_UP | IFF_PPROMISC;
76	ifr.ifr_flags = flags & 0xffff;
77	ifr.ifr_flagshigh = flags >> 16;
78	if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1)
79		err(1, "ioctl(SIOCSIFFLAGS)");
80
81	close(s);
82}
83
84int open_bpf(char *dev)
85{
86	char buf[64];
87	int i;
88	int fd;
89	struct ifreq ifr;
90	unsigned int dlt = DLT_IEEE802_11_RADIO;
91
92	for (i = 0; i < 64; i++) {
93		sprintf(buf, "/dev/bpf%d", i);
94
95		fd = open(buf, O_RDWR);
96		if (fd != -1)
97			break;
98		else if (errno != EBUSY)
99			err(1, "open()");
100	}
101	if (fd == -1) {
102		printf("Can't find bpf\n");
103		exit(1);
104	}
105
106	memset(&ifr, 0, sizeof(ifr));
107	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev);
108	if (ioctl(fd, BIOCSETIF, &ifr) == -1)
109		err(1, "ioctl(BIOCSETIF)");
110
111	if (ioctl(fd, BIOCSDLT, &dlt) == -1)
112		err(1, "ioctl(BIOCSDLT)");
113
114	i = 1;
115	if (ioctl(fd, BIOCIMMEDIATE, &i) == -1)
116		err(1, "ioctl(BIOCIMMEDIATE)");
117
118	return fd;
119}
120
121void inject(int fd, void *buf, int buflen, struct ieee80211_bpf_params *p)
122{
123	struct iovec iov[2];
124	int totlen;
125	int rc;
126
127	iov[0].iov_base = p;
128	iov[0].iov_len = p->ibp_len;
129
130	iov[1].iov_base = buf;
131	iov[1].iov_len = buflen;
132	totlen = iov[0].iov_len + iov[1].iov_len;
133
134	rc = writev(fd, iov, sizeof(iov)/sizeof(struct iovec));
135	if (rc == -1)
136		err(1, "writev()");
137	if (rc != totlen) {
138		printf("Wrote only %d/%d\n", rc, totlen);
139		exit(1);
140	}
141}
142
143void usage(char *progname)
144{
145	printf("Usage: %s <opts>\n"
146		"Physical:\n"
147		"\t-i\t<iface>\n"
148		"\t-c\t<chan>\n"
149		"\t-N\tno ack\n"
150		"\t-V\t<iface> [verify via iface whether packet was mangled]\n"
151		"\t-W\tWME AC\n"
152		"\t-X\ttransmit rate (Mbps)\n"
153		"\t-P\ttransmit power (device units)\n"
154		"802.11:\n"
155		"\t-h\tthis lame message\n"
156		"\t-v\t<version>\n"
157		"\t-t\t<type>\n"
158		"\t-s\t<subtype>\n"
159		"\t-T\tto ds\n"
160		"\t-F\tfrom ds\n"
161		"\t-m\tmore frags\n"
162		"\t-r\tretry\n"
163		"\t-p\tpower\n"
164		"\t-d\tmore data\n"
165		"\t-w\twep\n"
166		"\t-o\torder\n"
167		"\t-u\t<duration>\n"
168		"\t-1\t<addr 1>\n"
169		"\t-2\t<addr 2>\n"
170		"\t-3\t<addr 3>\n"
171		"\t-n\t<seqno>\n"
172		"\t-f\t<fragno>\n"
173		"\t-4\t<addr 4>\n"
174		"\t-b\t<payload file>\n"
175		"\t-l\t<len>\n"
176		"Management:\n"
177		"\t-e\t<info element [hex digits 010203... first is type]>\n"
178		"\t-S\t<SSID>\n"
179		"\t-a\t<algo no>\n"
180		"\t-A\t<transaction>\n"
181		"\t-C\t<status code>\n"
182		"\t-R\tstandard rates\n"
183	       , progname);
184	exit(1);
185}
186
187int str2type(const char *type)
188{
189#define	equal(a,b)	(strcasecmp(a,b) == 0)
190	if (equal(type, "mgt"))
191		return IEEE80211_FC0_TYPE_MGT >> IEEE80211_FC0_TYPE_SHIFT;
192	else if (equal(type, "ctl"))
193		return IEEE80211_FC0_TYPE_CTL >> IEEE80211_FC0_TYPE_SHIFT;
194	else if (equal(type, "data"))
195		return IEEE80211_FC0_TYPE_DATA >> IEEE80211_FC0_TYPE_SHIFT;
196
197	return atoi(type) & 3;
198#undef equal
199}
200
201int str2subtype(const char *subtype)
202{
203#define	equal(a,b)	(strcasecmp(a,b) == 0)
204	if (equal(subtype, "preq") || equal(subtype, "probereq"))
205		return IEEE80211_FC0_SUBTYPE_PROBE_REQ >>
206		       IEEE80211_FC0_SUBTYPE_SHIFT;
207	else if (equal(subtype, "auth"))
208		return IEEE80211_FC0_SUBTYPE_AUTH >>
209		       IEEE80211_FC0_SUBTYPE_SHIFT;
210	else if (equal(subtype, "areq") || equal(subtype, "assocreq"))
211		return IEEE80211_FC0_SUBTYPE_ASSOC_REQ >>
212		       IEEE80211_FC0_SUBTYPE_SHIFT;
213	else if (equal(subtype, "data"))
214		return IEEE80211_FC0_SUBTYPE_DATA >>
215		       IEEE80211_FC0_SUBTYPE_SHIFT;
216
217	return atoi(subtype) & 0xf;
218#undef equal
219}
220
221void str2mac(unsigned char *mac, char *str)
222{
223	unsigned int macf[6];
224	int i;
225
226	if (sscanf(str, "%x:%x:%x:%x:%x:%x",
227		   &macf[0], &macf[1], &macf[2],
228		   &macf[3], &macf[4], &macf[5]) != 6) {
229		   printf("can't parse mac %s\n", str);
230		   exit(1);
231	}
232
233	for (i = 0; i < 6; i++)
234		*mac++ = (unsigned char) macf[i];
235}
236
237int str2wmeac(const char *ac)
238{
239#define	equal(a,b)	(strcasecmp(a,b) == 0)
240	if (equal(ac, "ac_be") || equal(ac, "be"))
241		return WME_AC_BE;
242	if (equal(ac, "ac_bk") || equal(ac, "bk"))
243		return WME_AC_BK;
244	if (equal(ac, "ac_vi") || equal(ac, "vi"))
245		return WME_AC_VI;
246	if (equal(ac, "ac_vo") || equal(ac, "vo"))
247		return WME_AC_VO;
248	errx(1, "unknown wme access class %s", ac);
249#undef equal
250}
251
252int str2rate(const char *rate)
253{
254	switch (atoi(rate)) {
255	case 54: return 54*2;
256	case 48: return 48*2;
257	case 36: return 36*2;
258	case 24: return 24*2;
259	case 18: return 18*2;
260	case 12: return 12*2;
261	case 9: return 9*2;
262	case 6: return 6*2;
263	case 11: return 11*2;
264	case 5: return 11;
265	case 2: return 2*2;
266	case 1: return 1*2;
267	}
268	errx(1, "unknown transmit rate %s", rate);
269}
270
271const char *rate2str(int rate)
272{
273	static char buf[30];
274
275	if (rate == 11)
276		return "5.5";
277	snprintf(buf, sizeof(buf), "%u", rate/2);
278	return buf;
279}
280
281int load_payload(char *fname, void *buf, int len)
282{
283	int fd;
284	int rc;
285
286	if ((fd = open(fname, O_RDONLY)) == -1)
287		err(1, "open()");
288
289	if ((rc = read(fd, buf, len)) == -1)
290		err(1, "read()");
291
292	close(fd);
293	printf("Read %d bytes from %s\n", rc, fname);
294	return rc;
295}
296
297int header_len(struct ieee80211_frame *wh)
298{
299	int len = sizeof(*wh);
300
301	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
302	case IEEE80211_FC0_TYPE_MGT:
303		switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
304		case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
305			len += 2 + 2; /* capa & listen */
306			break;
307
308		case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
309			len += 2 + 2 + 2; /* capa & status & assoc */
310			break;
311
312		case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
313			len += 2 + 2 + 6; /* capa & listen & AP */
314			break;
315
316		case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
317			len += 2 + 2 + 2; /* capa & status & assoc */
318			break;
319
320		case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
321		case IEEE80211_FC0_SUBTYPE_ATIM:
322			break;
323
324		case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
325		case IEEE80211_FC0_SUBTYPE_BEACON:
326			len += 8 + 2 + 2; /* time & bint & capa */
327			break;
328
329		case IEEE80211_FC0_SUBTYPE_DISASSOC:
330			len += 2; /* reason */
331			break;
332
333		case IEEE80211_FC0_SUBTYPE_AUTH:
334			len += 2 + 2 + 2; /* algo & seq & status */
335			break;
336
337		case IEEE80211_FC0_SUBTYPE_DEAUTH:
338			len += 2; /* reason */
339			break;
340
341		default:
342			errx(1, "Unknown MGT subtype 0x%x",
343				wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
344		}
345		break;
346
347	case IEEE80211_FC0_TYPE_CTL:
348		switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) {
349		case IEEE80211_FC0_SUBTYPE_PS_POLL:
350			len = sizeof(struct ieee80211_frame_pspoll);
351			break;
352
353		case IEEE80211_FC0_SUBTYPE_RTS:
354			len = sizeof(struct ieee80211_frame_rts);
355			break;
356
357		case IEEE80211_FC0_SUBTYPE_CTS:
358			len = sizeof(struct ieee80211_frame_cts);
359			break;
360
361		case IEEE80211_FC0_SUBTYPE_ACK:
362			len = sizeof(struct ieee80211_frame_ack);
363			break;
364
365		case IEEE80211_FC0_SUBTYPE_CF_END_ACK:
366		case IEEE80211_FC0_SUBTYPE_CF_END:
367			len = sizeof(struct ieee80211_frame_cfend);
368			break;
369
370		default:
371			errx(1, "Unknown CTL subtype 0x%x",
372				wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
373		}
374		break;
375
376	case IEEE80211_FC0_TYPE_DATA:
377		if (wh->i_fc[1] & IEEE80211_FC1_DIR_DSTODS)
378			len += sizeof(wh->i_addr1);
379		break;
380
381	default:
382		errx(1, "Unknown type 0x%x",
383			wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
384		exit(1);
385	}
386
387	return len;
388}
389
390int parse_ie(char *str, unsigned char *ie, int len)
391{
392	int digits = 0;
393	char num[3];
394	int conv = 0;
395	int ielen;
396
397	ielen = strlen(str)/2;
398	if (ielen < 1 || (strlen(str) % 2)) {
399		printf("Invalid IE %s\n", str);
400		exit(1);
401	}
402
403	num[2] = 0;
404	while (ielen) {
405		num[digits++] = *str;
406		str++;
407		if (digits == 2) {
408			unsigned int x;
409
410			sscanf(num, "%x", &x);
411
412			if (len <= 0) {
413				printf("No space for IE\n");
414				exit(1);
415			}
416
417			*ie++ = (unsigned char) x;
418			len--;
419			ielen--;
420
421			/* first char */
422			if (conv == 0) {
423				if (len == 0) {
424					printf("No space for IE\n");
425					exit(1);
426				}
427				*ie++ = (unsigned char) ielen;
428				len--;
429				conv++;
430			}
431			conv++;
432			digits = 0;
433		}
434	}
435
436	return conv;
437}
438
439int possible_match(struct ieee80211_frame *sent, int slen,
440		   struct ieee80211_frame *got, int glen)
441{
442	if (slen != glen)
443		return 0;
444
445	if (memcmp(sent->i_addr1, got->i_addr1, 6) != 0)
446		printf("Addr1 doesn't match\n");
447
448	if ((sent->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
449	    (got->i_fc[0] & IEEE80211_FC0_TYPE_MASK))
450		return 0;
451
452	if ((sent->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) !=
453	    (got->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK))
454		return 0;
455
456	/* Good enough for CTL frames I guess */
457	if ((got->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
458		return 1;
459
460	if (memcmp(sent->i_addr2, got->i_addr2, 6) == 0 &&
461	    memcmp(sent->i_addr3, got->i_addr3, 6) == 0)
462	    	return 1;
463
464	return 0;
465}
466
467int do_verify(struct ieee80211_frame *sent, int slen, void *got, int glen)
468{
469#define BIT(n)  (1<<(n))
470	struct bpf_hdr *bpfh = got;
471	struct ieee80211_frame *wh;
472	struct ieee80211_radiotap_header *rth;
473	int i;
474	unsigned char *ptr, *ptr2;
475	uint32_t present;
476	uint8_t rflags;
477
478	/* get the 802.11 header */
479	glen -= bpfh->bh_hdrlen;
480	assert(glen > 0);
481	if (bpfh->bh_caplen != glen) {
482		abort();
483	}
484	rth = (struct ieee80211_radiotap_header*)
485	      ((char*) bpfh + bpfh->bh_hdrlen);
486	glen -= rth->it_len;
487	assert(glen > 0);
488	wh = (struct ieee80211_frame*) ((char*)rth + rth->it_len);
489
490        /* check if FCS/CRC is included in packet */
491	present = le32toh(rth->it_present);
492	if (present & BIT(IEEE80211_RADIOTAP_FLAGS)) {
493		if (present & BIT(IEEE80211_RADIOTAP_TSFT))
494			rflags = ((const uint8_t *)rth)[8];
495		else
496			rflags = ((const uint8_t *)rth)[0];
497	} else
498		rflags = 0;
499	if (rflags & IEEE80211_RADIOTAP_F_FCS)
500		glen -= IEEE80211_CRC_LEN;
501	assert(glen > 0);
502
503	/* did we receive the packet we sent? */
504	if (!possible_match(sent, slen, wh, glen))
505		return 0;
506
507	/* check if it got mangled */
508	if (memcmp(sent, wh, slen) == 0) {
509		printf("No mangling---got it perfect\n");
510		return 1;
511	}
512
513	/* print differences */
514	printf("Got mangled:\n");
515	ptr = (unsigned char*) sent;
516	ptr2 = (unsigned char *) wh;
517	for (i = 0; i < slen; i++, ptr++, ptr2++) {
518		if (*ptr != *ptr2)
519			printf("Position: %d Was: %.2X Got: %.2X\n",
520			       i, *ptr, *ptr2);
521	}
522	return -1;
523#undef BIT
524}
525
526int main(int argc, char *argv[])
527{
528	int fd, fd2;
529	char *iface = "wlan0";
530	char *verify = NULL;
531	int chan = 1;
532	struct {
533		struct ieee80211_frame w;
534		unsigned char buf[2048];
535	} __packed u;
536	int len = 0;
537	int ch;
538	struct ieee80211_bpf_params params;
539	struct ieee80211_frame *wh = &u.w;
540	unsigned char *body = u.buf;
541
542	memset(&u, 0, sizeof(u));
543	memset(&params, 0, sizeof(params));
544	params.ibp_vers = IEEE80211_BPF_VERSION;
545	params.ibp_len = sizeof(struct ieee80211_bpf_params) - 6,
546	params.ibp_rate0 = 2;		/* 1 MB/s XXX */
547	params.ibp_try0 = 1;		/* no retransmits */
548	params.ibp_power = 100;		/* nominal max */
549	params.ibp_pri = WME_AC_VO;	/* high priority */
550
551	while ((ch = getopt(argc, argv,
552	    "hv:t:s:TFmpdwou:1:2:3:4:b:i:c:l:n:f:e:S:a:A:C:NRV:W:X:P:")) != -1) {
553		switch (ch) {
554		case 'i':
555			iface = optarg;
556			break;
557
558		case 'c':
559			chan = atoi(optarg);
560			break;
561
562		case 'v':
563			wh->i_fc[0] |= atoi(optarg)& IEEE80211_FC0_VERSION_MASK;
564			break;
565
566		case 't':
567			wh->i_fc[0] |= str2type(optarg) <<
568				       IEEE80211_FC0_TYPE_SHIFT;
569			break;
570
571		case 's':
572			wh->i_fc[0] |= str2subtype(optarg) <<
573				       IEEE80211_FC0_SUBTYPE_SHIFT;
574			len = header_len(wh);
575			body += len;
576			break;
577
578		case 'T':
579			wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
580			break;
581
582		case 'F':
583			wh->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
584			break;
585
586		case 'm':
587			wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
588			break;
589
590		case 'r':
591			wh->i_fc[1] |= IEEE80211_FC1_RETRY;
592			break;
593
594		case 'p':
595			wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
596			break;
597
598		case 'd':
599			wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
600			break;
601
602		case 'w':
603			wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
604			break;
605
606		case 'o':
607			wh->i_fc[1] |= IEEE80211_FC1_ORDER;
608			break;
609
610		case 'u':
611			*(uint16_t*)wh->i_dur = htole16(atoi(optarg));
612			break;
613
614		case '1':
615			str2mac(wh->i_addr1, optarg);
616			break;
617
618		case '2':
619			str2mac(wh->i_addr2, optarg);
620			break;
621
622		case '3':
623			str2mac(wh->i_addr3, optarg);
624			break;
625
626		case '4':
627			str2mac(body, optarg);
628			break;
629
630		case 'n':
631			*(uint16_t*)wh->i_seq |= htole16((atoi(optarg) & 0xfff)
632				<< IEEE80211_SEQ_SEQ_SHIFT);
633			break;
634
635		case 'f':
636			wh->i_seq[0] |= atoi(optarg) & 0xf;
637			break;
638
639		case 'b':
640			len += load_payload(optarg, body,
641					    u.buf + sizeof(u.buf) - body);
642			break;
643
644		case 'l':
645			len = atoi(optarg);
646			break;
647
648		case 'e':
649			do {
650				int ln;
651
652				ln = parse_ie(optarg, body,
653					      u.buf + sizeof(u.buf) - body);
654				len += ln;
655				body += ln;
656			} while(0);
657			break;
658
659		case 'S':
660			do {
661				int ln;
662				int left = u.buf + sizeof(u.buf) - body;
663
664				ln = strlen(optarg) & 0xff;
665				if ((ln + 2) > left) {
666					printf("No space for SSID\n");
667					exit(1);
668				}
669
670				*body++ = 0;
671				*body++ = ln;
672				memcpy(body, optarg, ln);
673				body += ln;
674				len += ln + 2;
675			} while(0);
676			break;
677
678		case 'R':
679			do {
680				unsigned char rates[] = "\x1\x4\x82\x84\xb\x16";
681				int left = u.buf + sizeof(u.buf) - body;
682
683				if ((sizeof(rates) - 1) > left) {
684					printf("No space for rates\n");
685					exit(1);
686				}
687
688				memcpy(body, rates, sizeof(rates) - 1);
689				body += sizeof(rates) - 1;
690				len += sizeof(rates) - 1;
691			} while(0);
692			break;
693
694		case 'a':
695			do {
696				uint16_t *x = (uint16_t*) (wh+1);
697				*x = htole16(atoi(optarg));
698			} while(0);
699			break;
700
701		case 'A':
702			do {
703				uint16_t *x = (uint16_t*) (wh+1);
704				x += 1;
705				*x = htole16(atoi(optarg));
706			} while(0);
707			break;
708
709		case 'C':
710			do {
711				uint16_t *x = (uint16_t*) (wh+1);
712
713				if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
714				    == IEEE80211_FC0_SUBTYPE_AUTH)
715				    x += 1;
716				x += 1;
717				*x = htole16(atoi(optarg));
718			} while(0);
719			break;
720
721		case 'N':
722			params.ibp_flags |= IEEE80211_BPF_NOACK;
723			break;
724
725		case 'V':
726			verify = optarg;
727			break;
728
729		case 'W':
730			params.ibp_pri = str2wmeac(optarg);
731			break;
732
733		case 'X':
734			params.ibp_rate0 = str2rate(optarg);
735			break;
736
737		case 'P':
738			params.ibp_power = atoi(optarg);
739			break;
740
741		case 'h':
742		default:
743			usage(argv[0]);
744			break;
745		}
746	}
747
748	if (!len) {
749		usage(argv[0]);
750		exit(1);
751	}
752
753	printf("Using interface %s on chan %d, transmit at %s Mbp/s\n",
754		iface, chan, rate2str(params.ibp_rate0));
755	setup_if(iface, chan);
756	fd = open_bpf(iface);
757	printf("Dose: %db\n", len);
758
759	if (verify) {
760		setup_if(verify, chan);
761		fd2 = open_bpf(verify);
762	}
763	inject(fd, wh, len, &params);
764	close(fd);
765	if (verify) {
766		char buf2[4096];
767		int rc;
768		int max = 10;
769		int timeout = 2;
770		fd_set fds;
771		struct timeval tv;
772		time_t start;
773
774		printf("Verifying via %s\n", verify);
775		start = time(NULL);
776		while (max--) {
777			FD_ZERO(&fds);
778			FD_SET(fd2, &fds);
779
780			tv.tv_usec = 0;
781			tv.tv_sec = time(NULL) - start;
782			if (tv.tv_sec >= timeout) {
783				timeout = 0;
784				break;
785			}
786			tv.tv_sec = timeout - tv.tv_sec;
787			if (select(fd2+1, &fds, NULL, NULL, &tv) == -1)
788				err(1, "select()");
789			if (!FD_ISSET(fd2, &fds))
790				continue;
791
792			if ((rc = read(fd2, buf2, sizeof(buf2))) == -1)
793				err(1, "read()");
794
795			if (do_verify(wh, len, buf2, rc)) {
796				max = 666;
797				break;
798			}
799		}
800		if (max != 666 || !timeout)
801			printf("No luck\n");
802		close(fd2);
803	}
804
805	exit(0);
806}
807