/* * wavemon - a wireless network monitoring aplication * * Copyright (c) 2001-2002 Jan Morgenstern * * 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 #include #include #include #include #include #include #include #include #include /* 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 /** * struct if_info - wireless interface network information * @hwaddr: MAC address * @addr: IPv4 interface address * @netmask: IPv4 interface netmask * @bcast: IPv4 interface broadcast address * @mtu: interface MTU * @txqlen: tx queue length * @flags: interface flags * See also netdevice(7) */ struct if_info { struct ether_addr hwaddr; struct in_addr addr, netmask, bcast; uint16_t mtu; uint16_t txqlen; uint16_t flags; }; extern int if_set_up(const char *ifname); extern void if_getinf(const char *ifname, struct if_info *info); /** * struct iw_key - Encoding information * @key: encryption key * @size: length of @key in bytes * @flags: flags reported by SIOCGIWENCODE */ struct iw_key { uint8_t key[IW_ENCODING_TOKEN_MAX]; uint16_t size; uint16_t flags; }; /** * 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) * * @keys: array of encryption keys * @nkeys: length of @keys * @active_key: index of current key into @keys (counting from 1) * */ 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_txpower:1, cap_retry:1, cap_rts:1, cap_frag:1, cap_mode:1, cap_ap: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; struct iw_key *keys; uint8_t nkeys; uint8_t active_key; }; /* Return the number of encryption keys marked 'active' in @info *
# Sonera kaapeli-tv (Finland)
# Maksuttomat kanavat ovat 162 ja 170 MHz:n muxeissa
#
# freq      sr      fec  mod
C 154000000 6900000 NONE QAM128
C 162000000 6900000 NONE QAM128
C 170000000 6900000 NONE QAM128
C 314000000 6900000 NONE QAM128
C 322000000 6900000 NONE QAM128
C 338000000 6900000 NONE QAM128
C 346000000 6900000 NONE QAM128
C 354000000 6900000 NONE QAM128
== 0) 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); } /* Absolute power measurement in dBm (IW_QUAL_DBM): map into -192 .. 63 range */ static inline int u8_to_dbm(const int power) { return power > 63 ? power - 0x100 : power; } static inline uint8_t dbm_to_u8(const int dbm) { return dbm < 0 ? dbm + 0x100 : dbm; } /* 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 frequency or 0 on error. Based on iw_channel_to_freq() */ static inline double channel_to_freq(uint8_t chan, const struct iw_range *range) { int c; for (c = 0; c < range->num_frequency; c++) /* Check if it actually has stored a frequency */ if (range->freq[c].i == chan && range->freq[c].m > 1000) return freq_to_hz(&range->freq[c]); return 0.0; } /* 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 < 1e3) /* Convention: freq is channel number if < 1e3 */ return freq; 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(const struct iw_key *const iwk) { static char buf[128]; int i, is_printable = 0, len = 0; /* Over-estimate key size: 2 chars per hex digit plus '-' */ assert(iwk != NULL && iwk->size * 3 < sizeof(buf)); for (i = 0; i < iwk->size && (is_printable = isprint(iwk->key[i])); i++) ; if (is_printable) len += sprintf(buf, "\""); for (i = 0; i < iwk->size; i++) if (is_printable) { len += sprintf(buf + len, "%c", iwk->key[i]); } else { if (i > 0 && (i & 1) == 0) len += sprintf(buf + len, "-"); len += sprintf(buf + len, "%02X", iwk->key[i]); } if (is_printable) len += sprintf(buf + len, "\""); sprintf(buf + len, " (%u bits)", iwk->size * 8); return buf; } /* Human-readable representation of IW_ENC_CAPA_ types */ static inline const char *format_enc_capab(const uint32_t capa, const char *sep) { static char buf[32]; size_t len = 0, max = sizeof(buf); if (capa & IW_ENC_CAPA_WPA) len = snprintf(buf, max, "WPA"); if (capa & IW_ENC_CAPA_WPA2) len += snprintf(buf + len, max - len, "%sWPA2", len ? sep : ""); if (capa & IW_ENC_CAPA_CIPHER_TKIP) len += snprintf(buf + len, max - len, "%sTKIP", len ? sep : ""); if (capa & IW_ENC_CAPA_CIPHER_CCMP) len += snprintf(buf + len, max - len, "%sCCMP", len ? sep : ""); buf[len] = '\0'; return buf; } /* Display only the supported WPA type */ #define IW_WPA_MASK (IW_ENC_CAPA_WPA|IW_ENC_CAPA_WPA2) static inline const char *format_wpa(struct iw_range *ir) { return format_enc_capab(ir->enc_capa & IW_WPA_MASK, "/"); } 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; }