xref: /freebsd/tools/tools/net80211/w00t/assoc/assoc.c (revision d0b2dbfa)
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 
37 enum {
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 
50 struct 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 
69 void 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 
83 void 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 
98 void 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 
113 void 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 
147 void 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  */
182 static u_int8_t *
183 ieee80211_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 
191 void 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 
234 int for_me(struct ieee80211_frame *wh, char *mac)
235 {
236 	return memcmp(wh->i_addr1, mac, 6) == 0;
237 }
238 
239 int from_ap(struct ieee80211_frame *wh, char *mac)
240 {
241 	return memcmp(wh->i_addr2, mac, 6) == 0;
242 }
243 
244 void 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 
255 void 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 
418 int 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 
484 int 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 
538 int 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 
584 void 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 
647 void 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 
705 int 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