diff options
-rw-r--r-- | NEWS | 14 | ||||
-rw-r--r-- | conf.c | 2 | ||||
-rwxr-xr-x | configure | 18 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | iw_if.h | 13 | ||||
-rw-r--r-- | iw_scan.c | 60 | ||||
-rw-r--r-- | scan_scr.c | 57 | ||||
-rw-r--r-- | ui.c | 6 | ||||
-rw-r--r-- | wavemon.1 | 25 | ||||
-rw-r--r-- | wavemon.c | 51 | ||||
-rw-r--r-- | wavemon.h | 12 | ||||
-rw-r--r-- | wavemonrc.5 | 2 |
12 files changed, 218 insertions, 44 deletions
@@ -1,5 +1,19 @@ NEWS ==== + +-------------------- +0.7.5 (2012-05-04) +-------------------- + * Scan window: + - added a summary status line to present summary statistics. + * Bug fixes: + - added additional keyboard shortcuts for each screen to cope with + terminals which remap the function keys, fixing Ubuntu bug #725036; + - the shortcut is the first character of the screen's name (F1: i, + F2: l, F3: s, F7: p, F8: h, F9: a, F10: q), see manpage for details; + - added work-around for terminals with broken terminfo entries (e.g. + old aterm), now supporting the vt100 PF1..4 sequences in addition. + -------------------- 0.7.4 (2012-02-03) -------------------- @@ -48,7 +48,7 @@ static char *sort_order[] = { static char *screen_names[] = { [SCR_INFO] = "Info screen", [SCR_LHIST] = "Histogram", - [SCR_APLIST] = "Scan window", + [SCR_SCAN] = "Scan window", NULL }; @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for wavemon 0.7.4. +# Generated by GNU Autoconf 2.68 for wavemon 0.7.5. # # Report bugs to <gerrit@erg.abdn.ac.uk>. # @@ -560,8 +560,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='wavemon' PACKAGE_TARNAME='wavemon-current' -PACKAGE_VERSION='0.7.4' -PACKAGE_STRING='wavemon 0.7.4' +PACKAGE_VERSION='0.7.5' +PACKAGE_STRING='wavemon 0.7.5' PACKAGE_BUGREPORT='gerrit@erg.abdn.ac.uk' PACKAGE_URL='http://eden-feed.erg.abdn.ac.uk/wavemon' @@ -1217,7 +1217,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures wavemon 0.7.4 to adapt to many kinds of systems. +\`configure' configures wavemon 0.7.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1282,7 +1282,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of wavemon 0.7.4:";; + short | recursive ) echo "Configuration of wavemon 0.7.5:";; esac cat <<\_ACEOF @@ -1363,7 +1363,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -wavemon configure 0.7.4 +wavemon configure 0.7.5 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -1786,7 +1786,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by wavemon $as_me 0.7.4, which was +It was created by wavemon $as_me 0.7.5, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -4610,7 +4610,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by wavemon $as_me 0.7.4, which was +This file was extended by wavemon $as_me 0.7.5, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -4664,7 +4664,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -wavemon config.status 0.7.4 +wavemon config.status 0.7.5 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index 48e4d88..8d6cbce 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ dnl Process this file with autoconf to produce a configure script. AC_PREREQ(2.64) -AC_INIT([wavemon], [0.7.4], [gerrit@erg.abdn.ac.uk], [wavemon-current], +AC_INIT([wavemon], [0.7.5], [gerrit@erg.abdn.ac.uk], [wavemon-current], [http://eden-feed.erg.abdn.ac.uk/wavemon]) @@ -254,10 +254,21 @@ struct scan_result { struct scan_result *next; }; - extern struct scan_result *get_scan_list(int skfd, const char *ifname, int we_version); extern void free_scan_result(struct scan_result *head); +/** + * struct cnt - count frequency of integer numbers + * @val: value to count + * @count: how often @val occurs + */ +struct cnt { + int val; + int count; +}; +extern struct cnt *channel_stats(struct scan_result *head, + struct iw_range *iw_range, int *max_cnt); + /* * General helper routines */ @@ -5,6 +5,7 @@ * replaced by corresponding netlink calls. */ #include "iw_if.h" +#include <search.h> /* lsearch(3) */ #define MAX_SCAN_WAIT 10000 /* maximum milliseconds spent waiting */ @@ -687,14 +688,13 @@ struct scan_result *get_scan_list(int skfd, const char *ifname, int we_version) if (f == 127) { struct scan_result *cur = head, **prev = &head; - f = 0; - while (cur && scan_cmp[conf.scan_sort_order](cur, new) > 0) prev = &cur->next, cur = cur->next; *prev = new; new->next = cur; new = NULL; + f = 0; } } free(new); /* may have been allocated but not filled in */ @@ -709,3 +709,59 @@ void free_scan_result(struct scan_result *head) free(head); } } + +/* + * Channel statistics + */ + + +/* + * For lfind, it compares key value with array member, needs to + * return 0 if they are the same, non-0 otherwise. + */ +static int cmp_key(const void *a, const void *b) +{ + return ((struct cnt *)a)->val - ((struct cnt *)b)->val; +} + +/* For quick-sorting the array in descending order of counts */ +static int cmp_cnt(const void *a, const void *b) +{ + if (conf.scan_sort_order == SO_CHAN_REV) + return ((struct cnt *)a)->count - ((struct cnt *)b)->count; + return ((struct cnt *)b)->count - ((struct cnt *)a)->count; +} + +struct cnt *channel_stats(struct scan_result *head, + struct iw_range *iw_range, int *max_cnt) +{ + struct scan_result *cur; + struct cnt *arr = NULL, *bin, key = {0, 0}; + size_t cnt = 0, n = 0; + + for (cur = head; cur; cur = cur->next) + cnt++; + if (!cnt) + return NULL; + + arr = calloc(cnt, sizeof(key)); + for (cur = head; cur && n < *max_cnt; cur = cur->next) { + key.val = freq_to_channel(cur->freq, iw_range); + + if (key.val >= 0) { + bin = lsearch(&key, arr, &n, sizeof(key), cmp_key); + if (bin) + bin->count++; + } + } + + if (n < *max_cnt) + *max_cnt = n; + if (n > 0) { + qsort(arr, n, sizeof(key), cmp_cnt); + } else { + free(arr); + return NULL; + } + return arr; +} @@ -20,6 +20,7 @@ #include "iw_if.h" #define START_LINE 2 /* where to begin the screen */ +#define NUMTOP 5 /* maximum number of 'top' statistics entries */ /* GLOBALS */ static WINDOW *w_aplst; @@ -48,7 +49,6 @@ static char *fmt_scan_result(struct scan_result *cur, struct iw_range *iw_range, else len += snprintf(buf + len, buflen - len, "? dBm"); - if (cur->freq < 1e3) len += snprintf(buf + len, buflen - len, ", Chan %2.0f", cur->freq); @@ -77,8 +77,11 @@ 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) @@ -126,10 +129,17 @@ static void display_aplist(WINDOW *w_aplst) if (!head) waddstr_center(w_aplst, WAV_HEIGHT/2 - 1, s); - for (cur = head; cur; cur = cur->next) { + 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 */ @@ -161,8 +171,49 @@ static void display_aplist(WINDOW *w_aplst) waddstr(w_aplst, " "); waddstr(w_aplst, s); } - free_scan_result(head); + + /* Summary statistics at the bottom. */ + if (total < NUMTOP) + goto done; + + wmove(w_aplst, MAXYLEN, 1); + wadd_attr_str(w_aplst, A_REVERSE, "total:"); + sprintf(s, " %d", total); + waddstr(w_aplst, s); + + if (total + START_LINE > line) { + sprintf(s, " (%d not shown)", total + START_LINE - line); + waddstr(w_aplst, s); + } + if (open) { + sprintf(s, ", %d open", open); + waddstr(w_aplst, s); + } + if (tg && fg) { + waddch(w_aplst, ' '); + wadd_attr_str(w_aplst, A_REVERSE, "5/2GHz:"); + sprintf(s, " %d/%d", fg, tg); + waddstr(w_aplst, s); + } + + stats = channel_stats(head, &range, &max_cnt); + if (stats) { + waddch(w_aplst, ' '); + if (conf.scan_sort_order == SO_CHAN_REV) + sprintf(s, "bottom-%d:", max_cnt); + else + sprintf(s, "top-%d:", max_cnt); + 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); + waddstr(w_aplst, s); + } + } + free(stats); done: + free_scan_result(head); close(skfd); wrefresh(w_aplst); } @@ -70,11 +70,11 @@ void waddstr_center(WINDOW *win, int y, const char *s) mvwaddstr(win, y, (WAV_WIDTH - strlen(s)) / 2, s); } -void waddstr_b(WINDOW *win, const char *s) +void wadd_attr_str(WINDOW *win, const int attrs, const char *s) { - wattron(win, A_BOLD); + wattron(win, attrs); waddstr(win, s); - wattroff(win, A_BOLD); + wattroff(win, attrs); } /* Enforce that @str is at most @len characters (excluding the terminal '\0') */ @@ -18,9 +18,11 @@ represents the same levels as a moving histogram. On startup, you'll see (depending on configuration) one of the different monitor screens. At the bottom, you'll find a \fImenu-bar\fR listing the -screens and their function key names. The following screens can be selected: +screens and their activating keys. Each screen is activated by either the +corresponding function key or the key corresponding to the first character +of the screen name. The following screens can be selected: .TP -.B Info (F1) +.B Info (F1 or 'i') This is the most comprehensive screen. It displays a condensed overview of wireless-specific parameters and network statistics, as well as bar graphs. The layout is arranged into several sub-sections. @@ -60,10 +62,8 @@ also determine the broadcast address (last 32 \- \fIprefix_len\fR bits set to 1), that address is shown only if it does not derive from the interface address and prefix length. Likewise, the interface MTU is shown only if it differs from the default Ethernet MTU of 1500 bytes. - -Another keyboard shortcut for this screen is '\fIi\fR'. .TP -.B Level histogram (F2) +.B Level histogram (F2 or 'l') This is a full-screen histogram plot showing the evolution of levels with time. The screen is partitioned into a grid, with dBm levels shown in green at the right hand side (depending on configuration). At the very minimum, @@ -71,7 +71,7 @@ the evolution of the signal-level is shown. If the wireless driver also supports noise-level information, additionally a noise graph and associated SNR graph appear. .TP -.B Scan window (F3) +.B Scan window (F3 or 's') A periodically updated network scan, showing access points and other wireless clients, ordered by frequency and then descending order of signal quality. Each entry starts with the ESSID, followed by the colour-coded MAC @@ -81,26 +81,29 @@ points (in this case the mode is shown at the end of the line). The uncoloured information following the MAC address lists relative and absolute signal strengths, channel, frequency, and the mode if the node is not an access point. +A status line at the bottom informs about the most (least) crowded channels, +depending on how \fIsort_order\fR is set (reverse channel or other); see +\fBwavemonrc\fR(5). Please note that gathering meaningful scan data can take several seconds. Partly for this reason, the Scan window is the only screen that can not be suspended (CTRL-Z). .TP -.B Preferences (F7) +.B Preferences (F7 or 'p') This screen allows you to change all program options such as interface and level scale parameters, and to save the new settings to the configuration file. Select a parameter with <up> and <down>, then change the value with <left> and <right>. Please refer to \fBwavemonrc\fR(5) for an in-depth description of applicable settings. .TP -.B Help (F8) +.B Help (F8 or 'h') This page might show an online-help. .TP -.B About (F9) +.B About (F9 or 'a') Release information and contact URLs. .TP -\fBQuit (F10) -Exit \fIwavemon\fR. An alternative shortcut for quitting is '\fIq\fR'. +\fBQuit (F10 or 'q') +Exit \fIwavemon\fR. .LP \fBNote:\fR some operations, such as displaying encryption information or performing scans, require \fBCAP_NET_ADMIN\fR privileges (see \fBcapabilities\fR(7)). For non-root users, these can be @@ -48,7 +48,7 @@ static const struct { .loop = scr_lhist_loop, .fini = scr_lhist_fini }, - [SCR_APLIST] = { + [SCR_SCAN] = { .key_name = "scan", .init = scr_aplst_init, .loop = scr_aplst_loop, @@ -63,7 +63,7 @@ static const struct { [SCR_EMPTY_F6] = { .key_name = "", }, - [SCR_CONF] = { + [SCR_PREFS] = { .key_name = "prefs", .init = scr_conf_init, .loop = scr_conf_loop, @@ -183,6 +183,7 @@ int main(int argc, char *argv[]) sigaddset(&blockmask, SIGWINCH); for (cur = conf.startup_scr; cur != SCR_QUIT; cur = next) { + int escape = 0; if (sigprocmask(SIG_BLOCK, &blockmask, &oldmask) < 0) err_sys("cannot block SIGWINCH"); @@ -202,24 +203,54 @@ int main(int argc, char *argv[]) if (key <= 0) usleep(5000); + /* + * Translate vt100 PF1..4 escape sequences sent + * by some X terminals (e.g. aterm) into F1..F4. + */ switch (key) { + case 033: + escape = 1; + break; + case 'O': + escape = 2; + break; + case 'P' ... 'S': + if (escape == 2) + key = KEY_F(key - 'P' + 1); + /* fall through */ + default: + escape = 0; + } + + /* Main menu */ + switch (key) { + case 'i': case KEY_F(1): + next = SCR_INFO; + break; + case 'l': case KEY_F(2): + next = SCR_LHIST; + break; + case 's': case KEY_F(3): + next = SCR_SCAN; + break; + case 'p': case KEY_F(7): + next = SCR_PREFS; + break; + case 'h': case KEY_F(8): - case KEY_F(9): - case KEY_F(10): - next = key - KEY_F(1); + next = SCR_HELP; break; - case 'i': - next = SCR_INFO; + case 'a': + case KEY_F(9): + next = SCR_ABOUT; break; case 'q': + case KEY_F(10): next = SCR_QUIT; - break; - default: - continue; } } while (next == cur); } @@ -181,11 +181,11 @@ struct conf_item { enum wavemon_screen { SCR_INFO, /* F1 */ SCR_LHIST, /* F2 */ - SCR_APLIST, /* F3 */ + SCR_SCAN, /* F3 */ SCR_EMPTY_F4, /* placeholder */ SCR_EMPTY_F5, /* placeholder */ SCR_EMPTY_F6, /* placeholder */ - SCR_CONF, /* F7 */ + SCR_PREFS, /* F7 */ SCR_HELP, /* F8 */ SCR_ABOUT, /* F9 */ SCR_QUIT /* F10 */ @@ -223,7 +223,13 @@ extern WINDOW *wmenubar(const enum wavemon_screen active); extern void wclrtoborder(WINDOW *win); extern void mvwclrtoborder(WINDOW *win, int y, int x); -extern void waddstr_b(WINDOW * win, const char *s); + +extern void wadd_attr_str(WINDOW *win, const int attrs, const char *s); +static inline void waddstr_b(WINDOW * win, const char *s) +{ + wadd_attr_str(win, A_BOLD, s); +} + extern void waddstr_center(WINDOW * win, int y, const char *s); extern const char *curtail(const char *str, const char *sep, int len); diff --git a/wavemonrc.5 b/wavemonrc.5 index 87dc89a..f860b89 100644 --- a/wavemonrc.5 +++ b/wavemonrc.5 @@ -34,6 +34,8 @@ Determines the ordering used in the scan window: (\fIrev\fR) \fIchannel\fR sorts \fIopen\fR in descending order of openness. The combined variants \fIchan/sig\fR and \fIopen/sig\fR sort first by channel/openness and then by signal strength; their combined functionality is provided by \fIopen/chan/sig\fR. +It also affects the status line at the bottom: normally the most crowded channels are listed, +use of \fIrev\ channel\fR switches to least crowded ones instead. .P .RE .B stat_updates = <n> |