assoc.c revision 262007
1/*-
2 * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
13 *
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
24 * SUCH DAMAGE.
25 *
26 * $FreeBSD: stable/10/tools/tools/net80211/w00t/assoc/assoc.c 262007 2014-02-17 01:36:53Z kevlo $
27 */
28#include <sys/time.h>
29#include <stdlib.h>
30#include <stdio.h>
31#include <unistd.h>
32#include <string.h>
33#include <errno.h>
34#include <err.h>
35#include <net80211/ieee80211.h>
36#include <sys/endian.h>
37#include "w00t.h"
38
39enum {
40	S_START = 0,
41	S_SEND_PROBE_REQ,
42	S_WAIT_PROBE_RES,
43	S_SEND_AUTH,
44	S_WAIT_AUTH,
45	S_SEND_ASSOC,
46	S_WAIT_ASSOC,
47	S_ASSOCIATED,
48	S_SEND_DATA,
49	S_WAIT_ACK
50};
51
52struct params {
53	int seq;
54	int seq_rx;
55	char *mac;
56	char *ssid;
57	char bssid[6];
58	char ap[6];
59	int tx;
60	int rx;
61	int tap;
62	int aid;
63	char packet[4096];
64	int packet_len;
65	int state;
66	char wep_key[13];
67	int wep_iv;
68	int wep_len;
69};
70
71void usage(char *pname)
72{
73	printf("Usage: %s <opts>\n"
74		"-m\t<source mac>\n"
75		"-s\t<ssid>\n"
76		"-h\tusage\n"
77		"-i\t<iface>\n"
78		"-w\t<wep key>\n"
79		"-t\t<tap>\n"
80		"-b\t<bssid>\n"
81		, pname);
82	exit(0);
83}
84
85void fill_basic(struct ieee80211_frame *wh, struct params *p)
86{
87	short *seq;
88
89	wh->i_dur[0] = 0x69;
90	wh->i_dur[1] = 0x00;
91
92	memcpy(wh->i_addr1, p->ap, 6);
93	memcpy(wh->i_addr2, p->mac, 6);
94	memcpy(wh->i_addr3, p->bssid, 6);
95
96	seq = (short*)wh->i_seq;
97	*seq = seqfn(p->seq, 0);
98}
99
100void send_frame(struct params *p, void *buf, int len)
101{
102	int rc;
103
104	rc = inject(p->tx, buf, len);
105	if (rc == -1) {
106		if (errno == EMSGSIZE)
107			warnx("inject(len %d)", len);
108		else
109			err(1, "inject(len %d)", len);
110	} else if (rc != len)
111		errx(1, "injected %d but only %d sent", rc, len);
112	p->seq++;
113}
114
115void send_probe_request(struct params *p)
116{
117	char buf[2048];
118	struct ieee80211_frame *wh;
119	char *data;
120	int len;
121
122	memset(buf, 0, sizeof(buf));
123
124	wh = (struct ieee80211_frame*) buf;
125	fill_basic(wh, p);
126	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ;
127
128	memset(wh->i_addr1, 0xFF, 6);
129	memset(wh->i_addr3, 0xFF, 6);
130
131	data = (char*) (wh + 1);
132	*data++ = 0; /* SSID */
133	*data++ = strlen(p->ssid);
134	strcpy(data, p->ssid);
135	data += strlen(p->ssid);
136
137	*data++ = 1; /* rates */
138	*data++ = 4;
139	*data++ = 2 | 0x80;
140	*data++ = 4 | 0x80;
141	*data++ = 11;
142	*data++ = 22;
143
144	len = data - (char*)wh;
145
146	send_frame(p, buf, len);
147}
148
149void send_auth(struct params *p)
150{
151	char buf[2048];
152	struct ieee80211_frame *wh;
153	char *data;
154	int len;
155
156	memset(buf, 0, sizeof(buf));
157
158	wh = (struct ieee80211_frame*) buf;
159	fill_basic(wh, p);
160	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH;
161
162	data = (char*) (wh + 1);
163
164	/* algo */
165	*data++ = 0;
166	*data++ = 0;
167
168	/* transaction no. */
169	*data++ = 1;
170	*data++ = 0;
171
172	/* status code */
173	*data++ = 0;
174	*data++ = 0;
175
176	len = data - (char*)wh;
177
178	send_frame(p, buf, len);
179}
180
181/*
182 * Add an ssid element to a frame.
183 */
184static u_int8_t *
185ieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
186{
187	*frm++ = IEEE80211_ELEMID_SSID;
188	*frm++ = len;
189	memcpy(frm, ssid, len);
190	return frm + len;
191}
192
193void send_assoc(struct params *p)
194{
195	union {
196		struct ieee80211_frame w;
197		char buf[2048];
198	} u;
199	struct ieee80211_frame *wh;
200	char *data;
201	int len, capinfo, lintval;
202
203	memset(&u, 0, sizeof(u));
204
205	wh = (struct ieee80211_frame*) &u.w;
206	fill_basic(wh, p);
207	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
208
209	data = (char*) (wh + 1);
210
211	/* capability */
212	capinfo = IEEE80211_CAPINFO_ESS;
213	if (p->wep_len)
214		capinfo |= IEEE80211_CAPINFO_PRIVACY;
215	*(uint16_t *)data = htole16(capinfo);
216	data += 2;
217
218	/* listen interval */
219	*(uint16_t *)data = htole16(100);
220	data += 2;
221
222	data = ieee80211_add_ssid(data, p->ssid, strlen(p->ssid));
223
224	*data++ = 1; /* rates */
225	*data++ = 4;
226	*data++ = 2 | 0x80;
227	*data++ = 4 | 0x80;
228	*data++ = 11;
229	*data++ = 22;
230
231	len = data - (char*)wh;
232
233	send_frame(p, u.buf, len);
234}
235
236int for_me(struct ieee80211_frame *wh, char *mac)
237{
238	return memcmp(wh->i_addr1, mac, 6) == 0;
239}
240
241int from_ap(struct ieee80211_frame *wh, char *mac)
242{
243	return memcmp(wh->i_addr2, mac, 6) == 0;
244}
245
246void ack(struct params *p, struct ieee80211_frame *wh)
247{
248        if (memcmp(wh->i_addr1, p->mac, 6) != 0)
249                return;
250
251        if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
252                return;
253
254        send_ack(p->tx, wh->i_addr2);
255}
256
257void generic_process(struct ieee80211_frame *wh, struct params *p, int len)
258{
259	int type, stype;
260	int dup = 0;
261
262#if 0
263	ack(p, wh);
264#endif
265
266#if 0
267	if (!for_me(wh, p->mac))
268		return;
269#endif
270	/* ignore my own shit */
271	if (memcmp(wh->i_addr2, p->mac, 6) == 0) {
272		return;
273	}
274
275	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
276	stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
277
278	if (for_me(wh, p->mac) && type == IEEE80211_FC0_TYPE_DATA) {
279		/* sequence number & dups */
280		if (p->seq_rx == -1)
281			p->seq_rx = seqno(wh);
282		else {
283			int s = seqno(wh);
284
285			if (s > p->seq_rx) {
286				/* normal case */
287				if (p->seq_rx + 1 == s) {
288#if 0
289					printf("S=%d\n", s);
290#endif
291					p->seq_rx = s;
292				}
293				else { /* future */
294#if 0
295					printf("Got seq %d, prev %d\n",
296					       s, p->seq_rx);
297#endif
298					p->seq_rx = s;
299				}
300			} else { /* we got pas stuff... */
301				if (p->seq_rx - s > 1000) {
302#if 0
303					printf("Seqno wrap seq %d, last %d\n",
304					       s, p->seq_rx);
305#endif
306					/* seqno wrapping ? */
307					p->seq_rx = 0;
308				}
309				else { /* dup */
310					dup = 1;
311#if 0
312					printf("Got dup seq %d, last %d\n",
313					       s, p->seq_rx);
314#endif
315				}
316			}
317		}
318	}
319#if 0
320	if (wh->i_fc[1] & IEEE80211_FC1_RETRY) {
321		printf("Got retry\n");
322	}
323#endif
324#if 0
325	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
326		int rc = send_ack(p->tx, wh->i_addr2);
327		if (rc == -1)
328			err(1, "send_ack()");
329		if (rc != 10) {
330			printf("Wrote ACK %d/%d\n", rc, 10);
331			exit(1);
332		}
333	}
334#endif
335
336	/* data frames */
337	if (type == IEEE80211_FC0_TYPE_DATA && !dup) {
338		char *ptr;
339		char src[6], dst[6];
340		int rc;
341
342		if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
343			if (memcmp(wh->i_addr2, p->ap, 6) != 0)
344				return;
345		} else {
346			if (memcmp(wh->i_addr1, p->ap, 6) != 0)
347				return;
348		}
349
350
351		if (p->state < S_ASSOCIATED) {
352			printf("Got data when not associated!\n");
353			return;
354		}
355		if (stype != IEEE80211_FC0_SUBTYPE_DATA) {
356			printf("Got weird data frame stype=%d\n",
357			       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
358			return;
359		}
360
361		if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
362			memcpy(src, wh->i_addr3, 6);
363			memcpy(dst, wh->i_addr1, 6);
364		} else {
365			memcpy(src, wh->i_addr2, 6);
366			memcpy(dst, wh->i_addr3, 6);
367		}
368
369		ptr = (char*) (wh + 1);
370
371		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
372			if (!p->wep_len) {
373				char srca[3*6];
374				char dsta[3*6];
375
376				mac2str(srca, src);
377				mac2str(dsta, dst);
378				printf("Got wep but i aint wep %s->%s %d\n",
379				       srca, dsta, len-sizeof(*wh)-8);
380				return;
381			}
382
383			if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){
384				char srca[3*6];
385				char dsta[3*6];
386
387				mac2str(srca, src);
388				mac2str(dsta, dst);
389				printf("Can't decrypt %s->%s %d\n", srca, dsta,
390				       len-sizeof(*wh)-8);
391				return;
392			}
393
394			ptr += 4;
395			len -= 8;
396		}
397
398		/* ether header */
399		ptr += 8 - 2;
400		ptr -= 6;
401		memcpy(ptr, src, 6);
402		ptr -= 6;
403		memcpy(ptr, dst, 6);
404
405		len -= sizeof(*wh);
406		len -= 8;
407		len += 14;
408
409		/* send to tap */
410		rc = write(p->tap, ptr, len);
411		if (rc == -1)
412			err(1, "write()");
413		if (rc != len) {
414			printf("Wrote %d/%d\n", rc, len);
415			exit(1);
416		}
417	}
418}
419
420int get_probe_response(struct params *p)
421{
422	char buf[4096];
423	int rc;
424	struct ieee80211_frame *wh;
425	char *data;
426	int ess;
427	int wep;
428	char *ssid;
429	char from[18];
430	char bssid[18];
431
432	rc = sniff(p->rx, buf, sizeof(buf));
433	if (rc == -1)
434		err(1, "sniff()");
435
436	wh = get_wifi(buf, &rc);
437	if (!wh)
438		return 0;
439
440	generic_process(wh, p, rc);
441
442	if (!for_me(wh, p->mac))
443		return 0;
444
445	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
446			IEEE80211_FC0_SUBTYPE_PROBE_RESP))
447		return 0;
448
449	data = (char*) (wh+1);
450	data += 8; /* Timestamp */
451	data += 2; /* Beacon Interval */
452	ess = *data & 1;
453	wep = (*data & IEEE80211_CAPINFO_PRIVACY) ? 1 : 0;
454	data += 2; /* capability */
455
456	/* ssid */
457	if (*data != 0) {
458		printf("Warning, expecting SSID got %x\n", *data);
459		return 0;
460	}
461	data++;
462	ssid = data+1;
463	data += 1 + *data;
464	if (*data != 1) {
465		printf("Warning, expected rates got %x\n", *data);
466		return 0;
467	}
468	*data = 0;
469
470	/* rates */
471	data++;
472
473	mac2str(from, wh->i_addr2);
474	mac2str(bssid, wh->i_addr3);
475	printf("Got response from %s [%s] [%s] ESS=%d WEP=%d\n",
476	       from, bssid, ssid, ess, wep);
477
478	if (strcmp(ssid, p->ssid) != 0)
479		return 0;
480
481	memcpy(p->ap, wh->i_addr2, 6);
482	memcpy(p->bssid, wh->i_addr3, 6);
483	return 1;
484}
485
486int get_auth(struct params *p)
487{
488	char buf[4096];
489	int rc;
490	struct ieee80211_frame *wh;
491	short *data;
492
493	rc = sniff(p->rx, buf, sizeof(buf));
494	if (rc == -1)
495		err(1, "sniff()");
496
497	wh = get_wifi(buf, &rc);
498	if (!wh)
499		return 0;
500
501	generic_process(wh, p, rc);
502
503	if (!for_me(wh, p->mac))
504		return 0;
505
506	if (!from_ap(wh, p->ap))
507		return 0;
508
509	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
510			IEEE80211_FC0_SUBTYPE_AUTH))
511		return 0;
512
513	data = (short*) (wh+1);
514
515	/* algo */
516	if (le16toh(*data) != 0) {
517		printf("Not open-system %d!\n", le16toh(*data));
518		return 0;
519	}
520	data++;
521
522	/* transaction no. */
523	if (le16toh(*data) != 2) {
524		printf("Got transaction %d!\n", le16toh(*data));
525		return 0;
526	}
527	data++;
528
529	/* status code */
530	rc = le16toh(*data);
531	if (rc == 0) {
532		printf("Authenticated\n");
533		return 1;
534	}
535
536	printf("Authentication failed code=%d\n", rc);
537	return 0;
538}
539
540int get_assoc(struct params *p)
541{
542	char buf[4096];
543	int rc;
544	struct ieee80211_frame *wh;
545	unsigned short *data;
546
547	rc = sniff(p->rx, buf, sizeof(buf));
548	if (rc == -1)
549		err(1, "sniff()");
550
551	wh = get_wifi(buf, &rc);
552	if (!wh)
553		return 0;
554
555	generic_process(wh, p, rc);
556
557	if (!for_me(wh, p->mac))
558		return 0;
559
560	if (!from_ap(wh, p->ap))
561		return 0;
562
563	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
564			IEEE80211_FC0_SUBTYPE_ASSOC_RESP))
565		return 0;
566
567
568	data = (unsigned short*) (wh+1);
569
570	data++; /* caps */
571
572	/* status */
573	rc = le16toh(*data++);
574	if (rc != 0) {
575		printf("Assoc failed code %d\n", rc);
576		return 0;
577	}
578
579	/* aid */
580	p->aid = le16toh(*data & ~( (1 << 15) | (1 << 14)));
581	printf("Association ID=%d\n", p->aid);
582
583	return 1;
584}
585
586void read_wifi(struct params *p)
587{
588	char buf[4096];
589	int rc;
590	struct ieee80211_frame *wh;
591	int type, stype;
592
593	rc = sniff(p->rx, buf, sizeof(buf));
594	if (rc == -1)
595		err(1, "sniff()");
596
597	wh = get_wifi(buf, &rc);
598	if (!wh)
599		return;
600
601	generic_process(wh, p, rc);
602
603	if (!for_me(wh, p->mac))
604		return;
605
606	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
607	stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
608
609	/* control frames */
610	if (type == IEEE80211_FC0_TYPE_CTL) {
611		switch (stype) {
612		case IEEE80211_FC0_SUBTYPE_ACK:
613			if (p->state == S_WAIT_ACK)
614				p->state = S_ASSOCIATED;
615			break;
616
617		case IEEE80211_FC0_SUBTYPE_RTS:
618#if 0
619			printf("Got RTS\n");
620#endif
621			break;
622
623		default:
624			printf("Unknown CTL frame %d\n",
625			       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
626			abort();
627			break;
628		}
629		return;
630	}
631
632	if (!from_ap(wh, p->ap))
633		return;
634
635	if (type != IEEE80211_FC0_TYPE_MGT)
636		return;
637
638	if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
639	    stype == IEEE80211_FC0_SUBTYPE_DISASSOC) {
640		printf("Got management! %d\n",
641		       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
642		p->seq_rx = -1;
643		p->state = S_START;
644	}
645
646	return;
647}
648
649void read_tap(struct params *p)
650{
651	char *ptr;
652	int len = sizeof(p->packet);
653	int offset;
654	char mac[6];
655	struct ieee80211_frame *wh;
656
657	ptr = p->packet;
658	offset = sizeof(struct ieee80211_frame) + 8 - 14;
659	if (p->wep_len)
660		offset += 4;
661
662	ptr += offset;
663	len -= offset;
664
665	/* read packet */
666	memset(p->packet, 0, sizeof(p->packet));
667	p->packet_len = read(p->tap, ptr, len);
668	if (p->packet_len == -1)
669		err(1, "read()");
670
671	/* 802.11 header */
672	wh = (struct ieee80211_frame*) p->packet;
673	memcpy(mac, ptr, sizeof(mac));
674	fill_basic(wh, p);
675	memcpy(wh->i_addr3, mac, sizeof(wh->i_addr3));
676	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
677	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
678	if (p->wep_len)
679		wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
680
681	/* LLC & SNAP */
682	ptr = (char*) (wh+1);
683	if (p->wep_len)
684		ptr += 4;
685	*ptr++ = 0xAA;
686	*ptr++ = 0xAA;
687	*ptr++ = 0x03;
688	*ptr++ = 0x00;
689	*ptr++ = 0x00;
690	*ptr++ = 0x00;
691	/* ether type overlaps w00t */
692
693	p->packet_len += offset;
694
695	/* WEP */
696	if (p->wep_len) {
697		ptr = (char*) (wh+1);
698		memcpy(ptr, &p->wep_iv, 3);
699		ptr[3] = 0;
700		p->wep_iv++;
701
702		wep_encrypt(wh, p->packet_len, p->wep_key, p->wep_len);
703		p->packet_len += 4; /* ICV */
704	}
705}
706
707int main(int argc, char *argv[])
708{
709	char* ssid = 0;
710	char mac[] = { 0x00, 0x00, 0xde, 0xfa, 0xce, 0xd };
711	int ch;
712	struct params p;
713	char *iface = "wlan0";
714	char *tap = "tap0";
715	int timeout = 50*1000;
716	struct timeval start;
717
718	memset(&p, 0, sizeof(p));
719	p.wep_len = 0;
720	p.wep_iv = 0;
721	p.state = S_START;
722
723	while ((ch = getopt(argc, argv, "hm:s:i:w:t:b:")) != -1) {
724		switch (ch) {
725		case 'b':
726			if (str2mac(p.bssid, optarg)) {
727				printf("Error parsing BSSID\n");
728				exit(1);
729			}
730			memcpy(p.ap, p.bssid, sizeof(p.ap));
731			p.state = S_SEND_AUTH;
732			break;
733
734		case 's':
735			ssid = optarg;
736			break;
737
738		case 'm':
739			if (str2mac(mac, optarg)) {
740				printf("Error parsing MAC\n");
741				exit(1);
742			}
743			break;
744
745		case 'i':
746			iface = optarg;
747			break;
748
749		case 'w':
750			if (str2wep(p.wep_key, &p.wep_len, optarg)) {
751				printf("Error parsing WEP key\n");
752				exit(1);
753			}
754			break;
755
756		case 't':
757			tap = optarg;
758			break;
759
760		case 'h':
761		default:
762			usage(argv[0]);
763			break;
764		}
765	}
766
767	if (!ssid)
768		usage(argv[0]);
769
770	p.mac = mac;
771	p.ssid = ssid;
772	p.seq = getpid();
773	p.seq_rx = -1;
774	if (open_rxtx(iface, &p.rx, &p.tx) == -1)
775		err(1, "open_rxtx()");
776	p.tap = open_tap(tap);
777	if (p.tap == -1)
778		err(1, "open_tap()");
779	if (set_iface_mac(tap, mac) == -1)
780		err(1, "set_iface_mac()");
781
782	while (1) {
783		/* check for timeouts */
784		switch (p.state) {
785		case S_WAIT_PROBE_RES:
786		case S_WAIT_AUTH:
787		case S_WAIT_ASSOC:
788		case S_WAIT_ACK:
789			do {
790				int rc;
791				struct timeval tv;
792				int elapsed = 0;
793
794				/* check timeout */
795				if (gettimeofday(&tv, NULL) == -1)
796					err(1, "gettimeofday()");
797				elapsed = tv.tv_sec - start.tv_sec;
798				if (elapsed == 0) {
799					elapsed = tv.tv_usec - start.tv_usec;
800				} else {
801					elapsed *= (elapsed-1)*1000*1000;
802					elapsed += 1000*1000 - start.tv_usec;
803					elapsed += tv.tv_usec;
804				}
805				if (elapsed >= timeout)
806					rc = 0;
807				else {
808					fd_set fds;
809
810					FD_ZERO(&fds);
811					FD_SET(p.rx, &fds);
812
813					elapsed = timeout - elapsed;
814					tv.tv_sec = elapsed/1000/1000;
815					elapsed -= tv.tv_sec*1000*1000;
816					tv.tv_usec = elapsed;
817
818					rc = select(p.rx+1, &fds, NULL,
819						    NULL, &tv);
820					if (rc == -1)
821						err(1, "select()");
822				}
823
824				/* timeout */
825				if (!rc) {
826#if 0
827					printf("Timeout\n");
828#endif
829					p.state--;
830				}
831
832			} while(0);
833			break;
834		}
835
836		switch (p.state) {
837		case S_START:
838			p.state = S_SEND_PROBE_REQ;
839			break;
840
841		case S_SEND_PROBE_REQ:
842			printf("Sending probe request for %s\n", ssid);
843			send_probe_request(&p);
844			p.state = S_WAIT_PROBE_RES;
845			if (gettimeofday(&start, NULL) == -1)
846				err(1, "gettimeofday()");
847			break;
848
849		case S_WAIT_PROBE_RES:
850			if (get_probe_response(&p)) {
851				p.state = S_SEND_AUTH;
852			}
853			break;
854
855		case S_SEND_AUTH:
856			do {
857				char apmac[18];
858
859				mac2str(apmac, p.ap);
860				printf("Sending auth to %s\n", apmac);
861				send_auth(&p);
862				p.state = S_WAIT_AUTH;
863				if (gettimeofday(&start, NULL) == -1)
864					err(1, "gettimeofday()");
865			} while(0);
866			break;
867
868		case S_WAIT_AUTH:
869			if (get_auth(&p)) {
870				p.state = S_SEND_ASSOC;
871			}
872			break;
873
874		case S_SEND_ASSOC:
875			printf("Sending assoc\n");
876			send_assoc(&p);
877			p.state = S_WAIT_ASSOC;
878			if (gettimeofday(&start, NULL) == -1)
879				err(1, "gettimeofday()");
880			break;
881
882		case S_WAIT_ASSOC:
883			if (get_assoc(&p)) {
884				printf("Associated\n");
885				p.state = S_ASSOCIATED;
886			}
887			break;
888
889		case S_ASSOCIATED:
890			do {
891				fd_set fds;
892				int max;
893
894				FD_ZERO(&fds);
895				FD_SET(p.rx, &fds);
896				FD_SET(p.tap, &fds);
897				max = (p.rx > p.tap) ? p.rx : p.tap;
898
899				max = select(max+1, &fds, NULL, NULL, NULL);
900				if (max == -1)
901					err(1, "select()");
902
903				if (FD_ISSET(p.tap, &fds)) {
904					read_tap(&p);
905					p.state = S_SEND_DATA;
906				}
907				if (FD_ISSET(p.rx, &fds)) {
908					read_wifi(&p);
909				}
910			} while(0);
911			break;
912
913		case S_SEND_DATA:
914			send_frame(&p, p.packet, p.packet_len);
915			do {
916				struct ieee80211_frame *wh;
917
918				wh = (struct ieee80211_frame*) p.packet;
919				wh->i_fc[1] |= IEEE80211_FC1_RETRY;
920			} while (0);
921			p.state = S_WAIT_ACK;
922			if (gettimeofday(&start, NULL) == -1)
923				err(1, "gettimeofday()");
924			break;
925
926		case S_WAIT_ACK:
927			read_wifi(&p);
928			break;
929
930		default:
931			printf("Unknown state %d\n", p.state);
932			abort();
933			break;
934		}
935	}
936
937	exit(0);
938}
939