From 6c8c3a52c9fcd4a8dc5199067d8c1a734a165f7b Mon Sep 17 00:00:00 2001 From: sam Date: Sat, 5 Aug 2006 05:12:03 +0000 Subject: [PATCH] crude stumbler using raw packet api's Submitted by: Andrea Bittau --- tools/tools/net80211/stumbler/Makefile | 10 + tools/tools/net80211/stumbler/stumbler.c | 1067 ++++++++++++++++++++++ 2 files changed, 1077 insertions(+) create mode 100644 tools/tools/net80211/stumbler/Makefile create mode 100644 tools/tools/net80211/stumbler/stumbler.c diff --git a/tools/tools/net80211/stumbler/Makefile b/tools/tools/net80211/stumbler/Makefile new file mode 100644 index 000000000000..69abea7394bc --- /dev/null +++ b/tools/tools/net80211/stumbler/Makefile @@ -0,0 +1,10 @@ +# $FreeBSD$ + +PROG= stumbler +BINDIR= /usr/local/bin +DPADD= ${LIBPCAP} +LDADD= -lpcap -lncurses +CFLAGS=-g +NO_MAN= + +.include diff --git a/tools/tools/net80211/stumbler/stumbler.c b/tools/tools/net80211/stumbler/stumbler.c new file mode 100644 index 000000000000..ebedd71f6280 --- /dev/null +++ b/tools/tools/net80211/stumbler/stumbler.c @@ -0,0 +1,1067 @@ +/*- + * Copyright (c) 2006, Andrea Bittau + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +//int hopfreq = 3*1000; // ms +int hopfreq = 500; // ms +int sig_reset = 1*1000; // ms + + +int ioctl_s = -1; +int bpf_s = -1; + +struct chan_info { + int locked; + int chan; + struct ieee80211req ireq; + struct timeval last_hop; +} chaninfo; + + +#define CRYPT_NONE 0 +#define CRYPT_WEP 1 +#define CRYPT_WPA1 2 +#define CRYPT_WPA 3 +#define CRYPT_WPA1_TKIP 4 +#define CRYPT_WPA1_TKIP_PSK 5 +#define CRYPT_WPA1_CCMP 6 +#define CRYPT_WPA1_CCMP_PSK 7 +#define CRYPT_80211i 8 +#define CRYPT_80211i_TKIP 9 +#define CRYPT_80211i_TKIP_PSK 10 + +struct node_info { + unsigned char mac[6]; + int signal; + int noise; + int max; + unsigned char ssid[256]; + int chan; + int wep; + int pos; + int ap; + + struct timeval seen; + + struct node_info* prev; + struct node_info* next; +} *nodes = 0; + +void clean_crap() { + struct node_info* next; + + if (ioctl_s != -1) + close(ioctl_s); + if (bpf_s != -1) + close(bpf_s); + + while (nodes) { + next = nodes->next; + free(nodes); + nodes = next; + } +} + +char* mac2str(unsigned char* mac) { + static char ret[6*3]; + + sprintf(ret, "%.2X:%.2X:%.2X:%.2X:%.2X:%.2X", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + return ret; +} + +char* wep2str(int w) { + char* wep = 0; + static char res[14]; + + switch (w) { + case CRYPT_NONE: + wep = ""; + break; + + case CRYPT_WEP: + wep = "WEP"; + break; + + case CRYPT_WPA1: + wep = "WPA1"; + break; + + case CRYPT_WPA: + wep = "WPA?"; + break; + + case CRYPT_WPA1_TKIP: + wep = "WPA1-TKIP"; + break; + + case CRYPT_WPA1_TKIP_PSK: + wep = "WPA1-TKIP-PSK"; + break; + + case CRYPT_WPA1_CCMP: + wep = "WPA1-CCMP"; + break; + + case CRYPT_WPA1_CCMP_PSK: + wep = "WPA1-CCMP-PSK"; + break; + + case CRYPT_80211i: + wep = "i"; + break; + + case CRYPT_80211i_TKIP: + wep = "11i-TKIP"; + break; + + case CRYPT_80211i_TKIP_PSK: + wep = "11i-TKIP-PSK"; + break; + + default: + wep = "FIXME!"; + break; + } + + memset(res, ' ', sizeof(res)); + assert(strlen(wep) < sizeof(res)); + memcpy(res, wep, strlen(wep)); + res[sizeof(res)-1] = 0; + return res; +} + +char* ssid2str(struct node_info* node) { + static char res[24]; + + memset(res, ' ', sizeof(res)); + res[0] = '['; + strcpy(&res[sizeof(res)-2], "]"); + + if (node->ap) { + int left = sizeof(res) - 3; + + if (strlen(node->ssid) < left) + left = strlen(node->ssid); + memcpy(&res[1], node->ssid, left); + } + else { + memcpy(&res[1], "", 8); + } + return res; +} + +void save_state() { + FILE* f; + struct node_info* node = nodes; + + f = fopen("stumbler.log", "w"); + if (!f) { + perror("fopen()"); + exit(1); + } + + while (node) { + struct tm* t; + char tim[16]; + + t = localtime( (time_t*) &node->seen.tv_sec); + if (!t) { + perror("localtime()"); + exit(1); + } + tim[0] = 0; + strftime(tim, sizeof(tim), "%H:%M:%S", t); + + fprintf(f, "%s %s %s %2d %s 0x%.2x\n", tim, + mac2str(node->mac), wep2str(node->wep), + node->chan, ssid2str(node), node->max); + + node = node->next; + } + + fclose(f); +} + +void cleanup(int x) { + endwin(); + clean_crap(); + exit(0); +} + +void die(int p, char* msg) { + endwin(); + if (p) + perror(msg); + else + printf("%s\n", msg); + clean_crap(); + exit(1); +} + +void display_chan() { + int x, y; + char tmp[3]; + + x = COLS - 2; + y = LINES - 1; + + snprintf(tmp, sizeof(tmp), "%.2d", chaninfo.chan); + mvaddstr(y, x, tmp); + refresh(); +} + +void set_chan(int c) { + chaninfo.ireq.i_val = c; + + if (ioctl(ioctl_s, SIOCS80211, &chaninfo.ireq) == -1) + die(1, "ioctl(SIOCS80211) [chan]"); + + chaninfo.chan = c; + + if (gettimeofday(&chaninfo.last_hop, NULL) == -1) + die(1, "gettimeofday()"); + + display_chan(); +} + +void setup_if(char *dev) { + struct ifreq ifr; + unsigned int flags; + struct ifmediareq ifmr; + int *mwords; + + // set iface up and promisc + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, dev); + if (ioctl(ioctl_s, SIOCGIFFLAGS, &ifr) == -1) + die(1, "ioctl(SIOCGIFFLAGS)"); + + flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); + flags |= IFF_UP | IFF_PPROMISC; + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, dev); + ifr.ifr_flags = flags & 0xffff; + ifr.ifr_flagshigh = flags >> 16; + if (ioctl(ioctl_s, SIOCSIFFLAGS, &ifr) == -1) + die(1, "ioctl(SIOCSIFFLAGS)"); + + // set monitor mode + memset(&ifmr, 0, sizeof(ifmr)); + strcpy(ifmr.ifm_name, dev); + if (ioctl(ioctl_s, SIOCGIFMEDIA, &ifmr) == -1) + die(1, "ioctl(SIOCGIFMEDIA)"); + + if (ifmr.ifm_count == 0) + die(0, "0 media thinggies...\n"); + + mwords = (int *)malloc(ifmr.ifm_count * sizeof(int)); + if (!mwords) + die(1, "malloc()"); + + ifmr.ifm_ulist = mwords; + + if (ioctl(ioctl_s, SIOCGIFMEDIA, &ifmr) == -1) + die(1, "ioctl(SIOCGIFMEDIA)"); + + free(mwords); + + memset(&ifr, 0, sizeof(ifr)); + strcpy(ifr.ifr_name, dev); + ifr.ifr_media = ifmr.ifm_current | IFM_IEEE80211_MONITOR; + if (ioctl(ioctl_s, SIOCSIFMEDIA, &ifr) == -1) + die(1, "ioctl(SIOCSIFMEDIA)"); + + // set chan + memset(&chaninfo.ireq, 0, sizeof(chaninfo.ireq)); + strcpy(chaninfo.ireq.i_name, dev); + chaninfo.ireq.i_type = IEEE80211_IOC_CHANNEL; + + set_chan(1); +} + +void open_bpf(char *dev, int dlt) { + int i; + char buf[64]; + int fd = -1; + struct ifreq ifr; + + for(i = 0;i < 16; i++) { + sprintf(buf, "/dev/bpf%d", i); + + fd = open(buf, O_RDWR); + if(fd < 0) { + if(errno != EBUSY) + die(1,"can't open /dev/bpf"); + continue; + } + else + break; + } + + if(fd < 0) + die(1, "can't open /dev/bpf"); + + strncpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)-1); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = 0; + + if(ioctl(fd, BIOCSETIF, &ifr) < 0) + die(1, "ioctl(BIOCSETIF)"); + + if (ioctl(fd, BIOCSDLT, &dlt) < 0) + die(1, "ioctl(BIOCSDLT)"); + + i = 1; + if(ioctl(fd, BIOCIMMEDIATE, &i) < 0) + die(1, "ioctl(BIOCIMMEDIATE)"); + + bpf_s = fd; +} + +void user_input() { + static char chan[3]; + static int pos = 0; + int c; + + c = getch(); + + switch (c) { + case 'w': + save_state(); + break; + + case 'q': + cleanup(0); + break; + + case 'c': + chaninfo.locked = !chaninfo.locked; + break; + + case ERR: + die(0, "getch()"); + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + chan[pos++] = c; + if (pos == 2) { + int ch = atoi(chan); + if (ch <= 11 && ch >= 1) { + set_chan(atoi(chan)); + chaninfo.locked = 1; + } + pos = 0; + } + break; + + default: + pos = 0; + break; + } +} + +void display_node(struct node_info* node) { + int x = 0; + int y = 0; + int i; + char chan[3]; + char* ssid = 0; + int sig, max, left, noise; + char* wep = 0; + + y = node->pos; + if (y == -1) // offscreen + return; + + assert(y < LINES); + + // MAC + mvaddstr(y, x, mac2str(node->mac)); + x += 6*3; + + // WEP + wep = wep2str(node->wep); + assert(wep); + mvaddstr(y, x, wep); + x += strlen(wep); + x++; + + // CHAN + sprintf(chan, "%.2d", node->chan); + mvaddstr(y, x, chan); + x += 3; + + // ssid + ssid = ssid2str(node); + assert(ssid); + mvaddstr(y, x, ssid); + x += strlen(ssid); + x++; + + left = COLS - x - 1; + + sig = (int) ( ((double)node->signal)*left/100.0 ); + noise=(int) ( ((double)node->noise)*left/100.0 ); + max = (int) ( ((double)node->max)*left/100.0 ); + + // SIGNAL BAR + for (i = 0; i < noise; i++) + mvaddch(y, x++, 'N'); + + for (; i < sig; i++) + mvaddch(y,x++, 'X'); + + for (; i < max; i++) + mvaddch(y,x++, ' '); + mvaddch(y,x++, '|'); + + for (; x < COLS-1; x++) + mvaddch(y, x, ' '); + + assert (x <= COLS); +} + +void update_node(struct node_info* data) { + struct node_info* node; + int sort = 0; + + assert(data->signal <= 100); + + node = nodes; + + // first time [virgin] + if (!node) { + node = (struct node_info*) malloc(sizeof(struct node_info)); + if (!node) + die(1, "malloc()"); + + memset(node, 0, sizeof(*node)); + memcpy(node->mac, data->mac, 6); + nodes = node; + } + + while (node) { + // found it + if (memcmp(node->mac, data->mac, 6) == 0) + break; + + // end of chain + if (!node->next) { + node->next = (struct node_info*) + malloc(sizeof(struct node_info)); + if (!node->next) + die(1, "malloc()"); + + memset(node->next, 0, sizeof(*node->next)); + memcpy(node->next->mac, data->mac, 6); + node->next->prev = node; + node->next->pos = node->pos+1; + + node = node->next; + if (node->pos == LINES) + sort = 1; + break; + } + + node = node->next; + } + assert(node); + + // too many nodes for screen + if (sort) { + struct node_info* ni = nodes; + + while (ni) { + if (ni->pos != -1) + ni->pos--; + + display_node(ni); + ni = ni->next; + } + } + + node->signal = data->signal; + if (data->signal > node->max) + node->max = data->signal; + + if (gettimeofday(&node->seen, NULL) == -1) + die(1, "gettimeofday()"); + + if (data->ssid[0] != 0) + strcpy(node->ssid, data->ssid); + if (data->chan != -1) + node->chan = data->chan; + if (data->wep != -1) { + // XXX LAME --- won't detect if AP changes WEP mode in + // beacons... + if (node->wep != CRYPT_WEP && + node->wep != CRYPT_NONE && + data->wep == CRYPT_WEP) { + } + else + node->wep = data->wep; + } + if (data->ap != -1) + node->ap = data->ap; + + display_node(node); + refresh(); +} + +void get_beacon_info(unsigned char* data, int rd, + struct node_info* node) { + + int blen = 8 + 2 + 2; + + strcpy(node->ssid, ""); + node->chan = 0; + node->wep = CRYPT_NONE; + + assert(rd >= blen); + + if (IEEE80211_BEACON_CAPABILITY(data) & IEEE80211_CAPINFO_PRIVACY) + node->wep = CRYPT_WEP; + + data += blen; + rd -= blen; + + while (rd > 2) { + int eid, elen; + + eid = *data; + data++; + elen = *data; + data++; + rd -= 2; + + // short! + if (rd < elen) { + return; + } + + // ssid + if (eid == 0) { + if (elen == 1 && data[0] == 0) { + // hidden + } + else { + memcpy(node->ssid, data, elen); + node->ssid[elen] = 0; + } + } + // chan + else if(eid == 3) { + // weird chan! + if( elen != 1) + goto next; + + node->chan = *data; + } + // WPA + else if (eid == 221 && node->wep == CRYPT_WEP) { + struct ieee80211_ie_wpa* wpa; + + wpa = (struct ieee80211_ie_wpa*) data; + if (elen < 6) + goto next; + + if (!memcmp(wpa->wpa_oui, "\x00\x50\xf2", 3)) { + // node->wep = CRYPT_WPA; + } + else + goto next; + + if (wpa->wpa_type == WPA_OUI_TYPE && + le16toh(wpa->wpa_version) == WPA_VERSION) { + int cipher, auth; + unsigned char* ptr; + + node->wep = CRYPT_WPA1; + + if (elen < 12) + goto next; + + cipher = ((unsigned char*) wpa->wpa_mcipher)[3]; + + ptr = (unsigned char*)wpa + 12 + + 4 * le16toh(wpa->wpa_uciphercnt); + + if (elen < (ptr - data + 6)) + goto next; + + if ( *((unsigned short*) ptr) == 0) + goto next; + + ptr += 2 + 3; + auth = *ptr; + + if (cipher == WPA_CSE_TKIP) { + node->wep = CRYPT_WPA1_TKIP; + + if (auth == WPA_ASE_8021X_PSK) + node->wep = CRYPT_WPA1_TKIP_PSK; + } + + if (cipher == WPA_CSE_CCMP) { + node->wep = CRYPT_WPA1_CCMP; + + if (auth == WPA_ASE_8021X_PSK) + node->wep = CRYPT_WPA1_CCMP_PSK; + } + } + } + else if (eid == 48 && node->wep == CRYPT_WEP) { + unsigned char* ptr; + + // XXX no bounds checking + ptr = data; + + if (ptr[0] == 1 && ptr[1] == 0) { + unsigned short* count; + int cipher = 0; + + ptr += 2; + node->wep = CRYPT_80211i; + + if (!memcmp(ptr, "\x00\x0f\xac\x02", 4)) { + node->wep = CRYPT_80211i_TKIP; + cipher = 1; + } + + ptr += 4; + count = (unsigned short*) ptr; + ptr +=2 + *count*4; + + count = (unsigned short*) ptr; + if (*count) { + ptr += 2; + + if (!memcmp(ptr,"\x00\x0f\xac\x02", 4)) { + if (cipher) + node->wep = CRYPT_80211i_TKIP_PSK; + } + } + } + } + +next: + data += elen; + rd -= elen; + } +} + +int get_packet_info(struct ieee80211_frame* wh, + unsigned char* body, int bodylen, + struct node_info* node) { + + int type, stype; + + node->chan = chaninfo.chan; + node->wep = -1; + node->ssid[0] = 0; + node->ap = -1; + + type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK; + + if (type == IEEE80211_FC0_TYPE_CTL) + return 0; +#if 0 + if (wh->i_addr2[0] != 0) { + mvprintw(30,30,"%s %x",mac2str(wh->i_addr2), wh->i_fc[0]); + } +#endif + + stype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK; + + if (type == IEEE80211_FC0_TYPE_MGT && + stype == IEEE80211_FC0_SUBTYPE_BEACON) { + get_beacon_info(body, bodylen, node); + node->ap = 1; + } + + else if (type == IEEE80211_FC0_TYPE_DATA && + stype == IEEE80211_FC0_SUBTYPE_DATA) { + + if (wh->i_fc[1] & IEEE80211_FC1_WEP) { + unsigned char* iv; + + node->wep = CRYPT_WEP; + + iv = body; + iv += 3; + + // extended IV? + if (*iv & (1 << 1)) { +#if 0 + node->wep = CRYPT_WPA; + mvprintw(20,20, "shei"); + exit(1); +#endif + } + } + + if (wh->i_fc[1] & IEEE80211_FC1_DIR_FROMDS) + node->ap = 1; + else + node->ap = 0; + } + + memcpy(node->mac, wh->i_addr2, 6); + return 1; +} + +void radiotap(unsigned char* data, int rd) { + struct ieee80211_radiotap_header* rth; + struct ieee80211_frame* wh; + char* body; + struct node_info node; + int8_t signal_dbm, noise_dbm; + uint8_t signal_db, noise_db; + int dbm = 0; + int signal = 0; + int i; + + rd -= 4; // 802.11 CRC + + // radiotap + rth = (struct ieee80211_radiotap_header*) data; + + // 802.11 + wh = (struct ieee80211_frame*) + ((char*)rth + rth->it_len); + rd -= rth->it_len; + + assert (rd >= 0); + + // body + body = (char*) wh + sizeof(*wh); + rd -= sizeof(*wh); + + if (!get_packet_info(wh, body, rd, &node)) + return; + + // signal and noise + body = (char*) rth + sizeof(*rth); + signal_dbm = noise_dbm = signal_db = noise_db = 0; + + for (i = IEEE80211_RADIOTAP_TSFT; i <= IEEE80211_RADIOTAP_EXT; i++) { + if (!(rth->it_present & (1 << i))) + continue; + + switch (i) { + case IEEE80211_RADIOTAP_TSFT: + body += sizeof(uint64_t); + break; + + case IEEE80211_RADIOTAP_FLAGS: + case IEEE80211_RADIOTAP_RATE: + body += sizeof(uint8_t); + break; + + case IEEE80211_RADIOTAP_CHANNEL: + body += sizeof(uint16_t)*2; + break; + + case IEEE80211_RADIOTAP_FHSS: + body += sizeof(uint16_t); + break; + + case IEEE80211_RADIOTAP_DBM_ANTSIGNAL: + signal_dbm = *body; + body++; + dbm = 1; + break; + + case IEEE80211_RADIOTAP_DBM_ANTNOISE: + noise_dbm = *body; + body++; + break; + + case IEEE80211_RADIOTAP_DB_ANTSIGNAL: + signal_db = *((unsigned char*)body); + body++; + break; + + case IEEE80211_RADIOTAP_DB_ANTNOISE: + noise_db = *((unsigned char*)body); + body++; + break; + + case IEEE80211_RADIOTAP_EXT: + abort(); + break; + } + } + if (dbm) { + signal = signal_dbm - noise_dbm; + } + else { + signal = signal_db - noise_db; + } + if (signal < 0) + signal = 0; + + node.signal = signal; +#if 0 + if (node.signal > 100 || node.signal < 0) { + mvprintw(25,25, "sig=%d", node.signal); + } +#else + assert (node.signal <= 100 && node.signal >= 0); +#endif + + update_node(&node); +} + +void bpf_input() { + static unsigned char buf[4096]; + int rd; + struct bpf_hdr* bpfh; + unsigned char* data; + + rd = read(bpf_s, buf, sizeof(buf)); + if (rd == -1) + die(1,"read()"); + + bpfh = (struct bpf_hdr*) buf; + rd -= bpfh->bh_hdrlen; + + if (rd != bpfh->bh_caplen) { + assert( rd > bpfh->bh_caplen); + rd = bpfh->bh_caplen; + } + + data = (unsigned char*) bpfh + bpfh->bh_hdrlen; + radiotap(data, rd); +} + +unsigned long elapsed_ms(struct timeval* now, struct timeval* prev) { + unsigned long elapsed = 0; + + if (now->tv_sec > prev->tv_sec) + elapsed = 1000*1000 - prev->tv_usec + + now->tv_usec; + else { + assert(now->tv_sec == prev->tv_sec); + elapsed = now->tv_usec - prev->tv_usec; + } + elapsed /= 1000; //ms + + elapsed += (now->tv_sec - prev->tv_sec)*1000; + return elapsed; +} + +void chanhop(struct timeval* tv) { + unsigned long elapsed = 0; + + if (gettimeofday(tv, NULL) == -1) + die(1, "gettimeofday()"); + + + elapsed = elapsed_ms(tv, &chaninfo.last_hop); + + // need to chan hop + if (elapsed >= hopfreq) { + int c; + + c = chaninfo.chan + 1; + + if (c > 11) + c = 1; + + set_chan(c); + + elapsed = hopfreq; + } + // how much can we sleep? + else { + elapsed = hopfreq - elapsed; + } + + // ok calculate sleeping time... + tv->tv_sec = elapsed/1000; + tv->tv_usec = (elapsed - tv->tv_sec*1000)*1000; +} + +void check_seen(struct timeval* tv) { + unsigned long elapsed = 0; + struct timeval now; + int need_refresh = 0; + unsigned long min_wait = 0; + unsigned long will_wait; + + will_wait = tv->tv_sec*1000+tv->tv_usec/1000; + min_wait = will_wait; + + struct node_info* node = nodes; + + if (gettimeofday(&now, NULL) == -1) + die(1, "gettimeofday()"); + + while(node) { + if (node->signal) { + elapsed = elapsed_ms(&now, &node->seen); + + // node is dead... + if (elapsed >= sig_reset) { + node->signal = 0; + display_node(node); + need_refresh = 1; + } + + // need to check soon possibly... + else { + unsigned long left; + + left = sig_reset - elapsed; + if (left < min_wait) + left = min_wait; + } + } + node = node->next; + } + + if (need_refresh) + refresh(); + + // need to sleep for less... + if (min_wait < will_wait) { + tv->tv_sec = min_wait/1000; + tv->tv_usec = (min_wait - tv->tv_sec*1000)*1000; + } +} + +void own(char* ifname) { + int rd; + fd_set fds; + struct timeval tv; + int dlt = DLT_IEEE802_11_RADIO; + + hopfreq = 1000; + + setup_if(ifname); + open_bpf(ifname, dlt); + + while(1) { + // XXX innefficient all of this... + if (!chaninfo.locked) + chanhop(&tv); + else { + tv.tv_sec = 1; + tv.tv_usec = 0; + } + + // especially this... + check_seen(&tv); + + FD_ZERO(&fds); + FD_SET(0, &fds); + FD_SET(bpf_s, &fds); + + rd = select(bpf_s+1, &fds,NULL , NULL, &tv); + if (rd == -1) + die(1, "select()"); + if (FD_ISSET(0, &fds)) + user_input(); + if (FD_ISSET(bpf_s, &fds)) + bpf_input(); + } +} + +void init_globals() { + ioctl_s = socket(PF_INET, SOCK_DGRAM, 0); + if (ioctl_s == -1) { + perror("socket()"); + exit(1); + } + + chaninfo.locked = 0; + chaninfo.chan = 0; +} + +int main(int argc, char *argv[]) { + + + if (argc < 2) { + printf("Usage: %s \n", argv[0]); + exit(1); + } + + init_globals(); + + initscr(); cbreak(); noecho(); + + nonl(); + intrflush(stdscr, FALSE); + keypad(stdscr, TRUE); + + curs_set(0); + + clear(); + refresh(); + + signal(SIGINT, cleanup); + signal(SIGTERM, cleanup); + + own(argv[1]); + + cleanup(0); + exit(0); +}