commit 39a4ec480bc9db2e4fca1506856309dc884d1fb9
parent 36856fa7ba39356dcf456226797ff588a5733999
Author: lostd <lostd@2f30.org>
Date:   Wed,  2 Nov 2016 14:37:07 +0100
Add Linux support for the wifi plugin
Diffstat:
| M | util.h | | | 10 | ++++++++++ | 
| M | wifi.c | | | 93 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- | 
2 files changed, 99 insertions(+), 4 deletions(-)
diff --git a/util.h b/util.h
@@ -2,3 +2,13 @@
 size_t strlcat(char *, const char *, size_t);
 #undef strlcpy
 size_t strlcpy(char *, const char *, size_t);
+
+#ifdef DEBUG
+#define DPRINTF_S(x) printf(#x "=%s\n", x)
+#define DPRINTF_U(x) printf(#x "=%u\n", x)
+#define DPRINTF_D(x) printf(#x "=%d\n", x)
+#else
+#define DPRINTF_S(x)
+#define DPRINTF_U(x)
+#define DPRINTF_D(x)
+#endif
diff --git a/wifi.c b/wifi.c
@@ -1,5 +1,8 @@
 #include <err.h>
+#include <ifaddrs.h>
 #include <stdio.h>
+#include <string.h>
+#include <unistd.h>
 
 #include "util.h"
 
@@ -32,10 +35,6 @@ wifiprint(char *buf, size_t len, int quality)
 #include <net80211/ieee80211.h>
 #include <net80211/ieee80211_ioctl.h>
 
-#include <ifaddrs.h>
-#include <string.h>
-#include <unistd.h>
-
 int
 wifiread(void *arg, char *buf, size_t len)
 {
@@ -105,4 +104,90 @@ wifiread(void *arg, char *buf, size_t len)
 		return 0;
 	return -1;
 }
+#elif __linux__
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <linux/wireless.h>
+
+int
+wifiread(void *arg, char *buf, size_t len)
+{
+	struct ifaddrs *ifa, *ifas;
+	struct iw_quality *max_qual, *qual;
+	struct iw_statistics stats;
+	struct iw_range range;
+	struct iwreq wrq;
+	int quality = -1;
+	int level;
+	int ret, fd;
+
+	if (getifaddrs(&ifas) < 0) {
+		warn("getifaddrs");
+		return -1;
+	}
+	fd = socket(PF_INET, SOCK_DGRAM, 0);
+	if (fd == -1) {
+		warn("socket");
+		return -1;
+	}
+	for (ifa = ifas; ifa != NULL; ifa = ifa->ifa_next) {
+		DPRINTF_S(ifa->ifa_name);
+		memset(&wrq, 0, sizeof(wrq));
+		strlcpy(wrq.ifr_name, ifa->ifa_name, IFNAMSIZ);
+		ret = ioctl(fd, SIOCGIWNAME, &wrq);
+		if (ret != 0)
+			continue;
+		memset(&wrq, 0, sizeof(wrq));
+		strlcpy(wrq.ifr_name, ifa->ifa_name, IFNAMSIZ);
+		wrq.u.data.pointer = ⦥
+		wrq.u.data.length = sizeof(range);
+		memset(&range, 0, sizeof(range));
+		ret = ioctl(fd, SIOCGIWRANGE, &wrq);
+		if (ret < 0)
+			warnx("cannot get wifi range");
+		memset(&wrq, 0, sizeof(wrq));
+		strlcpy(wrq.ifr_name, ifa->ifa_name, IFNAMSIZ);
+		wrq.u.data.pointer = &stats;
+		wrq.u.data.length = sizeof(stats);
+		wrq.u.data.flags = 1;
+		memset(&stats, 0, sizeof(stats));
+		ret = ioctl(fd, SIOCGIWSTATS, &wrq);
+		if (ret < 0)
+			warnx("cannot get wifi stats");
+		max_qual = &range.max_qual;
+		qual = &stats.qual;
+		DPRINTF_U(max_qual->qual);
+		DPRINTF_U(max_qual->level);
+		DPRINTF_U(qual->qual);
+		DPRINTF_U(qual->level);
+		if (max_qual->qual != 0) {
+			/* driver provides a quality metric */
+			quality = (unsigned)
+			    (((float)qual->qual / max_qual->qual) * 100);
+		} else if (max_qual->level != 0) {
+			/* driver provides signal strength (RSSI) */
+			quality = (unsigned)
+			    (((float)qual->level / max_qual->level) * 100);
+		} else if (max_qual->level == 0) {
+			/* driver provides absolute dBm values */
+			level = qual->level - 0x100;
+			if (level <= -100)
+				quality = 0;
+			else if (level >= -50)
+				quality = 100;
+			else
+				quality = 2 * (level + 100);
+		}
+		break;
+	}
+	close(fd);
+	freeifaddrs(ifas);
+
+	DPRINTF_D(quality);
+	if (quality == -1)
+		return -1;
+	wifiprint(buf, len, quality);
+	return 0;
+}
 #endif