/* * wavemon - a wireless network monitoring aplication * * Copyright (c) 2001-2002 Jan Morgenstern * Copyright (c) 2009 Gerrit Renker * * wavemon is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2, or (at your option) any later * version. * * wavemon is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along * with wavemon; see the file COPYING. If not, write to the Free Software * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "llist.h" #define CFNAME ".wavemonrc" /** * Minimum screen dimensions. * The number of lines depends on the size requirements of scr_info(). The * number of columns comes from the menubar length (10 items of length 6 * plus the 'Fxx'). This value was also chosen since 24x80 is a very common * screen size, in particular allowing the use on the console. */ enum info_screen_geometry { WH_IFACE = 2, /* 'Interface' area at the top */ WH_LEVEL = 9, /* Level meters */ WH_STATS = 3, /* WiFi statistics area */ WH_INFO_MIN = 7, /* WiFi information area */ WH_NET_MIN = 3, /* Network interface information area */ WH_NET_MAX = 5, /* Network interface information area */ WH_MENU = 1 /* Menu bar at the bottom */ }; #define WH_INFO_SCR_BASE (WH_IFACE + WH_LEVEL + WH_STATS + WH_MENU) #define WH_INFO_SCR_MIN (WH_INFO_SCR_BASE + WH_INFO_MIN + WH_NET_MIN) #define MIN_SCREEN_LINES WH_INFO_SCR_MIN #define MIN_SCREEN_COLS 80 /* * Screen layout constants. * * All windows extend over the whole screen width; the vertical number of * rows is reduced by one due to the menubar at the bottom of the screen. */ #define WAV_WIDTH (COLS) #define WAV_HEIGHT (LINES-1) /* * Maximum lengths/coordinates inside the bordered screen. * * The printable window area is constrained by the frame lines connecting * the corner points (0, 0), (0, COLS-1), (LINES-1, 0), (LINES-1, COLS-1). */ #define MAXXLEN (WAV_WIDTH - 2) #define MAXYLEN (WAV_HEIGHT - 2) /* Number of seconds to display a warning message outside ncurses mode */ #define WARN_DISPLAY_DELAY 1 /* Minimum SSID length */ #define MAX_ESSID_LEN 16 /* * Symbolic names of actions to take when crossing thresholds. * These actions invoke the corresponding ncurses functions. */ enum threshold_action { TA_DISABLED, TA_BEEP, TA_FLASH, TA_BEEP_FLASH }; static inline void threshold_action(enum threshold_action action) { if (action & TA_FLASH) flash(); if (action & TA_BEEP) beep(); } /* * Symbolic names for scan sort order comparison. */ enum scan_sort_order { SO_CHAN, SO_SIGNAL, SO_MAC, SO_ESSID, SO_OPEN, SO_CHAN_SIG, SO_OPEN_SIG }; /* * Global in-memory representation of current wavemon configuration state */ extern struct wavemon_conf { int if_idx; /* Index into interface list */ int stat_iv, info_iv; int sig_min, sig_max, noise_min, noise_max; int lthreshold, hthreshold; int slotsize, meter_decay; /* Boolean values */ int check_geometry, /* ensure window is large enough */ cisco_mac, /* Cisco-style MAC addresses */ transparent_bg, /* Use terminal background instead of black */ override_bounds, /* override autodetection */ scan_sort_asc; /* direction of @scan_sort_order */ /* Enumerated values */ int scan_sort_order, /* channel|signal|open|chan/sig ... */ lthreshold_action, /* disabled|beep|flash|beep+flash */ hthreshold_action, /* disabled|beep|flash|beep+flash */ startup_scr; /* info|histogram|aplist */ } conf; /* * Initialisation & Configuration */ extern void getconf(int argc, char *argv[]); /* Configuration items to manipulate the current configuration */ struct conf_item { char *name, /* name for preferences screen */ *cfname; /* name for ~/.wavemonrc */ enum { /* type of parameter */ t_int, /* @v.i is interpreted as raw value */ t_list, /* @v.i is an index into @list */ t_sep, /* dummy, separator entry */ t_func /* void (*fp) (void) */ } type; union { /* type-dependent container for value */ int *i; /* t_int and t_list index into @list */ void (*fp)(); /* t_func */ } v; char **list; /* t_list: NULL-terminated array of strings */ int *dep; /* dependency */ bool hidden; /* only allow to set via wavemonrc */ int min, /* value boundaries */ max, inc; /* increment for value changes */ char *unit; /* name of units to display */ }; /* * Screen functions */ enum wavemon_screen { SCR_INFO, /* F1 */ SCR_LHIST, /* F2 */ SCR_SCAN, /* F3 */ SCR_EMPTY_F4, /* placeholder */ SCR_EMPTY_F5, /* placeholder */ SCR_EMPTY_F6, /* placeholder */ SCR_PREFS, /* F7 */ SCR_HELP, /* F8 */ SCR_ABOUT, /* F9 */ SCR_QUIT /* F10 */ }; extern void scr_info_init(void); extern int scr_info_loop(WINDOW *w_menu); extern void scr_info_fini(void); extern void scr_lhist_init(void); extern int scr_lhist_loop(WINDOW *w_menu); extern void scr_lhist_fini(void); extern void scr_aplst_init(void); extern int scr_aplst_loop(WINDOW *w_menu); extern void scr_aplst_fini(void); extern void scr_conf_init(void); extern int scr_conf_loop(WINDOW *w_menu); extern void scr_conf_fini(void); extern void scr_help_init(void); extern int scr_help_loop(WINDOW *w_menu); extern void scr_help_fini(void); extern void scr_about_init(void); extern int scr_about_loop(WINDOW *w_menu); extern void scr_about_fini(void); /* * Ncurses definitions and functions */ extern WINDOW *newwin_title(int y, int h, const char *title, bool nobottom); extern WINDOW *wmenubar(const enum wavemon_screen active); extern void wclrtoborder(WINDOW *win); extern void mvwclrtoborder(WINDOW *win, int y, int x); 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); extern void waddbar(WINDOW *win, int y, float v, float min, float max, int8_t *cscale, bool rev); extern void waddthreshold(WINDOW *win, int y, float v, float tv, float minv, float maxv, int8_t *cscale, chtype tch); enum colour_pair { CP_STANDARD = 1, CP_SCALEHI, CP_SCALEMID, CP_SCALELOW, CP_WTITLE, CP_INACTIVE, CP_ACTIVE, CP_STATSIG, CP_STATNOISE, CP_STATSNR, CP_STATBKG, CP_STATSIG_S, CP_STATNOISE_S, CP_PREF_NORMAL, CP_PREF_SELECT, CP_PREF_ARROW, CP_SCAN_CRYPT, CP_SCAN_UNENC, CP_SCAN_NON_AP }; static inline int cp_from_scale(float value, int8_t const *cscale, bool reverse) { enum colour_pair cp; if (value < (float)cscale[0]) cp = reverse ? CP_SCALEHI : CP_SCALELOW; else if (value < (float)cscale[1]) cp = CP_SCALEMID; else cp = reverse ? CP_SCALELOW : CP_SCALEHI; return COLOR_PAIR(cp); } /* * Wireless interfaces */ extern const char *conf_ifname(void); extern void conf_get_interface_list(void); extern void iw_get_interface_list(char** if_list, size_t max_entries); /* * Error handling */ extern bool has_net_admin_capability(void); extern void err_msg(const char *format, ...); extern void err_quit(const char *format, ...); extern void err_sys(const char *format, ...); /* * Helper functions */ #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) static inline void (*xsignal(int signo, void (*handler)(int)))(int) { struct sigaction old_sa, sa = { .sa_handler = handler, .sa_flags = 0 }; if (sigemptyset(&sa.sa_mask) < 0 || sigaction(signo, &sa, &old_sa) < 0) err_sys("xsignal(%d) failed", signo); return old_sa.sa_handler; } static inline size_t argv_count(char **argv) { int cnt = 0; assert(argv != NULL); while (*argv++) cnt++; return cnt; } static inline int argv_find(char **argv, const char *what) { int cnt = argv_count(argv), len, i; assert(what != NULL); for (i = 0, len = strlen(what); i < cnt; i++) if (strncasecmp(argv[i], what, len) == 0) return i; return -1; } static inline void str_tolower(char *s) { for (; s && *s; s++) *s = tolower(*s); } /* Check if @str is printable (compare iw_essid_escape()) */ static inline bool str_is_ascii(char *s) { if (!s || !*s) return false; for (; *s; s++) if (!isascii(*s) || iscntrl(*s)) return false; return true; } /* number of digits needed to display integer part of @val */ static inline int num_int_digits(const double val) { return 1 + (val > 1.0 ? log10(val) : val < -1.0 ? log10(-val) : 0); } static inline int max(const int a, const int b) { return a > b ? a : b; } static inline bool in_range(int val, int min, int max) { return min <= val && val <= max; } static inline int clamp(int val, int min, int max) { return val < min ? min : (val > max ? max : val); } /* SI units -- see units(7) */ static inline char *byte_units(const double bytes) { static char result[0x100]; if (bytes >= 1 << 30) sprintf(result, "%0.2lf GiB", bytes / (1 << 30)); else if (bytes >= 1 << 20) sprintf(result, "%0.2lf MiB", bytes / (1 << 20)); else if (bytes >= 1 << 10) sprintf(result, "%0.2lf KiB", bytes / (1 << 10)); else sprintf(result, "%.0lf B", bytes); return result; } /* Integer units - similar to %g for float. */ static inline char *int_counts(uint32_t count) { static char result[0x10]; if (count < 1000) sprintf(result, "%u", count); else if (count < 1000000) sprintf(result, "%uk", count/1000); else sprintf(result, "%.lg", (double)count); return result; } /** * Compute exponentially weighted moving average * @mavg: old value of the moving average * @sample: new sample to update @mavg * @weight: decay factor for new samples, 0 < weight <= 1 */ static inline double ewma(double mavg, double sample, double weight) { return mavg == 0 ? sample : weight * mavg + (1.0 - weight) * sample; } /* map 0.0 <= ratio <= 1.0 into min..max */ static inline double map_val(double ratio, double min, double max) { return min + ratio * (max - min); } /* map minv <= val <= maxv into the range min..max (no clamping) */ static inline double map_range(double val, double minv, double maxv, double min, double max) { return map_val((val - minv) / (maxv - minv), min, max); } /* map val into the reverse range max..min */ static inline int reverse_range(int val, int min, int max) { assert(min <= val && val <= max); return max - (val - min); }