802.11 packet injection test tool
Submitted by: Andrea Bittau <a.bittau@cs.ucl.ac.uk>
This commit is contained in:
parent
b86de580a1
commit
7c37a38d03
8
tools/tools/net80211/wlaninject/Makefile
Normal file
8
tools/tools/net80211/wlaninject/Makefile
Normal file
@ -0,0 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
PROG= wlaninject
|
||||
BINDIR= /usr/local/bin
|
||||
CFLAGS=-g
|
||||
NO_MAN=
|
||||
|
||||
.include <bsd.prog.mk>
|
82
tools/tools/net80211/wlaninject/README
Normal file
82
tools/tools/net80211/wlaninject/README
Normal file
@ -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.
|
789
tools/tools/net80211/wlaninject/wlaninject.c
Normal file
789
tools/tools/net80211/wlaninject/wlaninject.c
Normal file
@ -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);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user