slstatus

status monitor
git clone git://git.suckless.org/slstatus
Log | Files | Refs | README | LICENSE

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