wifi.c (5962B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <ifaddrs.h> 3 #include <stdio.h> 4 #include <string.h> 5 #include <sys/ioctl.h> 6 #include <sys/socket.h> 7 #include <unistd.h> 8 9 #include "../util.h" 10 11 #define RSSI_TO_PERC(rssi) \ 12 rssi >= -50 ? 100 : \ 13 (rssi <= -100 ? 0 : \ 14 (2 * (rssi + 100))) 15 16 #if defined(__linux__) 17 #include <limits.h> 18 #include <linux/wireless.h> 19 20 const char * 21 wifi_perc(const char *interface) 22 { 23 int cur; 24 size_t i; 25 char *p, *datastart; 26 char path[PATH_MAX]; 27 char status[5]; 28 FILE *fp; 29 30 if (esnprintf(path, sizeof(path), "/sys/class/net/%s/operstate", 31 interface) < 0) { 32 return NULL; 33 } 34 if (!(fp = fopen(path, "r"))) { 35 warn("fopen '%s':", path); 36 return NULL; 37 } 38 p = fgets(status, 5, fp); 39 fclose(fp); 40 if (!p || strcmp(status, "up\n") != 0) { 41 return NULL; 42 } 43 44 if (!(fp = fopen("/proc/net/wireless", "r"))) { 45 warn("fopen '/proc/net/wireless':"); 46 return NULL; 47 } 48 49 for (i = 0; i < 3; i++) { 50 if (!(p = fgets(buf, sizeof(buf) - 1, fp))) 51 break; 52 } 53 fclose(fp); 54 if (i < 2 || !p) { 55 return NULL; 56 } 57 58 if (!(datastart = strstr(buf, interface))) { 59 return NULL; 60 } 61 62 datastart = (datastart+(strlen(interface)+1)); 63 sscanf(datastart + 1, " %*d %d %*d %*d\t\t %*d\t " 64 "%*d\t\t%*d\t\t %*d\t %*d\t\t %*d", &cur); 65 66 /* 70 is the max of /proc/net/wireless */ 67 return bprintf("%d", (int)((float)cur / 70 * 100)); 68 } 69 70 const char * 71 wifi_essid(const char *interface) 72 { 73 static char id[IW_ESSID_MAX_SIZE+1]; 74 int sockfd; 75 struct iwreq wreq; 76 77 memset(&wreq, 0, sizeof(struct iwreq)); 78 wreq.u.essid.length = IW_ESSID_MAX_SIZE+1; 79 if (esnprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s", 80 interface) < 0) { 81 return NULL; 82 } 83 84 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 85 warn("socket 'AF_INET':"); 86 return NULL; 87 } 88 wreq.u.essid.pointer = id; 89 if (ioctl(sockfd,SIOCGIWESSID, &wreq) < 0) { 90 warn("ioctl 'SIOCGIWESSID':"); 91 close(sockfd); 92 return NULL; 93 } 94 95 close(sockfd); 96 97 if (!strcmp(id, "")) { 98 return NULL; 99 } 100 101 return id; 102 } 103 #elif defined(__OpenBSD__) 104 #include <net/if.h> 105 #include <net/if_media.h> 106 #include <net80211/ieee80211.h> 107 #include <sys/select.h> /* before <sys/ieee80211_ioctl.h> for NBBY */ 108 #include <net80211/ieee80211_ioctl.h> 109 #include <stdlib.h> 110 #include <sys/types.h> 111 112 static int 113 load_ieee80211_nodereq(const char *interface, struct ieee80211_nodereq *nr) 114 { 115 struct ieee80211_bssid bssid; 116 int sockfd; 117 uint8_t zero_bssid[IEEE80211_ADDR_LEN]; 118 119 memset(&bssid, 0, sizeof(bssid)); 120 memset(nr, 0, sizeof(struct ieee80211_nodereq)); 121 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 122 warn("socket 'AF_INET':"); 123 return 0; 124 } 125 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name)); 126 if ((ioctl(sockfd, SIOCG80211BSSID, &bssid)) < 0) { 127 warn("ioctl 'SIOCG80211BSSID':"); 128 close(sockfd); 129 return 0; 130 } 131 memset(&zero_bssid, 0, sizeof(zero_bssid)); 132 if (memcmp(bssid.i_bssid, zero_bssid, 133 IEEE80211_ADDR_LEN) == 0) { 134 close(sockfd); 135 return 0; 136 } 137 strlcpy(nr->nr_ifname, interface, sizeof(nr->nr_ifname)); 138 memcpy(&nr->nr_macaddr, bssid.i_bssid, sizeof(nr->nr_macaddr)); 139 if ((ioctl(sockfd, SIOCG80211NODE, nr)) < 0 && nr->nr_rssi) { 140 warn("ioctl 'SIOCG80211NODE':"); 141 close(sockfd); 142 return 0; 143 } 144 145 return close(sockfd), 1; 146 } 147 148 const char * 149 wifi_perc(const char *interface) 150 { 151 struct ieee80211_nodereq nr; 152 int q; 153 154 if (load_ieee80211_nodereq(interface, &nr)) { 155 if (nr.nr_max_rssi) { 156 q = IEEE80211_NODEREQ_RSSI(&nr); 157 } else { 158 q = RSSI_TO_PERC(nr.nr_rssi); 159 } 160 return bprintf("%d", q); 161 } 162 163 return NULL; 164 } 165 166 const char * 167 wifi_essid(const char *interface) 168 { 169 struct ieee80211_nodereq nr; 170 171 if (load_ieee80211_nodereq(interface, &nr)) { 172 return bprintf("%s", nr.nr_nwid); 173 } 174 175 return NULL; 176 } 177 #elif defined(__FreeBSD__) 178 #include <net/if.h> 179 #include <net80211/ieee80211_ioctl.h> 180 181 int 182 load_ieee80211req(int sock, const char *interface, void *data, int type, size_t *len) 183 { 184 char warn_buf[256]; 185 struct ieee80211req ireq; 186 memset(&ireq, 0, sizeof(ireq)); 187 ireq.i_type = type; 188 ireq.i_data = (caddr_t) data; 189 ireq.i_len = *len; 190 191 strlcpy(ireq.i_name, interface, sizeof(ireq.i_name)); 192 if (ioctl(sock, SIOCG80211, &ireq) < 0) { 193 snprintf(warn_buf, sizeof(warn_buf), 194 "ioctl: 'SIOCG80211': %d", type); 195 warn(warn_buf); 196 return 0; 197 } 198 199 *len = ireq.i_len; 200 return 1; 201 } 202 203 const char * 204 wifi_perc(const char *interface) 205 { 206 union { 207 struct ieee80211req_sta_req sta; 208 uint8_t buf[24 * 1024]; 209 } info; 210 uint8_t bssid[IEEE80211_ADDR_LEN]; 211 int rssi_dbm; 212 int sockfd; 213 size_t len; 214 const char *fmt; 215 216 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 217 warn("socket 'AF_INET':"); 218 return NULL; 219 } 220 221 /* Retreive MAC address of interface */ 222 len = IEEE80211_ADDR_LEN; 223 fmt = NULL; 224 if (load_ieee80211req(sockfd, interface, &bssid, IEEE80211_IOC_BSSID, &len)) 225 { 226 /* Retrieve info on station with above BSSID */ 227 memset(&info, 0, sizeof(info)); 228 memcpy(info.sta.is_u.macaddr, bssid, sizeof(bssid)); 229 230 len = sizeof(info); 231 if (load_ieee80211req(sockfd, interface, &info, IEEE80211_IOC_STA_INFO, &len)) { 232 rssi_dbm = info.sta.info[0].isi_noise + 233 info.sta.info[0].isi_rssi / 2; 234 235 fmt = bprintf("%d", RSSI_TO_PERC(rssi_dbm)); 236 } 237 } 238 239 close(sockfd); 240 return fmt; 241 } 242 243 const char * 244 wifi_essid(const char *interface) 245 { 246 char ssid[IEEE80211_NWID_LEN + 1]; 247 size_t len; 248 int sockfd; 249 const char *fmt; 250 251 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 252 warn("socket 'AF_INET':"); 253 return NULL; 254 } 255 256 fmt = NULL; 257 len = sizeof(ssid); 258 memset(&ssid, 0, len); 259 if (load_ieee80211req(sockfd, interface, &ssid, IEEE80211_IOC_SSID, &len )) { 260 if (len < sizeof(ssid)) 261 len += 1; 262 else 263 len = sizeof(ssid); 264 265 ssid[len - 1] = '\0'; 266 fmt = bprintf("%s", ssid); 267 } 268 269 close(sockfd); 270 return fmt; 271 } 272 #endif