iwinfo: continue scanning even if temporary mac cannot be changed
[openwrt/staging/wigyori.git] / package / network / utils / iwinfo / src / iwinfo_nl80211.c
1 /*
2 * iwinfo - Wireless Information Library - NL80211 Backend
3 *
4 * Copyright (C) 2010-2013 Jo-Philipp Wich <xm@subsignal.org>
5 *
6 * The iwinfo library is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version 2
8 * as published by the Free Software Foundation.
9 *
10 * The iwinfo library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
17 *
18 * The signal handling code is derived from the official madwifi tools,
19 * wlanconfig.c in particular. The encryption property handling was
20 * inspired by the hostapd madwifi driver.
21 *
22 * Parts of this code are derived from the Linux iw utility.
23 */
24
25 #include "iwinfo_nl80211.h"
26
27 #define min(x, y) ((x) < (y)) ? (x) : (y)
28
29 static struct nl80211_state *nls = NULL;
30
31 static void nl80211_close(void)
32 {
33 if (nls)
34 {
35 if (nls->nlctrl)
36 genl_family_put(nls->nlctrl);
37
38 if (nls->nl80211)
39 genl_family_put(nls->nl80211);
40
41 if (nls->nl_sock)
42 nl_socket_free(nls->nl_sock);
43
44 if (nls->nl_cache)
45 nl_cache_free(nls->nl_cache);
46
47 free(nls);
48 nls = NULL;
49 }
50 }
51
52 static int nl80211_init(void)
53 {
54 int err, fd;
55
56 if (!nls)
57 {
58 nls = malloc(sizeof(struct nl80211_state));
59 if (!nls) {
60 err = -ENOMEM;
61 goto err;
62 }
63
64 memset(nls, 0, sizeof(*nls));
65
66 nls->nl_sock = nl_socket_alloc();
67 if (!nls->nl_sock) {
68 err = -ENOMEM;
69 goto err;
70 }
71
72 if (genl_connect(nls->nl_sock)) {
73 err = -ENOLINK;
74 goto err;
75 }
76
77 fd = nl_socket_get_fd(nls->nl_sock);
78 if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0) {
79 err = -EINVAL;
80 goto err;
81 }
82
83 if (genl_ctrl_alloc_cache(nls->nl_sock, &nls->nl_cache)) {
84 err = -ENOMEM;
85 goto err;
86 }
87
88 nls->nl80211 = genl_ctrl_search_by_name(nls->nl_cache, "nl80211");
89 if (!nls->nl80211) {
90 err = -ENOENT;
91 goto err;
92 }
93
94 nls->nlctrl = genl_ctrl_search_by_name(nls->nl_cache, "nlctrl");
95 if (!nls->nlctrl) {
96 err = -ENOENT;
97 goto err;
98 }
99 }
100
101 return 0;
102
103
104 err:
105 nl80211_close();
106 return err;
107 }
108
109 static int nl80211_readint(const char *path)
110 {
111 int fd;
112 int rv = -1;
113 char buffer[16];
114
115 if ((fd = open(path, O_RDONLY)) > -1)
116 {
117 if (read(fd, buffer, sizeof(buffer)) > 0)
118 rv = atoi(buffer);
119
120 close(fd);
121 }
122
123 return rv;
124 }
125
126
127 static int nl80211_msg_error(struct sockaddr_nl *nla,
128 struct nlmsgerr *err, void *arg)
129 {
130 int *ret = arg;
131 *ret = err->error;
132 return NL_STOP;
133 }
134
135 static int nl80211_msg_finish(struct nl_msg *msg, void *arg)
136 {
137 int *ret = arg;
138 *ret = 0;
139 return NL_SKIP;
140 }
141
142 static int nl80211_msg_ack(struct nl_msg *msg, void *arg)
143 {
144 int *ret = arg;
145 *ret = 0;
146 return NL_STOP;
147 }
148
149 static int nl80211_msg_response(struct nl_msg *msg, void *arg)
150 {
151 return NL_SKIP;
152 }
153
154 static void nl80211_free(struct nl80211_msg_conveyor *cv)
155 {
156 if (cv)
157 {
158 if (cv->cb)
159 nl_cb_put(cv->cb);
160
161 if (cv->msg)
162 nlmsg_free(cv->msg);
163
164 cv->cb = NULL;
165 cv->msg = NULL;
166 }
167 }
168
169 static struct nl80211_msg_conveyor * nl80211_new(struct genl_family *family,
170 int cmd, int flags)
171 {
172 static struct nl80211_msg_conveyor cv;
173
174 struct nl_msg *req = NULL;
175 struct nl_cb *cb = NULL;
176
177 req = nlmsg_alloc();
178 if (!req)
179 goto err;
180
181 cb = nl_cb_alloc(NL_CB_DEFAULT);
182 if (!cb)
183 goto err;
184
185 genlmsg_put(req, 0, 0, genl_family_get_id(family), 0, flags, cmd, 0);
186
187 cv.msg = req;
188 cv.cb = cb;
189
190 return &cv;
191
192 err:
193 nla_put_failure:
194 if (cb)
195 nl_cb_put(cb);
196
197 if (req)
198 nlmsg_free(req);
199
200 return NULL;
201 }
202
203 static struct nl80211_msg_conveyor * nl80211_ctl(int cmd, int flags)
204 {
205 if (nl80211_init() < 0)
206 return NULL;
207
208 return nl80211_new(nls->nlctrl, cmd, flags);
209 }
210
211 static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname,
212 int cmd, int flags)
213 {
214 int ifidx = -1, phyidx = -1;
215 struct nl80211_msg_conveyor *cv;
216
217 if (nl80211_init() < 0)
218 return NULL;
219
220 if (!strncmp(ifname, "phy", 3))
221 phyidx = atoi(&ifname[3]);
222 else if (!strncmp(ifname, "radio", 5))
223 phyidx = atoi(&ifname[5]);
224 else if (!strncmp(ifname, "mon.", 4))
225 ifidx = if_nametoindex(&ifname[4]);
226 else
227 ifidx = if_nametoindex(ifname);
228
229 if ((ifidx < 0) && (phyidx < 0))
230 return NULL;
231
232 cv = nl80211_new(nls->nl80211, cmd, flags);
233 if (!cv)
234 return NULL;
235
236 if (ifidx > -1)
237 NLA_PUT_U32(cv->msg, NL80211_ATTR_IFINDEX, ifidx);
238
239 if (phyidx > -1)
240 NLA_PUT_U32(cv->msg, NL80211_ATTR_WIPHY, phyidx);
241
242 return cv;
243
244 nla_put_failure:
245 nl80211_free(cv);
246 return NULL;
247 }
248
249 static struct nl80211_msg_conveyor * nl80211_send(
250 struct nl80211_msg_conveyor *cv,
251 int (*cb_func)(struct nl_msg *, void *), void *cb_arg
252 ) {
253 static struct nl80211_msg_conveyor rcv;
254 int err = 1;
255
256 if (cb_func)
257 nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, cb_func, cb_arg);
258 else
259 nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_msg_response, &rcv);
260
261 if (nl_send_auto_complete(nls->nl_sock, cv->msg) < 0)
262 goto err;
263
264 nl_cb_err(cv->cb, NL_CB_CUSTOM, nl80211_msg_error, &err);
265 nl_cb_set(cv->cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_msg_finish, &err);
266 nl_cb_set(cv->cb, NL_CB_ACK, NL_CB_CUSTOM, nl80211_msg_ack, &err);
267
268 while (err > 0)
269 nl_recvmsgs(nls->nl_sock, cv->cb);
270
271 return &rcv;
272
273 err:
274 nl_cb_put(cv->cb);
275 nlmsg_free(cv->msg);
276
277 return NULL;
278 }
279
280 static struct nlattr ** nl80211_parse(struct nl_msg *msg)
281 {
282 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
283 static struct nlattr *attr[NL80211_ATTR_MAX + 1];
284
285 nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
286 genlmsg_attrlen(gnlh, 0), NULL);
287
288 return attr;
289 }
290
291
292 static int nl80211_subscribe_cb(struct nl_msg *msg, void *arg)
293 {
294 struct nl80211_group_conveyor *cv = arg;
295
296 struct nlattr **attr = nl80211_parse(msg);
297 struct nlattr *mgrpinfo[CTRL_ATTR_MCAST_GRP_MAX + 1];
298 struct nlattr *mgrp;
299 int mgrpidx;
300
301 if (!attr[CTRL_ATTR_MCAST_GROUPS])
302 return NL_SKIP;
303
304 nla_for_each_nested(mgrp, attr[CTRL_ATTR_MCAST_GROUPS], mgrpidx)
305 {
306 nla_parse(mgrpinfo, CTRL_ATTR_MCAST_GRP_MAX,
307 nla_data(mgrp), nla_len(mgrp), NULL);
308
309 if (mgrpinfo[CTRL_ATTR_MCAST_GRP_ID] &&
310 mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME] &&
311 !strncmp(nla_data(mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME]),
312 cv->name, nla_len(mgrpinfo[CTRL_ATTR_MCAST_GRP_NAME])))
313 {
314 cv->id = nla_get_u32(mgrpinfo[CTRL_ATTR_MCAST_GRP_ID]);
315 break;
316 }
317 }
318
319 return NL_SKIP;
320 }
321
322 static int nl80211_subscribe(const char *family, const char *group)
323 {
324 struct nl80211_group_conveyor cv = { .name = group, .id = -ENOENT };
325 struct nl80211_msg_conveyor *req;
326
327 req = nl80211_ctl(CTRL_CMD_GETFAMILY, 0);
328 if (req)
329 {
330 NLA_PUT_STRING(req->msg, CTRL_ATTR_FAMILY_NAME, family);
331 nl80211_send(req, nl80211_subscribe_cb, &cv);
332
333 nla_put_failure:
334 nl80211_free(req);
335 }
336
337 return nl_socket_add_membership(nls->nl_sock, cv.id);
338 }
339
340
341 static int nl80211_wait_cb(struct nl_msg *msg, void *arg)
342 {
343 struct nl80211_event_conveyor *cv = arg;
344 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
345
346 if (gnlh->cmd == cv->wait)
347 cv->recv = gnlh->cmd;
348
349 return NL_SKIP;
350 }
351
352 static int nl80211_wait_seq_check(struct nl_msg *msg, void *arg)
353 {
354 return NL_OK;
355 }
356
357 static int nl80211_wait(const char *family, const char *group, int cmd)
358 {
359 struct nl80211_event_conveyor cv = { .wait = cmd };
360 struct nl_cb *cb;
361
362 if (nl80211_subscribe(family, group))
363 return -ENOENT;
364
365 cb = nl_cb_alloc(NL_CB_DEFAULT);
366
367 if (!cb)
368 return -ENOMEM;
369
370 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, nl80211_wait_seq_check, NULL);
371 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_wait_cb, &cv );
372
373 while (!cv.recv)
374 nl_recvmsgs(nls->nl_sock, cb);
375
376 nl_cb_put(cb);
377
378 return 0;
379 }
380
381
382 static int nl80211_freq2channel(int freq)
383 {
384 if (freq == 2484)
385 return 14;
386 else if (freq < 2484)
387 return (freq - 2407) / 5;
388 else if (freq >= 4910 && freq <= 4980)
389 return (freq - 4000) / 5;
390 else
391 return (freq - 5000) / 5;
392 }
393
394 static int nl80211_channel2freq(int channel, const char *band)
395 {
396 if (!band || band[0] != 'a')
397 {
398 if (channel == 14)
399 return 2484;
400 else if (channel < 14)
401 return (channel * 5) + 2407;
402 }
403 else
404 {
405 if (channel >= 182 && channel <= 196)
406 return (channel * 5) + 4000;
407 else
408 return (channel * 5) + 5000;
409 }
410
411 return 0;
412 }
413
414 static char * nl80211_getval(const char *ifname, const char *buf, const char *key)
415 {
416 int i, len;
417 char lkey[64] = { 0 };
418 const char *ln = buf;
419 static char lval[256] = { 0 };
420
421 int matched_if = ifname ? 0 : 1;
422
423
424 for( i = 0, len = strlen(buf); i < len; i++ )
425 {
426 if (!lkey[0] && (buf[i] == ' ' || buf[i] == '\t'))
427 {
428 ln++;
429 }
430 else if (!lkey[0] && (buf[i] == '='))
431 {
432 if ((&buf[i] - ln) > 0)
433 memcpy(lkey, ln, min(sizeof(lkey) - 1, &buf[i] - ln));
434 }
435 else if (buf[i] == '\n')
436 {
437 if (lkey[0])
438 {
439 memcpy(lval, ln + strlen(lkey) + 1,
440 min(sizeof(lval) - 1, &buf[i] - ln - strlen(lkey) - 1));
441
442 if ((ifname != NULL) &&
443 (!strcmp(lkey, "interface") || !strcmp(lkey, "bss")) )
444 {
445 matched_if = !strcmp(lval, ifname);
446 }
447 else if (matched_if && !strcmp(lkey, key))
448 {
449 return lval;
450 }
451 }
452
453 ln = &buf[i+1];
454 memset(lkey, 0, sizeof(lkey));
455 memset(lval, 0, sizeof(lval));
456 }
457 }
458
459 return NULL;
460 }
461
462 static int nl80211_ifname2phy_cb(struct nl_msg *msg, void *arg)
463 {
464 char *buf = arg;
465 struct nlattr **attr = nl80211_parse(msg);
466
467 if (attr[NL80211_ATTR_WIPHY_NAME])
468 memcpy(buf, nla_data(attr[NL80211_ATTR_WIPHY_NAME]),
469 nla_len(attr[NL80211_ATTR_WIPHY_NAME]));
470 else
471 buf[0] = 0;
472
473 return NL_SKIP;
474 }
475
476 static char * nl80211_ifname2phy(const char *ifname)
477 {
478 static char phy[32] = { 0 };
479 struct nl80211_msg_conveyor *req;
480
481 memset(phy, 0, sizeof(phy));
482
483 req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
484 if (req)
485 {
486 nl80211_send(req, nl80211_ifname2phy_cb, phy);
487 nl80211_free(req);
488 }
489
490 return phy[0] ? phy : NULL;
491 }
492
493 static char * nl80211_phy2ifname(const char *ifname)
494 {
495 int fd, ifidx = -1, cifidx = -1, phyidx = -1;
496 char buffer[64];
497 static char nif[IFNAMSIZ] = { 0 };
498
499 DIR *d;
500 struct dirent *e;
501
502 if (!ifname)
503 return NULL;
504 else if (!strncmp(ifname, "phy", 3))
505 phyidx = atoi(&ifname[3]);
506 else if (!strncmp(ifname, "radio", 5))
507 phyidx = atoi(&ifname[5]);
508
509 memset(nif, 0, sizeof(nif));
510
511 if (phyidx > -1)
512 {
513 if ((d = opendir("/sys/class/net")) != NULL)
514 {
515 while ((e = readdir(d)) != NULL)
516 {
517 snprintf(buffer, sizeof(buffer),
518 "/sys/class/net/%s/phy80211/index", e->d_name);
519
520 if (nl80211_readint(buffer) == phyidx)
521 {
522 snprintf(buffer, sizeof(buffer),
523 "/sys/class/net/%s/ifindex", e->d_name);
524
525 if ((cifidx = nl80211_readint(buffer)) >= 0 &&
526 ((ifidx < 0) || (cifidx < ifidx)))
527 {
528 ifidx = cifidx;
529 strncpy(nif, e->d_name, sizeof(nif));
530 }
531 }
532 }
533
534 closedir(d);
535 }
536 }
537
538 return nif[0] ? nif : NULL;
539 }
540
541 static int nl80211_get_mode_cb(struct nl_msg *msg, void *arg)
542 {
543 int *mode = arg;
544 struct nlattr **tb = nl80211_parse(msg);
545 const int ifmodes[NL80211_IFTYPE_MAX + 1] = {
546 IWINFO_OPMODE_UNKNOWN, /* unspecified */
547 IWINFO_OPMODE_ADHOC, /* IBSS */
548 IWINFO_OPMODE_CLIENT, /* managed */
549 IWINFO_OPMODE_MASTER, /* AP */
550 IWINFO_OPMODE_AP_VLAN, /* AP/VLAN */
551 IWINFO_OPMODE_WDS, /* WDS */
552 IWINFO_OPMODE_MONITOR, /* monitor */
553 IWINFO_OPMODE_MESHPOINT, /* mesh point */
554 IWINFO_OPMODE_P2P_CLIENT, /* P2P-client */
555 IWINFO_OPMODE_P2P_GO, /* P2P-GO */
556 };
557
558 if (tb[NL80211_ATTR_IFTYPE])
559 *mode = ifmodes[nla_get_u32(tb[NL80211_ATTR_IFTYPE])];
560
561 return NL_SKIP;
562 }
563
564
565 static int nl80211_get_mode(const char *ifname, int *buf)
566 {
567 char *res;
568 struct nl80211_msg_conveyor *req;
569
570 res = nl80211_phy2ifname(ifname);
571 req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0);
572 *buf = IWINFO_OPMODE_UNKNOWN;
573
574 if (req)
575 {
576 nl80211_send(req, nl80211_get_mode_cb, buf);
577 nl80211_free(req);
578 }
579
580 return (*buf == IWINFO_OPMODE_UNKNOWN) ? -1 : 0;
581 }
582
583 static char * nl80211_hostapd_info(const char *ifname)
584 {
585 int mode;
586 char *phy;
587 char path[32] = { 0 };
588 static char buf[4096] = { 0 };
589 FILE *conf;
590
591 if (nl80211_get_mode(ifname, &mode))
592 return NULL;
593
594 if ((mode == IWINFO_OPMODE_MASTER || mode == IWINFO_OPMODE_AP_VLAN) &&
595 (phy = nl80211_ifname2phy(ifname)) != NULL)
596 {
597 snprintf(path, sizeof(path), "/var/run/hostapd-%s.conf", phy);
598
599 if ((conf = fopen(path, "r")) != NULL)
600 {
601 fread(buf, sizeof(buf) - 1, 1, conf);
602 fclose(conf);
603
604 return buf;
605 }
606 }
607
608 return NULL;
609 }
610
611 static inline int nl80211_wpactl_recv(int sock, char *buf, int blen)
612 {
613 fd_set rfds;
614 struct timeval tv = { 2, 0 };
615
616 FD_ZERO(&rfds);
617 FD_SET(sock, &rfds);
618
619 memset(buf, 0, blen);
620
621
622 if (select(sock + 1, &rfds, NULL, NULL, &tv) < 0)
623 return -1;
624
625 if (!FD_ISSET(sock, &rfds))
626 return -1;
627
628 return recv(sock, buf, blen, 0);
629 }
630
631 static char * nl80211_wpactl_info(const char *ifname, const char *cmd,
632 const char *event)
633 {
634 int numtry = 0;
635 int sock = -1;
636 char *rv = NULL;
637 size_t remote_length, local_length;
638 static char buffer[10240] = { 0 };
639
640 struct sockaddr_un local = { 0 };
641 struct sockaddr_un remote = { 0 };
642
643
644 sock = socket(PF_UNIX, SOCK_DGRAM, 0);
645 if (sock < 0)
646 return NULL;
647
648 remote.sun_family = AF_UNIX;
649 remote_length = sizeof(remote.sun_family) + sprintf(remote.sun_path,
650 "/var/run/wpa_supplicant-%s/%s", ifname, ifname);
651
652 if (fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC) < 0)
653 goto out;
654
655 if (connect(sock, (struct sockaddr *) &remote, remote_length))
656 {
657 remote_length = sizeof(remote.sun_family) + sprintf(remote.sun_path,
658 "/var/run/wpa_supplicant/%s", ifname);
659
660 if (connect(sock, (struct sockaddr *) &remote, remote_length))
661 goto out;
662 }
663
664 local.sun_family = AF_UNIX;
665 local_length = sizeof(local.sun_family) +
666 sprintf(local.sun_path, "/var/run/iwinfo-%s-%d", ifname, getpid());
667
668 if (bind(sock, (struct sockaddr *) &local, local_length))
669 goto out;
670
671
672 if (event)
673 {
674 send(sock, "ATTACH", 6, 0);
675
676 if (nl80211_wpactl_recv(sock, buffer, sizeof(buffer)-1) <= 0)
677 goto out;
678 }
679
680
681 send(sock, cmd, strlen(cmd), 0);
682
683 /* we might have to scan up to 72 channels / 256ms per channel */
684 /* this makes up to 18.5s hence 10 tries */
685 while( numtry++ < 10 )
686 {
687 char *bracket;
688
689 /* make sure there is a terminating nul byte */
690 if (nl80211_wpactl_recv(sock, buffer, sizeof(buffer)-1) <= 0)
691 {
692 if (event)
693 continue;
694
695 break;
696 }
697
698 if ((!event && buffer[0] != '<') || (event && strstr(buffer, event)))
699 break;
700
701 /* there may be more than max(numtry) BSS-ADDED events */
702 /* ignore them similar to wpa_cli */
703 if (buffer[0] == '<' &&
704 (bracket=strchr(buffer,'>')) != NULL &&
705 strncmp(bracket+1,"CTRL-EVENT-BSS-ADDED",20) == 0)
706 numtry--;
707 }
708
709 rv = buffer;
710
711 out:
712 close(sock);
713
714 if (local.sun_family)
715 unlink(local.sun_path);
716
717 return rv;
718 }
719
720 static char * nl80211_ifadd(const char *ifname)
721 {
722 int phyidx;
723 char *rv = NULL;
724 static char nif[IFNAMSIZ] = { 0 };
725 struct nl80211_msg_conveyor *req, *res;
726
727 req = nl80211_msg(ifname, NL80211_CMD_NEW_INTERFACE, 0);
728 if (req)
729 {
730 snprintf(nif, sizeof(nif), "tmp.%s", ifname);
731
732 NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, nif);
733 NLA_PUT_U32(req->msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION);
734
735 nl80211_send(req, NULL, NULL);
736
737 rv = nif;
738
739 nla_put_failure:
740 nl80211_free(req);
741 }
742
743 return rv;
744 }
745
746 static void nl80211_ifdel(const char *ifname)
747 {
748 struct nl80211_msg_conveyor *req;
749
750 req = nl80211_msg(ifname, NL80211_CMD_DEL_INTERFACE, 0);
751 if (req)
752 {
753 NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, ifname);
754
755 nl80211_send(req, NULL, NULL);
756
757 nla_put_failure:
758 nl80211_free(req);
759 }
760 }
761
762 static void nl80211_hostapd_hup(const char *ifname)
763 {
764 int fd, pid = 0;
765 char buf[32];
766 char *phy = nl80211_ifname2phy(ifname);
767
768 if (phy)
769 {
770 snprintf(buf, sizeof(buf), "/var/run/wifi-%s.pid", phy);
771 if ((fd = open(buf, O_RDONLY)) > 0)
772 {
773 if (read(fd, buf, sizeof(buf)) > 0)
774 pid = atoi(buf);
775
776 close(fd);
777 }
778
779 if (pid > 0)
780 kill(pid, 1);
781 }
782 }
783
784
785 static int nl80211_probe(const char *ifname)
786 {
787 return !!nl80211_ifname2phy(ifname);
788 }
789
790 struct nl80211_ssid_bssid {
791 unsigned char *ssid;
792 unsigned char bssid[7];
793 };
794
795 static int nl80211_get_ssid_bssid_cb(struct nl_msg *msg, void *arg)
796 {
797 int ielen;
798 unsigned char *ie;
799 struct nl80211_ssid_bssid *sb = arg;
800 struct nlattr **tb = nl80211_parse(msg);
801 struct nlattr *bss[NL80211_BSS_MAX + 1];
802
803 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
804 [NL80211_BSS_INFORMATION_ELEMENTS] = { },
805 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
806 };
807
808 if (!tb[NL80211_ATTR_BSS] ||
809 nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
810 bss_policy) ||
811 !bss[NL80211_BSS_BSSID] ||
812 !bss[NL80211_BSS_STATUS] ||
813 !bss[NL80211_BSS_INFORMATION_ELEMENTS])
814 {
815 return NL_SKIP;
816 }
817
818 switch (nla_get_u32(bss[NL80211_BSS_STATUS]))
819 {
820 case NL80211_BSS_STATUS_ASSOCIATED:
821 case NL80211_BSS_STATUS_AUTHENTICATED:
822 case NL80211_BSS_STATUS_IBSS_JOINED:
823
824 if (sb->ssid)
825 {
826 ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
827 ielen = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
828
829 while (ielen >= 2 && ielen >= ie[1])
830 {
831 if (ie[0] == 0)
832 {
833 memcpy(sb->ssid, ie + 2, min(ie[1], IWINFO_ESSID_MAX_SIZE));
834 return NL_SKIP;
835 }
836
837 ielen -= ie[1] + 2;
838 ie += ie[1] + 2;
839 }
840 }
841 else
842 {
843 sb->bssid[0] = 1;
844 memcpy(sb->bssid + 1, nla_data(bss[NL80211_BSS_BSSID]), 6);
845 return NL_SKIP;
846 }
847
848 default:
849 return NL_SKIP;
850 }
851 }
852
853 static int nl80211_get_ssid(const char *ifname, char *buf)
854 {
855 char *res;
856 struct nl80211_msg_conveyor *req;
857 struct nl80211_ssid_bssid sb;
858
859 /* try to find ssid from scan dump results */
860 res = nl80211_phy2ifname(ifname);
861 req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
862
863 sb.ssid = buf;
864 *buf = 0;
865
866 if (req)
867 {
868 nl80211_send(req, nl80211_get_ssid_bssid_cb, &sb);
869 nl80211_free(req);
870 }
871
872 /* failed, try to find from hostapd info */
873 if ((*buf == 0) &&
874 (res = nl80211_hostapd_info(ifname)) &&
875 (res = nl80211_getval(ifname, res, "ssid")))
876 {
877 memcpy(buf, res, strlen(res));
878 }
879
880 return (*buf == 0) ? -1 : 0;
881 }
882
883 static int nl80211_get_bssid(const char *ifname, char *buf)
884 {
885 char *res;
886 struct nl80211_msg_conveyor *req;
887 struct nl80211_ssid_bssid sb;
888
889 /* try to find bssid from scan dump results */
890 res = nl80211_phy2ifname(ifname);
891 req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
892
893 sb.ssid = NULL;
894 sb.bssid[0] = 0;
895
896 if (req)
897 {
898 nl80211_send(req, nl80211_get_ssid_bssid_cb, &sb);
899 nl80211_free(req);
900 }
901
902 /* failed, try to find mac from hostapd info */
903 if ((sb.bssid[0] == 0) &&
904 (res = nl80211_hostapd_info(ifname)) &&
905 (res = nl80211_getval(ifname, res, "bssid")))
906 {
907 sb.bssid[0] = 1;
908 sb.bssid[1] = strtol(&res[0], NULL, 16);
909 sb.bssid[2] = strtol(&res[3], NULL, 16);
910 sb.bssid[3] = strtol(&res[6], NULL, 16);
911 sb.bssid[4] = strtol(&res[9], NULL, 16);
912 sb.bssid[5] = strtol(&res[12], NULL, 16);
913 sb.bssid[6] = strtol(&res[15], NULL, 16);
914 }
915
916 if (sb.bssid[0])
917 {
918 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
919 sb.bssid[1], sb.bssid[2], sb.bssid[3],
920 sb.bssid[4], sb.bssid[5], sb.bssid[6]);
921
922 return 0;
923 }
924
925 return -1;
926 }
927
928
929 static int nl80211_get_frequency_scan_cb(struct nl_msg *msg, void *arg)
930 {
931 int *freq = arg;
932 struct nlattr **attr = nl80211_parse(msg);
933 struct nlattr *binfo[NL80211_BSS_MAX + 1];
934
935 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
936 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
937 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
938 };
939
940 if (attr[NL80211_ATTR_BSS] &&
941 !nla_parse_nested(binfo, NL80211_BSS_MAX,
942 attr[NL80211_ATTR_BSS], bss_policy))
943 {
944 if (binfo[NL80211_BSS_STATUS] && binfo[NL80211_BSS_FREQUENCY])
945 *freq = nla_get_u32(binfo[NL80211_BSS_FREQUENCY]);
946 }
947
948 return NL_SKIP;
949 }
950
951 static int nl80211_get_frequency_info_cb(struct nl_msg *msg, void *arg)
952 {
953 int *freq = arg;
954 struct nlattr **tb = nl80211_parse(msg);
955
956 if (tb[NL80211_ATTR_WIPHY_FREQ])
957 *freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
958
959 return NL_SKIP;
960 }
961
962 static int nl80211_get_frequency(const char *ifname, int *buf)
963 {
964 int chn;
965 char *res, *channel;
966 struct nl80211_msg_conveyor *req;
967
968 /* try to find frequency from interface info */
969 res = nl80211_phy2ifname(ifname);
970 req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_INTERFACE, 0);
971 *buf = 0;
972
973 if (req)
974 {
975 nl80211_send(req, nl80211_get_frequency_info_cb, buf);
976 nl80211_free(req);
977 }
978
979 /* failed, try to find frequency from hostapd info */
980 if ((*buf == 0) &&
981 (res = nl80211_hostapd_info(ifname)) &&
982 (channel = nl80211_getval(NULL, res, "channel")))
983 {
984 chn = atoi(channel);
985 *buf = nl80211_channel2freq(chn, nl80211_getval(NULL, res, "hw_mode"));
986 }
987 else
988 {
989 /* failed, try to find frequency from scan results */
990 if (*buf == 0)
991 {
992 res = nl80211_phy2ifname(ifname);
993 req = nl80211_msg(res ? res : ifname, NL80211_CMD_GET_SCAN,
994 NLM_F_DUMP);
995
996 if (req)
997 {
998 nl80211_send(req, nl80211_get_frequency_scan_cb, buf);
999 nl80211_free(req);
1000 }
1001 }
1002 }
1003
1004 return (*buf == 0) ? -1 : 0;
1005 }
1006
1007 static int nl80211_get_channel(const char *ifname, int *buf)
1008 {
1009 if (!nl80211_get_frequency(ifname, buf))
1010 {
1011 *buf = nl80211_freq2channel(*buf);
1012 return 0;
1013 }
1014
1015 return -1;
1016 }
1017
1018
1019 static int nl80211_get_txpower(const char *ifname, int *buf)
1020 {
1021 #if 0
1022 char *res;
1023 char path[PATH_MAX];
1024
1025 res = nl80211_ifname2phy(ifname);
1026 snprintf(path, sizeof(path), "/sys/kernel/debug/ieee80211/%s/power",
1027 res ? res : ifname);
1028
1029 if ((*buf = nl80211_readint(path)) > -1)
1030 return 0;
1031 #endif
1032
1033 return wext_ops.txpower(ifname, buf);
1034 }
1035
1036
1037 static int nl80211_fill_signal_cb(struct nl_msg *msg, void *arg)
1038 {
1039 int8_t dbm;
1040 int16_t mbit;
1041 struct nl80211_rssi_rate *rr = arg;
1042 struct nlattr **attr = nl80211_parse(msg);
1043 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1044 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1045
1046 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
1047 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
1048 [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
1049 [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
1050 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
1051 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
1052 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
1053 [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
1054 [NL80211_STA_INFO_LLID] = { .type = NLA_U16 },
1055 [NL80211_STA_INFO_PLID] = { .type = NLA_U16 },
1056 [NL80211_STA_INFO_PLINK_STATE] = { .type = NLA_U8 },
1057 };
1058
1059 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1060 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1061 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1062 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1063 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1064 };
1065
1066 if (attr[NL80211_ATTR_STA_INFO])
1067 {
1068 if (!nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1069 attr[NL80211_ATTR_STA_INFO], stats_policy))
1070 {
1071 if (sinfo[NL80211_STA_INFO_SIGNAL])
1072 {
1073 dbm = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1074 rr->rssi = rr->rssi ? (int8_t)((rr->rssi + dbm) / 2) : dbm;
1075 }
1076
1077 if (sinfo[NL80211_STA_INFO_TX_BITRATE])
1078 {
1079 if (!nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1080 sinfo[NL80211_STA_INFO_TX_BITRATE],
1081 rate_policy))
1082 {
1083 if (rinfo[NL80211_RATE_INFO_BITRATE])
1084 {
1085 mbit = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
1086 rr->rate = rr->rate
1087 ? (int16_t)((rr->rate + mbit) / 2) : mbit;
1088 }
1089 }
1090 }
1091 }
1092 }
1093
1094 return NL_SKIP;
1095 }
1096
1097 static void nl80211_fill_signal(const char *ifname, struct nl80211_rssi_rate *r)
1098 {
1099 DIR *d;
1100 struct dirent *de;
1101 struct nl80211_msg_conveyor *req;
1102
1103 r->rssi = 0;
1104 r->rate = 0;
1105
1106 if ((d = opendir("/sys/class/net")) != NULL)
1107 {
1108 while ((de = readdir(d)) != NULL)
1109 {
1110 if (!strncmp(de->d_name, ifname, strlen(ifname)) &&
1111 (!de->d_name[strlen(ifname)] ||
1112 !strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
1113 {
1114 req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
1115 NLM_F_DUMP);
1116
1117 if (req)
1118 {
1119 nl80211_send(req, nl80211_fill_signal_cb, r);
1120 nl80211_free(req);
1121 }
1122 }
1123 }
1124
1125 closedir(d);
1126 }
1127 }
1128
1129 static int nl80211_get_bitrate(const char *ifname, int *buf)
1130 {
1131 struct nl80211_rssi_rate rr;
1132
1133 nl80211_fill_signal(ifname, &rr);
1134
1135 if (rr.rate)
1136 {
1137 *buf = (rr.rate * 100);
1138 return 0;
1139 }
1140
1141 return -1;
1142 }
1143
1144 static int nl80211_get_signal(const char *ifname, int *buf)
1145 {
1146 struct nl80211_rssi_rate rr;
1147
1148 nl80211_fill_signal(ifname, &rr);
1149
1150 if (rr.rssi)
1151 {
1152 *buf = rr.rssi;
1153 return 0;
1154 }
1155
1156 return -1;
1157 }
1158
1159 static int nl80211_get_noise_cb(struct nl_msg *msg, void *arg)
1160 {
1161 int8_t *noise = arg;
1162 struct nlattr **tb = nl80211_parse(msg);
1163 struct nlattr *si[NL80211_SURVEY_INFO_MAX + 1];
1164
1165 static struct nla_policy sp[NL80211_SURVEY_INFO_MAX + 1] = {
1166 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
1167 [NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
1168 };
1169
1170 if (!tb[NL80211_ATTR_SURVEY_INFO])
1171 return NL_SKIP;
1172
1173 if (nla_parse_nested(si, NL80211_SURVEY_INFO_MAX,
1174 tb[NL80211_ATTR_SURVEY_INFO], sp))
1175 return NL_SKIP;
1176
1177 if (!si[NL80211_SURVEY_INFO_NOISE])
1178 return NL_SKIP;
1179
1180 if (!*noise || si[NL80211_SURVEY_INFO_IN_USE])
1181 *noise = (int8_t)nla_get_u8(si[NL80211_SURVEY_INFO_NOISE]);
1182
1183 return NL_SKIP;
1184 }
1185
1186
1187 static int nl80211_get_noise(const char *ifname, int *buf)
1188 {
1189 int8_t noise;
1190 struct nl80211_msg_conveyor *req;
1191
1192 req = nl80211_msg(ifname, NL80211_CMD_GET_SURVEY, NLM_F_DUMP);
1193 if (req)
1194 {
1195 noise = 0;
1196
1197 nl80211_send(req, nl80211_get_noise_cb, &noise);
1198 nl80211_free(req);
1199
1200 if (noise)
1201 {
1202 *buf = noise;
1203 return 0;
1204 }
1205 }
1206
1207 return -1;
1208 }
1209
1210 static int nl80211_get_quality(const char *ifname, int *buf)
1211 {
1212 int signal;
1213
1214 if (!nl80211_get_signal(ifname, &signal))
1215 {
1216 /* A positive signal level is usually just a quality
1217 * value, pass through as-is */
1218 if (signal >= 0)
1219 {
1220 *buf = signal;
1221 }
1222
1223 /* The cfg80211 wext compat layer assumes a signal range
1224 * of -110 dBm to -40 dBm, the quality value is derived
1225 * by adding 110 to the signal level */
1226 else
1227 {
1228 if (signal < -110)
1229 signal = -110;
1230 else if (signal > -40)
1231 signal = -40;
1232
1233 *buf = (signal + 110);
1234 }
1235
1236 return 0;
1237 }
1238
1239 return -1;
1240 }
1241
1242 static int nl80211_get_quality_max(const char *ifname, int *buf)
1243 {
1244 /* The cfg80211 wext compat layer assumes a maximum
1245 * quality of 70 */
1246 *buf = 70;
1247
1248 return 0;
1249 }
1250
1251 static int nl80211_get_encryption(const char *ifname, char *buf)
1252 {
1253 int i;
1254 char k[9];
1255 char *val, *res;
1256 struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf;
1257
1258 /* WPA supplicant */
1259 if ((res = nl80211_wpactl_info(ifname, "STATUS", NULL)) &&
1260 (val = nl80211_getval(NULL, res, "pairwise_cipher")))
1261 {
1262 /* WEP */
1263 if (strstr(val, "WEP"))
1264 {
1265 if (strstr(val, "WEP-40"))
1266 c->pair_ciphers |= IWINFO_CIPHER_WEP40;
1267
1268 else if (strstr(val, "WEP-104"))
1269 c->pair_ciphers |= IWINFO_CIPHER_WEP104;
1270
1271 c->enabled = 1;
1272 c->group_ciphers = c->pair_ciphers;
1273
1274 c->auth_suites |= IWINFO_KMGMT_NONE;
1275 c->auth_algs |= IWINFO_AUTH_OPEN; /* XXX: assumption */
1276 }
1277
1278 /* WPA */
1279 else
1280 {
1281 if (strstr(val, "TKIP"))
1282 c->pair_ciphers |= IWINFO_CIPHER_TKIP;
1283
1284 else if (strstr(val, "CCMP"))
1285 c->pair_ciphers |= IWINFO_CIPHER_CCMP;
1286
1287 else if (strstr(val, "NONE"))
1288 c->pair_ciphers |= IWINFO_CIPHER_NONE;
1289
1290 else if (strstr(val, "WEP-40"))
1291 c->pair_ciphers |= IWINFO_CIPHER_WEP40;
1292
1293 else if (strstr(val, "WEP-104"))
1294 c->pair_ciphers |= IWINFO_CIPHER_WEP104;
1295
1296
1297 if ((val = nl80211_getval(NULL, res, "group_cipher")))
1298 {
1299 if (strstr(val, "TKIP"))
1300 c->group_ciphers |= IWINFO_CIPHER_TKIP;
1301
1302 else if (strstr(val, "CCMP"))
1303 c->group_ciphers |= IWINFO_CIPHER_CCMP;
1304
1305 else if (strstr(val, "NONE"))
1306 c->group_ciphers |= IWINFO_CIPHER_NONE;
1307
1308 else if (strstr(val, "WEP-40"))
1309 c->group_ciphers |= IWINFO_CIPHER_WEP40;
1310
1311 else if (strstr(val, "WEP-104"))
1312 c->group_ciphers |= IWINFO_CIPHER_WEP104;
1313 }
1314
1315
1316 if ((val = nl80211_getval(NULL, res, "key_mgmt")))
1317 {
1318 if (strstr(val, "WPA2"))
1319 c->wpa_version = 2;
1320
1321 else if (strstr(val, "WPA"))
1322 c->wpa_version = 1;
1323
1324
1325 if (strstr(val, "PSK"))
1326 c->auth_suites |= IWINFO_KMGMT_PSK;
1327
1328 else if (strstr(val, "EAP") || strstr(val, "802.1X"))
1329 c->auth_suites |= IWINFO_KMGMT_8021x;
1330
1331 else if (strstr(val, "NONE"))
1332 c->auth_suites |= IWINFO_KMGMT_NONE;
1333 }
1334
1335 c->enabled = (c->wpa_version && c->auth_suites) ? 1 : 0;
1336 }
1337
1338 return 0;
1339 }
1340
1341 /* Hostapd */
1342 else if ((res = nl80211_hostapd_info(ifname)))
1343 {
1344 if ((val = nl80211_getval(ifname, res, "wpa")) != NULL)
1345 c->wpa_version = atoi(val);
1346
1347 val = nl80211_getval(ifname, res, "wpa_key_mgmt");
1348
1349 if (!val || strstr(val, "PSK"))
1350 c->auth_suites |= IWINFO_KMGMT_PSK;
1351
1352 if (val && strstr(val, "EAP"))
1353 c->auth_suites |= IWINFO_KMGMT_8021x;
1354
1355 if (val && strstr(val, "NONE"))
1356 c->auth_suites |= IWINFO_KMGMT_NONE;
1357
1358 if ((val = nl80211_getval(ifname, res, "wpa_pairwise")) != NULL)
1359 {
1360 if (strstr(val, "TKIP"))
1361 c->pair_ciphers |= IWINFO_CIPHER_TKIP;
1362
1363 if (strstr(val, "CCMP"))
1364 c->pair_ciphers |= IWINFO_CIPHER_CCMP;
1365
1366 if (strstr(val, "NONE"))
1367 c->pair_ciphers |= IWINFO_CIPHER_NONE;
1368 }
1369
1370 if ((val = nl80211_getval(ifname, res, "auth_algs")) != NULL)
1371 {
1372 switch(atoi(val)) {
1373 case 1:
1374 c->auth_algs |= IWINFO_AUTH_OPEN;
1375 break;
1376
1377 case 2:
1378 c->auth_algs |= IWINFO_AUTH_SHARED;
1379 break;
1380
1381 case 3:
1382 c->auth_algs |= IWINFO_AUTH_OPEN;
1383 c->auth_algs |= IWINFO_AUTH_SHARED;
1384 break;
1385
1386 default:
1387 break;
1388 }
1389
1390 for (i = 0; i < 4; i++)
1391 {
1392 snprintf(k, sizeof(k), "wep_key%d", i);
1393
1394 if ((val = nl80211_getval(ifname, res, k)))
1395 {
1396 if ((strlen(val) == 5) || (strlen(val) == 10))
1397 c->pair_ciphers |= IWINFO_CIPHER_WEP40;
1398
1399 else if ((strlen(val) == 13) || (strlen(val) == 26))
1400 c->pair_ciphers |= IWINFO_CIPHER_WEP104;
1401 }
1402 }
1403 }
1404
1405 c->group_ciphers = c->pair_ciphers;
1406 c->enabled = (c->wpa_version || c->pair_ciphers) ? 1 : 0;
1407
1408 return 0;
1409 }
1410
1411 return -1;
1412 }
1413
1414 static int nl80211_get_phyname(const char *ifname, char *buf)
1415 {
1416 const char *name;
1417
1418 name = nl80211_ifname2phy(ifname);
1419
1420 if (name)
1421 {
1422 strcpy(buf, name);
1423 return 0;
1424 }
1425 else if ((name = nl80211_phy2ifname(ifname)) != NULL)
1426 {
1427 name = nl80211_ifname2phy(name);
1428
1429 if (name)
1430 {
1431 strcpy(buf, ifname);
1432 return 0;
1433 }
1434 }
1435
1436 return -1;
1437 }
1438
1439
1440 static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg)
1441 {
1442 struct nl80211_array_buf *arr = arg;
1443 struct iwinfo_assoclist_entry *e = arr->buf;
1444 struct nlattr **attr = nl80211_parse(msg);
1445 struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1446 struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1447
1448 static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
1449 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
1450 [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
1451 [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
1452 [NL80211_STA_INFO_RX_BITRATE] = { .type = NLA_NESTED },
1453 [NL80211_STA_INFO_TX_BITRATE] = { .type = NLA_NESTED },
1454 [NL80211_STA_INFO_SIGNAL] = { .type = NLA_U8 },
1455 };
1456
1457 static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1458 [NL80211_RATE_INFO_BITRATE] = { .type = NLA_U16 },
1459 [NL80211_RATE_INFO_MCS] = { .type = NLA_U8 },
1460 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
1461 [NL80211_RATE_INFO_SHORT_GI] = { .type = NLA_FLAG },
1462 };
1463
1464 /* advance to end of array */
1465 e += arr->count;
1466 memset(e, 0, sizeof(*e));
1467
1468 if (attr[NL80211_ATTR_MAC])
1469 memcpy(e->mac, nla_data(attr[NL80211_ATTR_MAC]), 6);
1470
1471 if (attr[NL80211_ATTR_STA_INFO] &&
1472 !nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1473 attr[NL80211_ATTR_STA_INFO], stats_policy))
1474 {
1475 if (sinfo[NL80211_STA_INFO_SIGNAL])
1476 e->signal = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1477
1478 if (sinfo[NL80211_STA_INFO_INACTIVE_TIME])
1479 e->inactive = nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]);
1480
1481 if (sinfo[NL80211_STA_INFO_RX_PACKETS])
1482 e->rx_packets = nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]);
1483
1484 if (sinfo[NL80211_STA_INFO_TX_PACKETS])
1485 e->tx_packets = nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]);
1486
1487 if (sinfo[NL80211_STA_INFO_RX_BITRATE] &&
1488 !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1489 sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy))
1490 {
1491 if (rinfo[NL80211_RATE_INFO_BITRATE])
1492 e->rx_rate.rate =
1493 nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
1494
1495 if (rinfo[NL80211_RATE_INFO_MCS])
1496 e->rx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
1497
1498 if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
1499 e->rx_rate.is_40mhz = 1;
1500
1501 if (rinfo[NL80211_RATE_INFO_SHORT_GI])
1502 e->rx_rate.is_short_gi = 1;
1503 }
1504
1505 if (sinfo[NL80211_STA_INFO_TX_BITRATE] &&
1506 !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1507 sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy))
1508 {
1509 if (rinfo[NL80211_RATE_INFO_BITRATE])
1510 e->tx_rate.rate =
1511 nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
1512
1513 if (rinfo[NL80211_RATE_INFO_MCS])
1514 e->tx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
1515
1516 if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
1517 e->tx_rate.is_40mhz = 1;
1518
1519 if (rinfo[NL80211_RATE_INFO_SHORT_GI])
1520 e->tx_rate.is_short_gi = 1;
1521 }
1522 }
1523
1524 e->noise = 0; /* filled in by caller */
1525 arr->count++;
1526
1527 return NL_SKIP;
1528 }
1529
1530 static int nl80211_get_assoclist(const char *ifname, char *buf, int *len)
1531 {
1532 DIR *d;
1533 int i, noise = 0;
1534 struct dirent *de;
1535 struct nl80211_msg_conveyor *req;
1536 struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
1537 struct iwinfo_assoclist_entry *e;
1538
1539 if ((d = opendir("/sys/class/net")) != NULL)
1540 {
1541 while ((de = readdir(d)) != NULL)
1542 {
1543 if (!strncmp(de->d_name, ifname, strlen(ifname)) &&
1544 (!de->d_name[strlen(ifname)] ||
1545 !strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
1546 {
1547 req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
1548 NLM_F_DUMP);
1549
1550 if (req)
1551 {
1552 nl80211_send(req, nl80211_get_assoclist_cb, &arr);
1553 nl80211_free(req);
1554 }
1555 }
1556 }
1557
1558 closedir(d);
1559
1560 if (!nl80211_get_noise(ifname, &noise))
1561 for (i = 0, e = arr.buf; i < arr.count; i++, e++)
1562 e->noise = noise;
1563
1564 *len = (arr.count * sizeof(struct iwinfo_assoclist_entry));
1565 return 0;
1566 }
1567
1568 return -1;
1569 }
1570
1571 static int nl80211_get_txpwrlist_cb(struct nl_msg *msg, void *arg)
1572 {
1573 int *dbm_max = arg;
1574 int ch_cur, ch_cmp, bands_remain, freqs_remain;
1575
1576 struct nlattr **attr = nl80211_parse(msg);
1577 struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
1578 struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
1579 struct nlattr *band, *freq;
1580
1581 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
1582 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
1583 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
1584 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
1585 [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
1586 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
1587 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
1588 };
1589
1590 ch_cur = *dbm_max; /* value int* is initialized with channel by caller */
1591 *dbm_max = -1;
1592
1593 nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
1594 {
1595 nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band),
1596 nla_len(band), NULL);
1597
1598 nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
1599 {
1600 nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
1601 nla_data(freq), nla_len(freq), freq_policy);
1602
1603 ch_cmp = nl80211_freq2channel(nla_get_u32(
1604 freqs[NL80211_FREQUENCY_ATTR_FREQ]));
1605
1606 if ((!ch_cur || (ch_cmp == ch_cur)) &&
1607 freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
1608 {
1609 *dbm_max = (int)(0.01 * nla_get_u32(
1610 freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
1611
1612 break;
1613 }
1614 }
1615 }
1616
1617 return NL_SKIP;
1618 }
1619
1620 static int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len)
1621 {
1622 int ch_cur;
1623 int dbm_max = -1, dbm_cur, dbm_cnt;
1624 struct nl80211_msg_conveyor *req;
1625 struct iwinfo_txpwrlist_entry entry;
1626
1627 if (nl80211_get_channel(ifname, &ch_cur))
1628 ch_cur = 0;
1629
1630 req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
1631 if (req)
1632 {
1633 /* initialize the value pointer with channel for callback */
1634 dbm_max = ch_cur;
1635
1636 nl80211_send(req, nl80211_get_txpwrlist_cb, &dbm_max);
1637 nl80211_free(req);
1638 }
1639
1640 if (dbm_max > 0)
1641 {
1642 for (dbm_cur = 0, dbm_cnt = 0;
1643 dbm_cur < dbm_max;
1644 dbm_cur++, dbm_cnt++)
1645 {
1646 entry.dbm = dbm_cur;
1647 entry.mw = iwinfo_dbm2mw(dbm_cur);
1648
1649 memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry));
1650 }
1651
1652 entry.dbm = dbm_max;
1653 entry.mw = iwinfo_dbm2mw(dbm_max);
1654
1655 memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry));
1656 dbm_cnt++;
1657
1658 *len = dbm_cnt * sizeof(entry);
1659 return 0;
1660 }
1661
1662 return -1;
1663 }
1664
1665 static void nl80211_get_scancrypto(const char *spec,
1666 struct iwinfo_crypto_entry *c)
1667 {
1668 if (strstr(spec, "WPA") || strstr(spec, "WEP"))
1669 {
1670 c->enabled = 1;
1671
1672 if (strstr(spec, "WPA2-") && strstr(spec, "WPA-"))
1673 c->wpa_version = 3;
1674
1675 else if (strstr(spec, "WPA2"))
1676 c->wpa_version = 2;
1677
1678 else if (strstr(spec, "WPA"))
1679 c->wpa_version = 1;
1680
1681 else if (strstr(spec, "WEP"))
1682 c->auth_algs = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED;
1683
1684
1685 if (strstr(spec, "PSK"))
1686 c->auth_suites |= IWINFO_KMGMT_PSK;
1687
1688 if (strstr(spec, "802.1X") || strstr(spec, "EAP"))
1689 c->auth_suites |= IWINFO_KMGMT_8021x;
1690
1691 if (strstr(spec, "WPA-NONE"))
1692 c->auth_suites |= IWINFO_KMGMT_NONE;
1693
1694
1695 if (strstr(spec, "TKIP"))
1696 c->pair_ciphers |= IWINFO_CIPHER_TKIP;
1697
1698 if (strstr(spec, "CCMP"))
1699 c->pair_ciphers |= IWINFO_CIPHER_CCMP;
1700
1701 if (strstr(spec, "WEP-40"))
1702 c->pair_ciphers |= IWINFO_CIPHER_WEP40;
1703
1704 if (strstr(spec, "WEP-104"))
1705 c->pair_ciphers |= IWINFO_CIPHER_WEP104;
1706
1707 c->group_ciphers = c->pair_ciphers;
1708 }
1709 else
1710 {
1711 c->enabled = 0;
1712 }
1713 }
1714
1715
1716 struct nl80211_scanlist {
1717 struct iwinfo_scanlist_entry *e;
1718 int len;
1719 };
1720
1721
1722 static void nl80211_get_scanlist_ie(struct nlattr **bss,
1723 struct iwinfo_scanlist_entry *e)
1724 {
1725 int ielen = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1726 unsigned char *ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1727 static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
1728 int len;
1729
1730 while (ielen >= 2 && ielen >= ie[1])
1731 {
1732 switch (ie[0])
1733 {
1734 case 0: /* SSID */
1735 len = min(ie[1], IWINFO_ESSID_MAX_SIZE);
1736 memcpy(e->ssid, ie + 2, len);
1737 e->ssid[len] = 0;
1738 break;
1739
1740 case 48: /* RSN */
1741 iwinfo_parse_rsn(&e->crypto, ie + 2, ie[1],
1742 IWINFO_CIPHER_CCMP, IWINFO_KMGMT_8021x);
1743 break;
1744
1745 case 221: /* Vendor */
1746 if (ie[1] >= 4 && !memcmp(ie + 2, ms_oui, 3) && ie[5] == 1)
1747 iwinfo_parse_rsn(&e->crypto, ie + 6, ie[1] - 4,
1748 IWINFO_CIPHER_TKIP, IWINFO_KMGMT_PSK);
1749 break;
1750 }
1751
1752 ielen -= ie[1] + 2;
1753 ie += ie[1] + 2;
1754 }
1755 }
1756
1757 static int nl80211_get_scanlist_cb(struct nl_msg *msg, void *arg)
1758 {
1759 int8_t rssi;
1760 uint16_t caps;
1761
1762 struct nl80211_scanlist *sl = arg;
1763 struct nlattr **tb = nl80211_parse(msg);
1764 struct nlattr *bss[NL80211_BSS_MAX + 1];
1765
1766 static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
1767 [NL80211_BSS_TSF] = { .type = NLA_U64 },
1768 [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
1769 [NL80211_BSS_BSSID] = { },
1770 [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
1771 [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
1772 [NL80211_BSS_INFORMATION_ELEMENTS] = { },
1773 [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
1774 [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
1775 [NL80211_BSS_STATUS] = { .type = NLA_U32 },
1776 [NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
1777 [NL80211_BSS_BEACON_IES] = { },
1778 };
1779
1780 if (!tb[NL80211_ATTR_BSS] ||
1781 nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
1782 bss_policy) ||
1783 !bss[NL80211_BSS_BSSID])
1784 {
1785 return NL_SKIP;
1786 }
1787
1788 if (bss[NL80211_BSS_CAPABILITY])
1789 caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
1790 else
1791 caps = 0;
1792
1793 memset(sl->e, 0, sizeof(*sl->e));
1794 memcpy(sl->e->mac, nla_data(bss[NL80211_BSS_BSSID]), 6);
1795
1796 if (caps & (1<<1))
1797 sl->e->mode = IWINFO_OPMODE_ADHOC;
1798 else if (caps & (1<<0))
1799 sl->e->mode = IWINFO_OPMODE_MASTER;
1800 else
1801 sl->e->mode = IWINFO_OPMODE_MESHPOINT;
1802
1803 if (caps & (1<<4))
1804 sl->e->crypto.enabled = 1;
1805
1806 if (bss[NL80211_BSS_FREQUENCY])
1807 sl->e->channel = nl80211_freq2channel(nla_get_u32(
1808 bss[NL80211_BSS_FREQUENCY]));
1809
1810 if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
1811 nl80211_get_scanlist_ie(bss, sl->e);
1812
1813 if (bss[NL80211_BSS_SIGNAL_MBM])
1814 {
1815 sl->e->signal =
1816 (uint8_t)((int32_t)nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]) / 100);
1817
1818 rssi = sl->e->signal - 0x100;
1819
1820 if (rssi < -110)
1821 rssi = -110;
1822 else if (rssi > -40)
1823 rssi = -40;
1824
1825 sl->e->quality = (rssi + 110);
1826 sl->e->quality_max = 70;
1827 }
1828
1829 if (sl->e->crypto.enabled && !sl->e->crypto.wpa_version)
1830 {
1831 sl->e->crypto.auth_algs = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED;
1832 sl->e->crypto.pair_ciphers = IWINFO_CIPHER_WEP40 | IWINFO_CIPHER_WEP104;
1833 }
1834
1835 sl->e++;
1836 sl->len++;
1837
1838 return NL_SKIP;
1839 }
1840
1841 static int nl80211_get_scanlist_nl(const char *ifname, char *buf, int *len)
1842 {
1843 struct nl80211_msg_conveyor *req;
1844 struct nl80211_scanlist sl = { .e = (struct iwinfo_scanlist_entry *)buf };
1845
1846 req = nl80211_msg(ifname, NL80211_CMD_TRIGGER_SCAN, 0);
1847 if (req)
1848 {
1849 nl80211_send(req, NULL, NULL);
1850 nl80211_free(req);
1851 }
1852
1853 nl80211_wait("nl80211", "scan", NL80211_CMD_NEW_SCAN_RESULTS);
1854
1855 req = nl80211_msg(ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
1856 if (req)
1857 {
1858 nl80211_send(req, nl80211_get_scanlist_cb, &sl);
1859 nl80211_free(req);
1860 }
1861
1862 *len = sl.len * sizeof(struct iwinfo_scanlist_entry);
1863 return *len ? 0 : -1;
1864 }
1865
1866 static int nl80211_get_scanlist(const char *ifname, char *buf, int *len)
1867 {
1868 int freq, rssi, qmax, count;
1869 char *res;
1870 char ssid[128] = { 0 };
1871 char bssid[18] = { 0 };
1872 char cipher[256] = { 0 };
1873
1874 /* Got a radioX pseudo interface, find some interface on it or create one */
1875 if (!strncmp(ifname, "radio", 5))
1876 {
1877 /* Reuse existing interface */
1878 if ((res = nl80211_phy2ifname(ifname)) != NULL)
1879 {
1880 return nl80211_get_scanlist(res, buf, len);
1881 }
1882
1883 /* Need to spawn a temporary iface for scanning */
1884 else if ((res = nl80211_ifadd(ifname)) != NULL)
1885 {
1886 count = nl80211_get_scanlist(res, buf, len);
1887 nl80211_ifdel(res);
1888 return count;
1889 }
1890 }
1891
1892 struct iwinfo_scanlist_entry *e = (struct iwinfo_scanlist_entry *)buf;
1893
1894 /* WPA supplicant */
1895 if ((res = nl80211_wpactl_info(ifname, "SCAN", "CTRL-EVENT-SCAN-RESULTS")))
1896 {
1897 if ((res = nl80211_wpactl_info(ifname, "SCAN_RESULTS", NULL)))
1898 {
1899 nl80211_get_quality_max(ifname, &qmax);
1900
1901 count = -1;
1902
1903 do {
1904 if (res[0] == '<')
1905 {
1906 /* skip log lines */
1907 goto nextline;
1908 }
1909 if (count < 0)
1910 {
1911 /* skip header line */
1912 count++;
1913 goto nextline;
1914 }
1915 if (sscanf(res, "%17s %d %d %255s%*[ \t]%127[^\n]\n",
1916 bssid, &freq, &rssi, cipher, ssid) < 5)
1917 {
1918 /* skip malformed lines */
1919 goto nextline;
1920 }
1921 /* BSSID */
1922 e->mac[0] = strtol(&bssid[0], NULL, 16);
1923 e->mac[1] = strtol(&bssid[3], NULL, 16);
1924 e->mac[2] = strtol(&bssid[6], NULL, 16);
1925 e->mac[3] = strtol(&bssid[9], NULL, 16);
1926 e->mac[4] = strtol(&bssid[12], NULL, 16);
1927 e->mac[5] = strtol(&bssid[15], NULL, 16);
1928
1929 /* SSID */
1930 memcpy(e->ssid, ssid, min(strlen(ssid), sizeof(e->ssid) - 1));
1931
1932 /* Mode (assume master) */
1933 if (strstr(cipher,"[MESH]"))
1934 e->mode = IWINFO_OPMODE_MESHPOINT;
1935 else
1936 e->mode = IWINFO_OPMODE_MASTER;
1937
1938 /* Channel */
1939 e->channel = nl80211_freq2channel(freq);
1940
1941 /* Signal */
1942 e->signal = rssi;
1943
1944 /* Quality */
1945 if (rssi < 0)
1946 {
1947 /* The cfg80211 wext compat layer assumes a signal range
1948 * of -110 dBm to -40 dBm, the quality value is derived
1949 * by adding 110 to the signal level */
1950 if (rssi < -110)
1951 rssi = -110;
1952 else if (rssi > -40)
1953 rssi = -40;
1954
1955 e->quality = (rssi + 110);
1956 }
1957 else
1958 {
1959 e->quality = rssi;
1960 }
1961
1962 /* Max. Quality */
1963 e->quality_max = qmax;
1964
1965 /* Crypto */
1966 nl80211_get_scancrypto(cipher, &e->crypto);
1967
1968 count++;
1969 e++;
1970
1971 memset(ssid, 0, sizeof(ssid));
1972 memset(bssid, 0, sizeof(bssid));
1973 memset(cipher, 0, sizeof(cipher));
1974
1975 nextline:
1976 /* advance to next line */
1977 while( *res && *res++ != '\n' );
1978 }
1979 while( *res );
1980
1981 *len = count * sizeof(struct iwinfo_scanlist_entry);
1982 return 0;
1983 }
1984 }
1985
1986 /* AP scan */
1987 else
1988 {
1989 /* Got a temp interface, don't create yet another one */
1990 if (!strncmp(ifname, "tmp.", 4))
1991 {
1992 if (!iwinfo_ifup(ifname))
1993 return -1;
1994
1995 nl80211_get_scanlist_nl(ifname, buf, len);
1996 iwinfo_ifdown(ifname);
1997 return 0;
1998 }
1999
2000 /* Spawn a new scan interface */
2001 else
2002 {
2003 if (!(res = nl80211_ifadd(ifname)))
2004 goto out;
2005
2006 iwinfo_ifmac(res);
2007
2008 /* if we can take the new interface up, the driver supports an
2009 * additional interface and there's no need to tear down the ap */
2010 if (iwinfo_ifup(res))
2011 {
2012 nl80211_get_scanlist_nl(res, buf, len);
2013 iwinfo_ifdown(res);
2014 }
2015
2016 /* driver cannot create secondary interface, take down ap
2017 * during scan */
2018 else if (iwinfo_ifdown(ifname) && iwinfo_ifup(res))
2019 {
2020 nl80211_get_scanlist_nl(res, buf, len);
2021 iwinfo_ifdown(res);
2022 iwinfo_ifup(ifname);
2023 nl80211_hostapd_hup(ifname);
2024 }
2025
2026 out:
2027 nl80211_ifdel(res);
2028 return 0;
2029 }
2030 }
2031
2032 return -1;
2033 }
2034
2035 static int nl80211_get_freqlist_cb(struct nl_msg *msg, void *arg)
2036 {
2037 int bands_remain, freqs_remain;
2038
2039 struct nl80211_array_buf *arr = arg;
2040 struct iwinfo_freqlist_entry *e = arr->buf;
2041
2042 struct nlattr **attr = nl80211_parse(msg);
2043 struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
2044 struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
2045 struct nlattr *band, *freq;
2046
2047 static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
2048 [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
2049 [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
2050 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
2051 [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
2052 [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
2053 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
2054 };
2055
2056 nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
2057 {
2058 nla_parse(bands, NL80211_BAND_ATTR_MAX,
2059 nla_data(band), nla_len(band), NULL);
2060
2061 nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
2062 {
2063 nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
2064 nla_data(freq), nla_len(freq), NULL);
2065
2066 if (!freqs[NL80211_FREQUENCY_ATTR_FREQ] ||
2067 freqs[NL80211_FREQUENCY_ATTR_DISABLED])
2068 continue;
2069
2070 e->mhz = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]);
2071 e->channel = nl80211_freq2channel(e->mhz);
2072
2073 e->restricted = (
2074 freqs[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] ||
2075 freqs[NL80211_FREQUENCY_ATTR_NO_IBSS] ||
2076 freqs[NL80211_FREQUENCY_ATTR_RADAR]
2077 ) ? 1 : 0;
2078
2079 e++;
2080 arr->count++;
2081 }
2082 }
2083
2084 return NL_SKIP;
2085 }
2086
2087 static int nl80211_get_freqlist(const char *ifname, char *buf, int *len)
2088 {
2089 struct nl80211_msg_conveyor *req;
2090 struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
2091
2092 req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
2093 if (req)
2094 {
2095 nl80211_send(req, nl80211_get_freqlist_cb, &arr);
2096 nl80211_free(req);
2097 }
2098
2099 if (arr.count > 0)
2100 {
2101 *len = arr.count * sizeof(struct iwinfo_freqlist_entry);
2102 return 0;
2103 }
2104
2105 return -1;
2106 }
2107
2108 static int nl80211_get_country_cb(struct nl_msg *msg, void *arg)
2109 {
2110 char *buf = arg;
2111 struct nlattr **attr = nl80211_parse(msg);
2112
2113 if (attr[NL80211_ATTR_REG_ALPHA2])
2114 memcpy(buf, nla_data(attr[NL80211_ATTR_REG_ALPHA2]), 2);
2115 else
2116 buf[0] = 0;
2117
2118 return NL_SKIP;
2119 }
2120
2121 static int nl80211_get_country(const char *ifname, char *buf)
2122 {
2123 int rv = -1;
2124 struct nl80211_msg_conveyor *req;
2125
2126 req = nl80211_msg(ifname, NL80211_CMD_GET_REG, 0);
2127 if (req)
2128 {
2129 nl80211_send(req, nl80211_get_country_cb, buf);
2130 nl80211_free(req);
2131
2132 if (buf[0])
2133 rv = 0;
2134 }
2135
2136 return rv;
2137 }
2138
2139 static int nl80211_get_countrylist(const char *ifname, char *buf, int *len)
2140 {
2141 int i, count;
2142 struct iwinfo_country_entry *e = (struct iwinfo_country_entry *)buf;
2143 const struct iwinfo_iso3166_label *l;
2144
2145 for (l = IWINFO_ISO3166_NAMES, count = 0; l->iso3166; l++, e++, count++)
2146 {
2147 e->iso3166 = l->iso3166;
2148 e->ccode[0] = (l->iso3166 / 256);
2149 e->ccode[1] = (l->iso3166 % 256);
2150 }
2151
2152 *len = (count * sizeof(struct iwinfo_country_entry));
2153 return 0;
2154 }
2155
2156 static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg)
2157 {
2158 int *modes = arg;
2159 int bands_remain, freqs_remain;
2160 uint16_t caps = 0;
2161 uint32_t vht_caps = 0;
2162 struct nlattr **attr = nl80211_parse(msg);
2163 struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
2164 struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
2165 struct nlattr *band, *freq;
2166
2167 *modes = 0;
2168
2169 if (attr[NL80211_ATTR_WIPHY_BANDS])
2170 {
2171 nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
2172 {
2173 nla_parse(bands, NL80211_BAND_ATTR_MAX,
2174 nla_data(band), nla_len(band), NULL);
2175
2176 if (bands[NL80211_BAND_ATTR_HT_CAPA])
2177 caps = nla_get_u16(bands[NL80211_BAND_ATTR_HT_CAPA]);
2178
2179 /* Treat any nonzero capability as 11n */
2180 if (caps > 0)
2181 *modes |= IWINFO_80211_N;
2182
2183 if (bands[NL80211_BAND_ATTR_VHT_CAPA])
2184 vht_caps = nla_get_u32(bands[NL80211_BAND_ATTR_VHT_CAPA]);
2185
2186 /* Treat any nonzero capability as 11ac */
2187 if (vht_caps > 0)
2188 *modes |= IWINFO_80211_AC;
2189
2190 nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS],
2191 freqs_remain)
2192 {
2193 nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
2194 nla_data(freq), nla_len(freq), NULL);
2195
2196 if (!freqs[NL80211_FREQUENCY_ATTR_FREQ])
2197 continue;
2198
2199 if (nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) < 2485)
2200 {
2201 *modes |= IWINFO_80211_B;
2202 *modes |= IWINFO_80211_G;
2203 }
2204 else if (!(*modes & IWINFO_80211_AC))
2205 {
2206 *modes |= IWINFO_80211_A;
2207 }
2208 }
2209 }
2210 }
2211
2212 return NL_SKIP;
2213 }
2214
2215 static int nl80211_get_hwmodelist(const char *ifname, int *buf)
2216 {
2217 struct nl80211_msg_conveyor *req;
2218
2219 req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
2220 if (req)
2221 {
2222 nl80211_send(req, nl80211_get_hwmodelist_cb, buf);
2223 nl80211_free(req);
2224 }
2225
2226 return *buf ? 0 : -1;
2227 }
2228
2229 static int nl80211_get_ifcomb_cb(struct nl_msg *msg, void *arg)
2230 {
2231 struct nlattr **attr = nl80211_parse(msg);
2232 struct nlattr *comb;
2233 int *ret = arg;
2234 int comb_rem, limit_rem, mode_rem;
2235
2236 *ret = 0;
2237 if (!attr[NL80211_ATTR_INTERFACE_COMBINATIONS])
2238 return NL_SKIP;
2239
2240 nla_for_each_nested(comb, attr[NL80211_ATTR_INTERFACE_COMBINATIONS], comb_rem)
2241 {
2242 static struct nla_policy iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
2243 [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
2244 [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
2245 };
2246 struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
2247 static struct nla_policy iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
2248 [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
2249 [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
2250 };
2251 struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
2252 struct nlattr *limit;
2253
2254 nla_parse_nested(tb_comb, NL80211_BAND_ATTR_MAX, comb, iface_combination_policy);
2255
2256 if (!tb_comb[NL80211_IFACE_COMB_LIMITS])
2257 continue;
2258
2259 nla_for_each_nested(limit, tb_comb[NL80211_IFACE_COMB_LIMITS], limit_rem)
2260 {
2261 struct nlattr *mode;
2262
2263 nla_parse_nested(tb_limit, NUM_NL80211_IFACE_LIMIT, limit, iface_limit_policy);
2264
2265 if (!tb_limit[NL80211_IFACE_LIMIT_TYPES] ||
2266 !tb_limit[NL80211_IFACE_LIMIT_MAX])
2267 continue;
2268
2269 if (nla_get_u32(tb_limit[NL80211_IFACE_LIMIT_MAX]) < 2)
2270 continue;
2271
2272 nla_for_each_nested(mode, tb_limit[NL80211_IFACE_LIMIT_TYPES], mode_rem) {
2273 if (nla_type(mode) == NL80211_IFTYPE_AP)
2274 *ret = 1;
2275 }
2276 }
2277 }
2278
2279 return NL_SKIP;
2280 }
2281
2282 static int nl80211_get_mbssid_support(const char *ifname, int *buf)
2283 {
2284 struct nl80211_msg_conveyor *req;
2285
2286 req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
2287 if (!req)
2288 return -1;
2289
2290 nl80211_send(req, nl80211_get_ifcomb_cb, buf);
2291 nl80211_free(req);
2292 return 0;
2293 }
2294
2295 static int nl80211_get_hardware_id(const char *ifname, char *buf)
2296 {
2297 int rv;
2298 char *res;
2299
2300 /* Got a radioX pseudo interface, find some interface on it or create one */
2301 if (!strncmp(ifname, "radio", 5))
2302 {
2303 /* Reuse existing interface */
2304 if ((res = nl80211_phy2ifname(ifname)) != NULL)
2305 {
2306 rv = wext_ops.hardware_id(res, buf);
2307 }
2308
2309 /* Need to spawn a temporary iface for finding IDs */
2310 else if ((res = nl80211_ifadd(ifname)) != NULL)
2311 {
2312 rv = wext_ops.hardware_id(res, buf);
2313 nl80211_ifdel(res);
2314 }
2315 }
2316 else
2317 {
2318 rv = wext_ops.hardware_id(ifname, buf);
2319 }
2320
2321 /* Failed to obtain hardware IDs, search board config */
2322 if (rv)
2323 {
2324 rv = iwinfo_hardware_id_from_mtd((struct iwinfo_hardware_id *)buf);
2325 }
2326
2327 return rv;
2328 }
2329
2330 static const struct iwinfo_hardware_entry *
2331 nl80211_get_hardware_entry(const char *ifname)
2332 {
2333 struct iwinfo_hardware_id id;
2334
2335 if (nl80211_get_hardware_id(ifname, (char *)&id))
2336 return NULL;
2337
2338 return iwinfo_hardware(&id);
2339 }
2340
2341 static int nl80211_get_hardware_name(const char *ifname, char *buf)
2342 {
2343 const struct iwinfo_hardware_entry *hw;
2344
2345 if (!(hw = nl80211_get_hardware_entry(ifname)))
2346 sprintf(buf, "Generic MAC80211");
2347 else
2348 sprintf(buf, "%s %s", hw->vendor_name, hw->device_name);
2349
2350 return 0;
2351 }
2352
2353 static int nl80211_get_txpower_offset(const char *ifname, int *buf)
2354 {
2355 const struct iwinfo_hardware_entry *hw;
2356
2357 if (!(hw = nl80211_get_hardware_entry(ifname)))
2358 return -1;
2359
2360 *buf = hw->txpower_offset;
2361 return 0;
2362 }
2363
2364 static int nl80211_get_frequency_offset(const char *ifname, int *buf)
2365 {
2366 const struct iwinfo_hardware_entry *hw;
2367
2368 if (!(hw = nl80211_get_hardware_entry(ifname)))
2369 return -1;
2370
2371 *buf = hw->frequency_offset;
2372 return 0;
2373 }
2374
2375 const struct iwinfo_ops nl80211_ops = {
2376 .name = "nl80211",
2377 .probe = nl80211_probe,
2378 .channel = nl80211_get_channel,
2379 .frequency = nl80211_get_frequency,
2380 .frequency_offset = nl80211_get_frequency_offset,
2381 .txpower = nl80211_get_txpower,
2382 .txpower_offset = nl80211_get_txpower_offset,
2383 .bitrate = nl80211_get_bitrate,
2384 .signal = nl80211_get_signal,
2385 .noise = nl80211_get_noise,
2386 .quality = nl80211_get_quality,
2387 .quality_max = nl80211_get_quality_max,
2388 .mbssid_support = nl80211_get_mbssid_support,
2389 .hwmodelist = nl80211_get_hwmodelist,
2390 .mode = nl80211_get_mode,
2391 .ssid = nl80211_get_ssid,
2392 .bssid = nl80211_get_bssid,
2393 .country = nl80211_get_country,
2394 .hardware_id = nl80211_get_hardware_id,
2395 .hardware_name = nl80211_get_hardware_name,
2396 .encryption = nl80211_get_encryption,
2397 .phyname = nl80211_get_phyname,
2398 .assoclist = nl80211_get_assoclist,
2399 .txpwrlist = nl80211_get_txpwrlist,
2400 .scanlist = nl80211_get_scanlist,
2401 .freqlist = nl80211_get_freqlist,
2402 .countrylist = nl80211_get_countrylist,
2403 .close = nl80211_close
2404 };