diff options
author | sam <sam@FreeBSD.org> | 2006-08-05 05:13:31 +0000 |
---|---|---|
committer | sam <sam@FreeBSD.org> | 2006-08-05 05:13:31 +0000 |
commit | 68f1c8859e3a3e807e4de30a7936e056e55890b1 (patch) | |
tree | b8a54ab0f4a805039524b61cb3363681f4e8bf0b /tools | |
parent | 6c8c3a52c9fcd4a8dc5199067d8c1a734a165f7b (diff) | |
download | FreeBSD-src-68f1c8859e3a3e807e4de30a7936e056e55890b1.zip FreeBSD-src-68f1c8859e3a3e807e4de30a7936e056e55890b1.tar.gz |
802.11 packet injection test tool
Submitted by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/tools/net80211/wlaninject/Makefile | 8 | ||||
-rw-r--r-- | tools/tools/net80211/wlaninject/README | 82 | ||||
-rw-r--r-- | tools/tools/net80211/wlaninject/wlaninject.c | 789 |
3 files changed, 879 insertions, 0 deletions
diff --git a/tools/tools/net80211/wlaninject/Makefile b/tools/tools/net80211/wlaninject/Makefile new file mode 100644 index 0000000..6d692a6 --- /dev/null +++ b/tools/tools/net80211/wlaninject/Makefile @@ -0,0 +1,8 @@ +# $FreeBSD$ + +PROG= wlaninject +BINDIR= /usr/local/bin +CFLAGS=-g +NO_MAN= + +.include <bsd.prog.mk> diff --git a/tools/tools/net80211/wlaninject/README b/tools/tools/net80211/wlaninject/README new file mode 100644 index 0000000..706e3ae --- /dev/null +++ b/tools/tools/net80211/wlaninject/README @@ -0,0 +1,82 @@ +$FreeBSD$ + +This tool generates raw 802.11 frames. The resulting frame will +depend on the capabilities of the hardware. Some hardware mangles +the 802.11 header [e.g. wi] other hardware does not [e.g. ath]. +This tool does not deal with layers above 802.11. A payload from +a file must be supplied if, for example, IP data needs to be sent. + +Refer to the usage for a complete list of options. Here, the most +relevant will be described. There are three types of switches: + +physical layer Physical parameters for transmission + [such as iface and chan]. +802.11 header Fields in the 802.11 header. +802.11 body The payload of the 802.11 frame. This includes + management information elements. + +Interesting physical layer options. +----------------------------------- +-i The network interface to use to TX; defaults to ath0. +-c The channel to TX on; defaults to 1. +-N Mark transmitted frames such that no ACK is expected. In practice, + this will disable any retransmission done by the card. This + way, you are sure that a single copy of your packet will be TXed. +-V Verify that the packet you TXed did indeed fly in the air as + expected. This is done by sniffing on a second network interface + and comparing the received frame to what was sent. This option + is especially useful because some cards mangle 802.11 header + fields such as duration and fragment numbers. +-W The WME AC to use for transmission. Symbolic names are used: + ac_be, be best effort + ac_bk, bk background + ac_vi, vi video + ac_vo, vo voice +-X The rate to use for transmission; defaults to 1Mbps. +-P The txpower to use; defaults to the maximum permitted by the driver. + +Interesting 802.11 header options. +---------------------------------- +-t The 802.11 frame type. Symbolic names are: + mgt Management frame + ctl Control frame + data Data frame + Otherwise the numerical type must be supplied. +-s The 802.11 frame subtype. At this point, the length of the 802.11 header + will be calculated. Symbolic names are: + preq, probereq Probe Request + auth Authenticate + areq, assocreq Assocation Request + data Data + Otherwise the numerical subtype must be supplied. +-4 The 4th MAC addr used for WDS. Make sure you specify this before + -s so the header length is calculated correctly. +-l Override the length of the packet. This is useful for sending + truncated packets. +-b Specify a file which will be used as a payload inside the 802.11 + frame. The length should be calculated automatically correctly. + +Interesting 802.11 payload options. +----------------------------------- +This is mainly used for management frames. For data frames, -b +would typically be used. + +-e Add an information element. You can supply multiple -e options, + but make sure you add them in the expected order. The format + of the information element is a list of 2 digit hex numbers. + That is, 010203... The first hexdigit is the type of the IE. + Therefore, 00616161 should correspond to the SSID IE of 'aaa'. + The length is calculated automatically---you do not need to + supply it. +-S Add an SSID IE with the data specified in ascii; e.g. -S 'aaa' + is the equivalent of -e 0061616161. +-R Add an IE of 11b supported rates. + +Examples: +--------- + +wlaninject -t data -s data -i ral0 -V ath0 -m -n 1 -f 1 + +Transmit a data frame on ral0 and verify the transmission on ath0. +The frame is sent with sequence number 1, fragment number 1, and +the MoreFrag bit marked in the 802.11 header. diff --git a/tools/tools/net80211/wlaninject/wlaninject.c b/tools/tools/net80211/wlaninject/wlaninject.c new file mode 100644 index 0000000..32c62b4 --- /dev/null +++ b/tools/tools/net80211/wlaninject/wlaninject.c @@ -0,0 +1,789 @@ +/*- + * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <err.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/uio.h> +#include <net/bpf.h> +#include <sys/socket.h> +#include <net/if.h> +#include <net/if_media.h> +#include <string.h> +#include <net80211/ieee80211.h> +#include <net80211/ieee80211_ioctl.h> +#include <net80211/ieee80211_freebsd.h> +#include <net80211/ieee80211_radiotap.h> +#include <sys/endian.h> +#include <assert.h> + +void setup_if(char *dev, int chan) { + int s; + struct ifreq ifr; + unsigned int flags; + struct ifmediareq ifmr; + int *mwords; + struct ieee80211req ireq; + + if ((s = socket(PF_INET, SOCK_DGRAM, 0)) == -1) + err(1, "socket()"); + + /* UP & PROMISC */ + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev); + if (ioctl(s, SIOCGIFFLAGS, &ifr) == -1) + err(1, "ioctl(SIOCGIFFLAGS)"); + flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + flags |= IFF_UP | IFF_PPROMISC; + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; + if (ioctl(s, SIOCSIFFLAGS, &ifr) == -1) + err(1, "ioctl(SIOCSIFFLAGS)"); + + /* set monitor mode */ + memset(&ifmr, 0, sizeof(ifmr)); + snprintf(ifmr.ifm_name, sizeof(ifmr.ifm_name), "%s", dev); + if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) + err(1, "ioctl(SIOCGIFMEDIA)"); + if (ifmr.ifm_count == 0) { + printf("0 media thinggies...\n"); + exit(1); + } + mwords = (int *)malloc(ifmr.ifm_count * sizeof(int)); + if (!mwords) + err(1, "malloc()"); + ifmr.ifm_ulist = mwords; + if (ioctl(s, SIOCGIFMEDIA, &ifmr) == -1) + err(1, "ioctl(SIOCGIFMEDIA)"); + free(mwords); + ifr.ifr_media = ifmr.ifm_current | IFM_IEEE80211_MONITOR; + if (ioctl(s, SIOCSIFMEDIA, &ifr) == -1) + err(1, "ioctl(SIOCSIFMEDIA)"); + + /* chan */ + memset(&ireq, 0, sizeof(ireq)); + snprintf(ireq.i_name, sizeof(ireq.i_name), "%s", dev); + ireq.i_type = IEEE80211_IOC_CHANNEL; + ireq.i_val = chan; + if (ioctl(s, SIOCS80211, &ireq) == -1) + err(1, "ioctl(SIOCS80211)"); + + close(s); +} + +int open_bpf(char *dev) +{ + char buf[64]; + int i; + int fd; + struct ifreq ifr; + unsigned int dlt = DLT_IEEE802_11_RADIO; + + for (i = 0; i < 64; i++) { + sprintf(buf, "/dev/bpf%d", i); + + fd = open(buf, O_RDWR); + if (fd != -1) + break; + else if (errno != EBUSY) + err(1, "open()"); + } + if (fd == -1) { + printf("Can't find bpf\n"); + exit(1); + } + + memset(&ifr, 0, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", dev); + if (ioctl(fd, BIOCSETIF, &ifr) == -1) + err(1, "ioctl(BIOCSETIF)"); + + if (ioctl(fd, BIOCSDLT, &dlt) == -1) + err(1, "ioctl(BIOCSDLT)"); + + i = 1; + if (ioctl(fd, BIOCIMMEDIATE, &i) == -1) + err(1, "ioctl(BIOCIMMEDIATE)"); + + return fd; +} + +void inject(int fd, void *buf, int buflen, struct ieee80211_bpf_params *p) +{ + struct iovec iov[2]; + int totlen; + int rc; + + iov[0].iov_base = p; + iov[0].iov_len = sizeof(*p); + + iov[1].iov_base = buf; + iov[1].iov_len = buflen; + totlen = iov[0].iov_len + iov[1].iov_len; + + rc = writev(fd, iov, sizeof(iov)/sizeof(struct iovec)); + if (rc == -1) + err(1, "writev()"); + if (rc != totlen) { + printf("Wrote only %d/%d\n", rc, totlen); + exit(1); + } +} + +void usage(char *progname) +{ + printf("Usage: %s <opts>\n" + "Physical:\n" + "\t-i\t<iface>\n" + "\t-c\t<chan>\n" + "\t-N\tno ack\n" + "\t-V\t<iface> [verify via iface whether packet was mangled]\n" + "\t-W\tWME AC\n" + "\t-X\ttransmit rate (Mbps)\n" + "\t-P\ttransmit power (device units)\n" + "802.11:\n" + "\t-h\tthis lame message\n" + "\t-v\t<version>\n" + "\t-t\t<type>\n" + "\t-s\t<subtype>\n" + "\t-T\tto ds\n" + "\t-F\tfrom ds\n" + "\t-m\tmore frags\n" + "\t-r\tretry\n" + "\t-p\tpower\n" + "\t-d\tmore data\n" + "\t-w\twep\n" + "\t-o\torder\n" + "\t-u\t<duration>\n" + "\t-1\t<addr 1>\n" + "\t-2\t<addr 2>\n" + "\t-3\t<addr 3>\n" + "\t-n\t<seqno>\n" + "\t-f\t<fragno>\n" + "\t-4\t<addr 4>\n" + "\t-b\t<payload file>\n" + "\t-l\t<len>\n" + "Management:\n" + "\t-e\t<info element [hex digits 010203... first is type]>\n" + "\t-S\t<SSID>\n" + "\t-a\t<algo no>\n" + "\t-A\t<transaction>\n" + "\t-C\t<status code>\n" + "\t-R\tstandard rates\n" + , progname); + exit(1); +} + +int str2type(const char *type) +{ +#define equal(a,b) (strcasecmp(a,b) == 0) + if (equal(type, "mgt")) + return IEEE80211_FC0_TYPE_MGT >> IEEE80211_FC0_TYPE_SHIFT; + else if (equal(type, "ctl")) + return IEEE80211_FC0_TYPE_CTL >> IEEE80211_FC0_TYPE_SHIFT; + else if (equal(type, "data")) + return IEEE80211_FC0_TYPE_DATA >> IEEE80211_FC0_TYPE_SHIFT; + + return atoi(type) & 3; +#undef equal +} + +int str2subtype(const char *subtype) +{ +#define equal(a,b) (strcasecmp(a,b) == 0) + if (equal(subtype, "preq") || equal(subtype, "probereq")) + return IEEE80211_FC0_SUBTYPE_PROBE_REQ >> + IEEE80211_FC0_SUBTYPE_SHIFT; + else if (equal(subtype, "auth")) + return IEEE80211_FC0_SUBTYPE_AUTH >> + IEEE80211_FC0_SUBTYPE_SHIFT; + else if (equal(subtype, "areq") || equal(subtype, "assocreq")) + return IEEE80211_FC0_SUBTYPE_ASSOC_REQ >> + IEEE80211_FC0_SUBTYPE_SHIFT; + else if (equal(subtype, "data")) + return IEEE80211_FC0_SUBTYPE_DATA >> + IEEE80211_FC0_SUBTYPE_SHIFT; + + return atoi(subtype) & 0xf; +#undef equal +} + +void str2mac(unsigned char *mac, char *str) +{ + unsigned int macf[6]; + int i; + + if (sscanf(str, "%x:%x:%x:%x:%x:%x", + &macf[0], &macf[1], &macf[2], + &macf[3], &macf[4], &macf[5]) != 6) { + printf("can't parse mac %s\n", str); + exit(1); + } + + for (i = 0; i < 6; i++) + *mac++ = (unsigned char) macf[i]; +} + +int str2wmeac(const char *ac) +{ +#define equal(a,b) (strcasecmp(a,b) == 0) + if (equal(ac, "ac_be") || equal(ac, "be")) + return WME_AC_BE; + if (equal(ac, "ac_bk") || equal(ac, "bk")) + return WME_AC_BK; + if (equal(ac, "ac_vi") || equal(ac, "vi")) + return WME_AC_VI; + if (equal(ac, "ac_vo") || equal(ac, "vo")) + return WME_AC_VO; + errx(1, "unknown wme access class %s", ac); +#undef equal +} + +int str2rate(const char *rate) +{ + switch (atoi(rate)) { + case 54: return 54*2; + case 48: return 48*2; + case 36: return 36*2; + case 24: return 24*2; + case 18: return 18*2; + case 12: return 12*2; + case 9: return 9*2; + case 6: return 6*2; + case 11: return 11*2; + case 5: return 11; + case 2: return 2*2; + case 1: return 1*2; + } + errx(1, "unknown transmit rate %s", rate); +} + +const char *rate2str(int rate) +{ + static char buf[30]; + + if (rate == 11) + return "5.5"; + snprintf(buf, sizeof(buf), "%u", rate/2); + return buf; +} + +int load_payload(char *fname, void *buf, int len) +{ + int fd; + int rc; + + if ((fd = open(fname, O_RDONLY)) == -1) + err(1, "open()"); + + if ((rc = read(fd, buf, len)) == -1) + err(1, "read()"); + + close(fd); + printf("Read %d bytes from %s\n", rc, fname); + return rc; +} + +int header_len(struct ieee80211_frame *wh) +{ + int len = sizeof(*wh); + + switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) { + case IEEE80211_FC0_TYPE_MGT: + switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { + case IEEE80211_FC0_SUBTYPE_ASSOC_REQ: + len += 2 + 2; /* capa & listen */ + break; + + case IEEE80211_FC0_SUBTYPE_ASSOC_RESP: + len += 2 + 2 + 2; /* capa & status & assoc */ + break; + + case IEEE80211_FC0_SUBTYPE_REASSOC_REQ: + len += 2 + 2 + 6; /* capa & listen & AP */ + break; + + case IEEE80211_FC0_SUBTYPE_REASSOC_RESP: + len += 2 + 2 + 2; /* capa & status & assoc */ + break; + + case IEEE80211_FC0_SUBTYPE_PROBE_REQ: + case IEEE80211_FC0_SUBTYPE_ATIM: + break; + + case IEEE80211_FC0_SUBTYPE_PROBE_RESP: + case IEEE80211_FC0_SUBTYPE_BEACON: + len += 8 + 2 + 2; /* time & bint & capa */ + break; + + case IEEE80211_FC0_SUBTYPE_DISASSOC: + len += 2; /* reason */ + break; + + case IEEE80211_FC0_SUBTYPE_AUTH: + len += 2 + 2 + 2; /* algo & seq & status */ + break; + + case IEEE80211_FC0_SUBTYPE_DEAUTH: + len += 2; /* reason */ + break; + + default: + errx(1, "Unknown MGT subtype 0x%x", + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + } + break; + + case IEEE80211_FC0_TYPE_CTL: + switch (wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) { + case IEEE80211_FC0_SUBTYPE_PS_POLL: + len = sizeof(struct ieee80211_frame_pspoll); + break; + + case IEEE80211_FC0_SUBTYPE_RTS: + len = sizeof(struct ieee80211_frame_rts); + break; + + case IEEE80211_FC0_SUBTYPE_CTS: + len = sizeof(struct ieee80211_frame_cts); + break; + + case IEEE80211_FC0_SUBTYPE_ACK: + len = sizeof(struct ieee80211_frame_ack); + break; + + case IEEE80211_FC0_SUBTYPE_CF_END_ACK: + case IEEE80211_FC0_SUBTYPE_CF_END: + len = sizeof(struct ieee80211_frame_cfend); + break; + + default: + errx(1, "Unknown CTL subtype 0x%x", + wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK); + } + break; + + case IEEE80211_FC0_TYPE_DATA: + if (wh->i_fc[1] & IEEE80211_FC1_DIR_DSTODS) + len += sizeof(wh->i_addr1); + break; + + default: + errx(1, "Unknown type 0x%x", + wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK); + exit(1); + } + + return len; +} + +int parse_ie(char *str, unsigned char *ie, int len) +{ + int digits = 0; + char num[3]; + int conv = 0; + int ielen; + + ielen = strlen(str)/2; + if (ielen < 1 || (strlen(str) % 2)) { + printf("Invalid IE %s\n", str); + exit(1); + } + + num[2] = 0; + while (ielen) { + num[digits++] = *str; + str++; + if (digits == 2) { + unsigned int x; + + sscanf(num, "%x", &x); + + if (len <= 0) { + printf("No space for IE\n"); + exit(1); + } + + *ie++ = (unsigned char) x; + len--; + ielen--; + + /* first char */ + if (conv == 0) { + if (len == 0) { + printf("No space for IE\n"); + exit(1); + } + *ie++ = (unsigned char) ielen; + len--; + conv++; + } + conv++; + digits = 0; + } + } + + return conv; +} + +int possible_match(struct ieee80211_frame *sent, int slen, + struct ieee80211_frame *got, int glen) +{ + if (slen != glen) + return 0; + + if (memcmp(sent->i_addr1, got->i_addr1, 6) != 0) + printf("Addr1 doesn't match\n"); + + if ((sent->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != + (got->i_fc[0] & IEEE80211_FC0_TYPE_MASK)) + return 0; + + if ((sent->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) != + (got->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK)) + return 0; + + /* Good enough for CTL frames I guess */ + if ((got->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL) + return 1; + + if (memcmp(sent->i_addr2, got->i_addr2, 6) == 0 && + memcmp(sent->i_addr3, got->i_addr3, 6) == 0) + return 1; + + return 0; +} + +int do_verify(struct ieee80211_frame *sent, int slen, void *got, int glen) +{ + struct bpf_hdr *bpfh = got; + struct ieee80211_frame *wh; + struct ieee80211_radiotap_header *rth; + int i; + unsigned char *ptr, *ptr2; + + /* get the 802.11 header */ + glen -= bpfh->bh_hdrlen; + assert(glen > 0); + if (bpfh->bh_caplen != glen) { + abort(); + } + rth = (struct ieee80211_radiotap_header*) + ((char*) bpfh + bpfh->bh_hdrlen); + glen -= rth->it_len; + assert(glen > 0); + wh = (struct ieee80211_frame*) ((char*)rth + rth->it_len); + glen -= 4; /* 802.11 CRC */ + assert(glen > 0); + + /* did we receive the packet we sent? */ + if (!possible_match(sent, slen, wh, glen)) + return 0; + + /* check if it got mangled */ + if (memcmp(sent, wh, slen) == 0) { + printf("No mangling---got it perfect\n"); + return 1; + } + + /* print differences */ + printf("Got mangled:\n"); + ptr = (unsigned char*) sent; + ptr2 = (unsigned char *) wh; + for (i = 0; i < slen; i++, ptr++, ptr2++) { + if (*ptr != *ptr2) + printf("Position: %d Was: %.2X Got: %.2X\n", + i, *ptr, *ptr2); + } + return -1; +} + +int main(int argc, char *argv[]) +{ + int fd, fd2; + char *iface = "ath0"; + char *verify = NULL; + int chan = 1; + union { + struct ieee80211_frame w; + unsigned char buf[2048]; + } u; + int len = 0; + int ch; + struct ieee80211_bpf_params params; + struct ieee80211_frame *wh = &u.w; + unsigned char *body = u.buf; + + memset(&u, 0, sizeof(u)); + memset(¶ms, 0, sizeof(params)); + params.ibp_rate0 = 2; /* 1 MB/s XXX */ + params.ibp_try0 = 1; /* no retransmits */ + params.ibp_power = 100; /* nominal max */ + params.ibp_pri = WME_AC_VO; /* high priority */ + + while ((ch = getopt(argc, argv, + "hv:t:s:TFmpdwou:1:2:3:4:b:i:c:l:n:f:e:S:a:A:C:NRV:W:X:P:")) != -1) { + switch (ch) { + case 'i': + iface = optarg; + break; + + case 'c': + chan = atoi(optarg); + break; + + case 'v': + wh->i_fc[0] |= atoi(optarg)& IEEE80211_FC0_VERSION_MASK; + break; + + case 't': + wh->i_fc[0] |= str2type(optarg) << + IEEE80211_FC0_TYPE_SHIFT; + break; + + case 's': + wh->i_fc[0] |= str2subtype(optarg) << + IEEE80211_FC0_SUBTYPE_SHIFT; + len = header_len(wh); + body += len; + break; + + case 'T': + wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS; + break; + + case 'F': + wh->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS; + break; + + case 'm': + wh->i_fc[1] |= IEEE80211_FC1_MORE_FRAG; + break; + + case 'r': + wh->i_fc[1] |= IEEE80211_FC1_RETRY; + break; + + case 'p': + wh->i_fc[1] |= IEEE80211_FC1_PWR_MGT; + break; + + case 'd': + wh->i_fc[1] |= IEEE80211_FC1_MORE_DATA; + break; + + case 'w': + wh->i_fc[1] |= IEEE80211_FC1_WEP; + break; + + case 'o': + wh->i_fc[1] |= IEEE80211_FC1_ORDER; + break; + + case 'u': + *(uint16_t*)wh->i_dur = htole16(atoi(optarg)); + break; + + case '1': + str2mac(wh->i_addr1, optarg); + break; + + case '2': + str2mac(wh->i_addr2, optarg); + break; + + case '3': + str2mac(wh->i_addr3, optarg); + break; + + case '4': + str2mac(body, optarg); + break; + + case 'n': + *(uint16_t*)wh->i_seq |= htole16((atoi(optarg) & 0xfff) + << IEEE80211_SEQ_SEQ_SHIFT); + break; + + case 'f': + wh->i_seq[0] |= atoi(optarg) & 0xf; + break; + + case 'b': + len += load_payload(optarg, body, + u.buf + sizeof(u.buf) - body); + break; + + case 'l': + len = atoi(optarg); + break; + + case 'e': + do { + int ln; + + ln = parse_ie(optarg, body, + u.buf + sizeof(u.buf) - body); + len += ln; + body += ln; + } while(0); + break; + + case 'S': + do { + int ln; + int left = u.buf + sizeof(u.buf) - body; + + ln = strlen(optarg) & 0xff; + if ((ln + 2) > left) { + printf("No space for SSID\n"); + exit(1); + } + + *body++ = 0; + *body++ = ln; + memcpy(body, optarg, ln); + body += ln; + len += ln + 2; + } while(0); + break; + + case 'R': + do { + unsigned char rates[] = "\x1\x4\x82\x84\xb\x16"; + int left = u.buf + sizeof(u.buf) - body; + + if ((sizeof(rates) - 1) > left) { + printf("No space for rates\n"); + exit(1); + } + + memcpy(body, rates, sizeof(rates) - 1); + body += sizeof(rates) - 1; + len += sizeof(rates) - 1; + } while(0); + break; + + case 'a': + do { + uint16_t *x = (uint16_t*) (wh+1); + *x = htole16(atoi(optarg)); + } while(0); + break; + + case 'A': + do { + uint16_t *x = (uint16_t*) (wh+1); + x += 1; + *x = htole16(atoi(optarg)); + } while(0); + break; + + case 'C': + do { + uint16_t *x = (uint16_t*) (wh+1); + + if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) + == IEEE80211_FC0_SUBTYPE_AUTH) + x += 1; + x += 1; + *x = htole16(atoi(optarg)); + } while(0); + break; + + case 'N': + params.ibp_flags |= IEEE80211_BPF_NOACK; + break; + + case 'V': + verify = optarg; + break; + + case 'W': + params.ibp_pri = str2wmeac(optarg); + break; + + case 'X': + params.ibp_rate0 = str2rate(optarg); + break; + + case 'P': + params.ibp_power = atoi(optarg); + break; + + case 'h': + default: + usage(argv[0]); + break; + } + } + + if (!len) { + usage(argv[0]); + exit(1); + } + + printf("Using interface %s on chan %d, transmit at %s Mbp/s\n", + iface, chan, rate2str(params.ibp_rate0)); + setup_if(iface, chan); + fd = open_bpf(iface); + printf("Dose: %db\n", len); + + if (verify) { + setup_if(verify, chan); + fd2 = open_bpf(verify); + } + inject(fd, u.buf, len, ¶ms); + close(fd); + if (verify) { + char buf2[4096]; + int rc; + int max = 10; + + printf("Verifying via %s\n", verify); + while (max--) { + if ((rc = read(fd2, buf2, sizeof(buf2))) == -1) + err(1, "read()"); + + if (do_verify(wh, len, buf2, rc)) { + max = 666; + break; + } + } + if (max != 666) + printf("No luck\n"); + close(fd2); + } + + exit(0); +} |