diff options
Diffstat (limited to 'iw_if.c')
-rw-r--r-- | iw_if.c | 367 |
1 files changed, 19 insertions, 348 deletions
@@ -40,9 +40,15 @@ static int if_get_flags(int skfd, const char *ifname) } /* Return true if @ifname is known to be up. */ -bool if_is_up(int skfd, const char *ifname) +bool if_is_up(const char *ifname) { - return if_get_flags(skfd, ifname) & IFF_UP; + int ret, skfd = socket(AF_INET, SOCK_DGRAM, 0); + + if (skfd < 0) + err_sys("%s: can not open socket", __func__); + ret = if_get_flags(skfd, ifname) & IFF_UP; + close(skfd); + return ret; } /** Bring @ifname up if not already up. Return 0 if ok, < 0 on error. */ @@ -101,14 +107,15 @@ void if_getinf(const char *ifname, struct if_info *info) } /** - * iw_get_interface_list - Return NULL-terminated array of WiFi interfaces. + * iw_get_interface_list - fill if_list with NULL-terminated array of WiFi + * interfaces. * Use the safe route of checking /proc/net/dev/ for wireless interfaces: * - SIOCGIFCONF only returns running interfaces that have an IP address; * - /proc/net/wireless may exist, but may not list all wireless interfaces. */ -char **iw_get_interface_list(void) +void iw_get_interface_list(char** if_list, size_t max_entries) { - char **if_list = NULL, *p, tmp[BUFSIZ]; + char *p, tmp[BUFSIZ]; int nifs = 1; /* if_list[nifs-1] = NULL */ struct iwreq wrq; FILE *fp; @@ -129,27 +136,24 @@ char **iw_get_interface_list(void) * Use SIOCGIWNAME as indicator: if interface does not * support this ioctl, it has no wireless extensions. */ - strncpy(wrq.ifr_name, p, IFNAMSIZ); + snprintf(wrq.ifr_name, IFNAMSIZ, "%s", p); if (ioctl(skfd, SIOCGIWNAME, &wrq) < 0) continue; - - if_list = realloc(if_list, sizeof(char *) * (nifs + 1)); - if (if_list == NULL) - err_sys("can not reallocate interface list"); + if(nifs >= max_entries) break; if_list[nifs-1] = strdup(p); if_list[nifs++] = NULL; } } close(skfd); fclose(fp); - return if_list; } void if_getstat(const char *ifname, struct if_stat *stat) { char line[0x100]; - unsigned long d; + unsigned long long d; char *lp; + size_t l = strlen(ifname); const char path[] = "/proc/net/dev"; FILE *fp = fopen(path, "r"); @@ -161,11 +165,11 @@ void if_getstat(const char *ifname, struct if_stat *stat) */ while (fgets(line, sizeof(line), fp)) { lp = line + strspn(line, " "); - if (!strncmp(lp, ifname, strlen(ifname))) { - lp += strlen(ifname) + 1; + if (!strncmp(lp, ifname, l) && lp[l] == ':') { + lp += l + 1; lp += strspn(lp, " "); - sscanf(lp, "%Lu %Lu %lu %lu %lu %lu %lu %lu %Lu %Lu", + sscanf(lp, "%llu %llu %llu %llu %llu %llu %llu %llu %llu %llu", &stat->rx_bytes, &stat->rx_packets, &d, &d, &d, &d, &d, &d, &stat->tx_bytes, &stat->tx_packets); } @@ -205,11 +209,6 @@ void dyn_info_get(struct iw_dyn_info *info, info->essid[iwr.u.essid.length] = '\0'; } - if (ioctl(skfd, SIOCGIWNWID, &iwr) >= 0) { - info->cap_nwid = 1; - memcpy(&info->nwid, &iwr.u.nwid, sizeof(info->nwid)); - } - iwr.u.essid.pointer = (caddr_t) info->nickname; iwr.u.essid.length = sizeof(info->nickname); iwr.u.essid.flags = 0; @@ -334,331 +333,3 @@ void iw_getinf_range(const char *ifname, struct iw_range *range) err_sys("can not get range information"); close(skfd); } - -/* - * Obtain periodic IW statistics - */ -static int rand_wave(float *rlvl, float *step, float *rlvl_next, float range) -{ - int i; - - for (i = 0; i < WAVE_RAND_SPREAD; i++) - if (*rlvl < *rlvl_next) { - if (*rlvl_next - *rlvl < *step) - *step /= 2.0; - *rlvl += *step; - } else if (*rlvl > *rlvl_next) { - if (*rlvl - *rlvl_next < *step) - *step /= 2.0; - *rlvl -= *step; - } - *step += (random() / (float)RAND_MAX) - 0.5; - if (*rlvl == *rlvl_next || *step < 0.05) { - *rlvl_next = (range * random()) / RAND_MAX; - *step = random() / (float)RAND_MAX; - } - return *rlvl; -} - -/* Random signal/noise/quality levels */ -static void iw_getstat_random(struct iw_stat *iw) -{ - static float rnd_sig, snext, sstep = 1.0, rnd_noise, nnext, nstep = 1.0; - - rand_wave(&rnd_sig, &sstep, &snext, conf.sig_max - conf.sig_min); - rand_wave(&rnd_noise, &nstep, &nnext, conf.noise_max - conf.noise_min); - - if (iw->range.max_qual.qual == 0) - iw->range.max_qual.qual = WAVE_RAND_QUAL_MAX; - - iw->stat.qual.level = dbm_to_u8(conf.sig_min + rnd_sig); - iw->stat.qual.noise = dbm_to_u8(conf.noise_min + rnd_noise); - iw->stat.qual.updated = IW_QUAL_DBM; - iw->stat.qual.qual = map_range(conf.sig_min + rnd_sig, - conf.sig_min, conf.sig_max, - 0, iw->range.max_qual.qual); -} - -static void iw_getstat_real(struct iw_statistics *stat) -{ - struct iwreq wrq; - int skfd = socket(AF_INET, SOCK_DGRAM, 0); - - if (skfd < 0) - err_sys("%s: can not open socket", __func__); - - wrq.u.data.pointer = (caddr_t) stat; - wrq.u.data.length = sizeof(*stat); - wrq.u.data.flags = 0; - strncpy(wrq.ifr_name, conf_ifname(), IFNAMSIZ); - - if (ioctl(skfd, SIOCGIWSTATS, &wrq) < 0) { - /* - * iw_handler_get_iwstats() returns EOPNOTSUPP if - * there are no statistics. Bail out in this case. - */ - if (errno != EOPNOTSUPP) - err_sys("can not obtain iw statistics"); - errno = 0; - memset(&wrq, 0, sizeof(wrq)); - } - close(skfd); -} - -/* - * Generate dBm values and perform sanity checks on values. - * Code in part taken from wireless extensions #30 - * @range: range information, read-only - * @qual: wireless statistics, read-write - * @dbm: dBm level information, write-only - */ -void iw_sanitize(struct iw_range *range, struct iw_quality *qual, - struct iw_levelstat *dbm) -{ - memset(dbm, 0, sizeof(*dbm)); - - if (qual->level != 0 || (qual->updated & (IW_QUAL_DBM | IW_QUAL_RCPI))) { - /* - * RCPI (IEEE 802.11k) statistics: - * RCPI = int{(Power in dBm +110)*2} - * for 0 dBm > Power > -110 dBm - */ - if (qual->updated & IW_QUAL_RCPI) { - if (!(qual->updated & IW_QUAL_LEVEL_INVALID)) - dbm->signal = (double)(qual->level / 2.0) - 110.0; - if (!(qual->updated & IW_QUAL_NOISE_INVALID)) - dbm->noise = (double)(qual->noise / 2.0) - 110.0; - - } else if ((qual->updated & IW_QUAL_DBM) || - qual->level > range->max_qual.level) { - if (!(qual->updated & IW_QUAL_LEVEL_INVALID)) - dbm->signal = u8_to_dbm(qual->level); - if (!(qual->updated & IW_QUAL_NOISE_INVALID)) - dbm->noise = u8_to_dbm(qual->noise); - } else { - /* - * Relative values (0 -> max) - */ - if (!(qual->updated & IW_QUAL_LEVEL_INVALID)) - dbm->signal = mw2dbm(qual->level); - if (!(qual->updated & IW_QUAL_NOISE_INVALID)) - dbm->noise = mw2dbm(qual->noise); - } - } else { - qual->updated |= IW_QUAL_ALL_INVALID; - } - - /* - * Value sanity checks - * - * These rules serve to avoid "insensible" level displays. Please do send - * comments and/or bug reports if you encounter room for improvement. - * - * 1) if noise level is valid, but signal level is not, displaying just - * the noise level does not reveal very much - can be omitted; - * 2) if the noise level is below an "invalid" magic value (see iw_if.h), - * declare the noise value to be invalid; - * 3) SNR is only displayed if both signal and noise values are valid. - */ - if (qual->updated & IW_QUAL_LEVEL_INVALID) - qual->updated |= IW_QUAL_NOISE_INVALID; - if (dbm->noise <= NOISE_DBM_SANE_MIN) - qual->updated |= IW_QUAL_NOISE_INVALID; -} - -void iw_getstat(struct iw_stat *iw) -{ - memset(&iw->stat, 0, sizeof(iw->stat)); - - if (conf.random) - iw_getstat_random(iw); - else - iw_getstat_real(&iw->stat); - - iw_sanitize(&iw->range, &iw->stat.qual, &iw->dbm); -} - -const char *we_version(void) -{ - static char buf[BUFSIZ]; - struct iw_stat iw; - - iw_getinf_range(conf_ifname(), &iw.range); - sprintf(buf, "wireless extensions v%d (source v%d)", - iw.range.we_version_compiled, iw.range.we_version_source); - return buf; -} - -void dump_parameters(void) -{ - struct iw_dyn_info info; - struct iw_stat iw; - struct if_stat nstat; - int i; - - iw_getinf_range(conf_ifname(), &iw.range); - dyn_info_get(&info, conf_ifname(), &iw.range); - iw_getstat(&iw); - if_getstat(conf_ifname(), &nstat); - - printf("\n"); - printf("Configured device: %s (%s)\n", conf_ifname(), info.name); - printf(" Security: %s\n", iw.range.enc_capa ? - format_enc_capab(iw.range.enc_capa, ", ") : "WEP"); - if (iw.range.num_encoding_sizes && - iw.range.num_encoding_sizes < IW_MAX_ENCODING_SIZES) { - - printf(" Key sizes: "); - for (i = 0; i < iw.range.num_encoding_sizes; i++) { - if (i) - printf(", "); - if (iw.range.encoding_size[i] == 5) - printf("WEP-40"); - else if (iw.range.encoding_size[i] == 13) - printf("WEP-104"); - else - printf("%u bits", - iw.range.encoding_size[i] * 8); - } - printf("\n"); - } - printf("\n"); - - if (info.cap_essid) { - if (info.essid_ct > 1) - printf(" essid: \"%s\" [%d]\n", - info.essid, info.essid_ct); - else if (info.essid_ct) - printf(" essid: \"%s\"\n", info.essid); - else - printf(" essid: off/any\n"); - } - - if (info.cap_nickname) - printf(" nick: \"%s\"\n", info.nickname); - - if (info.cap_nwid) { - if (info.nwid.disabled) - printf(" nwid: off/any\n"); - else - printf(" nwid: %X\n", info.nwid.value); - } - - /* Some drivers only return the channel (e.g. ipw2100) */ - if (info.cap_freq && info.freq < 256) - info.freq = channel_to_freq(info.freq, &iw.range); - if (info.cap_freq && info.freq > 1e3) { - i = freq_to_channel(info.freq, &iw.range); - if (i >= 0) - printf(" channel: %d\n", i); - printf(" frequency: %g GHz\n", info.freq / 1.0e9); - } else - printf(" frequency: n/a\n"); - - if (info.cap_sens) { - if (info.sens < 0) - printf(" sensitivity: %d dBm\n", info.sens); - else - printf(" sensitivity: %d/%d\n", info.sens, - iw.range.sensitivity); - } - - if (info.cap_txpower && info.txpower.disabled) - printf(" tx-power: off\n"); - else if (info.cap_txpower && info.txpower.fixed) - printf(" tx-power: %s\n", format_txpower(&info.txpower)); - else if (info.cap_txpower) - printf(" TX-power: %s\n", format_txpower(&info.txpower)); - - printf(" mode: %s\n", iw_opmode(info.mode)); - - if (info.mode != 1 && info.cap_ap) - printf(" access point: %s\n", format_bssid(&info.ap_addr)); - - if (info.bitrate) - printf(" bitrate: %g Mbit/s\n", info.bitrate / 1.0e6); - else - printf(" bitrate: n/a\n"); - - printf(" retry: "); - if (info.cap_retry) - printf("%s\n", format_retry(&info.retry, &iw.range)); - else - printf("n/a\n"); - - printf(" rts thr: "); - if (info.cap_rts) { - if (info.rts.disabled) - printf("off\n"); - else - printf("%d B %s\n", info.rts.value, - info.rts.fixed ? "" : "(auto-select)"); - } else - printf("n/a\n"); - - printf(" frag thr: "); - if (info.cap_frag) { - if (info.frag.disabled) - printf("off\n"); - else - printf("%d B %s\n", info.frag.value, - info.frag.fixed ? "" : "(auto-select)"); - } else { - printf("n/a\n"); - } - - printf(" encryption: "); - if (!info.nkeys && has_net_admin_capability()) - printf("no information available\n"); - else if (!info.nkeys) - printf("n/a (requires CAP_NET_ADMIN permissions)\n"); - for (i = 0; i < info.nkeys; i++) { - if (i) - printf(" "); - /* Current key is marked by `=' sign */ - printf("[%u]%s ", i + 1, i + 1 == info.active_key ? "=" : ":"); - - if (info.keys[i].flags & IW_ENCODE_DISABLED || !info.keys[i].size) { - printf("off\n"); - } else { - printf("%s", format_key(info.keys + i)); - if (info.keys[i].flags & IW_ENCODE_RESTRICTED) - printf(", restricted"); - if (info.keys[i].flags & IW_ENCODE_OPEN) - printf(", open"); - printf("\n"); - } - } - - printf(" power management: "); - if (info.cap_power) - printf("%s\n", format_power(&info.power, &iw.range)); - else - printf("n/a\n"); - - printf("\n"); - printf(" link quality: %d/%d\n", iw.stat.qual.qual, - iw.range.max_qual.qual); - printf(" signal level: %.0f dBm (%s)\n", iw.dbm.signal, - dbm2units(iw.dbm.signal)); - printf(" noise level: %.0f dBm (%s)\n", iw.dbm.noise, - dbm2units(iw.dbm.noise)); - printf(" SNR: %.0f dB\n", iw.dbm.signal - iw.dbm.noise); - - /* RX stats */ - printf(" RX total: %'llu packets (%s)\n", nstat.rx_packets, - byte_units(nstat.rx_bytes)); - printf(" invalid nwid: %'u\n", iw.stat.discard.nwid); - printf(" invalid key: %'u\n", iw.stat.discard.code); - printf(" invalid fragm.: %'u\n", iw.stat.discard.fragment); - printf(" missed beacons: %'u\n", iw.stat.miss.beacon); - printf(" misc errors: %'u\n", iw.stat.discard.misc); - - /* TX stats */ - printf(" TX total: %'llu packets (%s)\n", nstat.tx_packets, - byte_units(nstat.tx_bytes)); - printf(" exc. MAC retries: %'u\n", iw.stat.discard.retries); - - printf("\n"); - dyn_info_cleanup(&info); -} |