Introduction
Introduction Statistics Contact Development Disclaimer Help
wifi.c - slstatus - status monitor
git clone git://git.suckless.org/slstatus
Log
Files
Refs
README
LICENSE
---
wifi.c (9672B)
---
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 <stdint.h>
19 #include <net/if.h>
20 #include <linux/netlink.h>
21 #include <linux/genetlink.h>
22 #include <linux/nl80211.h>
23
24 static int nlsock = -1;
25 static uint32_t seq = 1;
26 static char resp[4096];
27
28 static char *
29 findattr(int attr, const char *p, const char *e, size_t *len)
30 {
31 while (p < e) {
32 struct nlattr nla;
33 memcpy(&nla, p, sizeof(nla));
34 if (nla.nla_type == attr) {
35 *len = nla.nla_len - NLA_HDRLEN;
36 return (char *)(p + NLA_HDRLEN);
37 }
38 p += NLA_ALIGN(nla.nla_len);
39 }
40 return NULL;
41 }
42
43 static uint16_t
44 nl80211fam(void)
45 {
46 static const char family[] = "nl80211";
47 static uint16_t id;
48 ssize_t r;
49 size_t len;
50 char ctrl[NLMSG_HDRLEN+GENL_HDRLEN+NLA_HDRLEN+NLA_ALIGN(…
51
52 if (id)
53 return id;
54
55 memcpy(p, &(struct nlmsghdr){
56 .nlmsg_len = sizeof(ctrl),
57 .nlmsg_type = GENL_ID_CTRL,
58 .nlmsg_flags = NLM_F_REQUEST,
59 .nlmsg_seq = seq++,
60 .nlmsg_pid = 0,
61 }, sizeof(struct nlmsghdr));
62 p += NLMSG_HDRLEN;
63 memcpy(p, &(struct genlmsghdr){
64 .cmd = CTRL_CMD_GETFAMILY,
65 .version = 1,
66 }, sizeof(struct genlmsghdr));
67 p += GENL_HDRLEN;
68 memcpy(p, &(struct nlattr){
69 .nla_len = NLA_HDRLEN+sizeof(family),
70 .nla_type = CTRL_ATTR_FAMILY_NAME,
71 }, sizeof(struct nlattr));
72 p += NLA_HDRLEN;
73 memcpy(p, family, sizeof(family));
74
75 if (nlsock < 0)
76 nlsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GE…
77 if (nlsock < 0) {
78 warn("socket 'AF_NETLINK':");
79 return 0;
80 }
81 if (send(nlsock, ctrl, sizeof(ctrl), 0) != sizeof(ctrl))…
82 warn("send 'AF_NETLINK':");
83 return 0;
84 }
85 r = recv(nlsock, resp, sizeof(resp), 0);
86 if (r < 0) {
87 warn("recv 'AF_NETLINK':");
88 return 0;
89 }
90 if ((size_t)r <= sizeof(ctrl))
91 return 0;
92 p = findattr(CTRL_ATTR_FAMILY_ID, resp + sizeof(ctrl), r…
93 if (p && len == 2)
94 memcpy(&id, p, 2);
95
96 return id;
97 }
98
99 static int
100 ifindex(const char *interface)
101 {
102 static struct ifreq ifr;
103 static int ifsock = -1;
104
105 if (ifsock < 0)
106 ifsock = socket(AF_UNIX, SOCK_DGRAM, 0);
107 if (ifsock < 0) {
108 warn("socket 'AF_UNIX':");
109 return -1;
110 }
111 if (strcmp(ifr.ifr_name, interface) != 0) {
112 strcpy(ifr.ifr_name, interface);
113 if (ioctl(ifsock, SIOCGIFINDEX, &ifr) != 0) {
114 warn("ioctl 'SIOCGIFINDEX':");
115 return -1;
116 }
117 }
118 return ifr.ifr_ifindex;
119 }
120
121 const char *
122 wifi_essid(const char *interface)
123 {
124 uint16_t fam = nl80211fam();
125 ssize_t r;
126 size_t len;
127 char req[NLMSG_HDRLEN+GENL_HDRLEN+NLA_HDRLEN+NLA_ALIGN(4…
128 int idx = ifindex(interface);
129 if (!fam) {
130 fprintf(stderr, "nl80211 family not found\n");
131 return NULL;
132 }
133 if (idx < 0) {
134 fprintf(stderr, "interface %s not found\n", inte…
135 return NULL;
136 }
137
138 memcpy(p, &(struct nlmsghdr){
139 .nlmsg_len = sizeof(req),
140 .nlmsg_type = fam,
141 .nlmsg_flags = NLM_F_REQUEST,
142 .nlmsg_seq = seq++,
143 .nlmsg_pid = 0,
144 }, sizeof(struct nlmsghdr));
145 p += NLMSG_HDRLEN;
146 memcpy(p, &(struct genlmsghdr){
147 .cmd = NL80211_CMD_GET_INTERFACE,
148 .version = 1,
149 }, sizeof(struct genlmsghdr));
150 p += GENL_HDRLEN;
151 memcpy(p, &(struct nlattr){
152 .nla_len = NLA_HDRLEN+4,
153 .nla_type = NL80211_ATTR_IFINDEX,
154 }, sizeof(struct nlattr));
155 p += NLA_HDRLEN;
156 memcpy(p, &(uint32_t){idx}, 4);
157
158 if (send(nlsock, req, sizeof(req), 0) != sizeof(req)) {
159 warn("send 'AF_NETLINK':");
160 return NULL;
161 }
162 r = recv(nlsock, resp, sizeof(resp), 0);
163 if (r < 0) {
164 warn("recv 'AF_NETLINK':");
165 return NULL;
166 }
167
168 if ((size_t)r <= NLMSG_HDRLEN + GENL_HDRLEN)
169 return NULL;
170 p = findattr(NL80211_ATTR_SSID, resp + NLMSG_HDRLEN + GE…
171 if (p)
172 p[len] = 0;
173
174 return p;
175 }
176
177 const char *
178 wifi_perc(const char *interface)
179 {
180 static char strength[4];
181 struct nlmsghdr hdr;
182 uint16_t fam = nl80211fam();
183 ssize_t r;
184 size_t len;
185 char req[NLMSG_HDRLEN + GENL_HDRLEN + NLA_HDRLEN + NLA_A…
186 int idx = ifindex(interface);
187
188 if (idx < 0) {
189 fprintf(stderr, "interface %s not found\n", inte…
190 return NULL;
191 }
192
193 memcpy(p, &(struct nlmsghdr){
194 .nlmsg_len = sizeof(req),
195 .nlmsg_type = fam,
196 .nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP,
197 .nlmsg_seq = seq++,
198 .nlmsg_pid = 0,
199 }, sizeof(struct nlmsghdr));
200 p += NLMSG_HDRLEN;
201 memcpy(p, &(struct genlmsghdr){
202 .cmd = NL80211_CMD_GET_STATION,
203 .version = 1,
204 }, sizeof(struct genlmsghdr));
205 p += GENL_HDRLEN;
206 memcpy(p, &(struct nlattr){
207 .nla_len = NLA_HDRLEN + 4,
208 .nla_type = NL80211_ATTR_IFINDEX,
209 }, sizeof(struct nlattr));
210 p += NLA_HDRLEN;
211 memcpy(p, &idx, 4);
212
213 if (send(nlsock, req, sizeof(req), 0) != sizeof(req)) {
214 warn("send 'AF_NETLINK':");
215 return NULL;
216 }
217
218 *strength = 0;
219 while (1) {
220 r = recv(nlsock, resp, sizeof(resp), 0);
221 if (r < 0) {
222 warn("recv 'AF_NETLINK':");
223 return NULL;
224 }
225 if ((size_t)r < sizeof(hdr))
226 return NULL;
227
228 for (p = resp; p != resp + r && (size_t)(resp + …
229 memcpy(&hdr, p, sizeof(hdr));
230 e = resp + r - p < hdr.nlmsg_len ? resp …
231
232 if (!*strength && hdr.nlmsg_len > NLMSG_…
233 p += NLMSG_HDRLEN+GENL_HDRLEN;
234 p = findattr(NL80211_ATTR_STA_IN…
235 if (p)
236 p = findattr(NL80211_STA…
237 if (p && len == 1)
238 snprintf(strength, sizeo…
239 }
240 if (hdr.nlmsg_type == NLMSG_DONE)
241 return *strength ? strength : NU…
242 }
243 }
244 }
245 #elif defined(__OpenBSD__)
246 #include <net/if.h>
247 #include <net/if_media.h>
248 #include <net80211/ieee80211.h>
249 #include <sys/select.h> /* before <sys/ieee80211_ioctl.h> for NB…
250 #include <net80211/ieee80211_ioctl.h>
251 #include <stdlib.h>
252 #include <sys/types.h>
253
254 static int
255 load_ieee80211_nodereq(const char *interface, struct ieee80211_n…
256 {
257 struct ieee80211_bssid bssid;
258 int sockfd;
259 uint8_t zero_bssid[IEEE80211_ADDR_LEN];
260
261 memset(&bssid, 0, sizeof(bssid));
262 memset(nr, 0, sizeof(struct ieee80211_nodereq));
263 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
264 warn("socket 'AF_INET':");
265 return 0;
266 }
267 strlcpy(bssid.i_name, interface, sizeof(bssid.i_name));
268 if ((ioctl(sockfd, SIOCG80211BSSID, &bssid)) < 0) {
269 warn("ioctl 'SIOCG80211BSSID':");
270 close(sockfd);
271 return 0;
272 }
273 memset(&zero_bssid, 0, sizeof(zero_bssid));
274 if (memcmp(bssid.i_bssid, zero_bssid,
275 IEEE80211_ADDR_LEN) == 0) {
276 close(sockfd);
277 return 0;
278 }
279 strlcpy(nr->nr_ifname, interface, sizeof(nr->nr_ifname));
280 memcpy(&nr->nr_macaddr, bssid.i_bssid, sizeof(nr->nr_mac…
281 if ((ioctl(sockfd, SIOCG80211NODE, nr)) < 0 && nr->nr_rs…
282 warn("ioctl 'SIOCG80211NODE':");
283 close(sockfd);
284 return 0;
285 }
286
287 return close(sockfd), 1;
288 }
289
290 const char *
291 wifi_perc(const char *interface)
292 {
293 struct ieee80211_nodereq nr;
294 int q;
295
296 if (load_ieee80211_nodereq(interface, &nr)) {
297 if (nr.nr_max_rssi)
298 q = IEEE80211_NODEREQ_RSSI(&nr);
299 else
300 q = RSSI_TO_PERC(nr.nr_rssi);
301
302 return bprintf("%d", q);
303 }
304
305 return NULL;
306 }
307
308 const char *
309 wifi_essid(const char *interface)
310 {
311 struct ieee80211_nodereq nr;
312
313 if (load_ieee80211_nodereq(interface, &nr))
314 return bprintf("%s", nr.nr_nwid);
315
316 return NULL;
317 }
318 #elif defined(__FreeBSD__)
319 #include <net/if.h>
320 #include <net80211/ieee80211_ioctl.h>
321
322 int
323 load_ieee80211req(int sock, const char *interface, void *data, i…
324 {
325 char warn_buf[256];
326 struct ieee80211req ireq;
327 memset(&ireq, 0, sizeof(ireq));
328 ireq.i_type = type;
329 ireq.i_data = (caddr_t) data;
330 ireq.i_len = *len;
331
332 strlcpy(ireq.i_name, interface, sizeof(ireq.i_name));
333 if (ioctl(sock, SIOCG80211, &ireq) < 0) {
334 snprintf(warn_buf, sizeof(warn_buf),
335 "ioctl: 'SIOCG80211': %d", type);
336 warn(warn_buf);
337 return 0;
338 }
339
340 *len = ireq.i_len;
341 return 1;
342 }
343
344 const char *
345 wifi_perc(const char *interface)
346 {
347 union {
348 struct ieee80211req_sta_req sta;
349 uint8_t buf[24 * 1024];
350 } info;
351 uint8_t bssid[IEEE80211_ADDR_LEN];
352 int rssi_dbm;
353 int sockfd;
354 size_t len;
355 const char *fmt;
356
357 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
358 warn("socket 'AF_INET':");
359 return NULL;
360 }
361
362 /* Retreive MAC address of interface */
363 len = IEEE80211_ADDR_LEN;
364 fmt = NULL;
365 if (load_ieee80211req(sockfd, interface, &bssid, IEEE802…
366 {
367 /* Retrieve info on station with above BSSID */
368 memset(&info, 0, sizeof(info));
369 memcpy(info.sta.is_u.macaddr, bssid, sizeof(bssi…
370
371 len = sizeof(info);
372 if (load_ieee80211req(sockfd, interface, &info, …
373 rssi_dbm = info.sta.info[0].isi_noise +
374 info.sta.info[0].isi_r…
375
376 fmt = bprintf("%d", RSSI_TO_PERC(rssi_db…
377 }
378 }
379
380 close(sockfd);
381 return fmt;
382 }
383
384 const char *
385 wifi_essid(const char *interface)
386 {
387 char ssid[IEEE80211_NWID_LEN + 1];
388 size_t len;
389 int sockfd;
390 const char *fmt;
391
392 if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
393 warn("socket 'AF_INET':");
394 return NULL;
395 }
396
397 fmt = NULL;
398 len = sizeof(ssid);
399 memset(&ssid, 0, len);
400 if (load_ieee80211req(sockfd, interface, &ssid, IEEE8021…
401 if (len < sizeof(ssid))
402 len += 1;
403 else
404 len = sizeof(ssid);
405
406 ssid[len - 1] = '\0';
407 fmt = bprintf("%s", ssid);
408 }
409
410 close(sockfd);
411 return fmt;
412 }
413 #endif
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.