slstatus

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

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