From 0b0aac6ce21bcb38d7e03dc2b3ff419861476a24 Mon Sep 17 00:00:00 2001 From: Jonathan McCrohan Date: Sat, 30 Jan 2016 17:08:40 +0000 Subject: Imported Upstream version 0.8.0 --- utils.c | 261 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 utils.c (limited to 'utils.c') diff --git a/utils.c b/utils.c new file mode 100644 index 0000000..10818ba --- /dev/null +++ b/utils.c @@ -0,0 +1,261 @@ +/* + * General-purpose utilities used by multiple files. + */ +#include "wavemon.h" +#include "nl80211.h" +#include +#include +#include +#include +#include +#include +#include + +/* Maximum length of a MAC address: 2 * 6 hex digits, 6 - 1 colons, plus '\0' */ +#define MAC_ADDR_MAX 18 + +/* Return true if all ethernet octets are zero. */ +bool ether_addr_is_zero(const struct ether_addr *ea) +{ + static const struct ether_addr zero = {{0}}; + + return memcmp(ea, &zero, sizeof(zero)) == 0; +} + +/* Print a mac-address, include leading zeroes (unlike ether_ntoa(3)) */ +char *ether_addr(const struct ether_addr *ea) +{ + static char mac[MAC_ADDR_MAX]; + char *d = mac, *a = ether_ntoa(ea); +next_chunk: + if (a[0] == '\0' || a[1] == '\0' || a[1] == ':') + *d++ = '0'; + while ((*d++ = conf.cisco_mac ? (*a == ':' ? '.' : *a) : toupper(*a))) + if (*a++ == ':') + goto next_chunk; + return mac; +} + +/* Print mac-address translation from /etc/ethers if available */ +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 */ +char *mac_addr(const struct sockaddr *sa) +{ + if (sa->sa_family != ARPHRD_ETHER) + return "00:00:00:00:00:00"; + return ether_lookup((const struct ether_addr *)sa->sa_data); +} + +/* Format a (I)BSSID */ +char *format_bssid(const struct sockaddr *ap) +{ + uint8_t bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + uint8_t zero_addr[ETH_ALEN] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + if (memcmp(ap->sa_data, zero_addr, ETH_ALEN) == 0) + return "Not-Associated"; + if (memcmp(ap->sa_data, bcast_addr, ETH_ALEN) == 0) + return "Invalid"; + return mac_addr(ap); +} + +/* count bits set in @mask the Brian Kernighan way */ +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 */ +uint8_t prefix_len(const struct in_addr *netmask) +{ + return bit_count(netmask->s_addr); +} + +/* Pretty-print @sec into a string of up to 6 characters. */ +const char *pretty_time(const unsigned sec) +{ + static char buf[12]; + unsigned d = sec / 86400, + h = sec % 86400 / 3600, + m = sec % 3600 / 60; + + if (d > 9) { + sprintf(buf, "%u days", d); + } else if (d) { + if (h) { + sprintf(buf, "%ud %uh", d, h); + } else if (m) { + sprintf(buf, "%ud %dm", d, m); + } else { + sprintf(buf, "%u day%s", d, d == 1 ? "" : "s"); + } + } else if (h) { + sprintf(buf, "%u:%02uh", h, m); + } else if (m) { + sprintf(buf, "%u:%02um", m, sec % 60); + } else { + sprintf(buf, "%u sec", sec); + } + return buf; +} + +/* Like pretty_time, but allow milliseconds */ +const char *pretty_time_ms(const unsigned msec) +{ + static char buf[12]; + + if (msec < 1000) { + sprintf(buf, "%u ms", msec); + return buf; + } + return pretty_time(msec/1000); +} + +/* Absolute power measurement in dBm (IW_QUAL_DBM): map into -192 .. 63 range */ +int u8_to_dbm(const int power) +{ + return power > 63 ? power - 0x100 : power; +} +uint8_t dbm_to_u8(const int dbm) +{ + return dbm < 0 ? dbm + 0x100 : dbm; +} + +/* Convert log dBm values to linear mW */ +double dbm2mw(const double in) +{ + return pow(10.0, in / 10.0); +} + +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 */ +double mw2dbm(const double in) +{ + return 10.0 * log10(in); +} + +/* Stolen from iw:util.c */ +int ieee80211_frequency_to_channel(int freq) +{ + /* see 802.11-2007 17.3.8.3.2 and Annex J */ + if (freq == 2484) + return 14; + else if (freq < 2484) + return (freq - 2407) / 5; + else if (freq >= 4910 && freq <= 4980) + return (freq - 4000) / 5; + else if (freq <= 45000) /* DMG band lower limit */ + return (freq - 5000) / 5; + else if (freq >= 58320 && freq <= 64800) + return (freq - 56160) / 2160; + else + return 0; +} + +const char *channel_width_name(enum nl80211_chan_width width) +{ + switch (width) { + case NL80211_CHAN_WIDTH_20_NOHT: + return "20 MHz (no HT)"; + case NL80211_CHAN_WIDTH_20: + return "20 MHz"; + case NL80211_CHAN_WIDTH_40: + return "40 MHz"; + case NL80211_CHAN_WIDTH_80: + return "80 MHz"; + case NL80211_CHAN_WIDTH_80P80: + return "80+80 MHz"; + case NL80211_CHAN_WIDTH_160: + return "160 MHz"; + default: + return "unknown"; + } +} + +/* stolen from iw:interface.c */ +const char *channel_type_name(enum nl80211_channel_type channel_type) +{ + switch (channel_type) { + case NL80211_CHAN_NO_HT: + return "NO HT"; + case NL80211_CHAN_HT20: + return "HT20"; + case NL80211_CHAN_HT40MINUS: + return "HT40-"; + case NL80211_CHAN_HT40PLUS: + return "HT40+"; + default: + return "unknown"; + } +} + +/* stolen from iw:util.c */ +const char *iftype_name(enum nl80211_iftype iftype) +{ + static char modebuf[100]; + static const char *ifmodes[NL80211_IFTYPE_MAX + 1] = { + "Unspecified", + "IBSS", + "Managed", + "AP", + "AP/VLAN", + "WDS", + "Monitor", + "Mesh Point", + "P2P-Client", + "P2P-GO", + "P2P-Device", + "Outside of a BSS", + }; + + if (iftype <= NL80211_IFTYPE_MAX && ifmodes[iftype]) + return ifmodes[iftype]; + sprintf(modebuf, "Unknown mode (%d)", iftype); + return modebuf; +} + +/* stolen from iw:reg.c */ +const char *dfs_domain_name(enum nl80211_dfs_regions region) +{ + switch (region) { + case NL80211_DFS_UNSET: + return "DFS-UNSET"; + case NL80211_DFS_FCC: + return "DFS-FCC"; + case NL80211_DFS_ETSI: + return "DFS-ETSI"; + case NL80211_DFS_JP: + return "DFS-JP"; + default: + return "DFS-invalid"; + } +} -- cgit v1.2.3