diff options
author | Jonathan McCrohan <jmccrohan@gmail.com> | 2014-01-25 00:07:30 +0000 |
---|---|---|
committer | Jonathan McCrohan <jmccrohan@gmail.com> | 2014-01-25 00:07:30 +0000 |
commit | d7ca0c3e555ef0b5250873ddce48ccf2326b017a (patch) | |
tree | 52fc801f0893eb7752524b2602d420afbda4ed59 /scan_scr.c | |
parent | 3645c236e9720deb696e7aebc33cd9a6d8cbbdc6 (diff) | |
download | wavemon-d7ca0c3e555ef0b5250873ddce48ccf2326b017a.tar.gz |
Imported Upstream version 0.7.6upstream/0.7.6
Diffstat (limited to 'scan_scr.c')
-rw-r--r-- | scan_scr.c | 241 |
1 files changed, 108 insertions, 133 deletions
@@ -20,44 +20,42 @@ #include "iw_if.h" #define START_LINE 2 /* where to begin the screen */ -#define NUMTOP 5 /* maximum number of 'top' statistics entries */ /* GLOBALS */ +static struct scan_result sr; +static pthread_t scan_thread; static WINDOW *w_aplst; -static pid_t pid; -static void (*sig_tstp)(int); -static char *fmt_scan_result(struct scan_result *cur, struct iw_range *iw_range, - char buf[], size_t buflen) +/** + * Sanitize and format single scan entry as a string. + * @cur: entry to format + * @buf: buffer to put results into + * @buflen: length of @buf + */ +static void fmt_scan_entry(struct scan_entry *cur, char buf[], size_t buflen) { - struct iw_levelstat dbm; size_t len = 0; - int channel = freq_to_channel(cur->freq, iw_range); - - iw_sanitize(iw_range, &cur->qual, &dbm); if (!(cur->qual.updated & (IW_QUAL_QUAL_INVALID|IW_QUAL_LEVEL_INVALID))) len += snprintf(buf + len, buflen - len, "%3.0f%%, %.0f dBm", - 1E2 * cur->qual.qual / iw_range->max_qual.qual, - dbm.signal); + 1E2 * cur->qual.qual / sr.range.max_qual.qual, + cur->dbm.signal); else if (!(cur->qual.updated & IW_QUAL_QUAL_INVALID)) len += snprintf(buf + len, buflen - len, "%2d/%d", - cur->qual.qual, iw_range->max_qual.qual); + cur->qual.qual, sr.range.max_qual.qual); else if (!(cur->qual.updated & IW_QUAL_LEVEL_INVALID)) len += snprintf(buf + len, buflen - len, "%.0f dBm", - dbm.signal); + cur->dbm.signal); else len += snprintf(buf + len, buflen - len, "? dBm"); if (cur->freq < 1e3) len += snprintf(buf + len, buflen - len, ", Chan %2.0f", cur->freq); - else if (channel >= 0 && cur->freq < 5e9) - len += snprintf(buf + len, buflen - len, ", ch %2d, %g MHz", - channel, cur->freq / 1e6); - else if (channel >= 0) - len += snprintf(buf + len, buflen - len, ", CH %3d, %g MHz", - channel, cur->freq / 1e6); + else if (cur->chan >= 0) + len += snprintf(buf + len, buflen - len, ", %s %3d, %g MHz", + cur->freq < 5e9 ? "ch" : "CH", + cur->chan, cur->freq / 1e6); else len += snprintf(buf + len, buflen - len, ", %g GHz", cur->freq / 1e9); @@ -69,97 +67,53 @@ static char *fmt_scan_result(struct scan_result *cur, struct iw_range *iw_range, if (cur->flags) len += snprintf(buf + len, buflen - len, ", %s", format_enc_capab(cur->flags, "/")); - return buf; } static void display_aplist(WINDOW *w_aplst) { char s[IW_ESSID_MAX_SIZE << 3]; - int max_essid_len = 0; - int i, line = START_LINE; - int total = 0, open = 0, tg = 0, fg = 0; - struct iw_range range; - struct scan_result *head, *cur; - struct cnt *stats; - int max_cnt = NUMTOP; - int skfd = socket(AF_INET, SOCK_DGRAM, 0); - - if (skfd < 0) - err_sys("%s: can not open socket", __func__); - - iw_getinf_range(conf_ifname(), &range); - - head = get_scan_list(skfd, conf_ifname(), - range.we_version_compiled); - if (head) { - ; - } else if (errno == EPERM || !has_net_admin_capability()) { - /* - * Don't try to read leftover results, it does not work reliably - */ - sprintf(s, "This screen requires CAP_NET_ADMIN permissions"); - } else if (errno == EINTR || errno == EAGAIN || errno == EBUSY) { - /* Ignore temporary errors */ - goto done; - } else if (!if_is_up(skfd, conf_ifname())) { - sprintf(s, "Interface '%s' is down ", conf_ifname()); - if (!has_net_admin_capability()) - strcat(s, "- can not scan"); - else if (if_set_up(skfd, conf_ifname()) < 0) - sprintf(s, "Can not bring up '%s' for scanning: %s", - conf_ifname(), strerror(errno)); - else - strcat(s, "- setting it up ..."); - } else if (errno == EFAULT) { - /* - * EFAULT can occur after a window resizing event and is temporary. - * It may also occur when the interface is down, hence we need to - * test the interface status first. - */ - goto done; - } else if (errno) { - sprintf(s, "No scan on %s: %s", conf_ifname(), strerror(errno)); - } else { - sprintf(s, "No scan results on %s", conf_ifname()); - } - - for (i = 1; i <= MAXYLEN; i++) - mvwclrtoborder(w_aplst, i, 1); - - if (!head) - waddstr_center(w_aplst, WAV_HEIGHT/2 - 1, s); - - for (cur = head; cur; cur = cur->next, total++) { - if (str_is_ascii(cur->essid)) - max_essid_len = clamp(strlen(cur->essid), - max_essid_len, IW_ESSID_MAX_SIZE); - open += ! cur->has_key; - if (cur->freq < 1e3) - ; /* cur->freq is channel number */ - else if (cur->freq < 5e9) - tg++; - else - fg++; - } - - /* Truncate overly long access point lists to match screen height */ - for (cur = head; cur && line < MAXYLEN; line++, cur = cur->next) { - int col = CP_SCAN_NON_AP; + const char *sort_type[] = { + [SO_CHAN] = "Chan", + [SO_SIGNAL] = "Sig", + [SO_ESSID] = "Essid", + [SO_OPEN] = "Open", + [SO_CHAN_SIG] = "Ch/Sg", + [SO_OPEN_SIG] = "Op/Sg" + }; + int i, col, line = START_LINE; + struct scan_entry *cur; + + /* Scanning can take several seconds - do not refresh if locked. */ + if (pthread_mutex_trylock(&sr.mutex)) + return; + + if (sr.head || *sr.msg) + for (i = 1; i <= MAXYLEN; i++) + mvwclrtoborder(w_aplst, i, 1); + + if (!sr.head) + waddstr_center(w_aplst, WAV_HEIGHT/2 - 1, sr.msg); + + sort_scan_list(&sr.head); + + /* Truncate overly long access point lists to match screen height. */ + for (cur = sr.head; cur && line < MAXYLEN; line++, cur = cur->next) { + col = CP_SCAN_NON_AP; if (cur->mode == IW_MODE_MASTER) col = cur->has_key ? CP_SCAN_CRYPT : CP_SCAN_UNENC; wmove(w_aplst, line, 1); if (!*cur->essid) { - sprintf(s, "%-*s ", max_essid_len, "<hidden ESSID>"); + sprintf(s, "%-*s ", sr.max_essid_len, "<hidden ESSID>"); wattron(w_aplst, COLOR_PAIR(col)); waddstr(w_aplst, s); } else if (str_is_ascii(cur->essid)) { - sprintf(s, "%-*s ", max_essid_len, cur->essid); + sprintf(s, "%-*s ", sr.max_essid_len, cur->essid); waddstr_b(w_aplst, s); wattron(w_aplst, COLOR_PAIR(col)); } else { - sprintf(s, "%-*s ", max_essid_len, "<cryptic ESSID>"); + sprintf(s, "%-*s ", sr.max_essid_len, "<cryptic ESSID>"); wattron(w_aplst, COLOR_PAIR(col)); waddstr(w_aplst, s); } @@ -167,91 +121,112 @@ static void display_aplist(WINDOW *w_aplst) wattroff(w_aplst, COLOR_PAIR(col)); - fmt_scan_result(cur, &range, s, sizeof(s)); + fmt_scan_entry(cur, s, sizeof(s)); waddstr(w_aplst, " "); waddstr(w_aplst, s); } - /* Summary statistics at the bottom. */ - if (total < NUMTOP) + if (sr.num.entries < MAX_CH_STATS) goto done; wmove(w_aplst, MAXYLEN, 1); wadd_attr_str(w_aplst, A_REVERSE, "total:"); - sprintf(s, " %d", total); + sprintf(s, " %d ", sr.num.entries); waddstr(w_aplst, s); - if (total + START_LINE > line) { - sprintf(s, " (%d not shown)", total + START_LINE - line); + sprintf(s, "%s %ssc", sort_type[conf.scan_sort_order], conf.scan_sort_asc ? "a" : "de"); + wadd_attr_str(w_aplst, A_REVERSE, s); + + if (sr.num.entries + START_LINE > line) { + sprintf(s, ", %d not shown", sr.num.entries + START_LINE - line); waddstr(w_aplst, s); } - if (open) { - sprintf(s, ", %d open", open); + if (sr.num.open) { + sprintf(s, ", %d open", sr.num.open); waddstr(w_aplst, s); } - if (tg && fg) { + + if (sr.num.two_gig && sr.num.five_gig) { waddch(w_aplst, ' '); wadd_attr_str(w_aplst, A_REVERSE, "5/2GHz:"); - sprintf(s, " %d/%d", fg, tg); + sprintf(s, " %d/%d", sr.num.five_gig, sr.num.two_gig); waddstr(w_aplst, s); } - stats = channel_stats(head, &range, &max_cnt); - if (stats) { + if (sr.channel_stats) { waddch(w_aplst, ' '); - if (conf.scan_sort_order == SO_CHAN_REV) - sprintf(s, "bottom-%d:", max_cnt); + if (conf.scan_sort_order == SO_CHAN && !conf.scan_sort_asc) + sprintf(s, "bottom-%d:", (int)sr.num.ch_stats); else - sprintf(s, "top-%d:", max_cnt); + sprintf(s, "top-%d:", (int)sr.num.ch_stats); wadd_attr_str(w_aplst, A_REVERSE, s); - for (i = 0; i < max_cnt; i++) { - sprintf(s, "%s CH-%d(%d)", i ? "," : "", - stats[i].val, stats[i].count); + for (i = 0; i < sr.num.ch_stats; i++) { + waddstr(w_aplst, i ? ", " : " "); + sprintf(s, "ch#%d", sr.channel_stats[i].val); + wadd_attr_str(w_aplst, A_BOLD, s); + sprintf(s, " (%d)", sr.channel_stats[i].count); waddstr(w_aplst, s); } } - free(stats); done: - free_scan_result(head); - close(skfd); + pthread_mutex_unlock(&sr.mutex); wrefresh(w_aplst); } void scr_aplst_init(void) { w_aplst = newwin_title(0, WAV_HEIGHT, "Scan window", false); - /* - * Both parent and child process write to the terminal, updating - * different areas of the screen. Suspending wavemon brings the - * terminal state out of order, messing up the screen. The choice - * is between a more complicated (sophisticated) handling of - * signals, and to keep it simple by not allowing to suspend. - */ - sig_tstp = xsignal(SIGTSTP, SIG_IGN); /* Gathering scan data can take seconds. Inform user. */ mvwaddstr(w_aplst, START_LINE, 1, "Waiting for scan data ..."); wrefresh(w_aplst); - pid = fork(); - if (pid < 0) { - err_sys("could not fork scan process"); - } else if (pid == 0) { - do display_aplist(w_aplst); - while (usleep(conf.stat_iv * 1000) == 0); - exit(EXIT_SUCCESS); - } + scan_result_init(&sr); + pthread_create(&scan_thread, NULL, do_scan, &sr); } int scr_aplst_loop(WINDOW *w_menu) { - return wgetch(w_menu); + int key; + + display_aplist(w_aplst); + + key = wgetch(w_menu); + switch (key) { + case 'a': /* ascending */ + conf.scan_sort_asc = true; + return -1; + case 'c': /* channel */ + conf.scan_sort_order = SO_CHAN; + return -1; + case 'C': /* channel and signal */ + conf.scan_sort_order = SO_CHAN_SIG; + return -1; + case 'd': /* descending */ + conf.scan_sort_asc = false; + return -1; + case 'e': /* ESSID */ + conf.scan_sort_order = SO_ESSID; + return -1; + case 'o': /* open (descending is default) */ + conf.scan_sort_order = SO_OPEN; + conf.scan_sort_asc = false; + return -1; + case 'O': /* open and signal (descending) */ + conf.scan_sort_order = SO_OPEN_SIG; + conf.scan_sort_asc = false; + return -1; + case 's': /* signal */ + conf.scan_sort_order = SO_SIGNAL; + return -1; + } + return key; } void scr_aplst_fini(void) { - kill(pid, SIGTERM); + pthread_cancel(scan_thread); + scan_result_fini(&sr); delwin(w_aplst); - xsignal(SIGTSTP, sig_tstp); } |