2 This file is part of Wi-viz (http://wiviz.natetrue.com).
4 Wi-viz is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License v2 as published by
6 the Free Software Foundation.
8 Wi-viz is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with Wi-viz; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #define HOST_TIMEOUT 300
23 #include "wl_access.h"
25 #include "channelhopper.h"
34 #define nonzeromac(x) memcmp(x, "\0\0\0\0\0\0", 6)
36 void dealWithPacket(wiviz_cfg * cfg, struct pcap_pkthdr * header, const u_char * packet);
37 wiviz_host * gotHost(wiviz_cfg * cfg, u_char * mac, host_type type);
38 void fprint_mac(FILE * outf, u_char * mac, char * extra);
39 void print_mac(u_char * mac, char * extra);
40 void print_host(FILE * outf, wiviz_host * host);
41 void __cdecl signal_handler(int);
42 void readWL(wiviz_cfg * cfg);
45 wiviz_cfg * global_cfg;
47 ////////////////////////////////////////////////////////////////////////////////
48 int main(int argc, char * * argv) {
51 char errbuf[PCAP_ERRBUF_SIZE];
53 int oldMonitor, newMonitor;
54 struct pcap_pkthdr header;
58 int defaultHopSeq[] = { 1, 3, 6, 8, 11 };
61 signal(SIGUSR1, &signal_handler);
62 signal(SIGUSR2, &signal_handler);
64 fprintf(stderr, "Wi-Viz infogathering daemon by Nathan True\n");
66 memset(&cfg, 0, sizeof(wiviz_cfg));
68 cfg.lastKeepAlive = time(NULL);
69 cfg.channelHopping = 0;
70 cfg.channelDwellTime = 1000;
71 cfg.channelHopSeqLen = 5;
72 memcpy(cfg.channelHopSeq, defaultHopSeq, sizeof(defaultHopSeq));
74 wl_ioctl(WL_DEVICE, WLC_GET_MAGIC, &i, 4);
75 if (i != WLC_IOCTL_MAGIC) {
76 fprintf(stderr, "Wireless magic not correct, not querying wl for info\n");
81 wl_ioctl(WL_DEVICE, WLC_GET_MONITOR, &oldMonitor, 4);
83 wl_ioctl(WL_DEVICE, WLC_SET_MONITOR, &newMonitor, 4);
90 handle = pcap_open_live(dev, BUFSIZ, 1, 0, errbuf);
92 dev = "c:\\cifsroot\\wdump2.pcap";
93 handle = pcap_open_offline(dev, errbuf);
101 fprintf(stderr, "Failure to open pcap!\nErr=%s\n", errbuf);
105 packet = pcap_next(handle, &header);
107 dealWithPacket(&cfg, &header, packet);
108 if (time(NULL) - cfg.lastKeepAlive > 30) stop = 1;
111 signal_handler(SIGUSR1);
113 if (cfg.channelHopperPID) kill(cfg.channelHopperPID, SIGKILL);
115 for (i = 0; i < MAX_HOSTS; i++) {
116 print_host(stderr, cfg.hosts + i);
117 if (cfg.hosts[i].occupied) printf("\n");
118 if (cfg.hosts[i].apInfo) free(cfg.hosts[i].apInfo);
119 if (cfg.hosts[i].staInfo) free(cfg.hosts[i].staInfo);
122 wl_ioctl(WL_DEVICE, WLC_SET_MONITOR, &oldMonitor, 4);
128 ////////////////////////////////////////////////////////////////////////////////
129 void writeJavascript() {
134 outf = fopen("/tmp/wiviz-pipe", "w");
136 fprintf(stderr, "Failure to open output file\n");
140 global_cfg->lastKeepAlive = time(NULL);
142 if(global_cfg->readFromWl) readWL(global_cfg);
144 fprintf(outf, "top.hosts = new Array(\n");
145 for (i = 0; i < MAX_HOSTS; i++) {
146 h = global_cfg->hosts + i;
147 if (h->occupied == 0) continue;
148 if (time(NULL) - h->lastSeen > HOST_TIMEOUT) {
151 fprintf(outf, " new Array(");
153 fprintf(outf, "),\n");
155 fprintf(outf, "new Array());\n");
156 fprintf(outf, "var cfg_string = 'channel-");
157 if (global_cfg->channelHopping) {
158 fprintf(outf, "hopping");
161 fprintf(outf, "%i", global_cfg->curChannel);
163 fprintf(outf, "';\ntop.wiviz_callback(top.hosts, cfg_string);\n");
167 ////////////////////////////////////////////////////////////////////////////////
168 void reloadConfig() {
170 wiviz_cfg * cfg = global_cfg;
171 char filebuffer[512];
172 char * fbptr, * p, * v, * vv;
174 int hopCfgChanged = 0;
176 int newHopSeqLen = 0;
178 fprintf(stderr, "Loading config file\n");
180 cnf = fopen("/tmp/wiviz-cfg", "r");
182 fprintf(stderr, "Wiviz: No config file (/tmp/wiviz-cfg) present, using defaults\n");
186 fblen = fread(filebuffer, 1, 512, cnf);
189 fprintf(stderr, "Error reading config file\n");
192 filebuffer[fblen] = 0;
193 fprintf(stderr, "Read %i bytes from config file\n", fblen);
197 while (fbptr < filebuffer + fblen && *fbptr != 0) {
199 //Find end of parameter
200 for (; *fbptr != '=' && *fbptr != 0; fbptr++);
204 for (; *fbptr != '&' && *fbptr != 0; fbptr++);
206 fprintf(stderr, "Config: %s=%s\n", p, v);
207 //Apply configuration
208 if (!strcmp(p, "channelsel")) {
210 cfg->channelHopping = 0;
211 if (!strcmp(v, "hop")) {
212 //Set channel hopping
213 cfg->channelHopping = 1;
216 else if (!strcmp(v, "nochange")) {
217 //Don't change anything, read channel from wireless card
222 if (val < 1 || val > 14) {
223 fprintf(stderr, "Channel setting in config file invalid (%i)\n", cfg->curChannel);
226 cfg->curChannel = val;
227 if (cfg->readFromWl) {
228 if (wl_ioctl(WL_DEVICE, WLC_SET_CHANNEL, &cfg->curChannel, 4) < 0) {
229 fprintf(stderr, "Channel set to %i failed\n", cfg->curChannel);
233 fprintf(stderr, "Can't set channel, no Broadcom wireless device present\n");
238 if (!strcmp(p, "hopdwell")) {
240 if (val < 100) val = 100;
241 if (val > 30000) val = 30000;
242 if (cfg->channelDwellTime != val) hopCfgChanged = 1;
243 cfg->channelDwellTime = val;
245 if (!strcmp(p, "hopseq")) {
246 cfg->channelHopSeqLen = 0;
248 for (vv = v; *vv != ',' && *vv != 0; vv++);
250 cfg->channelHopSeq[cfg->channelHopSeqLen++] = atoi(v);
254 cfg->channelHopSeq[cfg->channelHopSeqLen++] = atoi(v);
259 if (!strcmp(p, "")) {
263 //Apply channel hopper settings
264 if (cfg->channelHopping == 0 && cfg->channelHopperPID) {
265 kill(cfg->channelHopperPID, SIGKILL);
266 cfg->channelHopperPID = 0;
268 if (cfg->channelHopping == 1 && hopCfgChanged) {
269 if (cfg->channelHopperPID) kill(cfg->channelHopperPID, SIGKILL);
270 if ((cfg->channelHopperPID = fork()) == 0) {
276 ////////////////////////////////////////////////////////////////////////////////
277 void __cdecl signal_handler(int signum) {
278 if (signum == SIGUSR1) writeJavascript();
279 if (signum == SIGUSR2) reloadConfig();
282 ////////////////////////////////////////////////////////////////////////////////
283 void dealWithPacket(wiviz_cfg * cfg, struct pcap_pkthdr * header, const u_char * packet) {
284 ieee802_11_hdr * hWifi;
287 wiviz_host * emergebss;
288 host_type type = typeUnknown;
294 ieee_802_11_mgt_frame * m;
295 char * src = "\0\0\0\0\0\0";
296 char * dst = "\0\0\0\0\0\0";
297 char * bss = "\0\0\0\0\0\0";
302 ap_enc_type encType = aetUnknown;
305 if (header->len < sizeof(prism_hdr) + sizeof(ieee802_11_hdr)) return;
306 hPrism = (prism_hdr *) packet;
307 hWifi = (ieee802_11_hdr *) (packet + (hPrism->msg_length));
309 //Parse the prism DIDs
310 i = (prism_did *)((char *)hPrism + sizeof(prism_hdr));
311 while ((int)i < (int)hWifi) {
312 if (i->did == pdn_rssi) rssi = *(int *)(i+1);
313 i = (prism_did *) ((int)(i+1) + i->length);
316 //Establish the frame type
317 wfType = ((hWifi->frame_control & 0xF0) >> 4) + ((hWifi->frame_control & 0xC) << 2);
319 case mgt_assocRequest:
320 case mgt_reassocRequest:
321 case mgt_probeRequest:
326 case mgt_assocResponse:
327 case mgt_reassocResponse:
328 case mgt_probeResponse:
336 to_ds = hWifi->flags & IEEE80211_TO_DS;
337 from_ds = hWifi->flags & IEEE80211_FROM_DS;
338 if ((wfType & 0xF0) == 0x20 && (wfType & 0xF) < 4) {
342 if (!from_ds) type = typeSta;
344 if (!to_ds && !from_ds) bss = hWifi->addr3;
345 if (to_ds && !from_ds) bss = hWifi->addr1;
346 if (!to_ds && from_ds) bss = hWifi->addr2;
348 if (type == typeUnknown) return;
350 //Parse the 802.11 tags
351 if (wfType == mgt_probeResponse || wfType == mgt_beacon) {
352 m = (ieee_802_11_mgt_frame *) (hWifi + 1);
353 if (m->caps & MGT_CAPS_IBSS) {
357 if (m->caps & MGT_CAPS_WEP) encType = aetEncWEP;
358 else encType = aetUnencrypted;
359 e = (ieee_802_11_tag *) ((int) m + sizeof(ieee_802_11_mgt_frame));
360 while ((u_int)e < (u_int)packet + header->len) {
361 if (e->tag == tagSSID) {
363 ssid = (char *)(e + 1);
365 if (e->tag == tagChannel) {
366 channel = *(char *)(e + 1);
368 if (e->tag == tagVendorSpecific) {
369 if (e->length >= 4 && memcmp(e + 1, "\x00\x50\xf2\x01", 4) == 0) {
374 e = (ieee_802_11_tag *) ((int)(e + 1) + e->length);
378 //Look up the host in the hash table
379 host = gotHost(cfg, src, type);
381 //Add any info we received
383 host->RSSI = host->RSSI * 9 / 10 + (-rssi * 10);
386 host->RSSI = -rssi * 100;
388 if (type == typeSta) {
389 if (nonzeromac(bss)) {
390 memcpy(host->staInfo->connectedBSSID, bss, 6);
391 host->staInfo->state = ssAssociated;
392 emergebss = gotHost(cfg, bss, typeAP);
393 if (emergebss->RSSI == 0) emergebss->RSSI = 10000;
394 memcpy(emergebss->apInfo->bssid, bss, 6);
396 emergebss->type = typeAdhocHub;
397 if (ssidlen > 0 && ssidlen <= 32) {
398 memcpy(emergebss->apInfo->ssid, ssid, ssidlen);
399 emergebss->apInfo->ssidlen = ssidlen;
401 if (channel) emergebss->apInfo->channel = channel;
402 emergebss->apInfo->flags = hWifi->flags;
403 emergebss->RSSI = host->RSSI;
404 if (encType != aetUnknown) emergebss->apInfo->encryption = encType;
407 if (wfType == mgt_probeRequest && host->staInfo->state == ssUnknown) host->staInfo->state = ssUnassociated;
409 if (type == typeAP) {
410 if (nonzeromac(bss)) {
411 memcpy(host->apInfo->bssid, bss, 6);
413 if (ssidlen > 0 && ssidlen <= 32) {
414 memcpy(host->apInfo->ssid, ssid, ssidlen);
415 host->apInfo->ssidlen = ssidlen;
417 if (channel) host->apInfo->channel = channel;
418 host->apInfo->flags = hWifi->flags;
419 if (encType != aetUnknown) host->apInfo->encryption = encType;
423 ////////////////////////////////////////////////////////////////////////////////
424 void print_mac(u_char * mac, char * extra) {
425 fprint_mac(stdout, mac, extra);
428 ////////////////////////////////////////////////////////////////////////////////
429 void fprint_mac(FILE * outf, u_char * mac, char * extra) {
430 fprintf(outf, "%02X:%02X:%02X:%02X:%02X:%02X%s",
440 ////////////////////////////////////////////////////////////////////////////////
441 #define MAX_PROBES MAX_HOSTS/2
442 wiviz_host * gotHost(wiviz_cfg * cfg, u_char * mac, host_type type) {
443 int i = (mac[5] + (mac[4] << 8)) % MAX_HOSTS;
445 wiviz_host * h = cfg->hosts + i;
446 while (h->occupied && memcmp(h->mac, mac, 6)) {
448 if (i >= MAX_HOSTS) {
452 if (c > MAX_PROBES) break;
455 fprintf(stderr, "New host, ");
456 fprint_mac(stderr, mac, ", type=");
457 fprintf(stderr, "%s\n", (type==typeAP) ? "AP" : ((type==typeSta) ? "Sta" : "Unk"));
460 h->lastSeen = time(NULL);
462 memcpy(h->mac, mac, 6);
463 if (h->type == typeAP && !h->apInfo) {
464 h->apInfo = (ap_info *) malloc(sizeof(ap_info));
465 memset(h->apInfo, 0, sizeof(ap_info));
467 if (h->type == typeSta && !h->staInfo) {
468 h->staInfo = (sta_info *) malloc(sizeof(sta_info));
469 memset(h->staInfo, 0, sizeof(sta_info));
474 ////////////////////////////////////////////////////////////////////////////////
475 void print_host(FILE * outf, wiviz_host * host) {
478 if (!host->occupied) return;
480 fprint_mac(outf, host->mac, "'");
481 fprintf(outf, ", -%i, '", host->RSSI / 100);
482 switch (host->type) {
483 case typeAP: fprintf(outf, "ap"); break;
484 case typeSta: fprintf(outf, "sta"); break;
485 case typeAdhocHub: fprintf(outf, "adhoc"); break;
487 if (host->type == typeSta) {
488 switch(host->staInfo->state) {
490 fprintf(outf, "-assoc-");
491 fprint_mac(outf, host->staInfo->connectedBSSID, "");
494 fprintf(outf, "-unassoc");
497 if (host->type == typeAP || host->type == typeAdhocHub) {
498 fprintf(outf, "-channel-%i-ssid-", host->apInfo->channel & 0xFF);
499 for (i = 0; i < host->apInfo->ssidlen; i++) {
500 fprintf(outf, "\\x%02X", *((char *)host->apInfo->ssid + i) & 0xFF);
502 switch (host->apInfo->encryption) {
503 case aetUnknown: fprintf(outf, "-?enc-?alg"); break;
504 case aetUnencrypted: fprintf(outf, "-unenc-na"); break;
505 case aetEncUnknown: fprintf(outf, "-enc-unknown"); break;
506 case aetEncWEP: fprintf(outf, "-enc-wep"); break;
507 case aetEncWPA: fprintf(outf, "-enc-wpa"); break;
510 fprintf(outf, "', %i", time(0) - host->lastSeen);
513 ////////////////////////////////////////////////////////////////////////////////
514 #define MAX_STA_COUNT 64
515 void readWL(wiviz_cfg * cfg) {
517 wiviz_host * host, * sta;
520 channel_info_t channel;
524 get_mac(WL_DEVICE, mac);
526 print_mac(mac, "\n");
527 if (!nonzeromac(mac)) return;
528 wl_ioctl(WL_DEVICE, WLC_GET_AP, &ap, 4);
530 host = gotHost(cfg, mac, typeAP);
531 wl_ioctl(WL_DEVICE, WLC_GET_BSSID, host->apInfo->bssid, 6);
532 wl_ioctl(WL_DEVICE, WLC_GET_SSID, &ssid, sizeof(wlc_ssid_t));
533 memcpy(host->apInfo->ssid, ssid.SSID, 32);
534 host->apInfo->ssidlen = ssid.SSID_len;
536 wl_ioctl(WL_DEVICE, WLC_GET_CHANNEL, &channel, sizeof(channel_info_t));
537 host->apInfo->channel = channel.hw_channel;
538 macs = (maclist_t *) malloc(4 + MAX_STA_COUNT * sizeof(ether_addr_t));
539 macs->count = MAX_STA_COUNT;
540 if (wl_ioctl(WL_DEVICE, WLC_GET_ASSOCLIST, macs, 4 + MAX_STA_COUNT * sizeof(ether_addr_t)) > -1) {
541 for (i = 0; i < macs->count; i++) {
542 sta = gotHost(cfg, (char *)&macs->ea[i], typeSta);
543 memcpy(starssi.mac, &macs->ea[i], 6);
545 starssi.zero_ex_forty_one = 0x41;
546 if (wl_ioctl(WL_DEVICE, WLC_GET_RSSI, &starssi, 12) < 0) printf("rssifail\n");
547 sta->RSSI = -starssi.RSSI * 100;
548 sta->staInfo->state = ssAssociated;
549 memcpy(sta->staInfo->connectedBSSID, host->apInfo->bssid, 6);
554 host = gotHost(cfg, mac, typeSta);
556 if (wl_ioctl(WL_DEVICE, WLC_GET_BSSID, &host->staInfo->connectedBSSID, 6) < 0) {
557 host->staInfo->state = ssUnassociated;
560 host->staInfo->state = ssAssociated;
563 if (wl_ioctl(WL_DEVICE, WLC_GET_CHANNEL, &channel, sizeof(channel_info_t)) >= 0) {
564 cfg->curChannel = channel.hw_channel;
565 fprintf(stderr, "Current channel is %i\n", cfg->curChannel);