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 = ⦥ 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