spoon

set dwm status
git clone git://git.2f30.org/spoon
Log | Files | Refs | LICENSE

wifi.c (4257B)


      1 #include <sys/ioctl.h>
      2 
      3 #include <err.h>
      4 #include <ifaddrs.h>
      5 #include <stdio.h>
      6 #include <string.h>
      7 #include <unistd.h>
      8 
      9 #include "util.h"
     10 
     11 void
     12 wifiprint(char *buf, size_t len, int quality)
     13 {
     14 	char *icon;
     15 
     16 	if (quality == 100)
     17 		icon = "::";
     18 	else if (quality >= 75)
     19 		icon = ":.";
     20 	else if (quality >= 50)
     21 		icon = "..";
     22 	else if (quality >= 25)
     23 		icon = ". ";
     24 	else
     25 		icon = "  ";
     26 	snprintf(buf, len, "%s", icon);
     27 }
     28 
     29 #ifdef __OpenBSD__
     30 #include <sys/types.h>
     31 #include <sys/socket.h>
     32 #include <sys/select.h>
     33 
     34 #include <net/if.h>
     35 #include <net/if_media.h>
     36 #include <net80211/ieee80211.h>
     37 #include <net80211/ieee80211_ioctl.h>
     38 
     39 int
     40 wifiread(void *arg, char *buf, size_t len)
     41 {
     42 	struct ifaddrs *ifa, *ifas;
     43 	struct ifmediareq ifmr;
     44 	struct ieee80211_nodereq nr;
     45 	struct ieee80211_bssid bssid;
     46 	int quality = -1;
     47 	int fd, ibssid;
     48 
     49 	if (getifaddrs(&ifas) < 0) {
     50 		warn("getifaddrs");
     51 		return -1;
     52 	}
     53 	fd = socket(AF_INET, SOCK_DGRAM, 0);
     54 	if (fd < 0) {
     55 		warn("socket");
     56 		return -1;
     57 	}
     58 	for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
     59 		memset(&ifmr, 0, sizeof(ifmr));
     60 		strlcpy(ifmr.ifm_name, ifa->ifa_name, IF_NAMESIZE);
     61 		if (ioctl(fd, SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
     62 			continue;
     63 		if ((ifmr.ifm_active & IFM_IEEE80211) == 0)
     64 			continue;
     65 		if ((ifmr.ifm_active & IFM_IEEE80211_HOSTAP) != 0)
     66 			continue;
     67 		memset(&bssid, 0, sizeof(bssid));
     68 		strlcpy(bssid.i_name, ifa->ifa_name, sizeof(bssid.i_name));
     69 		ibssid = ioctl(fd, SIOCG80211BSSID, &bssid);
     70 		if (ibssid < 0)
     71 			continue;
     72 		memset(&nr, 0, sizeof(nr));
     73 		memcpy(&nr.nr_macaddr, bssid.i_bssid, sizeof(nr.nr_macaddr));
     74 		strlcpy(nr.nr_ifname, ifa->ifa_name, sizeof(nr.nr_ifname));
     75 		if (ioctl(fd, SIOCG80211NODE, &nr) < 0)
     76 			continue;
     77 		if (nr.nr_rssi == 0)
     78 			continue;
     79 		if (nr.nr_max_rssi == 0) {
     80 			if (nr.nr_rssi <= -100)
     81 				quality = 0;
     82 			else if (nr.nr_rssi >= -50)
     83 				quality = 100;
     84 			else
     85 				quality = 2 * (nr.nr_rssi + 100);
     86 		} else {
     87 			quality = IEEE80211_NODEREQ_RSSI(&nr);
     88 		}
     89 		break;
     90 	}
     91 	close(fd);
     92 	freeifaddrs(ifas);
     93 
     94 	DPRINTF_D(quality);
     95 	if (quality == -1)
     96 		return -1;
     97 	wifiprint(buf, len, quality);
     98 	return 0;
     99 }
    100 #elif __linux__
    101 #include <sys/types.h>
    102 #include <sys/socket.h>
    103 
    104 #include <linux/wireless.h>
    105 
    106 int
    107 wifiread(void *arg, char *buf, size_t len)
    108 {
    109 	struct ifaddrs *ifa, *ifas;
    110 	struct iw_quality *max_qual, *qual;
    111 	struct iw_statistics stats;
    112 	struct iw_range range;
    113 	struct iwreq wrq;
    114 	int quality = -1;
    115 	int level;
    116 	int ret, fd;
    117 
    118 	if (getifaddrs(&ifas) < 0) {
    119 		warn("getifaddrs");
    120 		return -1;
    121 	}
    122 	fd = socket(PF_INET, SOCK_DGRAM, 0);
    123 	if (fd == -1) {
    124 		warn("socket");
    125 		return -1;
    126 	}
    127 	for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
    128 		DPRINTF_S(ifa->ifa_name);
    129 		memset(&wrq, 0, sizeof(wrq));
    130 		strlcpy(wrq.ifr_name, ifa->ifa_name, IFNAMSIZ);
    131 		ret = ioctl(fd, SIOCGIWNAME, &wrq);
    132 		if (ret != 0)
    133 			continue;
    134 		memset(&wrq, 0, sizeof(wrq));
    135 		strlcpy(wrq.ifr_name, ifa->ifa_name, IFNAMSIZ);
    136 		wrq.u.data.pointer = &range;
    137 		wrq.u.data.length = sizeof(range);
    138 		memset(&range, 0, sizeof(range));
    139 		ret = ioctl(fd, SIOCGIWRANGE, &wrq);
    140 		if (ret < 0) {
    141 			warnx("cannot get wifi range");
    142 			continue;
    143 		}
    144 		memset(&wrq, 0, sizeof(wrq));
    145 		strlcpy(wrq.ifr_name, ifa->ifa_name, IFNAMSIZ);
    146 		wrq.u.data.pointer = &stats;
    147 		wrq.u.data.length = sizeof(stats);
    148 		wrq.u.data.flags = 1;
    149 		memset(&stats, 0, sizeof(stats));
    150 		ret = ioctl(fd, SIOCGIWSTATS, &wrq);
    151 		if (ret < 0) {
    152 			warnx("cannot get wifi stats");
    153 			continue;
    154 		}
    155 		max_qual = &range.max_qual;
    156 		qual = &stats.qual;
    157 		DPRINTF_U(max_qual->qual);
    158 		DPRINTF_U(max_qual->level);
    159 		DPRINTF_U(qual->qual);
    160 		DPRINTF_U(qual->level);
    161 		if (max_qual->qual != 0) {
    162 			/* driver provides a quality metric */
    163 			quality = (((float)qual->qual / max_qual->qual) * 100);
    164 		} else if (max_qual->level != 0) {
    165 			/* driver provides signal strength (RSSI) */
    166 			quality = (((float)qual->level / max_qual->level) * 100);
    167 		} else if (max_qual->level == 0) {
    168 			/* driver provides absolute dBm values */
    169 			level = qual->level - 0x100;
    170 			if (level <= -100)
    171 				quality = 0;
    172 			else if (level >= -50)
    173 				quality = 100;
    174 			else
    175 				quality = 2 * (level + 100);
    176 		}
    177 		break;
    178 	}
    179 	close(fd);
    180 	freeifaddrs(ifas);
    181 
    182 	DPRINTF_D(quality);
    183 	if (quality == -1)
    184 		return -1;
    185 	wifiprint(buf, len, quality);
    186 	return 0;
    187 }
    188 #endif