Sweep-fix comparing pointers with 0 (and assigning 0 to pointers).
[dragonfly.git] / tools / tools / net80211 / w00t / assoc / assoc.c
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: src/tools/tools/net80211/w00t/assoc/assoc.c,v 1.2 2009/07/24 15:31:22 sam Exp $
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 <netproto/802_11/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 = NULL;
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 }