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