]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - tools/tools/net80211/stumbler/stumbler.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / tools / tools / net80211 / stumbler / stumbler.c
1 /*-
2  * Copyright (c) 2006, Andrea Bittau <a.bittau@cs.ucl.ac.uk>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
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
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         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
331 void 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
369 void 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
420 void 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
481 void 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
568 void 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
704 next:
705                 data += elen;
706                 rd -= elen;
707         }
708 }
709
710 int 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
770 void 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
873 void 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
895 unsigned 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
911 void 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
943 void 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
991 void 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
1028 void 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
1039 int 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 }