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(&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)");
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");
82 mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
85 ifmr.ifm_ulist = mwords;
86 if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1)
87 err(1, "ioctl(SIOCGIFMEDIA)");
89 ifr.ifr_media = ifmr.ifm_current | IFM_IEEE80211_MONITOR;
90 if (ioctl(s, SIOCSIFMEDIA, &ifr) == -1)
91 err(1, "ioctl(SIOCSIFMEDIA)");
94 memset(&ireq, 0, sizeof(ireq));
95 snprintf(ireq.i_name, sizeof(ireq.i_name), "%s", dev);
96 ireq.i_type = IEEE80211_IOC_CHANNEL;
98 if (ioctl(s, SIOCS80211, &ireq) == -1)
99 err(1, "ioctl(SIOCS80211)");
104 int open_bpf(char *dev)
110 unsigned int dlt = DLT_IEEE802_11_RADIO;
112 for (i = 0; i < 64; i++) {
113 sprintf(buf, "/dev/bpf%d", i);
115 fd = open(buf, O_RDWR);
118 else if (errno != EBUSY)
122 printf("Can't find bpf\n");
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)");
131 if (ioctl(fd, BIOCSDLT, &dlt) == -1)
132 err(1, "ioctl(BIOCSDLT)");
135 if (ioctl(fd, BIOCIMMEDIATE, &i) == -1)
136 err(1, "ioctl(BIOCIMMEDIATE)");
141 void inject(int fd, void *buf, int buflen, struct ieee80211_bpf_params *p)
148 iov[0].iov_len = p->ibp_len;
150 iov[1].iov_base = buf;
151 iov[1].iov_len = buflen;
152 totlen = iov[0].iov_len + iov[1].iov_len;
154 rc = writev(fd, iov, sizeof(iov)/sizeof(struct iovec));
158 printf("Wrote only %d/%d\n", rc, totlen);
163 void usage(char *progname)
165 printf("Usage: %s <opts>\n"
170 "\t-V\t<iface> [verify via iface whether packet was mangled]\n"
172 "\t-X\ttransmit rate (Mbps)\n"
173 "\t-P\ttransmit power (device units)\n"
175 "\t-h\tthis lame message\n"
194 "\t-b\t<payload file>\n"
197 "\t-e\t<info element [hex digits 010203... first is type]>\n"
200 "\t-A\t<transaction>\n"
201 "\t-C\t<status code>\n"
202 "\t-R\tstandard rates\n"
207 int str2type(const char *type)
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;
217 return atoi(type) & 3;
221 int str2subtype(const char *subtype)
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;
237 return atoi(subtype) & 0xf;
241 void str2mac(unsigned char *mac, char *str)
243 unsigned int macf[6];
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);
253 for (i = 0; i < 6; i++)
254 *mac++ = (unsigned char) macf[i];
257 int str2wmeac(const char *ac)
259 #define equal(a,b) (strcasecmp(a,b) == 0)
260 if (equal(ac, "ac_be") || equal(ac, "be"))
262 if (equal(ac, "ac_bk") || equal(ac, "bk"))
264 if (equal(ac, "ac_vi") || equal(ac, "vi"))
266 if (equal(ac, "ac_vo") || equal(ac, "vo"))
268 errx(1, "unknown wme access class %s", ac);
272 int str2rate(const char *rate)
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;
283 case 11: return 11*2;
288 errx(1, "unknown transmit rate %s", rate);
291 const char *rate2str(int rate)
297 snprintf(buf, sizeof(buf), "%u", rate/2);
301 int load_payload(char *fname, void *buf, int len)
306 if ((fd = open(fname, O_RDONLY)) == -1)
309 if ((rc = read(fd, buf, len)) == -1)
313 printf("Read %d bytes from %s\n", rc, fname);
317 int header_len(struct ieee80211_frame *wh)
319 int len = sizeof(*wh);
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 */
328 case IEEE80211_FC0_SUBTYPE_ASSOC_RESP:
329 len += 2 + 2 + 2; /* capa & status & assoc */
332 case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
333 len += 2 + 2 + 6; /* capa & listen & AP */
336 case IEEE80211_FC0_SUBTYPE_REASSOC_RESP:
337 len += 2 + 2 + 2; /* capa & status & assoc */
340 case IEEE80211_FC0_SUBTYPE_PROBE_REQ:
341 case IEEE80211_FC0_SUBTYPE_ATIM:
344 case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
345 case IEEE80211_FC0_SUBTYPE_BEACON:
346 len += 8 + 2 + 2; /* time & bint & capa */
349 case IEEE80211_FC0_SUBTYPE_DISASSOC:
350 len += 2; /* reason */
353 case IEEE80211_FC0_SUBTYPE_AUTH:
354 len += 2 + 2 + 2; /* algo & seq & status */
357 case IEEE80211_FC0_SUBTYPE_DEAUTH:
358 len += 2; /* reason */
362 errx(1, "Unknown MGT subtype 0x%x",
363 wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
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);
373 case IEEE80211_FC0_SUBTYPE_RTS:
374 len = sizeof(struct ieee80211_frame_rts);
377 case IEEE80211_FC0_SUBTYPE_CTS:
378 len = sizeof(struct ieee80211_frame_cts);
381 case IEEE80211_FC0_SUBTYPE_ACK:
382 len = sizeof(struct ieee80211_frame_ack);
385 case IEEE80211_FC0_SUBTYPE_CF_END_ACK:
386 case IEEE80211_FC0_SUBTYPE_CF_END:
387 len = sizeof(struct ieee80211_frame_cfend);
391 errx(1, "Unknown CTL subtype 0x%x",
392 wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
396 case IEEE80211_FC0_TYPE_DATA:
397 if (wh->i_fc[1] & IEEE80211_FC1_DIR_DSTODS)
398 len += sizeof(wh->i_addr1);
402 errx(1, "Unknown type 0x%x",
403 wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK);
410 int parse_ie(char *str, unsigned char *ie, int len)
417 ielen = strlen(str)/2;
418 if (ielen < 1 || (strlen(str) % 2)) {
419 printf("Invalid IE %s\n", str);
425 num[digits++] = *str;
430 sscanf(num, "%x", &x);
433 printf("No space for IE\n");
437 *ie++ = (unsigned char) x;
444 printf("No space for IE\n");
447 *ie++ = (unsigned char) ielen;
459 int possible_match(struct ieee80211_frame *sent, int slen,
460 struct ieee80211_frame *got, int glen)
465 if (memcmp(sent->i_addr1, got->i_addr1, 6) != 0)
466 printf("Addr1 doesn't match\n");
468 if ((sent->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
469 (got->i_fc[0] & IEEE80211_FC0_TYPE_MASK))
472 if ((sent->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) !=
473 (got->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK))
476 /* Good enough for CTL frames I guess */
477 if ((got->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
480 if (memcmp(sent->i_addr2, got->i_addr2, 6) == 0 &&
481 memcmp(sent->i_addr3, got->i_addr3, 6) == 0)
487 int do_verify(struct ieee80211_frame *sent, int slen, void *got, int glen)
489 #define BIT(n) (1<<(n))
490 struct bpf_hdr *bpfh = got;
491 struct ieee80211_frame *wh;
492 struct ieee80211_radiotap_header *rth;
494 unsigned char *ptr, *ptr2;
498 /* get the 802.11 header */
499 glen -= bpfh->bh_hdrlen;
501 if (bpfh->bh_caplen != glen) {
504 rth = (struct ieee80211_radiotap_header*)
505 ((char*) bpfh + bpfh->bh_hdrlen);
508 wh = (struct ieee80211_frame*) ((char*)rth + rth->it_len);
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];
516 rflags = ((const uint8_t *)rth)[0];
519 if (rflags & IEEE80211_RADIOTAP_F_FCS)
520 glen -= IEEE80211_CRC_LEN;
523 /* did we receive the packet we sent? */
524 if (!possible_match(sent, slen, wh, glen))
527 /* check if it got mangled */
528 if (memcmp(sent, wh, slen) == 0) {
529 printf("No mangling---got it perfect\n");
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++) {
539 printf("Position: %d Was: %.2X Got: %.2X\n",
546 int main(int argc, char *argv[])
549 char *iface = "ath0";
553 struct ieee80211_frame w;
554 unsigned char buf[2048];
558 struct ieee80211_bpf_params params;
559 struct ieee80211_frame *wh = &u.w;
560 unsigned char *body = u.buf;
562 memset(&u, 0, sizeof(u));
563 memset(¶ms, 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 */
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) {
583 wh->i_fc[0] |= atoi(optarg)& IEEE80211_FC0_VERSION_MASK;
587 wh->i_fc[0] |= str2type(optarg) <<
588 IEEE80211_FC0_TYPE_SHIFT;
592 wh->i_fc[0] |= str2subtype(optarg) <<
593 IEEE80211_FC0_SUBTYPE_SHIFT;
594 len = header_len(wh);
599 wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
603 wh->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
607 wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG;
611 wh->i_fc[1] |= IEEE80211_FC1_RETRY;
615 wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT;
619 wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA;
623 wh->i_fc[1] |= IEEE80211_FC1_WEP;
627 wh->i_fc[1] |= IEEE80211_FC1_ORDER;
631 *(uint16_t*)wh->i_dur = htole16(atoi(optarg));
635 str2mac(wh->i_addr1, optarg);
639 str2mac(wh->i_addr2, optarg);
643 str2mac(wh->i_addr3, optarg);
647 str2mac(body, optarg);
651 *(uint16_t*)wh->i_seq |= htole16((atoi(optarg) & 0xfff)
652 << IEEE80211_SEQ_SEQ_SHIFT);
656 wh->i_seq[0] |= atoi(optarg) & 0xf;
660 len += load_payload(optarg, body,
661 u.buf + sizeof(u.buf) - body);
672 ln = parse_ie(optarg, body,
673 u.buf + sizeof(u.buf) - body);
682 int left = u.buf + sizeof(u.buf) - body;
684 ln = strlen(optarg) & 0xff;
685 if ((ln + 2) > left) {
686 printf("No space for SSID\n");
692 memcpy(body, optarg, ln);
700 unsigned char rates[] = "\x1\x4\x82\x84\xb\x16";
701 int left = u.buf + sizeof(u.buf) - body;
703 if ((sizeof(rates) - 1) > left) {
704 printf("No space for rates\n");
708 memcpy(body, rates, sizeof(rates) - 1);
709 body += sizeof(rates) - 1;
710 len += sizeof(rates) - 1;
716 uint16_t *x = (uint16_t*) (wh+1);
717 *x = htole16(atoi(optarg));
723 uint16_t *x = (uint16_t*) (wh+1);
725 *x = htole16(atoi(optarg));
731 uint16_t *x = (uint16_t*) (wh+1);
733 if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)
734 == IEEE80211_FC0_SUBTYPE_AUTH)
737 *x = htole16(atoi(optarg));
742 params.ibp_flags |= IEEE80211_BPF_NOACK;
750 params.ibp_pri = str2wmeac(optarg);
754 params.ibp_rate0 = str2rate(optarg);
758 params.ibp_power = atoi(optarg);
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);
780 setup_if(verify, chan);
781 fd2 = open_bpf(verify);
783 inject(fd, wh, len, ¶ms);
794 printf("Verifying via %s\n", verify);
801 tv.tv_sec = time(NULL) - start;
802 if (tv.tv_sec >= timeout) {
806 tv.tv_sec = timeout - tv.tv_sec;
807 if (select(fd2+1, &fds, NULL, NULL, &tv) == -1)
809 if (!FD_ISSET(fd2, &fds))
812 if ((rc = read(fd2, buf2, sizeof(buf2))) == -1)
815 if (do_verify(wh, len, buf2, rc)) {
820 if (max != 666 || !timeout)