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