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/stumbler/stumbler.c,v 1.2 2009/07/24 15:31:22 sam Exp $
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 <netproto/802_11/ieee80211_ioctl.h>
37 #include <netproto/802_11/ieee80211.h>
38 #include <net/ethernet.h>
39 #include <netproto/802_11/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
52 int hopfreq = 500; // ms
53 int sig_reset = 1*1000; // ms
54 
55 
56 int ioctl_s = -1;
57 int bpf_s = -1;
58 
59 struct 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 
79 struct 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 
96 void 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 
111 char* 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 
120 char* 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 
181 char* 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 
201 void 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 
233 void cleanup(int x) {
234 	endwin();
235 	clean_crap();
236 	exit(0);
237 }
238 
239 void 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 
249 void 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 
261 void 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 
275 void setup_if(char *dev) {
276         struct ifreq ifr;
277         unsigned int flags;
278 
279         // set chan
280         memset(&chaninfo.ireq, 0, sizeof(chaninfo.ireq));
281         strcpy(chaninfo.ireq.i_name, dev);
282         chaninfo.ireq.i_type = IEEE80211_IOC_CHANNEL;
283 
284         set_chan(1);
285 
286         // set iface up and promisc
287         memset(&ifr, 0, sizeof(ifr));
288         strcpy(ifr.ifr_name, dev);
289         if (ioctl(ioctl_s, SIOCGIFFLAGS, &ifr) == -1)
290                 die(1, "ioctl(SIOCGIFFLAGS)");
291 
292         flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
293         flags |= IFF_UP | IFF_PPROMISC;
294 
295         memset(&ifr, 0, sizeof(ifr));
296         strcpy(ifr.ifr_name, dev);
297         ifr.ifr_flags = flags & 0xffff;
298         ifr.ifr_flagshigh = flags >> 16;
299         if (ioctl(ioctl_s, SIOCSIFFLAGS, &ifr) == -1)
300                 die(1, "ioctl(SIOCSIFFLAGS)");
301 }
302 
303 void open_bpf(char *dev, int dlt) {
304         int i;
305         char buf[64];
306         int fd = -1;
307         struct ifreq ifr;
308 
309         for(i = 0;i < 16; i++) {
310                 sprintf(buf, "/dev/bpf%d", i);
311 
312                 fd = open(buf, O_RDWR);
313                 if(fd < 0) {
314                         if(errno != EBUSY)
315 				die(1,"can't open /dev/bpf");
316                         continue;
317                 }
318                 else
319                         break;
320         }
321 
322         if(fd < 0)
323                 die(1, "can't open /dev/bpf");
324 
325         strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)-1);
326         ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0;
327 
328         if(ioctl(fd, BIOCSETIF, &ifr) < 0)
329                 die(1, "ioctl(BIOCSETIF)");
330 
331         if (ioctl(fd, BIOCSDLT, &dlt) < 0)
332                 die(1, "ioctl(BIOCSDLT)");
333 
334         i = 1;
335         if(ioctl(fd, BIOCIMMEDIATE, &i) < 0)
336                 die(1, "ioctl(BIOCIMMEDIATE)");
337 
338 	bpf_s = fd;
339 }
340 
341 void user_input() {
342 	static char chan[3];
343 	static int pos = 0;
344 	int c;
345 
346 	c = getch();
347 
348 	switch (c) {
349 		case 'w':
350 			save_state();
351 			break;
352 
353 		case 'q':
354 			cleanup(0);
355 			break;
356 
357 		case 'c':
358 			chaninfo.locked = !chaninfo.locked;
359 			break;
360 
361 		case ERR:
362 			die(0, "getch()");
363 			break;
364 
365 		case '0':
366 		case '1':
367 		case '2':
368 		case '3':
369 		case '4':
370 		case '5':
371 		case '6':
372 		case '7':
373 		case '8':
374 		case '9':
375 			chan[pos++] = c;
376 			if (pos == 2) {
377 				int ch = atoi(chan);
378 				if (ch <= 11 && ch >= 1) {
379 					set_chan(atoi(chan));
380 					chaninfo.locked = 1;
381 				}
382 				pos = 0;
383 			}
384 			break;
385 
386 		default:
387 			pos = 0;
388 			break;
389 	}
390 }
391 
392 void display_node(struct node_info* node) {
393 	int x = 0;
394 	int y = 0;
395 	int i;
396 	char chan[3];
397 	char* ssid = 0;
398 	int sig, max, left, noise;
399 	char* wep = 0;
400 
401 	y = node->pos;
402 	if (y == -1) // offscreen
403 		return;
404 
405 	assert(y < LINES);
406 
407 	// MAC
408 	mvaddstr(y, x, mac2str(node->mac));
409 	x += 6*3;
410 
411 	// WEP
412 	wep = wep2str(node->wep);
413 	assert(wep);
414 	mvaddstr(y, x, wep);
415 	x += strlen(wep);
416 	x++;
417 
418 	// CHAN
419 	sprintf(chan, "%.2d", node->chan);
420 	mvaddstr(y, x, chan);
421 	x += 3;
422 
423 	// ssid
424 	ssid = ssid2str(node);
425 	assert(ssid);
426 	mvaddstr(y, x, ssid);
427 	x += strlen(ssid);
428 	x++;
429 
430 	left = COLS - x - 1;
431 
432 	sig = (int)  ( ((double)node->signal)*left/100.0 );
433 	noise=(int)  ( ((double)node->noise)*left/100.0 );
434 	max = (int)  ( ((double)node->max)*left/100.0 );
435 
436 	// SIGNAL BAR
437 	for (i = 0; i < noise; i++)
438 		mvaddch(y, x++, 'N');
439 
440 	for (; i < sig; i++)
441 		mvaddch(y,x++, 'X');
442 
443 	for (; i < max; i++)
444 		mvaddch(y,x++, ' ');
445 	mvaddch(y,x++, '|');
446 
447 	for (; x < COLS-1; x++)
448 		mvaddch(y, x, ' ');
449 
450 	assert (x <= COLS);
451 }
452 
453 void update_node(struct node_info* data) {
454 	struct node_info* node;
455 	int sort = 0;
456 
457 	assert(data->signal <= 100);
458 
459 	node = nodes;
460 
461 	// first time [virgin]
462 	if (!node) {
463 		node = (struct node_info*) malloc(sizeof(struct node_info));
464 		if (!node)
465 			die(1, "malloc()");
466 
467 		memset(node, 0, sizeof(*node));
468 		memcpy(node->mac, data->mac, 6);
469 		nodes = node;
470 	}
471 
472 	while (node) {
473 		// found it
474 		if (memcmp(node->mac, data->mac, 6) == 0)
475 			break;
476 
477 		// end of chain
478 		if (!node->next) {
479 			node->next = (struct node_info*)
480 				      malloc(sizeof(struct node_info));
481 			if (!node->next)
482 				die(1, "malloc()");
483 
484 			memset(node->next, 0, sizeof(*node->next));
485 			memcpy(node->next->mac, data->mac, 6);
486 			node->next->prev = node;
487 			node->next->pos = node->pos+1;
488 
489 			node = node->next;
490 			if (node->pos == LINES)
491 				sort = 1;
492 			break;
493 		}
494 
495 		node = node->next;
496 	}
497 	assert(node);
498 
499 	// too many nodes for screen
500 	if (sort) {
501 		struct node_info* ni = nodes;
502 
503 		while (ni) {
504 			if (ni->pos != -1)
505 				ni->pos--;
506 
507 			display_node(ni);
508 			ni = ni->next;
509 		}
510 	}
511 
512 	node->signal = data->signal;
513 	if (data->signal > node->max)
514 		node->max = data->signal;
515 
516 	if (gettimeofday(&node->seen, NULL) == -1)
517 		die(1, "gettimeofday()");
518 
519 	if (data->ssid[0] != 0)
520 		strcpy(node->ssid, data->ssid);
521 	if (data->chan != -1)
522 		node->chan = data->chan;
523 	if (data->wep != -1) {
524 		// XXX LAME --- won't detect if AP changes WEP mode in
525 		// beacons...
526 		if (node->wep != CRYPT_WEP &&
527 		    node->wep != CRYPT_NONE &&
528 		    data->wep == CRYPT_WEP) {
529 		}
530 		else
531 			node->wep = data->wep;
532 	}
533 	if (data->ap != -1)
534 		node->ap = data->ap;
535 
536 	display_node(node);
537 	refresh();
538 }
539 
540 void get_beacon_info(unsigned char* data, int rd,
541 		     struct node_info* node) {
542 
543 	int blen = 8 + 2 + 2;
544 
545 	strcpy(node->ssid, "<hidden>");
546 	node->chan = 0;
547 	node->wep = CRYPT_NONE;
548 
549 	assert(rd >= blen);
550 
551 	if (IEEE80211_BEACON_CAPABILITY(data) & IEEE80211_CAPINFO_PRIVACY)
552 		node->wep = CRYPT_WEP;
553 
554 	data += blen;
555 	rd -= blen;
556 
557 	while (rd > 2) {
558                 int eid, elen;
559 
560                 eid = *data;
561                 data++;
562                 elen = *data;
563                 data++;
564                 rd -= 2;
565 
566 		// short!
567                 if (rd < elen) {
568                         return;
569                 }
570 
571                 // ssid
572                 if (eid == 0) {
573 			if (elen == 1 && data[0] == 0) {
574 			// hidden
575 			}
576 			else {
577 				memcpy(node->ssid, data, elen);
578 				node->ssid[elen] = 0;
579 			}
580                 }
581                 // chan
582                 else if(eid == 3) {
583 			// weird chan!
584                         if( elen != 1)
585 				goto next;
586 
587                         node->chan = *data;
588                 }
589 		// WPA
590 		else if (eid == 221 && node->wep == CRYPT_WEP) {
591 			struct ieee80211_ie_wpa* wpa;
592 
593 			wpa = (struct ieee80211_ie_wpa*) data;
594 			if (elen < 6)
595 				goto next;
596 
597 			if (!memcmp(wpa->wpa_oui, "\x00\x50\xf2", 3)) {
598 			//	node->wep = CRYPT_WPA;
599 			}
600 			else
601 				goto next;
602 
603 			if (wpa->wpa_type == WPA_OUI_TYPE &&
604 			    le16toh(wpa->wpa_version) == WPA_VERSION) {
605 				int cipher, auth;
606 				unsigned char* ptr;
607 
608 				node->wep = CRYPT_WPA1;
609 
610 				if (elen < 12)
611 					goto next;
612 
613 				cipher = ((unsigned char*) wpa->wpa_mcipher)[3];
614 
615 				ptr = (unsigned char*)wpa + 12 +
616 				      4 * le16toh(wpa->wpa_uciphercnt);
617 
618 				if (elen < (ptr - data + 6))
619 					goto next;
620 
621 				if ( *((unsigned short*) ptr) == 0)
622 					goto next;
623 
624 				ptr += 2 + 3;
625 				auth = *ptr;
626 
627 				if (cipher == WPA_CSE_TKIP) {
628 					node->wep = CRYPT_WPA1_TKIP;
629 
630 					if (auth == WPA_ASE_8021X_PSK)
631 						node->wep = CRYPT_WPA1_TKIP_PSK;
632 				}
633 
634 				if (cipher == WPA_CSE_CCMP) {
635 					node->wep = CRYPT_WPA1_CCMP;
636 
637 					if (auth == WPA_ASE_8021X_PSK)
638 						node->wep = CRYPT_WPA1_CCMP_PSK;
639 				}
640 			}
641 		}
642 		else if (eid == 48 && node->wep == CRYPT_WEP) {
643 			unsigned char* ptr;
644 
645 			// XXX no bounds checking
646 			ptr = data;
647 
648 			if (ptr[0] == 1 && ptr[1] == 0) {
649 				unsigned short* count;
650 				int cipher = 0;
651 
652 				ptr += 2;
653 				node->wep = CRYPT_80211i;
654 
655 				if (!memcmp(ptr, "\x00\x0f\xac\x02", 4)) {
656 					node->wep = CRYPT_80211i_TKIP;
657 					cipher = 1;
658 				}
659 
660 				ptr += 4;
661 				count = (unsigned short*) ptr;
662 				ptr +=2 + *count*4;
663 
664 				count = (unsigned short*) ptr;
665 				if (*count) {
666 					ptr += 2;
667 
668 					if (!memcmp(ptr,"\x00\x0f\xac\x02", 4)) {
669 						if (cipher)
670 							node->wep = CRYPT_80211i_TKIP_PSK;
671 					}
672 				}
673 			}
674 		}
675 
676 next:
677                 data += elen;
678                 rd -= elen;
679 	}
680 }
681 
682 int get_packet_info(struct ieee80211_frame* wh,
683 		     unsigned char* body, int bodylen,
684 		     struct node_info* node) {
685 
686 	int type, stype;
687 
688 	node->chan = chaninfo.chan;
689 	node->wep = -1;
690 	node->ssid[0] = 0;
691 	node->ap = -1;
692 
693 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
694 
695 	if (type == IEEE80211_FC0_TYPE_CTL)
696 		return 0;
697 #if 0
698 	if (wh->i_addr2[0] != 0) {
699 		mvprintw(30,30,"%s %x",mac2str(wh->i_addr2), wh->i_fc[0]);
700 	}
701 #endif
702 
703 	stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
704 
705 	if (type == IEEE80211_FC0_TYPE_MGT &&
706 	    stype == IEEE80211_FC0_SUBTYPE_BEACON) {
707 		get_beacon_info(body, bodylen, node);
708 		node->ap = 1;
709 	}
710 
711 	else if (type == IEEE80211_FC0_TYPE_DATA &&
712 	    stype == IEEE80211_FC0_SUBTYPE_DATA) {
713 
714 		if (wh->i_fc[1] & IEEE80211_FC1_WEP) {
715 			unsigned char* iv;
716 
717 			node->wep = CRYPT_WEP;
718 
719 			iv = body;
720 			iv += 3;
721 
722 			// extended IV?
723 			if (*iv & (1 << 1)) {
724 #if 0
725 				node->wep = CRYPT_WPA;
726 				mvprintw(20,20, "shei");
727 				exit(1);
728 #endif
729 			}
730 		}
731 
732 		if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS)
733 			node->ap = 1;
734 		else
735 			node->ap = 0;
736 	}
737 
738 	memcpy(node->mac, wh->i_addr2, 6);
739 	return 1;
740 }
741 
742 void radiotap(unsigned char* data, int rd) {
743 	struct ieee80211_radiotap_header* rth;
744 	struct ieee80211_frame* wh;
745 	char* body;
746 	struct node_info node;
747 	int8_t signal_dbm, noise_dbm;
748 	uint8_t signal_db, noise_db;
749 	int dbm = 0;
750 	int signal = 0;
751 	int i;
752 
753 	rd -= 4; // 802.11 CRC
754 
755 	// radiotap
756 	rth = (struct ieee80211_radiotap_header*) data;
757 
758 	// 802.11
759 	wh = (struct ieee80211_frame*)
760 	     ((char*)rth + rth->it_len);
761         rd -= rth->it_len;
762 
763 	assert (rd >= 0);
764 
765 	// body
766 	body = (char*) wh + sizeof(*wh);
767 	rd -= sizeof(*wh);
768 
769 	if (!get_packet_info(wh, body, rd, &node))
770 		return;
771 
772 	// signal and noise
773 	body = (char*) rth + sizeof(*rth);
774 	signal_dbm = noise_dbm = signal_db = noise_db = 0;
775 
776 	for (i = IEEE80211_RADIOTAP_TSFT; i <= IEEE80211_RADIOTAP_EXT; i++) {
777 		if (!(rth->it_present & (1 << i)))
778 			continue;
779 
780 		switch (i) {
781 		case IEEE80211_RADIOTAP_TSFT:
782 			body += sizeof(uint64_t);
783 			break;
784 
785 		case IEEE80211_RADIOTAP_FLAGS:
786 		case IEEE80211_RADIOTAP_RATE:
787 			body += sizeof(uint8_t);
788 			break;
789 
790 		case IEEE80211_RADIOTAP_CHANNEL:
791 			body += sizeof(uint16_t)*2;
792 			break;
793 
794 		case IEEE80211_RADIOTAP_FHSS:
795 			body += sizeof(uint16_t);
796 			break;
797 
798 		case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
799 			signal_dbm = *body;
800 			body++;
801 			dbm = 1;
802 			break;
803 
804 		case IEEE80211_RADIOTAP_DBM_ANTNOISE:
805 			noise_dbm = *body;
806 			body++;
807 			break;
808 
809 		case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
810 			signal_db = *((unsigned char*)body);
811 			body++;
812 			break;
813 
814 		case IEEE80211_RADIOTAP_DB_ANTNOISE:
815 			noise_db = *((unsigned char*)body);
816 			body++;
817 			break;
818 
819 		case IEEE80211_RADIOTAP_EXT:
820 			abort();
821 			break;
822 		}
823 	}
824 	if (dbm) {
825 		signal = signal_dbm - noise_dbm;
826 	}
827 	else {
828 		signal = signal_db - noise_db;
829 	}
830 	if (signal < 0)
831 		signal = 0;
832 
833 	node.signal = signal;
834 #if 0
835 	if (node.signal > 100 || node.signal < 0) {
836 		mvprintw(25,25, "sig=%d", node.signal);
837 	}
838 #else
839 	assert (node.signal <= 100 && node.signal >= 0);
840 #endif
841 
842 	update_node(&node);
843 }
844 
845 void bpf_input() {
846 	static unsigned char buf[4096];
847 	int rd;
848 	struct bpf_hdr* bpfh;
849 	unsigned char* data;
850 
851 	rd = read(bpf_s, buf, sizeof(buf));
852 	if (rd == -1)
853 		die(1,"read()");
854 
855 	bpfh = (struct bpf_hdr*) buf;
856 	rd -= bpfh->bh_hdrlen;
857 
858 	if (rd != bpfh->bh_caplen) {
859 		assert( rd > bpfh->bh_caplen);
860 		rd = bpfh->bh_caplen;
861 	}
862 
863 	data = (unsigned char*) bpfh + bpfh->bh_hdrlen;
864 	radiotap(data, rd);
865 }
866 
867 unsigned long elapsed_ms(struct timeval* now, struct timeval* prev) {
868 	unsigned long elapsed = 0;
869 
870 	if (now->tv_sec > prev->tv_sec)
871 		elapsed = 1000*1000 - prev->tv_usec +
872 			  now->tv_usec;
873 	else {
874 		assert(now->tv_sec == prev->tv_sec);
875 		elapsed = now->tv_usec - prev->tv_usec;
876 	}
877 	elapsed /= 1000; //ms
878 
879 	elapsed += (now->tv_sec - prev->tv_sec)*1000;
880 	return elapsed;
881 }
882 
883 void chanhop(struct timeval* tv) {
884 	unsigned long elapsed = 0;
885 
886 	if (gettimeofday(tv, NULL) == -1)
887 		die(1, "gettimeofday()");
888 
889 
890 	elapsed = elapsed_ms(tv, &chaninfo.last_hop);
891 
892 	// need to chan hop
893 	if (elapsed >= hopfreq) {
894 		int c;
895 
896 		c = chaninfo.chan + 1;
897 
898 		if (c > 11)
899 			c = 1;
900 
901 		set_chan(c);
902 
903 		elapsed = hopfreq;
904 	}
905 	// how much can we sleep?
906 	else {
907 		elapsed = hopfreq - elapsed;
908 	}
909 
910 	// ok calculate sleeping time...
911 	tv->tv_sec = elapsed/1000;
912 	tv->tv_usec = (elapsed - tv->tv_sec*1000)*1000;
913 }
914 
915 void check_seen(struct timeval* tv) {
916 	unsigned long elapsed  = 0;
917 	struct timeval now;
918 	int need_refresh = 0;
919 	unsigned long min_wait = 0;
920 	unsigned long will_wait;
921 
922 	will_wait = tv->tv_sec*1000+tv->tv_usec/1000;
923 	min_wait = will_wait;
924 
925 	struct node_info* node = nodes;
926 
927 	if (gettimeofday(&now, NULL) == -1)
928 		die(1, "gettimeofday()");
929 
930 	while(node) {
931 		if (node->signal) {
932 			elapsed = elapsed_ms(&now, &node->seen);
933 
934 			// node is dead...
935 			if (elapsed >= sig_reset) {
936 				node->signal = 0;
937 				display_node(node);
938 				need_refresh = 1;
939 			}
940 
941 			// need to check soon possibly...
942 			else {
943 				unsigned long left;
944 
945 				left = sig_reset - elapsed;
946 				if (left < min_wait)
947 					left = min_wait;
948 			}
949 		}
950 		node = node->next;
951 	}
952 
953 	if (need_refresh)
954 		refresh();
955 
956 	// need to sleep for less...
957 	if (min_wait < will_wait) {
958 		tv->tv_sec = min_wait/1000;
959 		tv->tv_usec = (min_wait - tv->tv_sec*1000)*1000;
960 	}
961 }
962 
963 void own(char* ifname) {
964 	int rd;
965 	fd_set fds;
966 	struct timeval tv;
967 	int dlt = DLT_IEEE802_11_RADIO;
968 
969 	hopfreq = 1000;
970 
971 	setup_if(ifname);
972 	open_bpf(ifname, dlt);
973 
974 	while(1) {
975 		// XXX innefficient all of this...
976 		if (!chaninfo.locked)
977 			chanhop(&tv);
978 		else {
979 			tv.tv_sec = 1;
980 			tv.tv_usec = 0;
981 		}
982 
983 		// especially this...
984 		check_seen(&tv);
985 
986 		FD_ZERO(&fds);
987 		FD_SET(0, &fds);
988 		FD_SET(bpf_s, &fds);
989 
990 		rd = select(bpf_s+1, &fds,NULL , NULL, &tv);
991 		if (rd == -1)
992 			die(1, "select()");
993 		if (FD_ISSET(0, &fds))
994 			user_input();
995 		if (FD_ISSET(bpf_s, &fds))
996 			bpf_input();
997 	}
998 }
999 
1000 void init_globals() {
1001 	ioctl_s = socket(PF_INET, SOCK_DGRAM, 0);
1002 	if (ioctl_s == -1) {
1003 		perror("socket()");
1004 		exit(1);
1005 	}
1006 
1007 	chaninfo.locked = 0;
1008 	chaninfo.chan = 0;
1009 }
1010 
1011 int main(int argc, char *argv[]) {
1012 
1013 
1014 	if (argc < 2) {
1015 		printf("Usage: %s <iface>\n", argv[0]);
1016 		exit(1);
1017 	}
1018 
1019 	init_globals();
1020 
1021 	initscr(); cbreak(); noecho();
1022 
1023 	nonl();
1024 	intrflush(stdscr, FALSE);
1025 	keypad(stdscr, TRUE);
1026 
1027 	curs_set(0);
1028 
1029 	clear();
1030 	refresh();
1031 
1032 	signal(SIGINT, cleanup);
1033 	signal(SIGTERM, cleanup);
1034 
1035 	own(argv[1]);
1036 
1037 	cleanup(0);
1038 	exit(0);
1039 }
1040