Introduction
Introduction Statistics Contact Development Disclaimer Help
wifi: switch to nl80211 interface - slstatus - status monitor
git clone git://git.suckless.org/slstatus
Log
Files
Refs
README
LICENSE
---
commit 0b00c0319c7b4a941b40aa8709bb4c478f9a9b1f
parent f68f49273e70b3767b30c549dda04ddd4d25fc91
Author: Joakim Sindholt <[email protected]>
Date: Tue, 30 Jul 2024 22:15:44 +0200
wifi: switch to nl80211 interface
Diffstat:
M components/wifi.c | 264 ++++++++++++++++++++++++-----…
1 file changed, 206 insertions(+), 58 deletions(-)
---
diff --git a/components/wifi.c b/components/wifi.c
@@ -15,86 +15,234 @@
(2 * (rssi + 100)))
#if defined(__linux__)
- #include <limits.h>
- #include <linux/wireless.h>
+ #include <stdint.h>
+ #include <net/if.h>
+ #include <linux/netlink.h>
+ #include <linux/genetlink.h>
+ #include <linux/nl80211.h>
- #define NET_OPERSTATE "/sys/class/net/%s/operstate"
+ static int nlsock = -1;
+ static uint32_t seq = 1;
+ static char resp[4096];
- const char *
- wifi_perc(const char *interface)
+ static char *
+ findattr(int attr, char *p, char *e, size_t *len)
{
- int cur;
- size_t i;
- char *p, *datastart;
- char path[PATH_MAX];
- char status[5];
- FILE *fp;
-
- if (esnprintf(path, sizeof(path), NET_OPERSTATE, interface) < …
- return NULL;
- if (!(fp = fopen(path, "r"))) {
- warn("fopen '%s':", path);
- return NULL;
+ struct nlattr nla;
+ size_t alen;
+
+ while ((size_t)(e-p) >= sizeof(nla)) {
+ memcpy(&nla, p, sizeof(nla));
+ if (nla.nla_len < NLA_HDRLEN)
+ return NULL;
+ if (nla.nla_type == attr) {
+ p += NLA_HDRLEN;
+ *len = nla.nla_len-NLA_HDRLEN;
+ return (size_t)(e-p)>=*len?p:NULL;
+ }
+ alen = NLA_ALIGN(nla.nla_len);
+ if ((size_t)(e-p) < alen)
+ return NULL;
+ p += alen;
}
- p = fgets(status, 5, fp);
- fclose(fp);
- if (!p || strcmp(status, "up\n") != 0)
- return NULL;
+ return NULL;
+ }
- if (!(fp = fopen("/proc/net/wireless", "r"))) {
- warn("fopen '/proc/net/wireless':");
- return NULL;
+ static uint16_t
+ nl80211fam(void)
+ {
+ static const char family[] = "nl80211";
+ static uint16_t id;
+ ssize_t r;
+ size_t len;
+ char ctrl[NLMSG_HDRLEN+GENL_HDRLEN+NLA_HDRLEN+NLA_ALIGN(sizeof…
+
+ if (id)
+ return id;
+
+ memcpy(p, &(struct nlmsghdr){
+ .nlmsg_len = sizeof(ctrl),
+ .nlmsg_type = GENL_ID_CTRL,
+ .nlmsg_flags = NLM_F_REQUEST,
+ .nlmsg_seq = seq++,
+ .nlmsg_pid = 0,
+ }, sizeof(struct nlmsghdr));
+ p += NLMSG_HDRLEN;
+ memcpy(p, &(struct genlmsghdr){
+ .cmd = CTRL_CMD_GETFAMILY,
+ .version = 1,
+ }, sizeof(struct genlmsghdr));
+ p += GENL_HDRLEN;
+ memcpy(p, &(struct nlattr){
+ .nla_len = NLA_HDRLEN+sizeof(family),
+ .nla_type = CTRL_ATTR_FAMILY_NAME,
+ }, sizeof(struct nlattr));
+ p += NLA_HDRLEN;
+ memcpy(p, family, sizeof(family));
+
+ if (nlsock < 0)
+ nlsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC);
+ if (nlsock < 0) {
+ warn("socket 'AF_NETLINK':");
+ return 0;
}
+ if (send(nlsock, ctrl, sizeof(ctrl), 0) != sizeof(ctrl)) {
+ warn("send 'AF_NETLINK':");
+ return 0;
+ }
+ r = recv(nlsock, resp, sizeof(resp), 0);
+ if (r < 0) {
+ warn("recv 'AF_NETLINK':");
+ return 0;
+ }
+ if ((size_t)r <= sizeof(ctrl))
+ return 0;
+ p = findattr(CTRL_ATTR_FAMILY_ID, resp+sizeof(ctrl), resp+r, &…
+ if (p && len == 2)
+ memcpy(&id, p, 2);
+ return id;
+ }
- for (i = 0; i < 3; i++)
- if (!(p = fgets(buf, sizeof(buf) - 1, fp)))
- break;
-
- fclose(fp);
- if (i < 2 || !p)
- return NULL;
-
- if (!(datastart = strstr(buf, interface)))
- return NULL;
-
- datastart = (datastart+(strlen(interface)+1));
- sscanf(datastart + 1, " %*d %d %*d %*d\t\t %*d\t "
- "%*d\t\t%*d\t\t %*d\t %*d\t\t %*d", &cur);
-
- /* 70 is the max of /proc/net/wireless */
- return bprintf("%d", (int)((float)cur / 70 * 100));
+ static int
+ ifindex(const char *interface)
+ {
+ static struct ifreq ifr;
+ static int ifsock = -1;
+
+ if (ifsock < 0)
+ ifsock = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if (ifsock < 0) {
+ warn("socket 'AF_UNIX':");
+ return -1;
+ }
+ if (strcmp(ifr.ifr_name, interface) != 0) {
+ strcpy(ifr.ifr_name, interface);
+ if (ioctl(ifsock, SIOCGIFINDEX, &ifr) != 0) {
+ warn("ioctl 'SIOCGIFINDEX':");
+ return -1;
+ }
+ }
+ return ifr.ifr_ifindex;
}
const char *
wifi_essid(const char *interface)
{
- static char id[IW_ESSID_MAX_SIZE+1];
- int sockfd;
- struct iwreq wreq;
-
- memset(&wreq, 0, sizeof(struct iwreq));
- wreq.u.essid.length = IW_ESSID_MAX_SIZE+1;
- if (esnprintf(wreq.ifr_name, sizeof(wreq.ifr_name), "%s",
- interface) < 0)
+ uint16_t fam = nl80211fam();
+ ssize_t r;
+ size_t len;
+ char req[NLMSG_HDRLEN+GENL_HDRLEN+NLA_HDRLEN+NLA_ALIGN(4)] = {…
+ int idx = ifindex(interface);
+ if (!fam) {
+ fprintf(stderr, "nl80211 family not found\n");
return NULL;
+ }
+ if (idx < 0) {
+ fprintf(stderr, "interface %s not found\n", interface);
+ return NULL;
+ }
- if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
- warn("socket 'AF_INET':");
+ memcpy(p, &(struct nlmsghdr){
+ .nlmsg_len = sizeof(req),
+ .nlmsg_type = fam,
+ .nlmsg_flags = NLM_F_REQUEST,
+ .nlmsg_seq = seq++,
+ .nlmsg_pid = 0,
+ }, sizeof(struct nlmsghdr));
+ p += NLMSG_HDRLEN;
+ memcpy(p, &(struct genlmsghdr){
+ .cmd = NL80211_CMD_GET_INTERFACE,
+ .version = 1,
+ }, sizeof(struct genlmsghdr));
+ p += GENL_HDRLEN;
+ memcpy(p, &(struct nlattr){
+ .nla_len = NLA_HDRLEN+4,
+ .nla_type = NL80211_ATTR_IFINDEX,
+ }, sizeof(struct nlattr));
+ p += NLA_HDRLEN;
+ memcpy(p, &(uint32_t){idx}, 4);
+
+ if (send(nlsock, req, sizeof(req), 0) != sizeof(req)) {
+ warn("send 'AF_NETLINK':");
return NULL;
}
- wreq.u.essid.pointer = id;
- if (ioctl(sockfd,SIOCGIWESSID, &wreq) < 0) {
- warn("ioctl 'SIOCGIWESSID':");
- close(sockfd);
+ r = recv(nlsock, resp, sizeof(resp), 0);
+ if (r < 0) {
+ warn("recv 'AF_NETLINK':");
return NULL;
}
- close(sockfd);
+ if ((size_t)r <= NLMSG_HDRLEN+GENL_HDRLEN)
+ return NULL;
+ p = findattr(NL80211_ATTR_SSID, resp+NLMSG_HDRLEN+GENL_HDRLEN,…
+ if (p)
+ p[len] = 0;
+ return p;
+ }
- if (!strcmp(id, ""))
+ const char *
+ wifi_perc(const char *interface)
+ {
+ static char strength[4];
+ struct nlmsghdr hdr;
+ uint16_t fam = nl80211fam();
+ ssize_t r;
+ size_t len;
+ char req[NLMSG_HDRLEN+GENL_HDRLEN+NLA_HDRLEN+NLA_ALIGN(4)] = {…
+ int idx = ifindex(interface);
+ if (idx < 0) {
+ fprintf(stderr, "interface %s not found\n", interface);
return NULL;
+ }
- return id;
+ memcpy(p, &(struct nlmsghdr){
+ .nlmsg_len = sizeof(req),
+ .nlmsg_type = fam,
+ .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP,
+ .nlmsg_seq = seq++,
+ .nlmsg_pid = 0,
+ }, sizeof(struct nlmsghdr));
+ p += NLMSG_HDRLEN;
+ memcpy(p, &(struct genlmsghdr){
+ .cmd = NL80211_CMD_GET_STATION,
+ .version = 1,
+ }, sizeof(struct genlmsghdr));
+ p += GENL_HDRLEN;
+ memcpy(p, &(struct nlattr){
+ .nla_len = NLA_HDRLEN+4,
+ .nla_type = NL80211_ATTR_IFINDEX,
+ }, sizeof(struct nlattr));
+ p += NLA_HDRLEN;
+ memcpy(p, &(uint32_t){idx}, 4);
+
+ if (send(nlsock, req, sizeof(req), 0) != sizeof(req)) {
+ warn("send 'AF_NETLINK':");
+ return NULL;
+ }
+ *strength = 0;
+ while (1) {
+ r = recv(nlsock, resp, sizeof(resp), 0);
+ if (r < 0) {
+ warn("recv 'AF_NETLINK':");
+ return NULL;
+ }
+ if ((size_t)r < sizeof(hdr))
+ return NULL;
+ for (p = resp; p != resp+r && (size_t)(resp+r-p) >= si…
+ memcpy(&hdr, p, sizeof(hdr));
+ e = resp+r-p<hdr.nlmsg_len?resp+r:p+hdr.nlmsg_…
+ if (!*strength && hdr.nlmsg_len > NLMSG_HDRLEN…
+ p += NLMSG_HDRLEN+GENL_HDRLEN;
+ p = findattr(NL80211_ATTR_STA_INFO, p,…
+ if (p)
+ p = findattr(NL80211_STA_INFO_…
+ if (p && len == 1)
+ snprintf(strength, sizeof(stre…
+ }
+ if (hdr.nlmsg_type == NLMSG_DONE)
+ return *strength?strength:NULL;
+ }
+ }
}
#elif defined(__OpenBSD__)
#include <net/if.h>
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.