xref: /freebsd/tools/tools/net80211/w00t/assoc/assoc.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
12137fdb5SSam Leffler /*-
22137fdb5SSam Leffler  * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
32137fdb5SSam Leffler  * All rights reserved.
42137fdb5SSam Leffler  *
52137fdb5SSam Leffler  * Redistribution and use in source and binary forms, with or without
62137fdb5SSam Leffler  * modification, are permitted provided that the following conditions
72137fdb5SSam Leffler  * are met:
82137fdb5SSam Leffler  * 1. Redistributions of source code must retain the above copyright
92137fdb5SSam Leffler  *    notice, this list of conditions and the following disclaimer.
102137fdb5SSam Leffler  * 2. Redistributions in binary form must reproduce the above copyright
112137fdb5SSam Leffler  *    notice, this list of conditions and the following disclaimer in the
122137fdb5SSam Leffler  *    documentation and/or other materials provided with the distribution.
132137fdb5SSam Leffler  *
142137fdb5SSam Leffler  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
152137fdb5SSam Leffler  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162137fdb5SSam Leffler  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172137fdb5SSam Leffler  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
182137fdb5SSam Leffler  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192137fdb5SSam Leffler  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202137fdb5SSam Leffler  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212137fdb5SSam Leffler  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222137fdb5SSam Leffler  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232137fdb5SSam Leffler  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242137fdb5SSam Leffler  * SUCH DAMAGE.
252137fdb5SSam Leffler  */
262137fdb5SSam Leffler #include <sys/time.h>
272137fdb5SSam Leffler #include <stdlib.h>
282137fdb5SSam Leffler #include <stdio.h>
292137fdb5SSam Leffler #include <unistd.h>
302137fdb5SSam Leffler #include <string.h>
312137fdb5SSam Leffler #include <errno.h>
322137fdb5SSam Leffler #include <err.h>
332137fdb5SSam Leffler #include <net80211/ieee80211.h>
342137fdb5SSam Leffler #include <sys/endian.h>
352137fdb5SSam Leffler #include "w00t.h"
362137fdb5SSam Leffler 
372137fdb5SSam Leffler enum {
382137fdb5SSam Leffler 	S_START = 0,
392137fdb5SSam Leffler 	S_SEND_PROBE_REQ,
402137fdb5SSam Leffler 	S_WAIT_PROBE_RES,
412137fdb5SSam Leffler 	S_SEND_AUTH,
422137fdb5SSam Leffler 	S_WAIT_AUTH,
432137fdb5SSam Leffler 	S_SEND_ASSOC,
442137fdb5SSam Leffler 	S_WAIT_ASSOC,
452137fdb5SSam Leffler 	S_ASSOCIATED,
462137fdb5SSam Leffler 	S_SEND_DATA,
472137fdb5SSam Leffler 	S_WAIT_ACK
482137fdb5SSam Leffler };
492137fdb5SSam Leffler 
502137fdb5SSam Leffler struct params {
512137fdb5SSam Leffler 	int seq;
522137fdb5SSam Leffler 	int seq_rx;
532137fdb5SSam Leffler 	char *mac;
542137fdb5SSam Leffler 	char *ssid;
552137fdb5SSam Leffler 	char bssid[6];
562137fdb5SSam Leffler 	char ap[6];
572137fdb5SSam Leffler 	int tx;
582137fdb5SSam Leffler 	int rx;
592137fdb5SSam Leffler 	int tap;
602137fdb5SSam Leffler 	int aid;
612137fdb5SSam Leffler 	char packet[4096];
622137fdb5SSam Leffler 	int packet_len;
632137fdb5SSam Leffler 	int state;
642137fdb5SSam Leffler 	char wep_key[13];
652137fdb5SSam Leffler 	int wep_iv;
662137fdb5SSam Leffler 	int wep_len;
672137fdb5SSam Leffler };
682137fdb5SSam Leffler 
usage(char * pname)692137fdb5SSam Leffler void usage(char *pname)
702137fdb5SSam Leffler {
712137fdb5SSam Leffler 	printf("Usage: %s <opts>\n"
722137fdb5SSam Leffler 		"-m\t<source mac>\n"
732137fdb5SSam Leffler 		"-s\t<ssid>\n"
742137fdb5SSam Leffler 		"-h\tusage\n"
752137fdb5SSam Leffler 		"-i\t<iface>\n"
762137fdb5SSam Leffler 		"-w\t<wep key>\n"
772137fdb5SSam Leffler 		"-t\t<tap>\n"
782137fdb5SSam Leffler 		"-b\t<bssid>\n"
792137fdb5SSam Leffler 		, pname);
802137fdb5SSam Leffler 	exit(0);
812137fdb5SSam Leffler }
822137fdb5SSam Leffler 
fill_basic(struct ieee80211_frame * wh,struct params * p)832137fdb5SSam Leffler void fill_basic(struct ieee80211_frame *wh, struct params *p)
842137fdb5SSam Leffler {
852137fdb5SSam Leffler 	short *seq;
862137fdb5SSam Leffler 
872137fdb5SSam Leffler 	wh->i_dur[0] = 0x69;
882137fdb5SSam Leffler 	wh->i_dur[1] = 0x00;
892137fdb5SSam Leffler 
902137fdb5SSam Leffler 	memcpy(wh->i_addr1, p->ap, 6);
912137fdb5SSam Leffler 	memcpy(wh->i_addr2, p->mac, 6);
922137fdb5SSam Leffler 	memcpy(wh->i_addr3, p->bssid, 6);
932137fdb5SSam Leffler 
942137fdb5SSam Leffler 	seq = (short*)wh->i_seq;
952137fdb5SSam Leffler 	*seq = seqfn(p->seq, 0);
962137fdb5SSam Leffler }
972137fdb5SSam Leffler 
send_frame(struct params * p,void * buf,int len)982137fdb5SSam Leffler void send_frame(struct params *p, void *buf, int len)
992137fdb5SSam Leffler {
1002137fdb5SSam Leffler 	int rc;
1012137fdb5SSam Leffler 
1022137fdb5SSam Leffler 	rc = inject(p->tx, buf, len);
1032137fdb5SSam Leffler 	if (rc == -1) {
1042137fdb5SSam Leffler 		if (errno == EMSGSIZE)
1052137fdb5SSam Leffler 			warnx("inject(len %d)", len);
1062137fdb5SSam Leffler 		else
1072137fdb5SSam Leffler 			err(1, "inject(len %d)", len);
1082137fdb5SSam Leffler 	} else if (rc != len)
1092137fdb5SSam Leffler 		errx(1, "injected %d but only %d sent", rc, len);
1102137fdb5SSam Leffler 	p->seq++;
1112137fdb5SSam Leffler }
1122137fdb5SSam Leffler 
send_probe_request(struct params * p)1132137fdb5SSam Leffler void send_probe_request(struct params *p)
1142137fdb5SSam Leffler {
1152137fdb5SSam Leffler 	char buf[2048];
1162137fdb5SSam Leffler 	struct ieee80211_frame *wh;
1172137fdb5SSam Leffler 	char *data;
1182137fdb5SSam Leffler 	int len;
1192137fdb5SSam Leffler 
1202137fdb5SSam Leffler 	memset(buf, 0, sizeof(buf));
1212137fdb5SSam Leffler 
1222137fdb5SSam Leffler 	wh = (struct ieee80211_frame*) buf;
1232137fdb5SSam Leffler 	fill_basic(wh, p);
1242137fdb5SSam Leffler 	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ;
1252137fdb5SSam Leffler 
1262137fdb5SSam Leffler 	memset(wh->i_addr1, 0xFF, 6);
1272137fdb5SSam Leffler 	memset(wh->i_addr3, 0xFF, 6);
1282137fdb5SSam Leffler 
1292137fdb5SSam Leffler 	data = (char*) (wh + 1);
1302137fdb5SSam Leffler 	*data++ = 0; /* SSID */
1312137fdb5SSam Leffler 	*data++ = strlen(p->ssid);
1322137fdb5SSam Leffler 	strcpy(data, p->ssid);
1332137fdb5SSam Leffler 	data += strlen(p->ssid);
1342137fdb5SSam Leffler 
1352137fdb5SSam Leffler 	*data++ = 1; /* rates */
1362137fdb5SSam Leffler 	*data++ = 4;
1372137fdb5SSam Leffler 	*data++ = 2 | 0x80;
1382137fdb5SSam Leffler 	*data++ = 4 | 0x80;
1392137fdb5SSam Leffler 	*data++ = 11;
1402137fdb5SSam Leffler 	*data++ = 22;
1412137fdb5SSam Leffler 
1422137fdb5SSam Leffler 	len = data - (char*)wh;
1432137fdb5SSam Leffler 
1442137fdb5SSam Leffler 	send_frame(p, buf, len);
1452137fdb5SSam Leffler }
1462137fdb5SSam Leffler 
send_auth(struct params * p)1472137fdb5SSam Leffler void send_auth(struct params *p)
1482137fdb5SSam Leffler {
1492137fdb5SSam Leffler 	char buf[2048];
1502137fdb5SSam Leffler 	struct ieee80211_frame *wh;
1512137fdb5SSam Leffler 	char *data;
1522137fdb5SSam Leffler 	int len;
1532137fdb5SSam Leffler 
1542137fdb5SSam Leffler 	memset(buf, 0, sizeof(buf));
1552137fdb5SSam Leffler 
1562137fdb5SSam Leffler 	wh = (struct ieee80211_frame*) buf;
1572137fdb5SSam Leffler 	fill_basic(wh, p);
1582137fdb5SSam Leffler 	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH;
1592137fdb5SSam Leffler 
1602137fdb5SSam Leffler 	data = (char*) (wh + 1);
1612137fdb5SSam Leffler 
1622137fdb5SSam Leffler 	/* algo */
1632137fdb5SSam Leffler 	*data++ = 0;
1642137fdb5SSam Leffler 	*data++ = 0;
1652137fdb5SSam Leffler 
1662137fdb5SSam Leffler 	/* transaction no. */
1672137fdb5SSam Leffler 	*data++ = 1;
1682137fdb5SSam Leffler 	*data++ = 0;
1692137fdb5SSam Leffler 
1702137fdb5SSam Leffler 	/* status code */
1712137fdb5SSam Leffler 	*data++ = 0;
1722137fdb5SSam Leffler 	*data++ = 0;
1732137fdb5SSam Leffler 
1742137fdb5SSam Leffler 	len = data - (char*)wh;
1752137fdb5SSam Leffler 
1762137fdb5SSam Leffler 	send_frame(p, buf, len);
1772137fdb5SSam Leffler }
1782137fdb5SSam Leffler 
1792137fdb5SSam Leffler /*
1802137fdb5SSam Leffler  * Add an ssid element to a frame.
1812137fdb5SSam Leffler  */
1822137fdb5SSam Leffler static u_int8_t *
ieee80211_add_ssid(u_int8_t * frm,const u_int8_t * ssid,u_int len)1832137fdb5SSam Leffler ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
1842137fdb5SSam Leffler {
1852137fdb5SSam Leffler 	*frm++ = IEEE80211_ELEMID_SSID;
1862137fdb5SSam Leffler 	*frm++ = len;
1872137fdb5SSam Leffler 	memcpy(frm, ssid, len);
1882137fdb5SSam Leffler 	return frm + len;
1892137fdb5SSam Leffler }
1902137fdb5SSam Leffler 
send_assoc(struct params * p)1912137fdb5SSam Leffler void send_assoc(struct params *p)
1922137fdb5SSam Leffler {
1932137fdb5SSam Leffler 	union {
1942137fdb5SSam Leffler 		struct ieee80211_frame w;
1952137fdb5SSam Leffler 		char buf[2048];
1962137fdb5SSam Leffler 	} u;
1972137fdb5SSam Leffler 	struct ieee80211_frame *wh;
1982137fdb5SSam Leffler 	char *data;
1992137fdb5SSam Leffler 	int len, capinfo, lintval;
2002137fdb5SSam Leffler 
2012137fdb5SSam Leffler 	memset(&u, 0, sizeof(u));
2022137fdb5SSam Leffler 
2032137fdb5SSam Leffler 	wh = (struct ieee80211_frame*) &u.w;
2042137fdb5SSam Leffler 	fill_basic(wh, p);
2052137fdb5SSam Leffler 	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
2062137fdb5SSam Leffler 
2072137fdb5SSam Leffler 	data = (char*) (wh + 1);
2082137fdb5SSam Leffler 
2092137fdb5SSam Leffler 	/* capability */
2102137fdb5SSam Leffler 	capinfo = IEEE80211_CAPINFO_ESS;
2112137fdb5SSam Leffler 	if (p->wep_len)
2122137fdb5SSam Leffler 		capinfo |= IEEE80211_CAPINFO_PRIVACY;
2132137fdb5SSam Leffler 	*(uint16_t *)data = htole16(capinfo);
2142137fdb5SSam Leffler 	data += 2;
2152137fdb5SSam Leffler 
2162137fdb5SSam Leffler 	/* listen interval */
2172137fdb5SSam Leffler 	*(uint16_t *)data = htole16(100);
2182137fdb5SSam Leffler 	data += 2;
2192137fdb5SSam Leffler 
2202137fdb5SSam Leffler 	data = ieee80211_add_ssid(data, p->ssid, strlen(p->ssid));
2212137fdb5SSam Leffler 
2222137fdb5SSam Leffler 	*data++ = 1; /* rates */
2232137fdb5SSam Leffler 	*data++ = 4;
2242137fdb5SSam Leffler 	*data++ = 2 | 0x80;
2252137fdb5SSam Leffler 	*data++ = 4 | 0x80;
2262137fdb5SSam Leffler 	*data++ = 11;
2272137fdb5SSam Leffler 	*data++ = 22;
2282137fdb5SSam Leffler 
2292137fdb5SSam Leffler 	len = data - (char*)wh;
2302137fdb5SSam Leffler 
2312137fdb5SSam Leffler 	send_frame(p, u.buf, len);
2322137fdb5SSam Leffler }
2332137fdb5SSam Leffler 
for_me(struct ieee80211_frame * wh,char * mac)2342137fdb5SSam Leffler int for_me(struct ieee80211_frame *wh, char *mac)
2352137fdb5SSam Leffler {
2362137fdb5SSam Leffler 	return memcmp(wh->i_addr1, mac, 6) == 0;
2372137fdb5SSam Leffler }
2382137fdb5SSam Leffler 
from_ap(struct ieee80211_frame * wh,char * mac)2392137fdb5SSam Leffler int from_ap(struct ieee80211_frame *wh, char *mac)
2402137fdb5SSam Leffler {
2412137fdb5SSam Leffler 	return memcmp(wh->i_addr2, mac, 6) == 0;
2422137fdb5SSam Leffler }
2432137fdb5SSam Leffler 
ack(struct params * p,struct ieee80211_frame * wh)2442137fdb5SSam Leffler void ack(struct params *p, struct ieee80211_frame *wh)
2452137fdb5SSam Leffler {
2462137fdb5SSam Leffler         if (memcmp(wh->i_addr1, p->mac, 6) != 0)
2472137fdb5SSam Leffler                 return;
2482137fdb5SSam Leffler 
2492137fdb5SSam Leffler         if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
2502137fdb5SSam Leffler                 return;
2512137fdb5SSam Leffler 
2522137fdb5SSam Leffler         send_ack(p->tx, wh->i_addr2);
2532137fdb5SSam Leffler }
2542137fdb5SSam Leffler 
generic_process(struct ieee80211_frame * wh,struct params * p,int len)2552137fdb5SSam Leffler void generic_process(struct ieee80211_frame *wh, struct params *p, int len)
2562137fdb5SSam Leffler {
2572137fdb5SSam Leffler 	int type, stype;
2582137fdb5SSam Leffler 	int dup = 0;
2592137fdb5SSam Leffler 
2602137fdb5SSam Leffler #if 0
2612137fdb5SSam Leffler 	ack(p, wh);
2622137fdb5SSam Leffler #endif
2632137fdb5SSam Leffler 
2642137fdb5SSam Leffler #if 0
2652137fdb5SSam Leffler 	if (!for_me(wh, p->mac))
2662137fdb5SSam Leffler 		return;
2672137fdb5SSam Leffler #endif
2682137fdb5SSam Leffler 	/* ignore my own shit */
2692137fdb5SSam Leffler 	if (memcmp(wh->i_addr2, p->mac, 6) == 0) {
2702137fdb5SSam Leffler 		return;
2712137fdb5SSam Leffler 	}
2722137fdb5SSam Leffler 
2732137fdb5SSam Leffler 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
2742137fdb5SSam Leffler 	stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
2752137fdb5SSam Leffler 
2762137fdb5SSam Leffler 	if (for_me(wh, p->mac) && type == IEEE80211_FC0_TYPE_DATA) {
2772137fdb5SSam Leffler 		/* sequence number & dups */
2782137fdb5SSam Leffler 		if (p->seq_rx == -1)
2792137fdb5SSam Leffler 			p->seq_rx = seqno(wh);
2802137fdb5SSam Leffler 		else {
2812137fdb5SSam Leffler 			int s = seqno(wh);
2822137fdb5SSam Leffler 
2832137fdb5SSam Leffler 			if (s > p->seq_rx) {
2842137fdb5SSam Leffler 				/* normal case */
2852137fdb5SSam Leffler 				if (p->seq_rx + 1 == s) {
2862137fdb5SSam Leffler #if 0
2872137fdb5SSam Leffler 					printf("S=%d\n", s);
2882137fdb5SSam Leffler #endif
2892137fdb5SSam Leffler 					p->seq_rx = s;
2902137fdb5SSam Leffler 				}
2912137fdb5SSam Leffler 				else { /* future */
2922137fdb5SSam Leffler #if 0
2932137fdb5SSam Leffler 					printf("Got seq %d, prev %d\n",
2942137fdb5SSam Leffler 					       s, p->seq_rx);
2952137fdb5SSam Leffler #endif
2962137fdb5SSam Leffler 					p->seq_rx = s;
2972137fdb5SSam Leffler 				}
2982137fdb5SSam Leffler 			} else { /* we got pas stuff... */
2992137fdb5SSam Leffler 				if (p->seq_rx - s > 1000) {
3002137fdb5SSam Leffler #if 0
3012137fdb5SSam Leffler 					printf("Seqno wrap seq %d, last %d\n",
3022137fdb5SSam Leffler 					       s, p->seq_rx);
3032137fdb5SSam Leffler #endif
3042137fdb5SSam Leffler 					/* seqno wrapping ? */
3052137fdb5SSam Leffler 					p->seq_rx = 0;
3062137fdb5SSam Leffler 				}
3072137fdb5SSam Leffler 				else { /* dup */
3082137fdb5SSam Leffler 					dup = 1;
3092137fdb5SSam Leffler #if 0
3102137fdb5SSam Leffler 					printf("Got dup seq %d, last %d\n",
3112137fdb5SSam Leffler 					       s, p->seq_rx);
3122137fdb5SSam Leffler #endif
3132137fdb5SSam Leffler 				}
3142137fdb5SSam Leffler 			}
3152137fdb5SSam Leffler 		}
3162137fdb5SSam Leffler 	}
3172137fdb5SSam Leffler #if 0
3182137fdb5SSam Leffler 	if (wh->i_fc[1] & IEEE80211_FC1_RETRY) {
3192137fdb5SSam Leffler 		printf("Got retry\n");
3202137fdb5SSam Leffler 	}
3212137fdb5SSam Leffler #endif
3222137fdb5SSam Leffler #if 0
3232137fdb5SSam Leffler 	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
3242137fdb5SSam Leffler 		int rc = send_ack(p->tx, wh->i_addr2);
3252137fdb5SSam Leffler 		if (rc == -1)
3262137fdb5SSam Leffler 			err(1, "send_ack()");
3272137fdb5SSam Leffler 		if (rc != 10) {
3282137fdb5SSam Leffler 			printf("Wrote ACK %d/%d\n", rc, 10);
3292137fdb5SSam Leffler 			exit(1);
3302137fdb5SSam Leffler 		}
3312137fdb5SSam Leffler 	}
3322137fdb5SSam Leffler #endif
3332137fdb5SSam Leffler 
3342137fdb5SSam Leffler 	/* data frames */
3352137fdb5SSam Leffler 	if (type == IEEE80211_FC0_TYPE_DATA && !dup) {
3362137fdb5SSam Leffler 		char *ptr;
3372137fdb5SSam Leffler 		char src[6], dst[6];
3382137fdb5SSam Leffler 		int rc;
3392137fdb5SSam Leffler 
3402137fdb5SSam Leffler 		if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
3412137fdb5SSam Leffler 			if (memcmp(wh->i_addr2, p->ap, 6) != 0)
3422137fdb5SSam Leffler 				return;
3432137fdb5SSam Leffler 		} else {
3442137fdb5SSam Leffler 			if (memcmp(wh->i_addr1, p->ap, 6) != 0)
3452137fdb5SSam Leffler 				return;
3462137fdb5SSam Leffler 		}
3472137fdb5SSam Leffler 
3482137fdb5SSam Leffler 
3492137fdb5SSam Leffler 		if (p->state < S_ASSOCIATED) {
3502137fdb5SSam Leffler 			printf("Got data when not associated!\n");
3512137fdb5SSam Leffler 			return;
3522137fdb5SSam Leffler 		}
3532137fdb5SSam Leffler 		if (stype != IEEE80211_FC0_SUBTYPE_DATA) {
3542137fdb5SSam Leffler 			printf("Got weird data frame stype=%d\n",
3552137fdb5SSam Leffler 			       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
3562137fdb5SSam Leffler 			return;
3572137fdb5SSam Leffler 		}
3582137fdb5SSam Leffler 
3592137fdb5SSam Leffler 		if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
3602137fdb5SSam Leffler 			memcpy(src, wh->i_addr3, 6);
3612137fdb5SSam Leffler 			memcpy(dst, wh->i_addr1, 6);
3622137fdb5SSam Leffler 		} else {
3632137fdb5SSam Leffler 			memcpy(src, wh->i_addr2, 6);
3642137fdb5SSam Leffler 			memcpy(dst, wh->i_addr3, 6);
3652137fdb5SSam Leffler 		}
3662137fdb5SSam Leffler 
3672137fdb5SSam Leffler 		ptr = (char*) (wh + 1);
3682137fdb5SSam Leffler 
369*5945b5f5SKevin Lo 		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
3702137fdb5SSam Leffler 			if (!p->wep_len) {
3712137fdb5SSam Leffler 				char srca[3*6];
3722137fdb5SSam Leffler 				char dsta[3*6];
3732137fdb5SSam Leffler 
3742137fdb5SSam Leffler 				mac2str(srca, src);
3752137fdb5SSam Leffler 				mac2str(dsta, dst);
3762137fdb5SSam Leffler 				printf("Got wep but i aint wep %s->%s %d\n",
3772137fdb5SSam Leffler 				       srca, dsta, len-sizeof(*wh)-8);
3782137fdb5SSam Leffler 				return;
3792137fdb5SSam Leffler 			}
3802137fdb5SSam Leffler 
3812137fdb5SSam Leffler 			if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){
3822137fdb5SSam Leffler 				char srca[3*6];
3832137fdb5SSam Leffler 				char dsta[3*6];
3842137fdb5SSam Leffler 
3852137fdb5SSam Leffler 				mac2str(srca, src);
3862137fdb5SSam Leffler 				mac2str(dsta, dst);
3872137fdb5SSam Leffler 				printf("Can't decrypt %s->%s %d\n", srca, dsta,
3882137fdb5SSam Leffler 				       len-sizeof(*wh)-8);
3892137fdb5SSam Leffler 				return;
3902137fdb5SSam Leffler 			}
3912137fdb5SSam Leffler 
3922137fdb5SSam Leffler 			ptr += 4;
3932137fdb5SSam Leffler 			len -= 8;
3942137fdb5SSam Leffler 		}
3952137fdb5SSam Leffler 
3962137fdb5SSam Leffler 		/* ether header */
3972137fdb5SSam Leffler 		ptr += 8 - 2;
3982137fdb5SSam Leffler 		ptr -= 6;
3992137fdb5SSam Leffler 		memcpy(ptr, src, 6);
4002137fdb5SSam Leffler 		ptr -= 6;
4012137fdb5SSam Leffler 		memcpy(ptr, dst, 6);
4022137fdb5SSam Leffler 
4032137fdb5SSam Leffler 		len -= sizeof(*wh);
4042137fdb5SSam Leffler 		len -= 8;
4052137fdb5SSam Leffler 		len += 14;
4062137fdb5SSam Leffler 
4072137fdb5SSam Leffler 		/* send to tap */
4082137fdb5SSam Leffler 		rc = write(p->tap, ptr, len);
4092137fdb5SSam Leffler 		if (rc == -1)
4102137fdb5SSam Leffler 			err(1, "write()");
4112137fdb5SSam Leffler 		if (rc != len) {
4122137fdb5SSam Leffler 			printf("Wrote %d/%d\n", rc, len);
4132137fdb5SSam Leffler 			exit(1);
4142137fdb5SSam Leffler 		}
4152137fdb5SSam Leffler 	}
4162137fdb5SSam Leffler }
4172137fdb5SSam Leffler 
get_probe_response(struct params * p)4182137fdb5SSam Leffler int get_probe_response(struct params *p)
4192137fdb5SSam Leffler {
4202137fdb5SSam Leffler 	char buf[4096];
4212137fdb5SSam Leffler 	int rc;
4222137fdb5SSam Leffler 	struct ieee80211_frame *wh;
4232137fdb5SSam Leffler 	char *data;
4242137fdb5SSam Leffler 	int ess;
4252137fdb5SSam Leffler 	int wep;
4262137fdb5SSam Leffler 	char *ssid;
4272137fdb5SSam Leffler 	char from[18];
4282137fdb5SSam Leffler 	char bssid[18];
4292137fdb5SSam Leffler 
4302137fdb5SSam Leffler 	rc = sniff(p->rx, buf, sizeof(buf));
4312137fdb5SSam Leffler 	if (rc == -1)
4322137fdb5SSam Leffler 		err(1, "sniff()");
4332137fdb5SSam Leffler 
4342137fdb5SSam Leffler 	wh = get_wifi(buf, &rc);
4352137fdb5SSam Leffler 	if (!wh)
4362137fdb5SSam Leffler 		return 0;
4372137fdb5SSam Leffler 
4382137fdb5SSam Leffler 	generic_process(wh, p, rc);
4392137fdb5SSam Leffler 
4402137fdb5SSam Leffler 	if (!for_me(wh, p->mac))
4412137fdb5SSam Leffler 		return 0;
4422137fdb5SSam Leffler 
4432137fdb5SSam Leffler 	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
4442137fdb5SSam Leffler 			IEEE80211_FC0_SUBTYPE_PROBE_RESP))
4452137fdb5SSam Leffler 		return 0;
4462137fdb5SSam Leffler 
4472137fdb5SSam Leffler 	data = (char*) (wh+1);
4482137fdb5SSam Leffler 	data += 8; /* Timestamp */
4492137fdb5SSam Leffler 	data += 2; /* Beacon Interval */
4502137fdb5SSam Leffler 	ess = *data & 1;
4512137fdb5SSam Leffler 	wep = (*data & IEEE80211_CAPINFO_PRIVACY) ? 1 : 0;
4522137fdb5SSam Leffler 	data += 2; /* capability */
4532137fdb5SSam Leffler 
4542137fdb5SSam Leffler 	/* ssid */
4552137fdb5SSam Leffler 	if (*data != 0) {
4562137fdb5SSam Leffler 		printf("Warning, expecting SSID got %x\n", *data);
4572137fdb5SSam Leffler 		return 0;
4582137fdb5SSam Leffler 	}
4592137fdb5SSam Leffler 	data++;
4602137fdb5SSam Leffler 	ssid = data+1;
4612137fdb5SSam Leffler 	data += 1 + *data;
4622137fdb5SSam Leffler 	if (*data != 1) {
4632137fdb5SSam Leffler 		printf("Warning, expected rates got %x\n", *data);
4642137fdb5SSam Leffler 		return 0;
4652137fdb5SSam Leffler 	}
4662137fdb5SSam Leffler 	*data = 0;
4672137fdb5SSam Leffler 
4682137fdb5SSam Leffler 	/* rates */
4692137fdb5SSam Leffler 	data++;
4702137fdb5SSam Leffler 
4712137fdb5SSam Leffler 	mac2str(from, wh->i_addr2);
4722137fdb5SSam Leffler 	mac2str(bssid, wh->i_addr3);
4732137fdb5SSam Leffler 	printf("Got response from %s [%s] [%s] ESS=%d WEP=%d\n",
4742137fdb5SSam Leffler 	       from, bssid, ssid, ess, wep);
4752137fdb5SSam Leffler 
4762137fdb5SSam Leffler 	if (strcmp(ssid, p->ssid) != 0)
4772137fdb5SSam Leffler 		return 0;
4782137fdb5SSam Leffler 
4792137fdb5SSam Leffler 	memcpy(p->ap, wh->i_addr2, 6);
4802137fdb5SSam Leffler 	memcpy(p->bssid, wh->i_addr3, 6);
4812137fdb5SSam Leffler 	return 1;
4822137fdb5SSam Leffler }
4832137fdb5SSam Leffler 
get_auth(struct params * p)4842137fdb5SSam Leffler int get_auth(struct params *p)
4852137fdb5SSam Leffler {
4862137fdb5SSam Leffler 	char buf[4096];
4872137fdb5SSam Leffler 	int rc;
4882137fdb5SSam Leffler 	struct ieee80211_frame *wh;
4892137fdb5SSam Leffler 	short *data;
4902137fdb5SSam Leffler 
4912137fdb5SSam Leffler 	rc = sniff(p->rx, buf, sizeof(buf));
4922137fdb5SSam Leffler 	if (rc == -1)
4932137fdb5SSam Leffler 		err(1, "sniff()");
4942137fdb5SSam Leffler 
4952137fdb5SSam Leffler 	wh = get_wifi(buf, &rc);
4962137fdb5SSam Leffler 	if (!wh)
4972137fdb5SSam Leffler 		return 0;
4982137fdb5SSam Leffler 
4992137fdb5SSam Leffler 	generic_process(wh, p, rc);
5002137fdb5SSam Leffler 
5012137fdb5SSam Leffler 	if (!for_me(wh, p->mac))
5022137fdb5SSam Leffler 		return 0;
5032137fdb5SSam Leffler 
5042137fdb5SSam Leffler 	if (!from_ap(wh, p->ap))
5052137fdb5SSam Leffler 		return 0;
5062137fdb5SSam Leffler 
5072137fdb5SSam Leffler 	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
5082137fdb5SSam Leffler 			IEEE80211_FC0_SUBTYPE_AUTH))
5092137fdb5SSam Leffler 		return 0;
5102137fdb5SSam Leffler 
5112137fdb5SSam Leffler 	data = (short*) (wh+1);
5122137fdb5SSam Leffler 
5132137fdb5SSam Leffler 	/* algo */
5142137fdb5SSam Leffler 	if (le16toh(*data) != 0) {
5152137fdb5SSam Leffler 		printf("Not open-system %d!\n", le16toh(*data));
5162137fdb5SSam Leffler 		return 0;
5172137fdb5SSam Leffler 	}
5182137fdb5SSam Leffler 	data++;
5192137fdb5SSam Leffler 
5202137fdb5SSam Leffler 	/* transaction no. */
5212137fdb5SSam Leffler 	if (le16toh(*data) != 2) {
5222137fdb5SSam Leffler 		printf("Got transaction %d!\n", le16toh(*data));
5232137fdb5SSam Leffler 		return 0;
5242137fdb5SSam Leffler 	}
5252137fdb5SSam Leffler 	data++;
5262137fdb5SSam Leffler 
5272137fdb5SSam Leffler 	/* status code */
5282137fdb5SSam Leffler 	rc = le16toh(*data);
5292137fdb5SSam Leffler 	if (rc == 0) {
5302137fdb5SSam Leffler 		printf("Authenticated\n");
5312137fdb5SSam Leffler 		return 1;
5322137fdb5SSam Leffler 	}
5332137fdb5SSam Leffler 
5342137fdb5SSam Leffler 	printf("Authentication failed code=%d\n", rc);
5352137fdb5SSam Leffler 	return 0;
5362137fdb5SSam Leffler }
5372137fdb5SSam Leffler 
get_assoc(struct params * p)5382137fdb5SSam Leffler int get_assoc(struct params *p)
5392137fdb5SSam Leffler {
5402137fdb5SSam Leffler 	char buf[4096];
5412137fdb5SSam Leffler 	int rc;
5422137fdb5SSam Leffler 	struct ieee80211_frame *wh;
5432137fdb5SSam Leffler 	unsigned short *data;
5442137fdb5SSam Leffler 
5452137fdb5SSam Leffler 	rc = sniff(p->rx, buf, sizeof(buf));
5462137fdb5SSam Leffler 	if (rc == -1)
5472137fdb5SSam Leffler 		err(1, "sniff()");
5482137fdb5SSam Leffler 
5492137fdb5SSam Leffler 	wh = get_wifi(buf, &rc);
5502137fdb5SSam Leffler 	if (!wh)
5512137fdb5SSam Leffler 		return 0;
5522137fdb5SSam Leffler 
5532137fdb5SSam Leffler 	generic_process(wh, p, rc);
5542137fdb5SSam Leffler 
5552137fdb5SSam Leffler 	if (!for_me(wh, p->mac))
5562137fdb5SSam Leffler 		return 0;
5572137fdb5SSam Leffler 
5582137fdb5SSam Leffler 	if (!from_ap(wh, p->ap))
5592137fdb5SSam Leffler 		return 0;
5602137fdb5SSam Leffler 
5612137fdb5SSam Leffler 	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
5622137fdb5SSam Leffler 			IEEE80211_FC0_SUBTYPE_ASSOC_RESP))
5632137fdb5SSam Leffler 		return 0;
5642137fdb5SSam Leffler 
5652137fdb5SSam Leffler 
5662137fdb5SSam Leffler 	data = (unsigned short*) (wh+1);
5672137fdb5SSam Leffler 
5682137fdb5SSam Leffler 	data++; /* caps */
5692137fdb5SSam Leffler 
5702137fdb5SSam Leffler 	/* status */
5712137fdb5SSam Leffler 	rc = le16toh(*data++);
5722137fdb5SSam Leffler 	if (rc != 0) {
5732137fdb5SSam Leffler 		printf("Assoc failed code %d\n", rc);
5742137fdb5SSam Leffler 		return 0;
5752137fdb5SSam Leffler 	}
5762137fdb5SSam Leffler 
5772137fdb5SSam Leffler 	/* aid */
5782137fdb5SSam Leffler 	p->aid = le16toh(*data & ~( (1 << 15) | (1 << 14)));
5792137fdb5SSam Leffler 	printf("Association ID=%d\n", p->aid);
5802137fdb5SSam Leffler 
5812137fdb5SSam Leffler 	return 1;
5822137fdb5SSam Leffler }
5832137fdb5SSam Leffler 
read_wifi(struct params * p)5842137fdb5SSam Leffler void read_wifi(struct params *p)
5852137fdb5SSam Leffler {
5862137fdb5SSam Leffler 	char buf[4096];
5872137fdb5SSam Leffler 	int rc;
5882137fdb5SSam Leffler 	struct ieee80211_frame *wh;
5892137fdb5SSam Leffler 	int type, stype;
5902137fdb5SSam Leffler 
5912137fdb5SSam Leffler 	rc = sniff(p->rx, buf, sizeof(buf));
5922137fdb5SSam Leffler 	if (rc == -1)
5932137fdb5SSam Leffler 		err(1, "sniff()");
5942137fdb5SSam Leffler 
5952137fdb5SSam Leffler 	wh = get_wifi(buf, &rc);
5962137fdb5SSam Leffler 	if (!wh)
5972137fdb5SSam Leffler 		return;
5982137fdb5SSam Leffler 
5992137fdb5SSam Leffler 	generic_process(wh, p, rc);
6002137fdb5SSam Leffler 
6012137fdb5SSam Leffler 	if (!for_me(wh, p->mac))
6022137fdb5SSam Leffler 		return;
6032137fdb5SSam Leffler 
6042137fdb5SSam Leffler 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
6052137fdb5SSam Leffler 	stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
6062137fdb5SSam Leffler 
6072137fdb5SSam Leffler 	/* control frames */
6082137fdb5SSam Leffler 	if (type == IEEE80211_FC0_TYPE_CTL) {
6092137fdb5SSam Leffler 		switch (stype) {
6102137fdb5SSam Leffler 		case IEEE80211_FC0_SUBTYPE_ACK:
6112137fdb5SSam Leffler 			if (p->state == S_WAIT_ACK)
6122137fdb5SSam Leffler 				p->state = S_ASSOCIATED;
6132137fdb5SSam Leffler 			break;
6142137fdb5SSam Leffler 
6152137fdb5SSam Leffler 		case IEEE80211_FC0_SUBTYPE_RTS:
6162137fdb5SSam Leffler #if 0
6172137fdb5SSam Leffler 			printf("Got RTS\n");
6182137fdb5SSam Leffler #endif
6192137fdb5SSam Leffler 			break;
6202137fdb5SSam Leffler 
6212137fdb5SSam Leffler 		default:
6222137fdb5SSam Leffler 			printf("Unknown CTL frame %d\n",
6232137fdb5SSam Leffler 			       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
6242137fdb5SSam Leffler 			abort();
6252137fdb5SSam Leffler 			break;
6262137fdb5SSam Leffler 		}
6272137fdb5SSam Leffler 		return;
6282137fdb5SSam Leffler 	}
6292137fdb5SSam Leffler 
6302137fdb5SSam Leffler 	if (!from_ap(wh, p->ap))
6312137fdb5SSam Leffler 		return;
6322137fdb5SSam Leffler 
6332137fdb5SSam Leffler 	if (type != IEEE80211_FC0_TYPE_MGT)
6342137fdb5SSam Leffler 		return;
6352137fdb5SSam Leffler 
6362137fdb5SSam Leffler 	if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
6372137fdb5SSam Leffler 	    stype == IEEE80211_FC0_SUBTYPE_DISASSOC) {
6382137fdb5SSam Leffler 		printf("Got management! %d\n",
6392137fdb5SSam Leffler 		       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
6402137fdb5SSam Leffler 		p->seq_rx = -1;
6412137fdb5SSam Leffler 		p->state = S_START;
6422137fdb5SSam Leffler 	}
6432137fdb5SSam Leffler 
6442137fdb5SSam Leffler 	return;
6452137fdb5SSam Leffler }
6462137fdb5SSam Leffler 
read_tap(struct params * p)6472137fdb5SSam Leffler void read_tap(struct params *p)
6482137fdb5SSam Leffler {
6492137fdb5SSam Leffler 	char *ptr;
6502137fdb5SSam Leffler 	int len = sizeof(p->packet);
6512137fdb5SSam Leffler 	int offset;
6522137fdb5SSam Leffler 	char mac[6];
6532137fdb5SSam Leffler 	struct ieee80211_frame *wh;
6542137fdb5SSam Leffler 
6552137fdb5SSam Leffler 	ptr = p->packet;
6562137fdb5SSam Leffler 	offset = sizeof(struct ieee80211_frame) + 8 - 14;
6572137fdb5SSam Leffler 	if (p->wep_len)
6582137fdb5SSam Leffler 		offset += 4;
6592137fdb5SSam Leffler 
6602137fdb5SSam Leffler 	ptr += offset;
6612137fdb5SSam Leffler 	len -= offset;
6622137fdb5SSam Leffler 
6632137fdb5SSam Leffler 	/* read packet */
6642137fdb5SSam Leffler 	memset(p->packet, 0, sizeof(p->packet));
6652137fdb5SSam Leffler 	p->packet_len = read(p->tap, ptr, len);
6662137fdb5SSam Leffler 	if (p->packet_len == -1)
6672137fdb5SSam Leffler 		err(1, "read()");
6682137fdb5SSam Leffler 
6692137fdb5SSam Leffler 	/* 802.11 header */
6702137fdb5SSam Leffler 	wh = (struct ieee80211_frame*) p->packet;
6712137fdb5SSam Leffler 	memcpy(mac, ptr, sizeof(mac));
6722137fdb5SSam Leffler 	fill_basic(wh, p);
6732137fdb5SSam Leffler 	memcpy(wh->i_addr3, mac, sizeof(wh->i_addr3));
6742137fdb5SSam Leffler 	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
6752137fdb5SSam Leffler 	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
6762137fdb5SSam Leffler 	if (p->wep_len)
677*5945b5f5SKevin Lo 		wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
6782137fdb5SSam Leffler 
6792137fdb5SSam Leffler 	/* LLC & SNAP */
6802137fdb5SSam Leffler 	ptr = (char*) (wh+1);
6812137fdb5SSam Leffler 	if (p->wep_len)
6822137fdb5SSam Leffler 		ptr += 4;
6832137fdb5SSam Leffler 	*ptr++ = 0xAA;
6842137fdb5SSam Leffler 	*ptr++ = 0xAA;
6852137fdb5SSam Leffler 	*ptr++ = 0x03;
6862137fdb5SSam Leffler 	*ptr++ = 0x00;
6872137fdb5SSam Leffler 	*ptr++ = 0x00;
6882137fdb5SSam Leffler 	*ptr++ = 0x00;
6892137fdb5SSam Leffler 	/* ether type overlaps w00t */
6902137fdb5SSam Leffler 
6912137fdb5SSam Leffler 	p->packet_len += offset;
6922137fdb5SSam Leffler 
6932137fdb5SSam Leffler 	/* WEP */
6942137fdb5SSam Leffler 	if (p->wep_len) {
6952137fdb5SSam Leffler 		ptr = (char*) (wh+1);
6962137fdb5SSam Leffler 		memcpy(ptr, &p->wep_iv, 3);
6972137fdb5SSam Leffler 		ptr[3] = 0;
6982137fdb5SSam Leffler 		p->wep_iv++;
6992137fdb5SSam Leffler 
7002137fdb5SSam Leffler 		wep_encrypt(wh, p->packet_len, p->wep_key, p->wep_len);
7012137fdb5SSam Leffler 		p->packet_len += 4; /* ICV */
7022137fdb5SSam Leffler 	}
7032137fdb5SSam Leffler }
7042137fdb5SSam Leffler 
main(int argc,char * argv[])7052137fdb5SSam Leffler int main(int argc, char *argv[])
7062137fdb5SSam Leffler {
7072137fdb5SSam Leffler 	char* ssid = 0;
7082137fdb5SSam Leffler 	char mac[] = { 0x00, 0x00, 0xde, 0xfa, 0xce, 0xd };
7092137fdb5SSam Leffler 	int ch;
7102137fdb5SSam Leffler 	struct params p;
7112c4e7faeSSam Leffler 	char *iface = "wlan0";
7122137fdb5SSam Leffler 	char *tap = "tap0";
7132137fdb5SSam Leffler 	int timeout = 50*1000;
7142137fdb5SSam Leffler 	struct timeval start;
7152137fdb5SSam Leffler 
7162137fdb5SSam Leffler 	memset(&p, 0, sizeof(p));
7172137fdb5SSam Leffler 	p.wep_len = 0;
7182137fdb5SSam Leffler 	p.wep_iv = 0;
7192137fdb5SSam Leffler 	p.state = S_START;
7202137fdb5SSam Leffler 
7212137fdb5SSam Leffler 	while ((ch = getopt(argc, argv, "hm:s:i:w:t:b:")) != -1) {
7222137fdb5SSam Leffler 		switch (ch) {
7232137fdb5SSam Leffler 		case 'b':
7242137fdb5SSam Leffler 			if (str2mac(p.bssid, optarg)) {
7252137fdb5SSam Leffler 				printf("Error parsing BSSID\n");
7262137fdb5SSam Leffler 				exit(1);
7272137fdb5SSam Leffler 			}
7282137fdb5SSam Leffler 			memcpy(p.ap, p.bssid, sizeof(p.ap));
7292137fdb5SSam Leffler 			p.state = S_SEND_AUTH;
7302137fdb5SSam Leffler 			break;
7312137fdb5SSam Leffler 
7322137fdb5SSam Leffler 		case 's':
7332137fdb5SSam Leffler 			ssid = optarg;
7342137fdb5SSam Leffler 			break;
7352137fdb5SSam Leffler 
7362137fdb5SSam Leffler 		case 'm':
7372137fdb5SSam Leffler 			if (str2mac(mac, optarg)) {
7382137fdb5SSam Leffler 				printf("Error parsing MAC\n");
7392137fdb5SSam Leffler 				exit(1);
7402137fdb5SSam Leffler 			}
7412137fdb5SSam Leffler 			break;
7422137fdb5SSam Leffler 
7432137fdb5SSam Leffler 		case 'i':
7442137fdb5SSam Leffler 			iface = optarg;
7452137fdb5SSam Leffler 			break;
7462137fdb5SSam Leffler 
7472137fdb5SSam Leffler 		case 'w':
7482137fdb5SSam Leffler 			if (str2wep(p.wep_key, &p.wep_len, optarg)) {
7492137fdb5SSam Leffler 				printf("Error parsing WEP key\n");
7502137fdb5SSam Leffler 				exit(1);
7512137fdb5SSam Leffler 			}
7522137fdb5SSam Leffler 			break;
7532137fdb5SSam Leffler 
7542137fdb5SSam Leffler 		case 't':
7552137fdb5SSam Leffler 			tap = optarg;
7562137fdb5SSam Leffler 			break;
7572137fdb5SSam Leffler 
7582137fdb5SSam Leffler 		case 'h':
7592137fdb5SSam Leffler 		default:
7602137fdb5SSam Leffler 			usage(argv[0]);
7612137fdb5SSam Leffler 			break;
7622137fdb5SSam Leffler 		}
7632137fdb5SSam Leffler 	}
7642137fdb5SSam Leffler 
7652137fdb5SSam Leffler 	if (!ssid)
7662137fdb5SSam Leffler 		usage(argv[0]);
7672137fdb5SSam Leffler 
7682137fdb5SSam Leffler 	p.mac = mac;
7692137fdb5SSam Leffler 	p.ssid = ssid;
7702137fdb5SSam Leffler 	p.seq = getpid();
7712137fdb5SSam Leffler 	p.seq_rx = -1;
7722137fdb5SSam Leffler 	if (open_rxtx(iface, &p.rx, &p.tx) == -1)
7732137fdb5SSam Leffler 		err(1, "open_rxtx()");
7742137fdb5SSam Leffler 	p.tap = open_tap(tap);
7752137fdb5SSam Leffler 	if (p.tap == -1)
7762137fdb5SSam Leffler 		err(1, "open_tap()");
7772137fdb5SSam Leffler 	if (set_iface_mac(tap, mac) == -1)
7782137fdb5SSam Leffler 		err(1, "set_iface_mac()");
7792137fdb5SSam Leffler 
7802137fdb5SSam Leffler 	while (1) {
7812137fdb5SSam Leffler 		/* check for timeouts */
7822137fdb5SSam Leffler 		switch (p.state) {
7832137fdb5SSam Leffler 		case S_WAIT_PROBE_RES:
7842137fdb5SSam Leffler 		case S_WAIT_AUTH:
7852137fdb5SSam Leffler 		case S_WAIT_ASSOC:
7862137fdb5SSam Leffler 		case S_WAIT_ACK:
7872137fdb5SSam Leffler 			do {
7882137fdb5SSam Leffler 				int rc;
7892137fdb5SSam Leffler 				struct timeval tv;
7902137fdb5SSam Leffler 				int elapsed = 0;
7912137fdb5SSam Leffler 
7922137fdb5SSam Leffler 				/* check timeout */
7932137fdb5SSam Leffler 				if (gettimeofday(&tv, NULL) == -1)
7942137fdb5SSam Leffler 					err(1, "gettimeofday()");
7952137fdb5SSam Leffler 				elapsed = tv.tv_sec - start.tv_sec;
7962137fdb5SSam Leffler 				if (elapsed == 0) {
7972137fdb5SSam Leffler 					elapsed = tv.tv_usec - start.tv_usec;
7982137fdb5SSam Leffler 				} else {
7992137fdb5SSam Leffler 					elapsed *= (elapsed-1)*1000*1000;
8002137fdb5SSam Leffler 					elapsed += 1000*1000 - start.tv_usec;
8012137fdb5SSam Leffler 					elapsed += tv.tv_usec;
8022137fdb5SSam Leffler 				}
8032137fdb5SSam Leffler 				if (elapsed >= timeout)
8042137fdb5SSam Leffler 					rc = 0;
8052137fdb5SSam Leffler 				else {
8062137fdb5SSam Leffler 					fd_set fds;
8072137fdb5SSam Leffler 
8082137fdb5SSam Leffler 					FD_ZERO(&fds);
8092137fdb5SSam Leffler 					FD_SET(p.rx, &fds);
8102137fdb5SSam Leffler 
8112137fdb5SSam Leffler 					elapsed = timeout - elapsed;
8122137fdb5SSam Leffler 					tv.tv_sec = elapsed/1000/1000;
8132137fdb5SSam Leffler 					elapsed -= tv.tv_sec*1000*1000;
8142137fdb5SSam Leffler 					tv.tv_usec = elapsed;
8152137fdb5SSam Leffler 
8162137fdb5SSam Leffler 					rc = select(p.rx+1, &fds, NULL,
8172137fdb5SSam Leffler 						    NULL, &tv);
8182137fdb5SSam Leffler 					if (rc == -1)
8192137fdb5SSam Leffler 						err(1, "select()");
8202137fdb5SSam Leffler 				}
8212137fdb5SSam Leffler 
8222137fdb5SSam Leffler 				/* timeout */
8232137fdb5SSam Leffler 				if (!rc) {
8242137fdb5SSam Leffler #if 0
8252137fdb5SSam Leffler 					printf("Timeout\n");
8262137fdb5SSam Leffler #endif
8272137fdb5SSam Leffler 					p.state--;
8282137fdb5SSam Leffler 				}
8292137fdb5SSam Leffler 
8302137fdb5SSam Leffler 			} while(0);
8312137fdb5SSam Leffler 			break;
8322137fdb5SSam Leffler 		}
8332137fdb5SSam Leffler 
8342137fdb5SSam Leffler 		switch (p.state) {
8352137fdb5SSam Leffler 		case S_START:
8362137fdb5SSam Leffler 			p.state = S_SEND_PROBE_REQ;
8372137fdb5SSam Leffler 			break;
8382137fdb5SSam Leffler 
8392137fdb5SSam Leffler 		case S_SEND_PROBE_REQ:
8402137fdb5SSam Leffler 			printf("Sending probe request for %s\n", ssid);
8412137fdb5SSam Leffler 			send_probe_request(&p);
8422137fdb5SSam Leffler 			p.state = S_WAIT_PROBE_RES;
8432137fdb5SSam Leffler 			if (gettimeofday(&start, NULL) == -1)
8442137fdb5SSam Leffler 				err(1, "gettimeofday()");
8452137fdb5SSam Leffler 			break;
8462137fdb5SSam Leffler 
8472137fdb5SSam Leffler 		case S_WAIT_PROBE_RES:
8482137fdb5SSam Leffler 			if (get_probe_response(&p)) {
8492137fdb5SSam Leffler 				p.state = S_SEND_AUTH;
8502137fdb5SSam Leffler 			}
8512137fdb5SSam Leffler 			break;
8522137fdb5SSam Leffler 
8532137fdb5SSam Leffler 		case S_SEND_AUTH:
8542137fdb5SSam Leffler 			do {
8552137fdb5SSam Leffler 				char apmac[18];
8562137fdb5SSam Leffler 
8572137fdb5SSam Leffler 				mac2str(apmac, p.ap);
8582137fdb5SSam Leffler 				printf("Sending auth to %s\n", apmac);
8592137fdb5SSam Leffler 				send_auth(&p);
8602137fdb5SSam Leffler 				p.state = S_WAIT_AUTH;
8612137fdb5SSam Leffler 				if (gettimeofday(&start, NULL) == -1)
8622137fdb5SSam Leffler 					err(1, "gettimeofday()");
8632137fdb5SSam Leffler 			} while(0);
8642137fdb5SSam Leffler 			break;
8652137fdb5SSam Leffler 
8662137fdb5SSam Leffler 		case S_WAIT_AUTH:
8672137fdb5SSam Leffler 			if (get_auth(&p)) {
8682137fdb5SSam Leffler 				p.state = S_SEND_ASSOC;
8692137fdb5SSam Leffler 			}
8702137fdb5SSam Leffler 			break;
8712137fdb5SSam Leffler 
8722137fdb5SSam Leffler 		case S_SEND_ASSOC:
8732137fdb5SSam Leffler 			printf("Sending assoc\n");
8742137fdb5SSam Leffler 			send_assoc(&p);
8752137fdb5SSam Leffler 			p.state = S_WAIT_ASSOC;
8762137fdb5SSam Leffler 			if (gettimeofday(&start, NULL) == -1)
8772137fdb5SSam Leffler 				err(1, "gettimeofday()");
8782137fdb5SSam Leffler 			break;
8792137fdb5SSam Leffler 
8802137fdb5SSam Leffler 		case S_WAIT_ASSOC:
8812137fdb5SSam Leffler 			if (get_assoc(&p)) {
8822137fdb5SSam Leffler 				printf("Associated\n");
8832137fdb5SSam Leffler 				p.state = S_ASSOCIATED;
8842137fdb5SSam Leffler 			}
8852137fdb5SSam Leffler 			break;
8862137fdb5SSam Leffler 
8872137fdb5SSam Leffler 		case S_ASSOCIATED:
8882137fdb5SSam Leffler 			do {
8892137fdb5SSam Leffler 				fd_set fds;
8902137fdb5SSam Leffler 				int max;
8912137fdb5SSam Leffler 
8922137fdb5SSam Leffler 				FD_ZERO(&fds);
8932137fdb5SSam Leffler 				FD_SET(p.rx, &fds);
8942137fdb5SSam Leffler 				FD_SET(p.tap, &fds);
8952137fdb5SSam Leffler 				max = (p.rx > p.tap) ? p.rx : p.tap;
8962137fdb5SSam Leffler 
8972137fdb5SSam Leffler 				max = select(max+1, &fds, NULL, NULL, NULL);
8982137fdb5SSam Leffler 				if (max == -1)
8992137fdb5SSam Leffler 					err(1, "select()");
9002137fdb5SSam Leffler 
9012137fdb5SSam Leffler 				if (FD_ISSET(p.tap, &fds)) {
9022137fdb5SSam Leffler 					read_tap(&p);
9032137fdb5SSam Leffler 					p.state = S_SEND_DATA;
9042137fdb5SSam Leffler 				}
9052137fdb5SSam Leffler 				if (FD_ISSET(p.rx, &fds)) {
9062137fdb5SSam Leffler 					read_wifi(&p);
9072137fdb5SSam Leffler 				}
9082137fdb5SSam Leffler 			} while(0);
9092137fdb5SSam Leffler 			break;
9102137fdb5SSam Leffler 
9112137fdb5SSam Leffler 		case S_SEND_DATA:
9122137fdb5SSam Leffler 			send_frame(&p, p.packet, p.packet_len);
9132137fdb5SSam Leffler 			do {
9142137fdb5SSam Leffler 				struct ieee80211_frame *wh;
9152137fdb5SSam Leffler 
9162137fdb5SSam Leffler 				wh = (struct ieee80211_frame*) p.packet;
9172137fdb5SSam Leffler 				wh->i_fc[1] |= IEEE80211_FC1_RETRY;
9182137fdb5SSam Leffler 			} while (0);
9192137fdb5SSam Leffler 			p.state = S_WAIT_ACK;
9202137fdb5SSam Leffler 			if (gettimeofday(&start, NULL) == -1)
9212137fdb5SSam Leffler 				err(1, "gettimeofday()");
9222137fdb5SSam Leffler 			break;
9232137fdb5SSam Leffler 
9242137fdb5SSam Leffler 		case S_WAIT_ACK:
9252137fdb5SSam Leffler 			read_wifi(&p);
9262137fdb5SSam Leffler 			break;
9272137fdb5SSam Leffler 
9282137fdb5SSam Leffler 		default:
9292137fdb5SSam Leffler 			printf("Unknown state %d\n", p.state);
9302137fdb5SSam Leffler 			abort();
9312137fdb5SSam Leffler 			break;
9322137fdb5SSam Leffler 		}
9332137fdb5SSam Leffler 	}
9342137fdb5SSam Leffler 
9352137fdb5SSam Leffler 	exit(0);
9362137fdb5SSam Leffler }
937