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