diff options
Diffstat (limited to 'iw_if.h')
-rw-r--r-- | iw_if.h | 451 |
1 files changed, 451 insertions, 0 deletions
@@ -0,0 +1,451 @@ +/* + * wavemon - a wireless network monitoring aplication + * + * Copyright (c) 2001-2002 Jan Morgenstern <jan@jm-music.de> + * + * 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 "wavemon.h" +#include <netdb.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netinet/ether.h> +#include <net/if_arp.h> +#include <net/ethernet.h> +#include <sys/socket.h> +#include <linux/if.h> +#include <linux/wireless.h> + +/* Definitions that appeared in more recent versions of wireless.h */ +#ifndef IW_POWER_SAVING +#define IW_POWER_SAVING 0x4000 /* version 20 -> 21 */ +#endif +#ifndef IW_MODE_MESH +#define IW_MODE_MESH 7 /* introduced in 2.6.26-rc1 */ +#endif + +/* Maximum length of a MAC address: 2 * 6 hex digits, 6 - 1 colons, plus '\0' */ +#define MAC_ADDR_MAX 18 + +/* + * Threshold for 'sane' noise levels. + * + * Some drivers simply set an arbitrary minimum noise level to mean 'invalid', + * but do not set IW_QUAL_NOISE_INVALID so that the display gets stuck at a + * "house number". The value below is suggested by and taken from the iwl3945 + * driver (constant IWL_NOISE_MEAS_NOT_AVAILABLE in iwl-3945.h). + */ +#define NOISE_DBM_SANE_MIN -127 + +/* Static network interface information - see netdevice(7) */ +struct if_info { /* modified ifreq */ + struct ether_addr hwaddr; + struct in_addr addr, + netmask, + bcast; +}; +extern void if_getinf(char *ifname, struct if_info *info); + +/** + * struct iw_dyn_info - modified iw_req + * @name: interface name + * @mode: current operation mode (IW_MODE_xxx) + * + * @cap_*: indicating capability/presence + * + * @essid: Extended Service Set ID (network name) + * @essid_ct: index number of the @essid (starts at 1, 0 = off) + * @nickname: optional station nickname + * @nwid: Network ID (pre-802.11 hardware only) + * @ap_addr: BSSID or IBSSID + * + * @retry: MAC-retransmission retry behaviour + * @rts: minimum packet size for which to perform RTS/CTS handshake + * @frag: 802.11 frame fragmentation threshold size + * @txpower: TX power information + * @power power management information + * + * @freq: frequency in Hz + * @sens: sensitivity threshold of the card + * @bitrate: bitrate (client mode) + * + * @key: encryption key + * @key_size: length of @key in bytes + * @key_flags: bitmask with information about @key + * + */ +struct iw_dyn_info { + char name[IFNAMSIZ]; + uint8_t mode; + + bool cap_essid:1, + cap_nwid:1, + cap_nickname:1, + cap_freq:1, + cap_sens:1, + cap_bitrate:1, + cap_txpower:1, + cap_retry:1, + cap_rts:1, + cap_frag:1, + cap_mode:1, + cap_ap:1, + cap_key:1, + cap_power:1, + cap_aplist:1; + + char essid[IW_ESSID_MAX_SIZE+2]; + uint8_t essid_ct; + char nickname[IW_ESSID_MAX_SIZE+2]; + struct iw_param nwid; + struct sockaddr ap_addr; + + struct iw_param retry; + struct iw_param rts; + struct iw_param frag; + struct iw_param txpower; + struct iw_param power; + + float freq; + int32_t sens; + unsigned long bitrate; + + char key[IW_ENCODING_TOKEN_MAX]; + uint16_t key_size; + uint16_t key_flags; +}; + +struct if_stat { + unsigned long long rx_packets, + tx_packets; + unsigned long long rx_bytes, + tx_bytes; +}; + +extern void if_getstat(char *ifname, struct if_stat *stat); + +/* + * Structs to communicate WiFi statistics + */ +struct iw_levelstat { + float signal; /* signal level in dBm */ + float noise; /* noise level in dBm */ + uint8_t flags; /* level validity */ +}; +#define IW_LSTAT_INIT { 0, 0, IW_QUAL_LEVEL_INVALID | IW_QUAL_NOISE_INVALID } + +extern void iw_sanitize(struct iw_range *range, + struct iw_quality *qual, + struct iw_levelstat *dbm); + +/** + * struct iw_stat - record current WiFi state + * @range: current range information + * @stats: current signal level statistics + * @dbm: the noise/signal of @stats in dBm + */ +struct iw_stat { + struct iw_range range; + struct iw_statistics stat; + struct iw_levelstat dbm; +}; + +extern void iw_getstat(struct iw_stat *stat); +extern void iw_cache_update(struct iw_stat *stat); + +extern void iw_getinf_dyn(char *ifname, struct iw_dyn_info *info); +extern void iw_getinf_range(char *ifname, struct iw_range *range); + +extern void (*iw_stat_redraw) (void); + +/* + * Helper routines + */ +static inline const char *iw_opmode(const uint8_t mode) +{ + static char *modes[] = { "Auto", + "Ad-Hoc", + "Managed", + "Master", + "Repeater", + "Secondary", + "Monitor", + "Mesh" + }; + + return mode < ARRAY_SIZE(modes) ? modes[mode] : "Unknown/bug"; +} + +static inline bool is_zero_ether_addr(const uint8_t *mac) +{ + return ! (mac[0] | mac[1] | mac[2] | mac[3] | mac[4] | mac[5]); +} + +static inline bool is_broadcast_ether_addr(const uint8_t *mac) +{ + return (mac[0] & mac[1] & mac[2] & mac[3] & mac[4] & mac[5]) == 0xff; +} + +/* Print a mac-address, include leading zeroes (unlike ether_ntoa(3)) */ +static inline char *ether_addr(const struct ether_addr *ea) +{ + static char str[MAC_ADDR_MAX]; + + sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", + ea->ether_addr_octet[0], ea->ether_addr_octet[1], + ea->ether_addr_octet[2], ea->ether_addr_octet[3], + ea->ether_addr_octet[4], ea->ether_addr_octet[5]); + return str; +} + +/* Print mac-address translation from /etc/ethers if available */ +static inline char *ether_lookup(const struct ether_addr *ea) +{ + static char hostname[BUFSIZ]; + + if (ether_ntohost(hostname, ea) == 0) + return hostname; + return ether_addr(ea); +} + +/* Format an Ethernet mac address */ +static inline char *mac_addr(const struct sockaddr *sa) +{ + struct ether_addr zero = { {0} }; + + if (sa->sa_family != ARPHRD_ETHER) + return ether_addr(&zero); + return ether_lookup((struct ether_addr *)sa->sa_data); +} + +/* Format a (I)BSSID */ +static inline char *format_bssid(const struct sockaddr *ap) +{ + const struct ether_addr *bssid = (struct ether_addr *)ap->sa_data; + + if (is_zero_ether_addr(bssid->ether_addr_octet)) + return "Not-Associated"; + if (is_broadcast_ether_addr(bssid->ether_addr_octet)) + return "Invalid"; + return mac_addr(ap); +} + +/* count bits set in @mask the Brian Kernighan way */ +static inline uint8_t bit_count(uint32_t mask) +{ + uint8_t bits_set; + + for (bits_set = 0; mask; bits_set++) + mask &= mask - 1; + + return bits_set; +} + +/* netmask = contiguous 1's followed by contiguous 0's */ +static inline uint8_t prefix_len(const struct in_addr *netmask) +{ + return bit_count(netmask->s_addr); +} + +/* Convert log dBm values to linear mW */ +static inline double dbm2mw(const double in) +{ + return pow(10.0, in / 10.0); +} + +static inline char *dbm2units(const double in) +{ + static char with_units[0x100]; + double val = dbm2mw(in); + + if (val < 0.00000001) { + sprintf(with_units, "%.2f pW", val * 1e9); + } else if (val < 0.00001) { + sprintf(with_units, "%.2f nW", val * 1e6); + } else if (val < 0.01) { + sprintf(with_units, "%.2f uW", val * 1e3); + } else { + sprintf(with_units, "%.2f mW", val); + } + return with_units; +} + +/* Convert linear mW values to log dBm */ +static inline double mw2dbm(const double in) +{ + return 10.0 * log10(in); +} + +/* Format driver TX power information */ +static inline char *format_txpower(const struct iw_param *txpwr) +{ + static char txline[0x40]; + + if (txpwr->flags & IW_TXPOW_RELATIVE) + snprintf(txline, sizeof(txline), "%d (no units)", txpwr->value); + else if (txpwr->flags & IW_TXPOW_MWATT) + snprintf(txline, sizeof(txline), "%.0f dBm (%d mW)", + mw2dbm(txpwr->value), txpwr->value); + else + snprintf(txline, sizeof(txline), "%d dBm (%.2f mW)", + txpwr->value, dbm2mw(txpwr->value)); + return txline; +} + +/* Format driver Power Management information */ +static inline char *format_power(const struct iw_param *pwr, + const struct iw_range *range) +{ + static char buf[0x80]; + double val = pwr->value; + int len = 0; + + if (pwr->disabled) + return "off"; + else if (pwr->flags == IW_POWER_ON) + return "on"; + + if (pwr->flags & IW_POWER_MIN) + len += snprintf(buf + len, sizeof(buf) - len, "min "); + if (pwr->flags & IW_POWER_MAX) + len += snprintf(buf + len, sizeof(buf) - len, "max "); + + if (pwr->flags & IW_POWER_TIMEOUT) + len += snprintf(buf + len, sizeof(buf) - len, "timeout "); + else if (pwr->flags & IW_POWER_SAVING) + len += snprintf(buf + len, sizeof(buf) - len, "saving "); + else + len += snprintf(buf + len, sizeof(buf) - len, "period "); + + if (pwr->flags & IW_POWER_RELATIVE && range->we_version_compiled < 21) + len += snprintf(buf + len, sizeof(buf) - len, "%+g", val/1e6); + else if (pwr->flags & IW_POWER_RELATIVE) + len += snprintf(buf + len, sizeof(buf) - len, "%+g", val); + else if (val > 1e6) + len += snprintf(buf + len, sizeof(buf) - len, "%g s", val/1e6); + else if (val > 1e3) + len += snprintf(buf + len, sizeof(buf) - len, "%g ms", val/1e3); + else + len += snprintf(buf + len, sizeof(buf) - len, "%g us", val); + + switch (pwr->flags & IW_POWER_MODE) { + case IW_POWER_UNICAST_R: + len += snprintf(buf + len, sizeof(buf) - len, ", rcv unicast"); + break; + case IW_POWER_MULTICAST_R: + len += snprintf(buf + len, sizeof(buf) - len, ", rcv mcast"); + break; + case IW_POWER_ALL_R: + len += snprintf(buf + len, sizeof(buf) - len, ", rcv all"); + break; + case IW_POWER_FORCE_S: + len += snprintf(buf + len, sizeof(buf) - len, ", force send"); + break; + case IW_POWER_REPEATER: + len += snprintf(buf + len, sizeof(buf) - len, ", repeat mcast"); + } + + return buf; +} + +/* See comments on 'struct iw_freq' in wireless.h */ +static inline float freq_to_hz(const struct iw_freq *freq) +{ + return freq->m * pow(10, freq->e); +} + +/* Return channel number or -1 on error. Based on iw_freq_to_channel() */ +static inline int freq_to_channel(double freq, const struct iw_range *range) +{ + int i; + + if (freq < 1.0e3) + return -1; + + for (i = 0; i < range->num_frequency; i++) + if (freq_to_hz(&range->freq[i]) == freq) + return range->freq[i].i; + return -1; +} + +/* print @key in cleartext if it is in ASCII format, use hex format otherwise */ +static inline char *format_key(char *key, uint8_t key_len) +{ + static char buf[128]; + int len = 0, i, is_printable; + + for (i = 0, is_printable = 1; i < key_len && is_printable; i++) + is_printable = isprint(key[i]); + + if (is_printable) + len += sprintf(buf, "\""); + + for (i = 0; i < key_len; i++) + if (is_printable) { + len += sprintf(buf + len, "%c", key[i]); + } else { + if (i > 0 && (i & 1) == 0) + len += sprintf(buf + len, "-"); + len += sprintf(buf + len, "%2X", key[i]); + } + + if (is_printable) + sprintf(buf + len, "\""); + + return buf; +} + +static inline char *format_retry(const struct iw_param *retry, + const struct iw_range *range) +{ + static char buf[0x80]; + double val = retry->value; + int len = 0; + + if (retry->disabled) + return "off"; + else if (retry->flags == IW_RETRY_ON) + return "on"; + + if (retry->flags & IW_RETRY_MIN) + len += snprintf(buf + len, sizeof(buf) - len, "min "); + if (retry->flags & IW_RETRY_MAX) + len += snprintf(buf + len, sizeof(buf) - len, "max "); + if (retry->flags & IW_RETRY_SHORT) + len += snprintf(buf + len, sizeof(buf) - len, "short "); + if (retry->flags & IW_RETRY_LONG) + len += snprintf(buf + len, sizeof(buf) - len, "long "); + + if (retry->flags & IW_RETRY_LIFETIME) + len += snprintf(buf + len, sizeof(buf) - len, "lifetime "); + else { + snprintf(buf + len, sizeof(buf) - len, "limit %d", retry->value); + return buf; + } + + if (retry->flags & IW_RETRY_RELATIVE && range->we_version_compiled < 21) + len += snprintf(buf + len, sizeof(buf) - len, "%+g", val/1e6); + else if (retry->flags & IW_RETRY_RELATIVE) + len += snprintf(buf + len, sizeof(buf) - len, "%+g", val); + else if (val > 1e6) + len += snprintf(buf + len, sizeof(buf) - len, "%g s", val/1e6); + else if (val > 1e3) + len += snprintf(buf + len, sizeof(buf) - len, "%g ms", val/1e3); + else + len += snprintf(buf + len, sizeof(buf) - len, "%g us", val); + + return buf; +} + |