stumbler.c revision 160994
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: head/tools/tools/net80211/stumbler/stumbler.c 160994 2006-08-05 05:12:03Z sam $
27 */
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <sys/ioctl.h>
31#include <sys/select.h>
32#include <sys/time.h>
33#include <net/if.h>
34#include <net/if_media.h>
35#include <net/bpf.h>
36#include <net80211/ieee80211_ioctl.h>
37#include <net80211/ieee80211.h>
38#include <net/ethernet.h>
39#include <net80211/ieee80211_radiotap.h>
40#include <sys/endian.h>
41#include <fcntl.h>
42#include <errno.h>
43#include <string.h>
44#include <stdlib.h>
45#include <stdio.h>
46#include <curses.h>
47#include <signal.h>
48#include <unistd.h>
49#include <assert.h>
50
51//int hopfreq = 3*1000; // ms
52int hopfreq = 500; // ms
53int sig_reset = 1*1000; // ms
54
55
56int ioctl_s = -1;
57int bpf_s = -1;
58
59struct chan_info {
60	int locked;
61	int chan;
62	struct ieee80211req ireq;
63	struct timeval last_hop;
64} chaninfo;
65
66
67#define CRYPT_NONE		0
68#define CRYPT_WEP		1
69#define CRYPT_WPA1		2
70#define CRYPT_WPA		3
71#define CRYPT_WPA1_TKIP		4
72#define CRYPT_WPA1_TKIP_PSK	5
73#define CRYPT_WPA1_CCMP		6
74#define CRYPT_WPA1_CCMP_PSK	7
75#define CRYPT_80211i		8
76#define CRYPT_80211i_TKIP	9
77#define CRYPT_80211i_TKIP_PSK	10
78
79struct node_info {
80	unsigned char mac[6];
81	int signal;
82	int noise;
83	int max;
84	unsigned char ssid[256];
85	int chan;
86	int wep;
87	int pos;
88	int ap;
89
90	struct timeval seen;
91
92	struct node_info* prev;
93	struct node_info* next;
94} *nodes = 0;
95
96void clean_crap() {
97	struct node_info* next;
98
99	if (ioctl_s != -1)
100		close(ioctl_s);
101	if (bpf_s != -1)
102		close(bpf_s);
103
104	while (nodes) {
105		next = nodes->next;
106		free(nodes);
107		nodes = next;
108	}
109}
110
111char* mac2str(unsigned char* mac) {
112        static char ret[6*3];
113
114        sprintf(ret, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
115                mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
116
117        return ret;
118}
119
120char* wep2str(int w) {
121	char* wep = 0;
122	static char res[14];
123
124	switch (w) {
125	case CRYPT_NONE:
126		wep = "";
127		break;
128
129	case CRYPT_WEP:
130		wep = "WEP";
131		break;
132
133	case CRYPT_WPA1:
134		wep = "WPA1";
135		break;
136
137	case CRYPT_WPA:
138		wep = "WPA?";
139		break;
140
141	case CRYPT_WPA1_TKIP:
142		wep = "WPA1-TKIP";
143		break;
144
145	case CRYPT_WPA1_TKIP_PSK:
146		wep = "WPA1-TKIP-PSK";
147		break;
148
149	case CRYPT_WPA1_CCMP:
150		wep = "WPA1-CCMP";
151		break;
152
153	case CRYPT_WPA1_CCMP_PSK:
154		wep = "WPA1-CCMP-PSK";
155		break;
156
157	case CRYPT_80211i:
158		wep = "i";
159		break;
160
161	case CRYPT_80211i_TKIP:
162		wep = "11i-TKIP";
163		break;
164
165	case CRYPT_80211i_TKIP_PSK:
166		wep = "11i-TKIP-PSK";
167		break;
168
169	default:
170		wep = "FIXME!";
171		break;
172	}
173
174	memset(res, ' ', sizeof(res));
175	assert(strlen(wep) < sizeof(res));
176	memcpy(res, wep, strlen(wep));
177	res[sizeof(res)-1] = 0;
178	return res;
179}
180
181char* ssid2str(struct node_info* node) {
182	static char res[24];
183
184	memset(res, ' ', sizeof(res));
185	res[0] = '[';
186	strcpy(&res[sizeof(res)-2], "]");
187
188	if (node->ap) {
189		int left = sizeof(res) - 3;
190
191		if (strlen(node->ssid) < left)
192			left = strlen(node->ssid);
193		memcpy(&res[1], node->ssid, left);
194	}
195	else {
196		memcpy(&res[1], "<client>", 8);
197	}
198	return res;
199}
200
201void save_state() {
202	FILE* f;
203	struct node_info* node = nodes;
204
205	f = fopen("stumbler.log", "w");
206	if (!f) {
207		perror("fopen()");
208		exit(1);
209	}
210
211	while (node) {
212		struct tm* t;
213		char tim[16];
214
215		t = localtime( (time_t*) &node->seen.tv_sec);
216		if (!t) {
217			perror("localtime()");
218			exit(1);
219		}
220		tim[0] = 0;
221		strftime(tim, sizeof(tim), "%H:%M:%S", t);
222
223		fprintf(f, "%s %s %s %2d %s 0x%.2x\n", tim,
224			mac2str(node->mac), wep2str(node->wep),
225			node->chan, ssid2str(node), node->max);
226
227		node = node->next;
228	}
229
230	fclose(f);
231}
232
233void cleanup(int x) {
234	endwin();
235	clean_crap();
236	exit(0);
237}
238
239void die(int p, char* msg) {
240	endwin();
241	if (p)
242		perror(msg);
243	else
244		printf("%s\n", msg);
245	clean_crap();
246	exit(1);
247}
248
249void display_chan() {
250	int x, y;
251	char tmp[3];
252
253	x = COLS - 2;
254	y = LINES - 1;
255
256	snprintf(tmp, sizeof(tmp), "%.2d", chaninfo.chan);
257	mvaddstr(y, x, tmp);
258	refresh();
259}
260
261void set_chan(int c) {
262        chaninfo.ireq.i_val = c;
263
264        if (ioctl(ioctl_s, SIOCS80211, &chaninfo.ireq) == -1)
265                die(1, "ioctl(SIOCS80211) [chan]");
266
267	chaninfo.chan = c;
268
269	if (gettimeofday(&chaninfo.last_hop, NULL) == -1)
270		die(1, "gettimeofday()");
271
272	display_chan();
273}
274
275void setup_if(char *dev) {
276        struct ifreq ifr;
277        unsigned int flags;
278        struct ifmediareq ifmr;
279        int *mwords;
280
281        // set iface up and promisc
282        memset(&ifr, 0, sizeof(ifr));
283        strcpy(ifr.ifr_name, dev);
284        if (ioctl(ioctl_s, SIOCGIFFLAGS, &ifr) == -1)
285                die(1, "ioctl(SIOCGIFFLAGS)");
286
287        flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
288        flags |= IFF_UP | IFF_PPROMISC;
289
290        memset(&ifr, 0, sizeof(ifr));
291        strcpy(ifr.ifr_name, dev);
292        ifr.ifr_flags = flags & 0xffff;
293        ifr.ifr_flagshigh = flags >> 16;
294        if (ioctl(ioctl_s, SIOCSIFFLAGS, &ifr) == -1)
295                die(1, "ioctl(SIOCSIFFLAGS)");
296
297        // set monitor mode
298        memset(&ifmr, 0, sizeof(ifmr));
299        strcpy(ifmr.ifm_name, dev);
300        if (ioctl(ioctl_s, SIOCGIFMEDIA, &ifmr) == -1)
301                die(1, "ioctl(SIOCGIFMEDIA)");
302
303        if (ifmr.ifm_count == 0)
304                die(0, "0 media thinggies...\n");
305
306        mwords = (int *)malloc(ifmr.ifm_count * sizeof(int));
307        if (!mwords)
308                die(1, "malloc()");
309
310        ifmr.ifm_ulist = mwords;
311
312        if (ioctl(ioctl_s, SIOCGIFMEDIA, &ifmr) == -1)
313                die(1, "ioctl(SIOCGIFMEDIA)");
314
315	free(mwords);
316
317        memset(&ifr, 0, sizeof(ifr));
318        strcpy(ifr.ifr_name, dev);
319        ifr.ifr_media = ifmr.ifm_current | IFM_IEEE80211_MONITOR;
320        if (ioctl(ioctl_s, SIOCSIFMEDIA, &ifr) == -1)
321                die(1, "ioctl(SIOCSIFMEDIA)");
322
323        // set chan
324        memset(&chaninfo.ireq, 0, sizeof(chaninfo.ireq));
325        strcpy(chaninfo.ireq.i_name, dev);
326        chaninfo.ireq.i_type = IEEE80211_IOC_CHANNEL;
327
328        set_chan(1);
329}
330
331void open_bpf(char *dev, int dlt) {
332        int i;
333        char buf[64];
334        int fd = -1;
335        struct ifreq ifr;
336
337        for(i = 0;i < 16; i++) {
338                sprintf(buf, "/dev/bpf%d", i);
339
340                fd = open(buf, O_RDWR);
341                if(fd < 0) {
342                        if(errno != EBUSY)
343				die(1,"can't open /dev/bpf");
344                        continue;
345                }
346                else
347                        break;
348        }
349
350        if(fd < 0)
351                die(1, "can't open /dev/bpf");
352
353        strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)-1);
354        ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
355
356        if(ioctl(fd, BIOCSETIF, &ifr) < 0)
357                die(1, "ioctl(BIOCSETIF)");
358
359        if (ioctl(fd, BIOCSDLT, &dlt) < 0)
360                die(1, "ioctl(BIOCSDLT)");
361
362        i = 1;
363        if(ioctl(fd, BIOCIMMEDIATE, &i) < 0)
364                die(1, "ioctl(BIOCIMMEDIATE)");
365
366	bpf_s = fd;
367}
368
369void user_input() {
370	static char chan[3];
371	static int pos = 0;
372	int c;
373
374	c = getch();
375
376	switch (c) {
377		case 'w':
378			save_state();
379			break;
380
381		case 'q':
382			cleanup(0);
383			break;
384
385		case 'c':
386			chaninfo.locked = !chaninfo.locked;
387			break;
388
389		case ERR:
390			die(0, "getch()");
391			break;
392
393		case '0':
394		case '1':
395		case '2':
396		case '3':
397		case '4':
398		case '5':
399		case '6':
400		case '7':
401		case '8':
402		case '9':
403			chan[pos++] = c;
404			if (pos == 2) {
405				int ch = atoi(chan);
406				if (ch <= 11 && ch >= 1) {
407					set_chan(atoi(chan));
408					chaninfo.locked = 1;
409				}
410				pos = 0;
411			}
412			break;
413
414		default:
415			pos = 0;
416			break;
417	}
418}
419
420void display_node(struct node_info* node) {
421	int x = 0;
422	int y = 0;
423	int i;
424	char chan[3];
425	char* ssid = 0;
426	int sig, max, left, noise;
427	char* wep = 0;
428
429	y = node->pos;
430	if (y == -1) // offscreen
431		return;
432
433	assert(y < LINES);
434
435	// MAC
436	mvaddstr(y, x, mac2str(node->mac));
437	x += 6*3;
438
439	// WEP
440	wep = wep2str(node->wep);
441	assert(wep);
442	mvaddstr(y, x, wep);
443	x += strlen(wep);
444	x++;
445
446	// CHAN
447	sprintf(chan, "%.2d", node->chan);
448	mvaddstr(y, x, chan);
449	x += 3;
450
451	// ssid
452	ssid = ssid2str(node);
453	assert(ssid);
454	mvaddstr(y, x, ssid);
455	x += strlen(ssid);
456	x++;
457
458	left = COLS - x - 1;
459
460	sig = (int)  ( ((double)node->signal)*left/100.0 );
461	noise=(int)  ( ((double)node->noise)*left/100.0 );
462	max = (int)  ( ((double)node->max)*left/100.0 );
463
464	// SIGNAL BAR
465	for (i = 0; i < noise; i++)
466		mvaddch(y, x++, 'N');
467
468	for (; i < sig; i++)
469		mvaddch(y,x++, 'X');
470
471	for (; i < max; i++)
472		mvaddch(y,x++, ' ');
473	mvaddch(y,x++, '|');
474
475	for (; x < COLS-1; x++)
476		mvaddch(y, x, ' ');
477
478	assert (x <= COLS);
479}
480
481void update_node(struct node_info* data) {
482	struct node_info* node;
483	int sort = 0;
484
485	assert(data->signal <= 100);
486
487	node = nodes;
488
489	// first time [virgin]
490	if (!node) {
491		node = (struct node_info*) malloc(sizeof(struct node_info));
492		if (!node)
493			die(1, "malloc()");
494
495		memset(node, 0, sizeof(*node));
496		memcpy(node->mac, data->mac, 6);
497		nodes = node;
498	}
499
500	while (node) {
501		// found it
502		if (memcmp(node->mac, data->mac, 6) == 0)
503			break;
504
505		// end of chain
506		if (!node->next) {
507			node->next = (struct node_info*)
508				      malloc(sizeof(struct node_info));
509			if (!node->next)
510				die(1, "malloc()");
511
512			memset(node->next, 0, sizeof(*node->next));
513			memcpy(node->next->mac, data->mac, 6);
514			node->next->prev = node;
515			node->next->pos = node->pos+1;
516
517			node = node->next;
518			if (node->pos == LINES)
519				sort = 1;
520			break;
521		}
522
523		node = node->next;
524	}
525	assert(node);
526
527	// too many nodes for screen
528	if (sort) {
529		struct node_info* ni = nodes;
530
531		while (ni) {
532			if (ni->pos != -1)
533				ni->pos--;
534
535			display_node(ni);
536			ni = ni->next;
537		}
538	}
539
540	node->signal = data->signal;
541	if (data->signal > node->max)
542		node->max = data->signal;
543
544	if (gettimeofday(&node->seen, NULL) == -1)
545		die(1, "gettimeofday()");
546
547	if (data->ssid[0] != 0)
548		strcpy(node->ssid, data->ssid);
549	if (data->chan != -1)
550		node->chan = data->chan;
551	if (data->wep != -1) {
552		// XXX LAME --- won't detect if AP changes WEP mode in
553		// beacons...
554		if (node->wep != CRYPT_WEP &&
555		    node->wep != CRYPT_NONE &&
556		    data->wep == CRYPT_WEP) {
557		}
558		else
559			node->wep = data->wep;
560	}
561	if (data->ap != -1)
562		node->ap = data->ap;
563
564	display_node(node);
565	refresh();
566}
567
568void get_beacon_info(unsigned char* data, int rd,
569		     struct node_info* node) {
570
571	int blen = 8 + 2 + 2;
572
573	strcpy(node->ssid, "<hidden>");
574	node->chan = 0;
575	node->wep = CRYPT_NONE;
576
577	assert(rd >= blen);
578
579	if (IEEE80211_BEACON_CAPABILITY(data) & IEEE80211_CAPINFO_PRIVACY)
580		node->wep = CRYPT_WEP;
581
582	data += blen;
583	rd -= blen;
584
585	while (rd > 2) {
586                int eid, elen;
587
588                eid = *data;
589                data++;
590                elen = *data;
591                data++;
592                rd -= 2;
593
594		// short!
595                if (rd < elen) {
596                        return;
597                }
598
599                // ssid
600                if (eid == 0) {
601			if (elen == 1 && data[0] == 0) {
602			// hidden
603			}
604			else {
605                        	memcpy(node->ssid, data, elen);
606                        	node->ssid[elen] = 0;
607			}
608                }
609                // chan
610                else if(eid == 3) {
611			// weird chan!
612                        if( elen != 1)
613				goto next;
614
615                        node->chan = *data;
616                }
617		// WPA
618		else if (eid == 221 && node->wep == CRYPT_WEP) {
619			struct ieee80211_ie_wpa* wpa;
620
621			wpa = (struct ieee80211_ie_wpa*) data;
622			if (elen < 6)
623				goto next;
624
625			if (!memcmp(wpa->wpa_oui, "\x00\x50\xf2", 3)) {
626			//	node->wep = CRYPT_WPA;
627			}
628			else
629				goto next;
630
631			if (wpa->wpa_type == WPA_OUI_TYPE &&
632			    le16toh(wpa->wpa_version) == WPA_VERSION) {
633			    	int cipher, auth;
634				unsigned char* ptr;
635
636				node->wep = CRYPT_WPA1;
637
638				if (elen < 12)
639					goto next;
640
641				cipher = ((unsigned char*) wpa->wpa_mcipher)[3];
642
643				ptr = (unsigned char*)wpa + 12 +
644				      4 * le16toh(wpa->wpa_uciphercnt);
645
646				if (elen < (ptr - data + 6))
647					goto next;
648
649				if ( *((unsigned short*) ptr) == 0)
650					goto next;
651
652				ptr += 2 + 3;
653				auth = *ptr;
654
655				if (cipher == WPA_CSE_TKIP) {
656					node->wep = CRYPT_WPA1_TKIP;
657
658					if (auth == WPA_ASE_8021X_PSK)
659						node->wep = CRYPT_WPA1_TKIP_PSK;
660				}
661
662				if (cipher == WPA_CSE_CCMP) {
663					node->wep = CRYPT_WPA1_CCMP;
664
665					if (auth == WPA_ASE_8021X_PSK)
666						node->wep = CRYPT_WPA1_CCMP_PSK;
667				}
668			}
669		}
670		else if (eid == 48 && node->wep == CRYPT_WEP) {
671			unsigned char* ptr;
672
673			// XXX no bounds checking
674			ptr = data;
675
676			if (ptr[0] == 1 && ptr[1] == 0) {
677				unsigned short* count;
678				int cipher = 0;
679
680				ptr += 2;
681				node->wep = CRYPT_80211i;
682
683				if (!memcmp(ptr, "\x00\x0f\xac\x02", 4)) {
684					node->wep = CRYPT_80211i_TKIP;
685					cipher = 1;
686				}
687
688				ptr += 4;
689				count = (unsigned short*) ptr;
690				ptr +=2 + *count*4;
691
692				count = (unsigned short*) ptr;
693				if (*count) {
694					ptr += 2;
695
696					if (!memcmp(ptr,"\x00\x0f\xac\x02", 4)) {
697						if (cipher)
698							node->wep = CRYPT_80211i_TKIP_PSK;
699					}
700				}
701			}
702		}
703
704next:
705                data += elen;
706                rd -= elen;
707	}
708}
709
710int get_packet_info(struct ieee80211_frame* wh,
711		     unsigned char* body, int bodylen,
712		     struct node_info* node) {
713
714	int type, stype;
715
716	node->chan = chaninfo.chan;
717	node->wep = -1;
718	node->ssid[0] = 0;
719	node->ap = -1;
720
721	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
722
723	if (type == IEEE80211_FC0_TYPE_CTL)
724		return 0;
725#if 0
726	if (wh->i_addr2[0] != 0) {
727		mvprintw(30,30,"%s %x",mac2str(wh->i_addr2), wh->i_fc[0]);
728	}
729#endif
730
731	stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
732
733	if (type == IEEE80211_FC0_TYPE_MGT &&
734	    stype == IEEE80211_FC0_SUBTYPE_BEACON) {
735		get_beacon_info(body, bodylen, node);
736		node->ap = 1;
737	}
738
739	else if (type == IEEE80211_FC0_TYPE_DATA &&
740	    stype == IEEE80211_FC0_SUBTYPE_DATA) {
741
742		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
743			unsigned char* iv;
744
745			node->wep = CRYPT_WEP;
746
747			iv = body;
748			iv += 3;
749
750			// extended IV?
751			if (*iv & (1 << 1)) {
752#if 0
753				node->wep = CRYPT_WPA;
754				mvprintw(20,20, "shei");
755				exit(1);
756#endif
757			}
758		}
759
760		if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS)
761			node->ap = 1;
762		else
763			node->ap = 0;
764	}
765
766	memcpy(node->mac, wh->i_addr2, 6);
767	return 1;
768}
769
770void radiotap(unsigned char* data, int rd) {
771	struct ieee80211_radiotap_header* rth;
772	struct ieee80211_frame* wh;
773	char* body;
774	struct node_info node;
775	int8_t signal_dbm, noise_dbm;
776	uint8_t signal_db, noise_db;
777	int dbm = 0;
778	int signal = 0;
779	int i;
780
781	rd -= 4; // 802.11 CRC
782
783	// radiotap
784	rth = (struct ieee80211_radiotap_header*) data;
785
786	// 802.11
787	wh = (struct ieee80211_frame*)
788	     ((char*)rth + rth->it_len);
789        rd -= rth->it_len;
790
791	assert (rd >= 0);
792
793	// body
794	body = (char*) wh + sizeof(*wh);
795	rd -= sizeof(*wh);
796
797	if (!get_packet_info(wh, body, rd, &node))
798		return;
799
800	// signal and noise
801	body = (char*) rth + sizeof(*rth);
802	signal_dbm = noise_dbm = signal_db = noise_db = 0;
803
804	for (i = IEEE80211_RADIOTAP_TSFT; i <= IEEE80211_RADIOTAP_EXT; i++) {
805		if (!(rth->it_present & (1 << i)))
806			continue;
807
808		switch (i) {
809		case IEEE80211_RADIOTAP_TSFT:
810			body += sizeof(uint64_t);
811			break;
812
813		case IEEE80211_RADIOTAP_FLAGS:
814		case IEEE80211_RADIOTAP_RATE:
815			body += sizeof(uint8_t);
816			break;
817
818		case IEEE80211_RADIOTAP_CHANNEL:
819			body += sizeof(uint16_t)*2;
820			break;
821
822		case IEEE80211_RADIOTAP_FHSS:
823			body += sizeof(uint16_t);
824			break;
825
826		case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
827			signal_dbm = *body;
828			body++;
829			dbm = 1;
830			break;
831
832		case IEEE80211_RADIOTAP_DBM_ANTNOISE:
833			noise_dbm = *body;
834			body++;
835			break;
836
837		case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
838			signal_db = *((unsigned char*)body);
839			body++;
840			break;
841
842		case IEEE80211_RADIOTAP_DB_ANTNOISE:
843			noise_db = *((unsigned char*)body);
844			body++;
845			break;
846
847		case IEEE80211_RADIOTAP_EXT:
848			abort();
849			break;
850		}
851	}
852	if (dbm) {
853		signal = signal_dbm - noise_dbm;
854	}
855	else {
856		signal = signal_db - noise_db;
857	}
858	if (signal < 0)
859		signal = 0;
860
861	node.signal = signal;
862#if 0
863	if (node.signal > 100 || node.signal < 0) {
864		mvprintw(25,25, "sig=%d", node.signal);
865	}
866#else
867	assert (node.signal <= 100 && node.signal >= 0);
868#endif
869
870	update_node(&node);
871}
872
873void bpf_input() {
874	static unsigned char buf[4096];
875	int rd;
876	struct bpf_hdr* bpfh;
877	unsigned char* data;
878
879	rd = read(bpf_s, buf, sizeof(buf));
880	if (rd == -1)
881		die(1,"read()");
882
883	bpfh = (struct bpf_hdr*) buf;
884	rd -= bpfh->bh_hdrlen;
885
886	if (rd != bpfh->bh_caplen) {
887		assert( rd > bpfh->bh_caplen);
888		rd = bpfh->bh_caplen;
889	}
890
891	data = (unsigned char*) bpfh + bpfh->bh_hdrlen;
892	radiotap(data, rd);
893}
894
895unsigned long elapsed_ms(struct timeval* now, struct timeval* prev) {
896	unsigned long elapsed = 0;
897
898	if (now->tv_sec > prev->tv_sec)
899		elapsed = 1000*1000 - prev->tv_usec +
900			  now->tv_usec;
901	else {
902		assert(now->tv_sec == prev->tv_sec);
903		elapsed = now->tv_usec - prev->tv_usec;
904	}
905	elapsed /= 1000; //ms
906
907	elapsed += (now->tv_sec - prev->tv_sec)*1000;
908	return elapsed;
909}
910
911void chanhop(struct timeval* tv) {
912	unsigned long elapsed = 0;
913
914	if (gettimeofday(tv, NULL) == -1)
915		die(1, "gettimeofday()");
916
917
918	elapsed = elapsed_ms(tv, &chaninfo.last_hop);
919
920	// need to chan hop
921	if (elapsed >= hopfreq) {
922		int c;
923
924		c = chaninfo.chan + 1;
925
926		if (c > 11)
927			c = 1;
928
929		set_chan(c);
930
931		elapsed = hopfreq;
932	}
933	// how much can we sleep?
934	else {
935		elapsed = hopfreq - elapsed;
936	}
937
938	// ok calculate sleeping time...
939	tv->tv_sec = elapsed/1000;
940	tv->tv_usec = (elapsed - tv->tv_sec*1000)*1000;
941}
942
943void check_seen(struct timeval* tv) {
944	unsigned long elapsed  = 0;
945	struct timeval now;
946	int need_refresh = 0;
947	unsigned long min_wait = 0;
948	unsigned long will_wait;
949
950	will_wait = tv->tv_sec*1000+tv->tv_usec/1000;
951	min_wait = will_wait;
952
953	struct node_info* node = nodes;
954
955	if (gettimeofday(&now, NULL) == -1)
956		die(1, "gettimeofday()");
957
958	while(node) {
959		if (node->signal) {
960			elapsed = elapsed_ms(&now, &node->seen);
961
962			// node is dead...
963			if (elapsed >= sig_reset) {
964				node->signal = 0;
965				display_node(node);
966				need_refresh = 1;
967			}
968
969			// need to check soon possibly...
970			else {
971				unsigned long left;
972
973				left = sig_reset - elapsed;
974				if (left < min_wait)
975					left = min_wait;
976			}
977		}
978		node = node->next;
979	}
980
981	if (need_refresh)
982		refresh();
983
984	// need to sleep for less...
985	if (min_wait < will_wait) {
986		tv->tv_sec = min_wait/1000;
987		tv->tv_usec = (min_wait - tv->tv_sec*1000)*1000;
988	}
989}
990
991void own(char* ifname) {
992	int rd;
993	fd_set fds;
994	struct timeval tv;
995	int dlt = DLT_IEEE802_11_RADIO;
996
997	hopfreq = 1000;
998
999	setup_if(ifname);
1000	open_bpf(ifname, dlt);
1001
1002	while(1) {
1003		// XXX innefficient all of this...
1004		if (!chaninfo.locked)
1005			chanhop(&tv);
1006		else {
1007			tv.tv_sec = 1;
1008			tv.tv_usec = 0;
1009		}
1010
1011		// especially this...
1012		check_seen(&tv);
1013
1014		FD_ZERO(&fds);
1015		FD_SET(0, &fds);
1016		FD_SET(bpf_s, &fds);
1017
1018		rd = select(bpf_s+1, &fds,NULL , NULL, &tv);
1019		if (rd == -1)
1020			die(1, "select()");
1021		if (FD_ISSET(0, &fds))
1022			user_input();
1023		if (FD_ISSET(bpf_s, &fds))
1024			bpf_input();
1025	}
1026}
1027
1028void init_globals() {
1029	ioctl_s = socket(PF_INET, SOCK_DGRAM, 0);
1030	if (ioctl_s == -1) {
1031		perror("socket()");
1032		exit(1);
1033	}
1034
1035	chaninfo.locked = 0;
1036	chaninfo.chan = 0;
1037}
1038
1039int main(int argc, char *argv[]) {
1040
1041
1042	if (argc < 2) {
1043		printf("Usage: %s <iface>\n", argv[0]);
1044		exit(1);
1045	}
1046
1047	init_globals();
1048
1049	initscr(); cbreak(); noecho();
1050
1051	nonl();
1052	intrflush(stdscr, FALSE);
1053	keypad(stdscr, TRUE);
1054
1055	curs_set(0);
1056
1057	clear();
1058	refresh();
1059
1060	signal(SIGINT, cleanup);
1061	signal(SIGTERM, cleanup);
1062
1063	own(argv[1]);
1064
1065	cleanup(0);
1066	exit(0);
1067}
1068