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