2 * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
34 #include <sys/types.h>
36 #include <sys/ioctl.h>
39 #include <sys/socket.h>
41 #include <net/if_media.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>
50 void setup_if(char *dev, int chan) {
54 struct ifmediareq ifmr;
56 struct ieee80211req ireq;
58 if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
62 memset(&ireq, 0, sizeof(ireq));
63 snprintf(ireq.i_name, sizeof(ireq.i_name), "%s", dev);
64 ireq.i_type = IEEE80211_IOC_CHANNEL;
66 if (ioctl(s, SIOCS80211, &ireq) == -1)
67 err(1, "ioctl(SIOCS80211)");
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)");
84 int open_bpf(char *dev)
90 unsigned int dlt = DLT_IEEE802_11_RADIO;
92 for (i = 0; i < 64; i++) {
93 sprintf(buf, "/dev/bpf%d", i);
95 fd = open(buf, O_RDWR);
98 else if (errno != EBUSY)
102 printf("Can't find bpf\n");
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)");
111 if (ioctl(fd, BIOCSDLT, &dlt) == -1)
112 err(1, "ioctl(BIOCSDLT)");
115 if (ioctl(fd, BIOCIMMEDIATE, &i) == -1)
116 err(1, "ioctl(BIOCIMMEDIATE)");
121 void inject(int fd, void *buf, int buflen, struct ieee80211_bpf_params *p)
128 iov[0].iov_len = p->ibp_len;
130 iov[1].iov_base = buf;
131 iov[1].iov_len = buflen;
132 totlen = iov[0].iov_len + iov[1].iov_len;
134 rc = writev(fd, iov, sizeof(iov)/sizeof(struct iovec));
138 printf("Wrote only %d/%d\n", rc, totlen);
143 void usage(char *progname)
145 printf("Usage: %s <opts>\n"
150 "\t-V\t<iface> [verify via iface whether packet was mangled]\n"
152 "\t-X\ttransmit rate (Mbps)\n"
153 "\t-P\ttransmit power (device units)\n"
155 "\t-h\tthis lame message\n"
174 "\t-b\t<payload file>\n"
177 "\t-e\t<info element [hex digits 010203... first is type]>\n"
180 "\t-A\t<transaction>\n"
181 "\t-C\t<status code>\n"
182 "\t-R\tstandard rates\n"
187 int str2type(const char *type)
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;
197 return atoi(type) & 3;
201 int str2subtype(const char *subtype)
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;
217 return atoi(subtype) & 0xf;
221 void str2mac(unsigned char *mac, char *str)
223 unsigned int macf[6];
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);
233 for (i = 0; i < 6; i++)
234 *mac++ = (unsigned char) macf[i];
237 int str2wmeac(const char *ac)
239 #define equal(a,b) (strcasecmp(a,b) == 0)
240 if (equal(ac, "ac_be") || equal(ac, "be"))
242 if (equal(ac, "ac_bk") || equal(ac, "bk"))
244 if (equal(ac, "ac_vi") || equal(ac, "vi"))
246 if (equal(ac, "ac_vo") || equal(ac, "vo"))
248 errx(1, "unknown wme access class %s", ac);
252 int str2rate(const char *rate)
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;
263 case 11: return 11*2;
268 errx(1, "unknown transmit rate %s", rate);
271 const char *rate2str(int rate)
277 snprintf(buf, sizeof(buf), "%u", rate/2);
281 int load_payload(char *fname, void *buf, int len)
286 if ((fd = open(fname, O_RDONLY)) == -1)
289 if ((rc = read(fd, buf, len)) == -1)
293 printf("Read %d bytes from %s\n", rc, fname);
297 int header_len(struct ieee80211_frame *wh)
299 int len = sizeof(*wh);
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 */
308 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
309 len += 2 + 2 + 2; /* capa & status & assoc */
312 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
313 len += 2 + 2 + 6; /* capa & listen & AP */
316 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
317 len += 2 + 2 + 2; /* capa & status & assoc */
320 case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
321 case IEEE80211_FC0_SUBTYPE_ATIM:
324 case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
325 case IEEE80211_FC0_SUBTYPE_BEACON:
326 len += 8 + 2 + 2; /* time & bint & capa */
329 case IEEE80211_FC0_SUBTYPE_DISASSOC:
330 len += 2; /* reason */
333 case IEEE80211_FC0_SUBTYPE_AUTH:
334 len += 2 + 2 + 2; /* algo & seq & status */
337 case IEEE80211_FC0_SUBTYPE_DEAUTH:
338 len += 2; /* reason */
342 errx(1, "Unknown MGT subtype 0x%x",
343 wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
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);
353 case IEEE80211_FC0_SUBTYPE_RTS:
354 len = sizeof(struct ieee80211_frame_rts);
357 case IEEE80211_FC0_SUBTYPE_CTS:
358 len = sizeof(struct ieee80211_frame_cts);
361 case IEEE80211_FC0_SUBTYPE_ACK:
362 len = sizeof(struct ieee80211_frame_ack);
365 case IEEE80211_FC0_SUBTYPE_CF_END_ACK:
366 case IEEE80211_FC0_SUBTYPE_CF_END:
367 len = sizeof(struct ieee80211_frame_cfend);
371 errx(1, "Unknown CTL subtype 0x%x",
372 wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
376 case IEEE80211_FC0_TYPE_DATA:
377 if (wh->i_fc[1] & IEEE80211_FC1_DIR_DSTODS)
378 len += sizeof(wh->i_addr1);
382 errx(1, "Unknown type 0x%x",
383 wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
390 int parse_ie(char *str, unsigned char *ie, int len)
397 ielen = strlen(str)/2;
398 if (ielen < 1 || (strlen(str) % 2)) {
399 printf("Invalid IE %s\n", str);
405 num[digits++] = *str;
410 sscanf(num, "%x", &x);
413 printf("No space for IE\n");
417 *ie++ = (unsigned char) x;
424 printf("No space for IE\n");
427 *ie++ = (unsigned char) ielen;
439 int possible_match(struct ieee80211_frame *sent, int slen,
440 struct ieee80211_frame *got, int glen)
445 if (memcmp(sent->i_addr1, got->i_addr1, 6) != 0)
446 printf("Addr1 doesn't match\n");
448 if ((sent->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
449 (got->i_fc[0] & IEEE80211_FC0_TYPE_MASK))
452 if ((sent->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) !=
453 (got->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK))
456 /* Good enough for CTL frames I guess */
457 if ((got->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
460 if (memcmp(sent->i_addr2, got->i_addr2, 6) == 0 &&
461 memcmp(sent->i_addr3, got->i_addr3, 6) == 0)
467 int do_verify(struct ieee80211_frame *sent, int slen, void *got, int glen)
469 #define BIT(n) (1<<(n))
470 struct bpf_hdr *bpfh = got;
471 struct ieee80211_frame *wh;
472 struct ieee80211_radiotap_header *rth;
474 unsigned char *ptr, *ptr2;
478 /* get the 802.11 header */
479 glen -= bpfh->bh_hdrlen;
481 if (bpfh->bh_caplen != glen) {
484 rth = (struct ieee80211_radiotap_header*)
485 ((char*) bpfh + bpfh->bh_hdrlen);
488 wh = (struct ieee80211_frame*) ((char*)rth + rth->it_len);
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];
496 rflags = ((const uint8_t *)rth)[0];
499 if (rflags & IEEE80211_RADIOTAP_F_FCS)
500 glen -= IEEE80211_CRC_LEN;
503 /* did we receive the packet we sent? */
504 if (!possible_match(sent, slen, wh, glen))
507 /* check if it got mangled */
508 if (memcmp(sent, wh, slen) == 0) {
509 printf("No mangling---got it perfect\n");
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++) {
519 printf("Position: %d Was: %.2X Got: %.2X\n",
526 int main(int argc, char *argv[])
529 char *iface = "wlan0";
533 struct ieee80211_frame w;
534 unsigned char buf[2048];
538 struct ieee80211_bpf_params params;
539 struct ieee80211_frame *wh = &u.w;
540 unsigned char *body = u.buf;
542 memset(&u, 0, sizeof(u));
543 memset(¶ms, 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 */
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) {
563 wh->i_fc[0] |= atoi(optarg)& IEEE80211_FC0_VERSION_MASK;
567 wh->i_fc[0] |= str2type(optarg) <<
568 IEEE80211_FC0_TYPE_SHIFT;
572 wh->i_fc[0] |= str2subtype(optarg) <<
573 IEEE80211_FC0_SUBTYPE_SHIFT;
574 len = header_len(wh);
579 wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
583 wh->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
587 wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
591 wh->i_fc[1] |= IEEE80211_FC1_RETRY;
595 wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
599 wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
603 wh->i_fc[1] |= IEEE80211_FC1_WEP;
607 wh->i_fc[1] |= IEEE80211_FC1_ORDER;
611 *(uint16_t*)wh->i_dur = htole16(atoi(optarg));
615 str2mac(wh->i_addr1, optarg);
619 str2mac(wh->i_addr2, optarg);
623 str2mac(wh->i_addr3, optarg);
627 str2mac(body, optarg);
631 *(uint16_t*)wh->i_seq |= htole16((atoi(optarg) & 0xfff)
632 << IEEE80211_SEQ_SEQ_SHIFT);
636 wh->i_seq[0] |= atoi(optarg) & 0xf;
640 len += load_payload(optarg, body,
641 u.buf + sizeof(u.buf) - body);
652 ln = parse_ie(optarg, body,
653 u.buf + sizeof(u.buf) - body);
662 int left = u.buf + sizeof(u.buf) - body;
664 ln = strlen(optarg) & 0xff;
665 if ((ln + 2) > left) {
666 printf("No space for SSID\n");
672 memcpy(body, optarg, ln);
680 unsigned char rates[] = "\x1\x4\x82\x84\xb\x16";
681 int left = u.buf + sizeof(u.buf) - body;
683 if ((sizeof(rates) - 1) > left) {
684 printf("No space for rates\n");
688 memcpy(body, rates, sizeof(rates) - 1);
689 body += sizeof(rates) - 1;
690 len += sizeof(rates) - 1;
696 uint16_t *x = (uint16_t*) (wh+1);
697 *x = htole16(atoi(optarg));
703 uint16_t *x = (uint16_t*) (wh+1);
705 *x = htole16(atoi(optarg));
711 uint16_t *x = (uint16_t*) (wh+1);
713 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
714 == IEEE80211_FC0_SUBTYPE_AUTH)
717 *x = htole16(atoi(optarg));
722 params.ibp_flags |= IEEE80211_BPF_NOACK;
730 params.ibp_pri = str2wmeac(optarg);
734 params.ibp_rate0 = str2rate(optarg);
738 params.ibp_power = atoi(optarg);
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);
760 setup_if(verify, chan);
761 fd2 = open_bpf(verify);
763 inject(fd, wh, len, ¶ms);
774 printf("Verifying via %s\n", verify);
781 tv.tv_sec = time(NULL) - start;
782 if (tv.tv_sec >= timeout) {
786 tv.tv_sec = timeout - tv.tv_sec;
787 if (select(fd2+1, &fds, NULL, NULL, &tv) == -1)
789 if (!FD_ISSET(fd2, &fds))
792 if ((rc = read(fd2, buf2, sizeof(buf2))) == -1)
795 if (do_verify(wh, len, buf2, rc)) {
800 if (max != 666 || !timeout)