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