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