xref: /freebsd/tools/tools/net80211/w00t/assoc/assoc.c (revision 9a14aa017b21c292740c00ee098195cd46642730)
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$
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 
39 enum {
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 
52 struct 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 
71 void 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 
85 void 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 
100 void 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 
115 void 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 
149 void 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  */
184 static u_int8_t *
185 ieee80211_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 
193 void 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 
236 int for_me(struct ieee80211_frame *wh, char *mac)
237 {
238 	return memcmp(wh->i_addr1, mac, 6) == 0;
239 }
240 
241 int from_ap(struct ieee80211_frame *wh, char *mac)
242 {
243 	return memcmp(wh->i_addr2, mac, 6) == 0;
244 }
245 
246 void 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 
257 void 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_WEP) {
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 
420 int 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 
486 int 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 
540 int 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 
586 void 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 
649 void 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_WEP;
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 
707 int 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