1160996Ssam/*-
2160996Ssam * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3160996Ssam * All rights reserved.
4160996Ssam *
5160996Ssam * Redistribution and use in source and binary forms, with or without
6160996Ssam * modification, are permitted provided that the following conditions
7160996Ssam * are met:
8160996Ssam * 1. Redistributions of source code must retain the above copyright
9160996Ssam *    notice, this list of conditions and the following disclaimer.
10160996Ssam * 2. Redistributions in binary form must reproduce the above copyright
11160996Ssam *    notice, this list of conditions and the following disclaimer in the
12160996Ssam *    documentation and/or other materials provided with the distribution.
13160996Ssam *
14160996Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15160996Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16160996Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17160996Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18160996Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19160996Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20160996Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21160996Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22160996Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23160996Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24160996Ssam * SUCH DAMAGE.
25160996Ssam *
26160996Ssam * $FreeBSD$
27160996Ssam */
28160996Ssam#include <sys/time.h>
29160996Ssam#include <stdlib.h>
30160996Ssam#include <stdio.h>
31160996Ssam#include <unistd.h>
32160996Ssam#include <string.h>
33160996Ssam#include <errno.h>
34160996Ssam#include <err.h>
35160996Ssam#include <net80211/ieee80211.h>
36160996Ssam#include <sys/endian.h>
37160996Ssam#include "w00t.h"
38160996Ssam
39160996Ssamenum {
40160996Ssam	S_START = 0,
41160996Ssam	S_SEND_PROBE_REQ,
42160996Ssam	S_WAIT_PROBE_RES,
43160996Ssam	S_SEND_AUTH,
44160996Ssam	S_WAIT_AUTH,
45160996Ssam	S_SEND_ASSOC,
46160996Ssam	S_WAIT_ASSOC,
47160996Ssam	S_ASSOCIATED,
48160996Ssam	S_SEND_DATA,
49160996Ssam	S_WAIT_ACK
50160996Ssam};
51160996Ssam
52160996Ssamstruct params {
53160996Ssam	int seq;
54160996Ssam	int seq_rx;
55160996Ssam	char *mac;
56160996Ssam	char *ssid;
57160996Ssam	char bssid[6];
58160996Ssam	char ap[6];
59160996Ssam	int tx;
60160996Ssam	int rx;
61160996Ssam	int tap;
62160996Ssam	int aid;
63160996Ssam	char packet[4096];
64160996Ssam	int packet_len;
65160996Ssam	int state;
66160996Ssam	char wep_key[13];
67160996Ssam	int wep_iv;
68160996Ssam	int wep_len;
69160996Ssam};
70160996Ssam
71160996Ssamvoid usage(char *pname)
72160996Ssam{
73160996Ssam	printf("Usage: %s <opts>\n"
74160996Ssam		"-m\t<source mac>\n"
75160996Ssam		"-s\t<ssid>\n"
76160996Ssam		"-h\tusage\n"
77160996Ssam		"-i\t<iface>\n"
78160996Ssam		"-w\t<wep key>\n"
79160996Ssam		"-t\t<tap>\n"
80160996Ssam		"-b\t<bssid>\n"
81160996Ssam		, pname);
82160996Ssam	exit(0);
83160996Ssam}
84160996Ssam
85160996Ssamvoid fill_basic(struct ieee80211_frame *wh, struct params *p)
86160996Ssam{
87160996Ssam	short *seq;
88160996Ssam
89160996Ssam	wh->i_dur[0] = 0x69;
90160996Ssam	wh->i_dur[1] = 0x00;
91160996Ssam
92160996Ssam	memcpy(wh->i_addr1, p->ap, 6);
93160996Ssam	memcpy(wh->i_addr2, p->mac, 6);
94160996Ssam	memcpy(wh->i_addr3, p->bssid, 6);
95160996Ssam
96160996Ssam	seq = (short*)wh->i_seq;
97160996Ssam	*seq = seqfn(p->seq, 0);
98160996Ssam}
99160996Ssam
100160996Ssamvoid send_frame(struct params *p, void *buf, int len)
101160996Ssam{
102160996Ssam	int rc;
103160996Ssam
104160996Ssam	rc = inject(p->tx, buf, len);
105160996Ssam	if (rc == -1) {
106160996Ssam		if (errno == EMSGSIZE)
107160996Ssam			warnx("inject(len %d)", len);
108160996Ssam		else
109160996Ssam			err(1, "inject(len %d)", len);
110160996Ssam	} else if (rc != len)
111160996Ssam		errx(1, "injected %d but only %d sent", rc, len);
112160996Ssam	p->seq++;
113160996Ssam}
114160996Ssam
115160996Ssamvoid send_probe_request(struct params *p)
116160996Ssam{
117160996Ssam	char buf[2048];
118160996Ssam	struct ieee80211_frame *wh;
119160996Ssam	char *data;
120160996Ssam	int len;
121160996Ssam
122160996Ssam	memset(buf, 0, sizeof(buf));
123160996Ssam
124160996Ssam	wh = (struct ieee80211_frame*) buf;
125160996Ssam	fill_basic(wh, p);
126160996Ssam	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_PROBE_REQ;
127160996Ssam
128160996Ssam	memset(wh->i_addr1, 0xFF, 6);
129160996Ssam	memset(wh->i_addr3, 0xFF, 6);
130160996Ssam
131160996Ssam	data = (char*) (wh + 1);
132160996Ssam	*data++ = 0; /* SSID */
133160996Ssam	*data++ = strlen(p->ssid);
134160996Ssam	strcpy(data, p->ssid);
135160996Ssam	data += strlen(p->ssid);
136160996Ssam
137160996Ssam	*data++ = 1; /* rates */
138160996Ssam	*data++ = 4;
139160996Ssam	*data++ = 2 | 0x80;
140160996Ssam	*data++ = 4 | 0x80;
141160996Ssam	*data++ = 11;
142160996Ssam	*data++ = 22;
143160996Ssam
144160996Ssam	len = data - (char*)wh;
145160996Ssam
146160996Ssam	send_frame(p, buf, len);
147160996Ssam}
148160996Ssam
149160996Ssamvoid send_auth(struct params *p)
150160996Ssam{
151160996Ssam	char buf[2048];
152160996Ssam	struct ieee80211_frame *wh;
153160996Ssam	char *data;
154160996Ssam	int len;
155160996Ssam
156160996Ssam	memset(buf, 0, sizeof(buf));
157160996Ssam
158160996Ssam	wh = (struct ieee80211_frame*) buf;
159160996Ssam	fill_basic(wh, p);
160160996Ssam	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_AUTH;
161160996Ssam
162160996Ssam	data = (char*) (wh + 1);
163160996Ssam
164160996Ssam	/* algo */
165160996Ssam	*data++ = 0;
166160996Ssam	*data++ = 0;
167160996Ssam
168160996Ssam	/* transaction no. */
169160996Ssam	*data++ = 1;
170160996Ssam	*data++ = 0;
171160996Ssam
172160996Ssam	/* status code */
173160996Ssam	*data++ = 0;
174160996Ssam	*data++ = 0;
175160996Ssam
176160996Ssam	len = data - (char*)wh;
177160996Ssam
178160996Ssam	send_frame(p, buf, len);
179160996Ssam}
180160996Ssam
181160996Ssam/*
182160996Ssam * Add an ssid element to a frame.
183160996Ssam */
184160996Ssamstatic u_int8_t *
185160996Ssamieee80211_add_ssid(u_int8_t *frm, const u_int8_t *ssid, u_int len)
186160996Ssam{
187160996Ssam	*frm++ = IEEE80211_ELEMID_SSID;
188160996Ssam	*frm++ = len;
189160996Ssam	memcpy(frm, ssid, len);
190160996Ssam	return frm + len;
191160996Ssam}
192160996Ssam
193160996Ssamvoid send_assoc(struct params *p)
194160996Ssam{
195160996Ssam	union {
196160996Ssam		struct ieee80211_frame w;
197160996Ssam		char buf[2048];
198160996Ssam	} u;
199160996Ssam	struct ieee80211_frame *wh;
200160996Ssam	char *data;
201160996Ssam	int len, capinfo, lintval;
202160996Ssam
203160996Ssam	memset(&u, 0, sizeof(u));
204160996Ssam
205160996Ssam	wh = (struct ieee80211_frame*) &u.w;
206160996Ssam	fill_basic(wh, p);
207160996Ssam	wh->i_fc[0] |= IEEE80211_FC0_TYPE_MGT | IEEE80211_FC0_SUBTYPE_ASSOC_REQ;
208160996Ssam
209160996Ssam	data = (char*) (wh + 1);
210160996Ssam
211160996Ssam	/* capability */
212160996Ssam	capinfo = IEEE80211_CAPINFO_ESS;
213160996Ssam	if (p->wep_len)
214160996Ssam		capinfo |= IEEE80211_CAPINFO_PRIVACY;
215160996Ssam	*(uint16_t *)data = htole16(capinfo);
216160996Ssam	data += 2;
217160996Ssam
218160996Ssam	/* listen interval */
219160996Ssam	*(uint16_t *)data = htole16(100);
220160996Ssam	data += 2;
221160996Ssam
222160996Ssam	data = ieee80211_add_ssid(data, p->ssid, strlen(p->ssid));
223160996Ssam
224160996Ssam	*data++ = 1; /* rates */
225160996Ssam	*data++ = 4;
226160996Ssam	*data++ = 2 | 0x80;
227160996Ssam	*data++ = 4 | 0x80;
228160996Ssam	*data++ = 11;
229160996Ssam	*data++ = 22;
230160996Ssam
231160996Ssam	len = data - (char*)wh;
232160996Ssam
233160996Ssam	send_frame(p, u.buf, len);
234160996Ssam}
235160996Ssam
236160996Ssamint for_me(struct ieee80211_frame *wh, char *mac)
237160996Ssam{
238160996Ssam	return memcmp(wh->i_addr1, mac, 6) == 0;
239160996Ssam}
240160996Ssam
241160996Ssamint from_ap(struct ieee80211_frame *wh, char *mac)
242160996Ssam{
243160996Ssam	return memcmp(wh->i_addr2, mac, 6) == 0;
244160996Ssam}
245160996Ssam
246160996Ssamvoid ack(struct params *p, struct ieee80211_frame *wh)
247160996Ssam{
248160996Ssam        if (memcmp(wh->i_addr1, p->mac, 6) != 0)
249160996Ssam                return;
250160996Ssam
251160996Ssam        if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) == IEEE80211_FC0_TYPE_CTL)
252160996Ssam                return;
253160996Ssam
254160996Ssam        send_ack(p->tx, wh->i_addr2);
255160996Ssam}
256160996Ssam
257160996Ssamvoid generic_process(struct ieee80211_frame *wh, struct params *p, int len)
258160996Ssam{
259160996Ssam	int type, stype;
260160996Ssam	int dup = 0;
261160996Ssam
262160996Ssam#if 0
263160996Ssam	ack(p, wh);
264160996Ssam#endif
265160996Ssam
266160996Ssam#if 0
267160996Ssam	if (!for_me(wh, p->mac))
268160996Ssam		return;
269160996Ssam#endif
270160996Ssam	/* ignore my own shit */
271160996Ssam	if (memcmp(wh->i_addr2, p->mac, 6) == 0) {
272160996Ssam		return;
273160996Ssam	}
274160996Ssam
275160996Ssam	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
276160996Ssam	stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
277160996Ssam
278160996Ssam	if (for_me(wh, p->mac) && type == IEEE80211_FC0_TYPE_DATA) {
279160996Ssam		/* sequence number & dups */
280160996Ssam		if (p->seq_rx == -1)
281160996Ssam			p->seq_rx = seqno(wh);
282160996Ssam		else {
283160996Ssam			int s = seqno(wh);
284160996Ssam
285160996Ssam			if (s > p->seq_rx) {
286160996Ssam				/* normal case */
287160996Ssam				if (p->seq_rx + 1 == s) {
288160996Ssam#if 0
289160996Ssam					printf("S=%d\n", s);
290160996Ssam#endif
291160996Ssam					p->seq_rx = s;
292160996Ssam				}
293160996Ssam				else { /* future */
294160996Ssam#if 0
295160996Ssam					printf("Got seq %d, prev %d\n",
296160996Ssam					       s, p->seq_rx);
297160996Ssam#endif
298160996Ssam					p->seq_rx = s;
299160996Ssam				}
300160996Ssam			} else { /* we got pas stuff... */
301160996Ssam				if (p->seq_rx - s > 1000) {
302160996Ssam#if 0
303160996Ssam					printf("Seqno wrap seq %d, last %d\n",
304160996Ssam					       s, p->seq_rx);
305160996Ssam#endif
306160996Ssam					/* seqno wrapping ? */
307160996Ssam					p->seq_rx = 0;
308160996Ssam				}
309160996Ssam				else { /* dup */
310160996Ssam					dup = 1;
311160996Ssam#if 0
312160996Ssam					printf("Got dup seq %d, last %d\n",
313160996Ssam					       s, p->seq_rx);
314160996Ssam#endif
315160996Ssam				}
316160996Ssam			}
317160996Ssam		}
318160996Ssam	}
319160996Ssam#if 0
320160996Ssam	if (wh->i_fc[1] & IEEE80211_FC1_RETRY) {
321160996Ssam		printf("Got retry\n");
322160996Ssam	}
323160996Ssam#endif
324160996Ssam#if 0
325160996Ssam	if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_CTL) {
326160996Ssam		int rc = send_ack(p->tx, wh->i_addr2);
327160996Ssam		if (rc == -1)
328160996Ssam			err(1, "send_ack()");
329160996Ssam		if (rc != 10) {
330160996Ssam			printf("Wrote ACK %d/%d\n", rc, 10);
331160996Ssam			exit(1);
332160996Ssam		}
333160996Ssam	}
334160996Ssam#endif
335160996Ssam
336160996Ssam	/* data frames */
337160996Ssam	if (type == IEEE80211_FC0_TYPE_DATA && !dup) {
338160996Ssam		char *ptr;
339160996Ssam		char src[6], dst[6];
340160996Ssam		int rc;
341160996Ssam
342160996Ssam		if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
343160996Ssam			if (memcmp(wh->i_addr2, p->ap, 6) != 0)
344160996Ssam				return;
345160996Ssam		} else {
346160996Ssam			if (memcmp(wh->i_addr1, p->ap, 6) != 0)
347160996Ssam				return;
348160996Ssam		}
349160996Ssam
350160996Ssam
351160996Ssam		if (p->state < S_ASSOCIATED) {
352160996Ssam			printf("Got data when not associated!\n");
353160996Ssam			return;
354160996Ssam		}
355160996Ssam		if (stype != IEEE80211_FC0_SUBTYPE_DATA) {
356160996Ssam			printf("Got weird data frame stype=%d\n",
357160996Ssam			       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
358160996Ssam			return;
359160996Ssam		}
360160996Ssam
361160996Ssam		if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) {
362160996Ssam			memcpy(src, wh->i_addr3, 6);
363160996Ssam			memcpy(dst, wh->i_addr1, 6);
364160996Ssam		} else {
365160996Ssam			memcpy(src, wh->i_addr2, 6);
366160996Ssam			memcpy(dst, wh->i_addr3, 6);
367160996Ssam		}
368160996Ssam
369160996Ssam		ptr = (char*) (wh + 1);
370160996Ssam
371262007Skevlo		if (wh->i_fc[1] & IEEE80211_FC1_PROTECTED) {
372160996Ssam			if (!p->wep_len) {
373160996Ssam				char srca[3*6];
374160996Ssam				char dsta[3*6];
375160996Ssam
376160996Ssam				mac2str(srca, src);
377160996Ssam				mac2str(dsta, dst);
378160996Ssam				printf("Got wep but i aint wep %s->%s %d\n",
379160996Ssam				       srca, dsta, len-sizeof(*wh)-8);
380160996Ssam				return;
381160996Ssam			}
382160996Ssam
383160996Ssam			if (wep_decrypt(wh, len, p->wep_key, p->wep_len) == -1){
384160996Ssam				char srca[3*6];
385160996Ssam				char dsta[3*6];
386160996Ssam
387160996Ssam				mac2str(srca, src);
388160996Ssam				mac2str(dsta, dst);
389160996Ssam				printf("Can't decrypt %s->%s %d\n", srca, dsta,
390160996Ssam				       len-sizeof(*wh)-8);
391160996Ssam				return;
392160996Ssam			}
393160996Ssam
394160996Ssam			ptr += 4;
395160996Ssam			len -= 8;
396160996Ssam		}
397160996Ssam
398160996Ssam		/* ether header */
399160996Ssam		ptr += 8 - 2;
400160996Ssam		ptr -= 6;
401160996Ssam		memcpy(ptr, src, 6);
402160996Ssam		ptr -= 6;
403160996Ssam		memcpy(ptr, dst, 6);
404160996Ssam
405160996Ssam		len -= sizeof(*wh);
406160996Ssam		len -= 8;
407160996Ssam		len += 14;
408160996Ssam
409160996Ssam		/* send to tap */
410160996Ssam		rc = write(p->tap, ptr, len);
411160996Ssam		if (rc == -1)
412160996Ssam			err(1, "write()");
413160996Ssam		if (rc != len) {
414160996Ssam			printf("Wrote %d/%d\n", rc, len);
415160996Ssam			exit(1);
416160996Ssam		}
417160996Ssam	}
418160996Ssam}
419160996Ssam
420160996Ssamint get_probe_response(struct params *p)
421160996Ssam{
422160996Ssam	char buf[4096];
423160996Ssam	int rc;
424160996Ssam	struct ieee80211_frame *wh;
425160996Ssam	char *data;
426160996Ssam	int ess;
427160996Ssam	int wep;
428160996Ssam	char *ssid;
429160996Ssam	char from[18];
430160996Ssam	char bssid[18];
431160996Ssam
432160996Ssam	rc = sniff(p->rx, buf, sizeof(buf));
433160996Ssam	if (rc == -1)
434160996Ssam		err(1, "sniff()");
435160996Ssam
436160996Ssam	wh = get_wifi(buf, &rc);
437160996Ssam	if (!wh)
438160996Ssam		return 0;
439160996Ssam
440160996Ssam	generic_process(wh, p, rc);
441160996Ssam
442160996Ssam	if (!for_me(wh, p->mac))
443160996Ssam		return 0;
444160996Ssam
445160996Ssam	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
446160996Ssam			IEEE80211_FC0_SUBTYPE_PROBE_RESP))
447160996Ssam		return 0;
448160996Ssam
449160996Ssam	data = (char*) (wh+1);
450160996Ssam	data += 8; /* Timestamp */
451160996Ssam	data += 2; /* Beacon Interval */
452160996Ssam	ess = *data & 1;
453160996Ssam	wep = (*data & IEEE80211_CAPINFO_PRIVACY) ? 1 : 0;
454160996Ssam	data += 2; /* capability */
455160996Ssam
456160996Ssam	/* ssid */
457160996Ssam	if (*data != 0) {
458160996Ssam		printf("Warning, expecting SSID got %x\n", *data);
459160996Ssam		return 0;
460160996Ssam	}
461160996Ssam	data++;
462160996Ssam	ssid = data+1;
463160996Ssam	data += 1 + *data;
464160996Ssam	if (*data != 1) {
465160996Ssam		printf("Warning, expected rates got %x\n", *data);
466160996Ssam		return 0;
467160996Ssam	}
468160996Ssam	*data = 0;
469160996Ssam
470160996Ssam	/* rates */
471160996Ssam	data++;
472160996Ssam
473160996Ssam	mac2str(from, wh->i_addr2);
474160996Ssam	mac2str(bssid, wh->i_addr3);
475160996Ssam	printf("Got response from %s [%s] [%s] ESS=%d WEP=%d\n",
476160996Ssam	       from, bssid, ssid, ess, wep);
477160996Ssam
478160996Ssam	if (strcmp(ssid, p->ssid) != 0)
479160996Ssam		return 0;
480160996Ssam
481160996Ssam	memcpy(p->ap, wh->i_addr2, 6);
482160996Ssam	memcpy(p->bssid, wh->i_addr3, 6);
483160996Ssam	return 1;
484160996Ssam}
485160996Ssam
486160996Ssamint get_auth(struct params *p)
487160996Ssam{
488160996Ssam	char buf[4096];
489160996Ssam	int rc;
490160996Ssam	struct ieee80211_frame *wh;
491160996Ssam	short *data;
492160996Ssam
493160996Ssam	rc = sniff(p->rx, buf, sizeof(buf));
494160996Ssam	if (rc == -1)
495160996Ssam		err(1, "sniff()");
496160996Ssam
497160996Ssam	wh = get_wifi(buf, &rc);
498160996Ssam	if (!wh)
499160996Ssam		return 0;
500160996Ssam
501160996Ssam	generic_process(wh, p, rc);
502160996Ssam
503160996Ssam	if (!for_me(wh, p->mac))
504160996Ssam		return 0;
505160996Ssam
506160996Ssam	if (!from_ap(wh, p->ap))
507160996Ssam		return 0;
508160996Ssam
509160996Ssam	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
510160996Ssam			IEEE80211_FC0_SUBTYPE_AUTH))
511160996Ssam		return 0;
512160996Ssam
513160996Ssam	data = (short*) (wh+1);
514160996Ssam
515160996Ssam	/* algo */
516160996Ssam	if (le16toh(*data) != 0) {
517160996Ssam		printf("Not open-system %d!\n", le16toh(*data));
518160996Ssam		return 0;
519160996Ssam	}
520160996Ssam	data++;
521160996Ssam
522160996Ssam	/* transaction no. */
523160996Ssam	if (le16toh(*data) != 2) {
524160996Ssam		printf("Got transaction %d!\n", le16toh(*data));
525160996Ssam		return 0;
526160996Ssam	}
527160996Ssam	data++;
528160996Ssam
529160996Ssam	/* status code */
530160996Ssam	rc = le16toh(*data);
531160996Ssam	if (rc == 0) {
532160996Ssam		printf("Authenticated\n");
533160996Ssam		return 1;
534160996Ssam	}
535160996Ssam
536160996Ssam	printf("Authentication failed code=%d\n", rc);
537160996Ssam	return 0;
538160996Ssam}
539160996Ssam
540160996Ssamint get_assoc(struct params *p)
541160996Ssam{
542160996Ssam	char buf[4096];
543160996Ssam	int rc;
544160996Ssam	struct ieee80211_frame *wh;
545160996Ssam	unsigned short *data;
546160996Ssam
547160996Ssam	rc = sniff(p->rx, buf, sizeof(buf));
548160996Ssam	if (rc == -1)
549160996Ssam		err(1, "sniff()");
550160996Ssam
551160996Ssam	wh = get_wifi(buf, &rc);
552160996Ssam	if (!wh)
553160996Ssam		return 0;
554160996Ssam
555160996Ssam	generic_process(wh, p, rc);
556160996Ssam
557160996Ssam	if (!for_me(wh, p->mac))
558160996Ssam		return 0;
559160996Ssam
560160996Ssam	if (!from_ap(wh, p->ap))
561160996Ssam		return 0;
562160996Ssam
563160996Ssam	if (!frame_type(wh, IEEE80211_FC0_TYPE_MGT,
564160996Ssam			IEEE80211_FC0_SUBTYPE_ASSOC_RESP))
565160996Ssam		return 0;
566160996Ssam
567160996Ssam
568160996Ssam	data = (unsigned short*) (wh+1);
569160996Ssam
570160996Ssam	data++; /* caps */
571160996Ssam
572160996Ssam	/* status */
573160996Ssam	rc = le16toh(*data++);
574160996Ssam	if (rc != 0) {
575160996Ssam		printf("Assoc failed code %d\n", rc);
576160996Ssam		return 0;
577160996Ssam	}
578160996Ssam
579160996Ssam	/* aid */
580160996Ssam	p->aid = le16toh(*data & ~( (1 << 15) | (1 << 14)));
581160996Ssam	printf("Association ID=%d\n", p->aid);
582160996Ssam
583160996Ssam	return 1;
584160996Ssam}
585160996Ssam
586160996Ssamvoid read_wifi(struct params *p)
587160996Ssam{
588160996Ssam	char buf[4096];
589160996Ssam	int rc;
590160996Ssam	struct ieee80211_frame *wh;
591160996Ssam	int type, stype;
592160996Ssam
593160996Ssam	rc = sniff(p->rx, buf, sizeof(buf));
594160996Ssam	if (rc == -1)
595160996Ssam		err(1, "sniff()");
596160996Ssam
597160996Ssam	wh = get_wifi(buf, &rc);
598160996Ssam	if (!wh)
599160996Ssam		return;
600160996Ssam
601160996Ssam	generic_process(wh, p, rc);
602160996Ssam
603160996Ssam	if (!for_me(wh, p->mac))
604160996Ssam		return;
605160996Ssam
606160996Ssam	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
607160996Ssam	stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
608160996Ssam
609160996Ssam	/* control frames */
610160996Ssam	if (type == IEEE80211_FC0_TYPE_CTL) {
611160996Ssam		switch (stype) {
612160996Ssam		case IEEE80211_FC0_SUBTYPE_ACK:
613160996Ssam			if (p->state == S_WAIT_ACK)
614160996Ssam				p->state = S_ASSOCIATED;
615160996Ssam			break;
616160996Ssam
617160996Ssam		case IEEE80211_FC0_SUBTYPE_RTS:
618160996Ssam#if 0
619160996Ssam			printf("Got RTS\n");
620160996Ssam#endif
621160996Ssam			break;
622160996Ssam
623160996Ssam		default:
624160996Ssam			printf("Unknown CTL frame %d\n",
625160996Ssam			       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
626160996Ssam			abort();
627160996Ssam			break;
628160996Ssam		}
629160996Ssam		return;
630160996Ssam	}
631160996Ssam
632160996Ssam	if (!from_ap(wh, p->ap))
633160996Ssam		return;
634160996Ssam
635160996Ssam	if (type != IEEE80211_FC0_TYPE_MGT)
636160996Ssam		return;
637160996Ssam
638160996Ssam	if (stype == IEEE80211_FC0_SUBTYPE_DEAUTH ||
639160996Ssam	    stype == IEEE80211_FC0_SUBTYPE_DISASSOC) {
640160996Ssam		printf("Got management! %d\n",
641160996Ssam		       stype >> IEEE80211_FC0_SUBTYPE_SHIFT);
642160996Ssam		p->seq_rx = -1;
643160996Ssam		p->state = S_START;
644160996Ssam	}
645160996Ssam
646160996Ssam	return;
647160996Ssam}
648160996Ssam
649160996Ssamvoid read_tap(struct params *p)
650160996Ssam{
651160996Ssam	char *ptr;
652160996Ssam	int len = sizeof(p->packet);
653160996Ssam	int offset;
654160996Ssam	char mac[6];
655160996Ssam	struct ieee80211_frame *wh;
656160996Ssam
657160996Ssam	ptr = p->packet;
658160996Ssam	offset = sizeof(struct ieee80211_frame) + 8 - 14;
659160996Ssam	if (p->wep_len)
660160996Ssam		offset += 4;
661160996Ssam
662160996Ssam	ptr += offset;
663160996Ssam	len -= offset;
664160996Ssam
665160996Ssam	/* read packet */
666160996Ssam	memset(p->packet, 0, sizeof(p->packet));
667160996Ssam	p->packet_len = read(p->tap, ptr, len);
668160996Ssam	if (p->packet_len == -1)
669160996Ssam		err(1, "read()");
670160996Ssam
671160996Ssam	/* 802.11 header */
672160996Ssam	wh = (struct ieee80211_frame*) p->packet;
673160996Ssam	memcpy(mac, ptr, sizeof(mac));
674160996Ssam	fill_basic(wh, p);
675160996Ssam	memcpy(wh->i_addr3, mac, sizeof(wh->i_addr3));
676160996Ssam	wh->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
677160996Ssam	wh->i_fc[1] |= IEEE80211_FC1_DIR_TODS;
678160996Ssam	if (p->wep_len)
679262007Skevlo		wh->i_fc[1] |= IEEE80211_FC1_PROTECTED;
680160996Ssam
681160996Ssam	/* LLC & SNAP */
682160996Ssam	ptr = (char*) (wh+1);
683160996Ssam	if (p->wep_len)
684160996Ssam		ptr += 4;
685160996Ssam	*ptr++ = 0xAA;
686160996Ssam	*ptr++ = 0xAA;
687160996Ssam	*ptr++ = 0x03;
688160996Ssam	*ptr++ = 0x00;
689160996Ssam	*ptr++ = 0x00;
690160996Ssam	*ptr++ = 0x00;
691160996Ssam	/* ether type overlaps w00t */
692160996Ssam
693160996Ssam	p->packet_len += offset;
694160996Ssam
695160996Ssam	/* WEP */
696160996Ssam	if (p->wep_len) {
697160996Ssam		ptr = (char*) (wh+1);
698160996Ssam		memcpy(ptr, &p->wep_iv, 3);
699160996Ssam		ptr[3] = 0;
700160996Ssam		p->wep_iv++;
701160996Ssam
702160996Ssam		wep_encrypt(wh, p->packet_len, p->wep_key, p->wep_len);
703160996Ssam		p->packet_len += 4; /* ICV */
704160996Ssam	}
705160996Ssam}
706160996Ssam
707160996Ssamint main(int argc, char *argv[])
708160996Ssam{
709160996Ssam	char* ssid = 0;
710160996Ssam	char mac[] = { 0x00, 0x00, 0xde, 0xfa, 0xce, 0xd };
711160996Ssam	int ch;
712160996Ssam	struct params p;
713195848Ssam	char *iface = "wlan0";
714160996Ssam	char *tap = "tap0";
715160996Ssam	int timeout = 50*1000;
716160996Ssam	struct timeval start;
717160996Ssam
718160996Ssam	memset(&p, 0, sizeof(p));
719160996Ssam	p.wep_len = 0;
720160996Ssam	p.wep_iv = 0;
721160996Ssam	p.state = S_START;
722160996Ssam
723160996Ssam	while ((ch = getopt(argc, argv, "hm:s:i:w:t:b:")) != -1) {
724160996Ssam		switch (ch) {
725160996Ssam		case 'b':
726160996Ssam			if (str2mac(p.bssid, optarg)) {
727160996Ssam				printf("Error parsing BSSID\n");
728160996Ssam				exit(1);
729160996Ssam			}
730160996Ssam			memcpy(p.ap, p.bssid, sizeof(p.ap));
731160996Ssam			p.state = S_SEND_AUTH;
732160996Ssam			break;
733160996Ssam
734160996Ssam		case 's':
735160996Ssam			ssid = optarg;
736160996Ssam			break;
737160996Ssam
738160996Ssam		case 'm':
739160996Ssam			if (str2mac(mac, optarg)) {
740160996Ssam				printf("Error parsing MAC\n");
741160996Ssam				exit(1);
742160996Ssam			}
743160996Ssam			break;
744160996Ssam
745160996Ssam		case 'i':
746160996Ssam			iface = optarg;
747160996Ssam			break;
748160996Ssam
749160996Ssam		case 'w':
750160996Ssam			if (str2wep(p.wep_key, &p.wep_len, optarg)) {
751160996Ssam				printf("Error parsing WEP key\n");
752160996Ssam				exit(1);
753160996Ssam			}
754160996Ssam			break;
755160996Ssam
756160996Ssam		case 't':
757160996Ssam			tap = optarg;
758160996Ssam			break;
759160996Ssam
760160996Ssam		case 'h':
761160996Ssam		default:
762160996Ssam			usage(argv[0]);
763160996Ssam			break;
764160996Ssam		}
765160996Ssam	}
766160996Ssam
767160996Ssam	if (!ssid)
768160996Ssam		usage(argv[0]);
769160996Ssam
770160996Ssam	p.mac = mac;
771160996Ssam	p.ssid = ssid;
772160996Ssam	p.seq = getpid();
773160996Ssam	p.seq_rx = -1;
774160996Ssam	if (open_rxtx(iface, &p.rx, &p.tx) == -1)
775160996Ssam		err(1, "open_rxtx()");
776160996Ssam	p.tap = open_tap(tap);
777160996Ssam	if (p.tap == -1)
778160996Ssam		err(1, "open_tap()");
779160996Ssam	if (set_iface_mac(tap, mac) == -1)
780160996Ssam		err(1, "set_iface_mac()");
781160996Ssam
782160996Ssam	while (1) {
783160996Ssam		/* check for timeouts */
784160996Ssam		switch (p.state) {
785160996Ssam		case S_WAIT_PROBE_RES:
786160996Ssam		case S_WAIT_AUTH:
787160996Ssam		case S_WAIT_ASSOC:
788160996Ssam		case S_WAIT_ACK:
789160996Ssam			do {
790160996Ssam				int rc;
791160996Ssam				struct timeval tv;
792160996Ssam				int elapsed = 0;
793160996Ssam
794160996Ssam				/* check timeout */
795160996Ssam				if (gettimeofday(&tv, NULL) == -1)
796160996Ssam					err(1, "gettimeofday()");
797160996Ssam				elapsed = tv.tv_sec - start.tv_sec;
798160996Ssam				if (elapsed == 0) {
799160996Ssam					elapsed = tv.tv_usec - start.tv_usec;
800160996Ssam				} else {
801160996Ssam					elapsed *= (elapsed-1)*1000*1000;
802160996Ssam					elapsed += 1000*1000 - start.tv_usec;
803160996Ssam					elapsed += tv.tv_usec;
804160996Ssam				}
805160996Ssam				if (elapsed >= timeout)
806160996Ssam					rc = 0;
807160996Ssam				else {
808160996Ssam					fd_set fds;
809160996Ssam
810160996Ssam					FD_ZERO(&fds);
811160996Ssam					FD_SET(p.rx, &fds);
812160996Ssam
813160996Ssam					elapsed = timeout - elapsed;
814160996Ssam					tv.tv_sec = elapsed/1000/1000;
815160996Ssam					elapsed -= tv.tv_sec*1000*1000;
816160996Ssam					tv.tv_usec = elapsed;
817160996Ssam
818160996Ssam					rc = select(p.rx+1, &fds, NULL,
819160996Ssam						    NULL, &tv);
820160996Ssam					if (rc == -1)
821160996Ssam						err(1, "select()");
822160996Ssam				}
823160996Ssam
824160996Ssam				/* timeout */
825160996Ssam				if (!rc) {
826160996Ssam#if 0
827160996Ssam					printf("Timeout\n");
828160996Ssam#endif
829160996Ssam					p.state--;
830160996Ssam				}
831160996Ssam
832160996Ssam			} while(0);
833160996Ssam			break;
834160996Ssam		}
835160996Ssam
836160996Ssam		switch (p.state) {
837160996Ssam		case S_START:
838160996Ssam			p.state = S_SEND_PROBE_REQ;
839160996Ssam			break;
840160996Ssam
841160996Ssam		case S_SEND_PROBE_REQ:
842160996Ssam			printf("Sending probe request for %s\n", ssid);
843160996Ssam			send_probe_request(&p);
844160996Ssam			p.state = S_WAIT_PROBE_RES;
845160996Ssam			if (gettimeofday(&start, NULL) == -1)
846160996Ssam				err(1, "gettimeofday()");
847160996Ssam			break;
848160996Ssam
849160996Ssam		case S_WAIT_PROBE_RES:
850160996Ssam			if (get_probe_response(&p)) {
851160996Ssam				p.state = S_SEND_AUTH;
852160996Ssam			}
853160996Ssam			break;
854160996Ssam
855160996Ssam		case S_SEND_AUTH:
856160996Ssam			do {
857160996Ssam				char apmac[18];
858160996Ssam
859160996Ssam				mac2str(apmac, p.ap);
860160996Ssam				printf("Sending auth to %s\n", apmac);
861160996Ssam				send_auth(&p);
862160996Ssam				p.state = S_WAIT_AUTH;
863160996Ssam				if (gettimeofday(&start, NULL) == -1)
864160996Ssam					err(1, "gettimeofday()");
865160996Ssam			} while(0);
866160996Ssam			break;
867160996Ssam
868160996Ssam		case S_WAIT_AUTH:
869160996Ssam			if (get_auth(&p)) {
870160996Ssam				p.state = S_SEND_ASSOC;
871160996Ssam			}
872160996Ssam			break;
873160996Ssam
874160996Ssam		case S_SEND_ASSOC:
875160996Ssam			printf("Sending assoc\n");
876160996Ssam			send_assoc(&p);
877160996Ssam			p.state = S_WAIT_ASSOC;
878160996Ssam			if (gettimeofday(&start, NULL) == -1)
879160996Ssam				err(1, "gettimeofday()");
880160996Ssam			break;
881160996Ssam
882160996Ssam		case S_WAIT_ASSOC:
883160996Ssam			if (get_assoc(&p)) {
884160996Ssam				printf("Associated\n");
885160996Ssam				p.state = S_ASSOCIATED;
886160996Ssam			}
887160996Ssam			break;
888160996Ssam
889160996Ssam		case S_ASSOCIATED:
890160996Ssam			do {
891160996Ssam				fd_set fds;
892160996Ssam				int max;
893160996Ssam
894160996Ssam				FD_ZERO(&fds);
895160996Ssam				FD_SET(p.rx, &fds);
896160996Ssam				FD_SET(p.tap, &fds);
897160996Ssam				max = (p.rx > p.tap) ? p.rx : p.tap;
898160996Ssam
899160996Ssam				max = select(max+1, &fds, NULL, NULL, NULL);
900160996Ssam				if (max == -1)
901160996Ssam					err(1, "select()");
902160996Ssam
903160996Ssam				if (FD_ISSET(p.tap, &fds)) {
904160996Ssam					read_tap(&p);
905160996Ssam					p.state = S_SEND_DATA;
906160996Ssam				}
907160996Ssam				if (FD_ISSET(p.rx, &fds)) {
908160996Ssam					read_wifi(&p);
909160996Ssam				}
910160996Ssam			} while(0);
911160996Ssam			break;
912160996Ssam
913160996Ssam		case S_SEND_DATA:
914160996Ssam			send_frame(&p, p.packet, p.packet_len);
915160996Ssam			do {
916160996Ssam				struct ieee80211_frame *wh;
917160996Ssam
918160996Ssam				wh = (struct ieee80211_frame*) p.packet;
919160996Ssam				wh->i_fc[1] |= IEEE80211_FC1_RETRY;
920160996Ssam			} while (0);
921160996Ssam			p.state = S_WAIT_ACK;
922160996Ssam			if (gettimeofday(&start, NULL) == -1)
923160996Ssam				err(1, "gettimeofday()");
924160996Ssam			break;
925160996Ssam
926160996Ssam		case S_WAIT_ACK:
927160996Ssam			read_wifi(&p);
928160996Ssam			break;
929160996Ssam
930160996Ssam		default:
931160996Ssam			printf("Unknown state %d\n", p.state);
932160996Ssam			abort();
933160996Ssam			break;
934160996Ssam		}
935160996Ssam	}
936160996Ssam
937160996Ssam	exit(0);
938160996Ssam}
939