suckless/slstatus

components/wifi.c in master
Repositories | Summary | Log | Files | README | LICENSE

wifi.c (5951B) download


  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