iwinfo: assign explicit length to IWINFO_*_NAMES[] to fix compile issues
[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 int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg)
1629 {
1630         struct nl80211_array_buf *arr = arg;
1631         struct iwinfo_assoclist_entry *e = arr->buf;
1632         struct nlattr **attr = nl80211_parse(msg);
1633         struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1634         struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
1635         struct nl80211_sta_flag_update *sta_flags;
1636
1637         static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
1638                 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32    },
1639                 [NL80211_STA_INFO_RX_PACKETS]    = { .type = NLA_U32    },
1640                 [NL80211_STA_INFO_TX_PACKETS]    = { .type = NLA_U32    },
1641                 [NL80211_STA_INFO_RX_BITRATE]    = { .type = NLA_NESTED },
1642                 [NL80211_STA_INFO_TX_BITRATE]    = { .type = NLA_NESTED },
1643                 [NL80211_STA_INFO_SIGNAL]        = { .type = NLA_U8     },
1644                 [NL80211_STA_INFO_RX_BYTES]      = { .type = NLA_U32    },
1645                 [NL80211_STA_INFO_TX_BYTES]      = { .type = NLA_U32    },
1646                 [NL80211_STA_INFO_TX_RETRIES]    = { .type = NLA_U32    },
1647                 [NL80211_STA_INFO_TX_FAILED]     = { .type = NLA_U32    },
1648                 [NL80211_STA_INFO_T_OFFSET]      = { .type = NLA_U64    },
1649                 [NL80211_STA_INFO_STA_FLAGS] =
1650                         { .minlen = sizeof(struct nl80211_sta_flag_update) },
1651         };
1652
1653         static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
1654                 [NL80211_RATE_INFO_BITRATE]      = { .type = NLA_U16    },
1655                 [NL80211_RATE_INFO_MCS]          = { .type = NLA_U8     },
1656                 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG   },
1657                 [NL80211_RATE_INFO_SHORT_GI]     = { .type = NLA_FLAG   },
1658         };
1659
1660         /* advance to end of array */
1661         e += arr->count;
1662         memset(e, 0, sizeof(*e));
1663
1664         if (attr[NL80211_ATTR_MAC])
1665                 memcpy(e->mac, nla_data(attr[NL80211_ATTR_MAC]), 6);
1666
1667         if (attr[NL80211_ATTR_STA_INFO] &&
1668             !nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1669                               attr[NL80211_ATTR_STA_INFO], stats_policy))
1670         {
1671                 if (sinfo[NL80211_STA_INFO_SIGNAL])
1672                         e->signal = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1673
1674                 if (sinfo[NL80211_STA_INFO_INACTIVE_TIME])
1675                         e->inactive = nla_get_u32(sinfo[NL80211_STA_INFO_INACTIVE_TIME]);
1676
1677                 if (sinfo[NL80211_STA_INFO_RX_PACKETS])
1678                         e->rx_packets = nla_get_u32(sinfo[NL80211_STA_INFO_RX_PACKETS]);
1679
1680                 if (sinfo[NL80211_STA_INFO_TX_PACKETS])
1681                         e->tx_packets = nla_get_u32(sinfo[NL80211_STA_INFO_TX_PACKETS]);
1682
1683                 if (sinfo[NL80211_STA_INFO_RX_BITRATE] &&
1684                     !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1685                                       sinfo[NL80211_STA_INFO_RX_BITRATE], rate_policy))
1686                 {
1687                         if (rinfo[NL80211_RATE_INFO_BITRATE])
1688                                 e->rx_rate.rate =
1689                                         nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
1690
1691                         if (rinfo[NL80211_RATE_INFO_MCS])
1692                                 e->rx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
1693
1694                         if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
1695                                 e->rx_rate.is_40mhz = 1;
1696
1697                         if (rinfo[NL80211_RATE_INFO_SHORT_GI])
1698                                 e->rx_rate.is_short_gi = 1;
1699                 }
1700
1701                 if (sinfo[NL80211_STA_INFO_TX_BITRATE] &&
1702                     !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
1703                                       sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy))
1704                 {
1705                         if (rinfo[NL80211_RATE_INFO_BITRATE])
1706                                 e->tx_rate.rate =
1707                                         nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]) * 100;
1708
1709                         if (rinfo[NL80211_RATE_INFO_MCS])
1710                                 e->tx_rate.mcs = nla_get_u8(rinfo[NL80211_RATE_INFO_MCS]);
1711
1712                         if (rinfo[NL80211_RATE_INFO_40_MHZ_WIDTH])
1713                                 e->tx_rate.is_40mhz = 1;
1714
1715                         if (rinfo[NL80211_RATE_INFO_SHORT_GI])
1716                                 e->tx_rate.is_short_gi = 1;
1717                 }
1718
1719                 if (sinfo[NL80211_STA_INFO_RX_BYTES])
1720                         e->rx_bytes = nla_get_u32(sinfo[NL80211_STA_INFO_RX_BYTES]);
1721
1722                 if (sinfo[NL80211_STA_INFO_TX_BYTES])
1723                         e->tx_bytes = nla_get_u32(sinfo[NL80211_STA_INFO_TX_BYTES]);
1724
1725                 if (sinfo[NL80211_STA_INFO_TX_RETRIES])
1726                         e->tx_retries = nla_get_u32(sinfo[NL80211_STA_INFO_TX_RETRIES]);
1727
1728                 if (sinfo[NL80211_STA_INFO_TX_FAILED])
1729                         e->tx_failed = nla_get_u32(sinfo[NL80211_STA_INFO_TX_FAILED]);
1730
1731                 if (sinfo[NL80211_STA_INFO_T_OFFSET])
1732                         e->t_offset = nla_get_u64(sinfo[NL80211_STA_INFO_T_OFFSET]);
1733
1734                 /* Station flags */
1735                 if (sinfo[NL80211_STA_INFO_STA_FLAGS])
1736                 {
1737                         sta_flags = (struct nl80211_sta_flag_update *)
1738                                 nla_data(sinfo[NL80211_STA_INFO_STA_FLAGS]);
1739
1740                         if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHORIZED) &&
1741                             sta_flags->set & BIT(NL80211_STA_FLAG_AUTHORIZED))
1742                                 e->is_authorized = 1;
1743
1744                         if (sta_flags->mask & BIT(NL80211_STA_FLAG_AUTHENTICATED) &&
1745                             sta_flags->set & BIT(NL80211_STA_FLAG_AUTHENTICATED))
1746                                 e->is_authenticated = 1;
1747
1748                         if (sta_flags->mask & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE) &&
1749                             sta_flags->set & BIT(NL80211_STA_FLAG_SHORT_PREAMBLE))
1750                                 e->is_preamble_short = 1;
1751
1752                         if (sta_flags->mask & BIT(NL80211_STA_FLAG_WME) &&
1753                             sta_flags->set & BIT(NL80211_STA_FLAG_WME))
1754                                 e->is_wme = 1;
1755
1756                         if (sta_flags->mask & BIT(NL80211_STA_FLAG_MFP) &&
1757                             sta_flags->set & BIT(NL80211_STA_FLAG_MFP))
1758                                 e->is_mfp = 1;
1759
1760                         if (sta_flags->mask & BIT(NL80211_STA_FLAG_TDLS_PEER) &&
1761                             sta_flags->set & BIT(NL80211_STA_FLAG_TDLS_PEER))
1762                                 e->is_tdls = 1;
1763                 }
1764         }
1765
1766         e->noise = 0; /* filled in by caller */
1767         arr->count++;
1768
1769         return NL_SKIP;
1770 }
1771
1772 static int nl80211_get_assoclist(const char *ifname, char *buf, int *len)
1773 {
1774         DIR *d;
1775         int i, noise = 0;
1776         struct dirent *de;
1777         struct nl80211_msg_conveyor *req;
1778         struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
1779         struct iwinfo_assoclist_entry *e;
1780
1781         if ((d = opendir("/sys/class/net")) != NULL)
1782         {
1783                 while ((de = readdir(d)) != NULL)
1784                 {
1785                         if (!strncmp(de->d_name, ifname, strlen(ifname)) &&
1786                             (!de->d_name[strlen(ifname)] ||
1787                              !strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
1788                         {
1789                                 req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
1790                                                   NLM_F_DUMP);
1791
1792                                 if (req)
1793                                 {
1794                                         nl80211_send(req, nl80211_get_assoclist_cb, &arr);
1795                                         nl80211_free(req);
1796                                 }
1797                         }
1798                 }
1799
1800                 closedir(d);
1801
1802                 if (!nl80211_get_noise(ifname, &noise))
1803                         for (i = 0, e = arr.buf; i < arr.count; i++, e++)
1804                                 e->noise = noise;
1805
1806                 *len = (arr.count * sizeof(struct iwinfo_assoclist_entry));
1807                 return 0;
1808         }
1809
1810         return -1;
1811 }
1812
1813 static int nl80211_get_txpwrlist_cb(struct nl_msg *msg, void *arg)
1814 {
1815         int *dbm_max = arg;
1816         int ch_cur, ch_cmp, bands_remain, freqs_remain;
1817
1818         struct nlattr **attr = nl80211_parse(msg);
1819         struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
1820         struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
1821         struct nlattr *band, *freq;
1822
1823         static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
1824                 [NL80211_FREQUENCY_ATTR_FREQ]         = { .type = NLA_U32  },
1825                 [NL80211_FREQUENCY_ATTR_DISABLED]     = { .type = NLA_FLAG },
1826                 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
1827                 [NL80211_FREQUENCY_ATTR_NO_IBSS]      = { .type = NLA_FLAG },
1828                 [NL80211_FREQUENCY_ATTR_RADAR]        = { .type = NLA_FLAG },
1829                 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32  },
1830         };
1831
1832         ch_cur = *dbm_max; /* value int* is initialized with channel by caller */
1833         *dbm_max = -1;
1834
1835         nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
1836         {
1837                 nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band),
1838                           nla_len(band), NULL);
1839
1840                 nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
1841                 {
1842                         nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
1843                                   nla_data(freq), nla_len(freq), freq_policy);
1844
1845                         ch_cmp = nl80211_freq2channel(nla_get_u32(
1846                                 freqs[NL80211_FREQUENCY_ATTR_FREQ]));
1847
1848                         if ((!ch_cur || (ch_cmp == ch_cur)) &&
1849                             freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER])
1850                         {
1851                                 *dbm_max = (int)(0.01 * nla_get_u32(
1852                                         freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
1853
1854                                 break;
1855                         }
1856                 }
1857         }
1858
1859         return NL_SKIP;
1860 }
1861
1862 static int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len)
1863 {
1864         int ch_cur;
1865         int dbm_max = -1, dbm_cur, dbm_cnt;
1866         struct nl80211_msg_conveyor *req;
1867         struct iwinfo_txpwrlist_entry entry;
1868
1869         if (nl80211_get_channel(ifname, &ch_cur))
1870                 ch_cur = 0;
1871
1872         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
1873         if (req)
1874         {
1875                 /* initialize the value pointer with channel for callback */
1876                 dbm_max = ch_cur;
1877
1878                 nl80211_send(req, nl80211_get_txpwrlist_cb, &dbm_max);
1879                 nl80211_free(req);
1880         }
1881
1882         if (dbm_max > 0)
1883         {
1884                 for (dbm_cur = 0, dbm_cnt = 0;
1885                      dbm_cur < dbm_max;
1886                      dbm_cur++, dbm_cnt++)
1887                 {
1888                         entry.dbm = dbm_cur;
1889                         entry.mw  = iwinfo_dbm2mw(dbm_cur);
1890
1891                         memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry));
1892                 }
1893
1894                 entry.dbm = dbm_max;
1895                 entry.mw  = iwinfo_dbm2mw(dbm_max);
1896
1897                 memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry));
1898                 dbm_cnt++;
1899
1900                 *len = dbm_cnt * sizeof(entry);
1901                 return 0;
1902         }
1903
1904         return -1;
1905 }
1906
1907 static void nl80211_get_scancrypto(const char *spec,
1908         struct iwinfo_crypto_entry *c)
1909 {
1910         if (strstr(spec, "WPA") || strstr(spec, "WEP"))
1911         {
1912                 c->enabled = 1;
1913
1914                 if (strstr(spec, "WPA2-") && strstr(spec, "WPA-"))
1915                         c->wpa_version = 3;
1916
1917                 else if (strstr(spec, "WPA2"))
1918                         c->wpa_version = 2;
1919
1920                 else if (strstr(spec, "WPA"))
1921                         c->wpa_version = 1;
1922
1923                 else if (strstr(spec, "WEP"))
1924                         c->auth_algs = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED;
1925
1926
1927                 if (strstr(spec, "PSK"))
1928                         c->auth_suites |= IWINFO_KMGMT_PSK;
1929
1930                 if (strstr(spec, "802.1X") || strstr(spec, "EAP"))
1931                         c->auth_suites |= IWINFO_KMGMT_8021x;
1932
1933                 if (strstr(spec, "WPA-NONE"))
1934                         c->auth_suites |= IWINFO_KMGMT_NONE;
1935
1936
1937                 if (strstr(spec, "TKIP"))
1938                         c->pair_ciphers |= IWINFO_CIPHER_TKIP;
1939
1940                 if (strstr(spec, "CCMP"))
1941                         c->pair_ciphers |= IWINFO_CIPHER_CCMP;
1942
1943                 if (strstr(spec, "WEP-40"))
1944                         c->pair_ciphers |= IWINFO_CIPHER_WEP40;
1945
1946                 if (strstr(spec, "WEP-104"))
1947                         c->pair_ciphers |= IWINFO_CIPHER_WEP104;
1948
1949                 c->group_ciphers = c->pair_ciphers;
1950         }
1951         else
1952         {
1953                 c->enabled = 0;
1954         }
1955 }
1956
1957
1958 struct nl80211_scanlist {
1959         struct iwinfo_scanlist_entry *e;
1960         int len;
1961 };
1962
1963
1964 static void nl80211_get_scanlist_ie(struct nlattr **bss,
1965                                     struct iwinfo_scanlist_entry *e)
1966 {
1967         int ielen = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1968         unsigned char *ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
1969         static unsigned char ms_oui[3] = { 0x00, 0x50, 0xf2 };
1970         int len;
1971
1972         while (ielen >= 2 && ielen >= ie[1])
1973         {
1974                 switch (ie[0])
1975                 {
1976                 case 0: /* SSID */
1977                         len = min(ie[1], IWINFO_ESSID_MAX_SIZE);
1978                         memcpy(e->ssid, ie + 2, len);
1979                         e->ssid[len] = 0;
1980                         break;
1981
1982                 case 48: /* RSN */
1983                         iwinfo_parse_rsn(&e->crypto, ie + 2, ie[1],
1984                                          IWINFO_CIPHER_CCMP, IWINFO_KMGMT_8021x);
1985                         break;
1986
1987                 case 221: /* Vendor */
1988                         if (ie[1] >= 4 && !memcmp(ie + 2, ms_oui, 3) && ie[5] == 1)
1989                                 iwinfo_parse_rsn(&e->crypto, ie + 6, ie[1] - 4,
1990                                                  IWINFO_CIPHER_TKIP, IWINFO_KMGMT_PSK);
1991                         break;
1992                 }
1993
1994                 ielen -= ie[1] + 2;
1995                 ie += ie[1] + 2;
1996         }
1997 }
1998
1999 static int nl80211_get_scanlist_cb(struct nl_msg *msg, void *arg)
2000 {
2001         int8_t rssi;
2002         uint16_t caps;
2003
2004         struct nl80211_scanlist *sl = arg;
2005         struct nlattr **tb = nl80211_parse(msg);
2006         struct nlattr *bss[NL80211_BSS_MAX + 1];
2007
2008         static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
2009                 [NL80211_BSS_TSF]                  = { .type = NLA_U64 },
2010                 [NL80211_BSS_FREQUENCY]            = { .type = NLA_U32 },
2011                 [NL80211_BSS_BSSID]                = { 0 },
2012                 [NL80211_BSS_BEACON_INTERVAL]      = { .type = NLA_U16 },
2013                 [NL80211_BSS_CAPABILITY]           = { .type = NLA_U16 },
2014                 [NL80211_BSS_INFORMATION_ELEMENTS] = { 0 },
2015                 [NL80211_BSS_SIGNAL_MBM]           = { .type = NLA_U32 },
2016                 [NL80211_BSS_SIGNAL_UNSPEC]        = { .type = NLA_U8  },
2017                 [NL80211_BSS_STATUS]               = { .type = NLA_U32 },
2018                 [NL80211_BSS_SEEN_MS_AGO]          = { .type = NLA_U32 },
2019                 [NL80211_BSS_BEACON_IES]           = { 0 },
2020         };
2021
2022         if (!tb[NL80211_ATTR_BSS] ||
2023                 nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
2024                                  bss_policy) ||
2025                 !bss[NL80211_BSS_BSSID])
2026         {
2027                 return NL_SKIP;
2028         }
2029
2030         if (bss[NL80211_BSS_CAPABILITY])
2031                 caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
2032         else
2033                 caps = 0;
2034
2035         memset(sl->e, 0, sizeof(*sl->e));
2036         memcpy(sl->e->mac, nla_data(bss[NL80211_BSS_BSSID]), 6);
2037
2038         if (caps & (1<<1))
2039                 sl->e->mode = IWINFO_OPMODE_ADHOC;
2040         else if (caps & (1<<0))
2041                 sl->e->mode = IWINFO_OPMODE_MASTER;
2042         else
2043                 sl->e->mode = IWINFO_OPMODE_MESHPOINT;
2044
2045         if (caps & (1<<4))
2046                 sl->e->crypto.enabled = 1;
2047
2048         if (bss[NL80211_BSS_FREQUENCY])
2049                 sl->e->channel = nl80211_freq2channel(nla_get_u32(
2050                         bss[NL80211_BSS_FREQUENCY]));
2051
2052         if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
2053                 nl80211_get_scanlist_ie(bss, sl->e);
2054
2055         if (bss[NL80211_BSS_SIGNAL_MBM])
2056         {
2057                 sl->e->signal =
2058                         (uint8_t)((int32_t)nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]) / 100);
2059
2060                 rssi = sl->e->signal - 0x100;
2061
2062                 if (rssi < -110)
2063                         rssi = -110;
2064                 else if (rssi > -40)
2065                         rssi = -40;
2066
2067                 sl->e->quality = (rssi + 110);
2068                 sl->e->quality_max = 70;
2069         }
2070
2071         if (sl->e->crypto.enabled && !sl->e->crypto.wpa_version)
2072         {
2073                 sl->e->crypto.auth_algs    = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED;
2074                 sl->e->crypto.pair_ciphers = IWINFO_CIPHER_WEP40 | IWINFO_CIPHER_WEP104;
2075         }
2076
2077         sl->e++;
2078         sl->len++;
2079
2080         return NL_SKIP;
2081 }
2082
2083 static int nl80211_get_scanlist_nl(const char *ifname, char *buf, int *len)
2084 {
2085         struct nl80211_msg_conveyor *req;
2086         struct nl80211_scanlist sl = { .e = (struct iwinfo_scanlist_entry *)buf };
2087
2088         req = nl80211_msg(ifname, NL80211_CMD_TRIGGER_SCAN, 0);
2089         if (req)
2090         {
2091                 nl80211_send(req, NULL, NULL);
2092                 nl80211_free(req);
2093         }
2094
2095         nl80211_wait("nl80211", "scan", NL80211_CMD_NEW_SCAN_RESULTS);
2096
2097         req = nl80211_msg(ifname, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
2098         if (req)
2099         {
2100                 nl80211_send(req, nl80211_get_scanlist_cb, &sl);
2101                 nl80211_free(req);
2102         }
2103
2104         *len = sl.len * sizeof(struct iwinfo_scanlist_entry);
2105         return *len ? 0 : -1;
2106 }
2107
2108 static int wpasupp_ssid_decode(const char *in, char *out, int outlen)
2109 {
2110 #define hex(x) \
2111         (((x) >= 'a') ? ((x) - 'a' + 10) : \
2112                 (((x) >= 'A') ? ((x) - 'A' + 10) : ((x) - '0')))
2113
2114         int len = 0;
2115
2116         while (*in)
2117         {
2118                 if (len + 1 >= outlen)
2119                         break;
2120
2121                 switch (*in)
2122                 {
2123                 case '\\':
2124                         in++;
2125                         switch (*in)
2126                         {
2127                         case 'n':
2128                                 out[len++] = '\n'; in++;
2129                                 break;
2130
2131                         case 'r':
2132                                 out[len++] = '\r'; in++;
2133                                 break;
2134
2135                         case 't':
2136                                 out[len++] = '\t'; in++;
2137                                 break;
2138
2139                         case 'e':
2140                                 out[len++] = '\033'; in++;
2141                                 break;
2142
2143                         case 'x':
2144                                 if (isxdigit(*(in+1)) && isxdigit(*(in+2)))
2145                                         out[len++] = hex(*(in+1)) * 16 + hex(*(in+2));
2146                                 in += 3;
2147                                 break;
2148
2149                         default:
2150                                 out[len++] = *in++;
2151                                 break;
2152                         }
2153                         break;
2154
2155                 default:
2156                         out[len++] = *in++;
2157                         break;
2158                 }
2159         }
2160
2161         if (outlen > len)
2162                 out[len] = '\0';
2163
2164         return len;
2165 }
2166
2167 static int nl80211_get_scanlist_wpactl(const char *ifname, char *buf, int *len)
2168 {
2169         int sock, qmax, rssi, tries, count = -1, ready = 0;
2170         char *pos, *line, *bssid, *freq, *signal, *flags, *ssid, reply[4096];
2171         struct sockaddr_un local = { 0 };
2172         struct iwinfo_scanlist_entry *e = (struct iwinfo_scanlist_entry *)buf;
2173
2174         sock = nl80211_wpactl_connect(ifname, &local);
2175
2176         if (sock < 0)
2177                 return sock;
2178
2179         send(sock, "ATTACH", 6, 0);
2180         send(sock, "SCAN", 4, 0);
2181
2182         /*
2183          * wait for scan results:
2184          *   nl80211_wpactl_recv() will use a timeout of 256ms and we need to scan
2185          *   72 channels at most. We'll also receive two "OK" messages acknowledging
2186          *   the "ATTACH" and "SCAN" commands and the driver might need a bit extra
2187          *   time to process the results, so try 72 + 2 + 1 times.
2188          */
2189         for (tries = 0; tries < 75; tries++)
2190         {
2191                 if (nl80211_wpactl_recv(sock, reply, sizeof(reply)) <= 0)
2192                         continue;
2193
2194                 /* got an event notification */
2195                 if (reply[0] == '<')
2196                 {
2197                         /* scan results are ready */
2198                         if (strstr(reply, "CTRL-EVENT-SCAN-RESULTS"))
2199                         {
2200                                 /* send "SCAN_RESULTS" command */
2201                                 ready = (send(sock, "SCAN_RESULTS", 12, 0) == 12);
2202                                 break;
2203                         }
2204
2205                         /* is another unrelated event, retry */
2206                         tries--;
2207                 }
2208         }
2209
2210         /* receive and parse scan results if the wait above didn't time out */
2211         if (ready && nl80211_wpactl_recv(sock, reply, sizeof(reply)) > 0)
2212         {
2213                 nl80211_get_quality_max(ifname, &qmax);
2214
2215                 for (line = strtok_r(reply, "\n", &pos);
2216                      line != NULL;
2217                      line = strtok_r(NULL, "\n", &pos))
2218                 {
2219                         /* skip header line */
2220                         if (count < 0)
2221                         {
2222                                 count++;
2223                                 continue;
2224                         }
2225
2226                         bssid  = strtok(line, "\t");
2227                         freq   = strtok(NULL, "\t");
2228                         signal = strtok(NULL, "\t");
2229                         flags  = strtok(NULL, "\t");
2230                         ssid   = strtok(NULL, "\n");
2231
2232                         if (!bssid || !freq || !signal || !flags || !ssid)
2233                                 continue;
2234
2235                         /* BSSID */
2236                         e->mac[0] = strtol(&bssid[0],  NULL, 16);
2237                         e->mac[1] = strtol(&bssid[3],  NULL, 16);
2238                         e->mac[2] = strtol(&bssid[6],  NULL, 16);
2239                         e->mac[3] = strtol(&bssid[9],  NULL, 16);
2240                         e->mac[4] = strtol(&bssid[12], NULL, 16);
2241                         e->mac[5] = strtol(&bssid[15], NULL, 16);
2242
2243                         /* SSID */
2244                         wpasupp_ssid_decode(ssid, e->ssid, sizeof(e->ssid));
2245
2246                         /* Mode */
2247                         if (strstr(flags, "[MESH]"))
2248                                 e->mode = IWINFO_OPMODE_MESHPOINT;
2249                         else if (strstr(flags, "[IBSS]"))
2250                                 e->mode = IWINFO_OPMODE_ADHOC;
2251                         else
2252                                 e->mode = IWINFO_OPMODE_MASTER;
2253
2254                         /* Channel */
2255                         e->channel = nl80211_freq2channel(atoi(freq));
2256
2257                         /* Signal */
2258                         rssi = atoi(signal);
2259                         e->signal = rssi;
2260
2261                         /* Quality */
2262                         if (rssi < 0)
2263                         {
2264                                 /* The cfg80211 wext compat layer assumes a signal range
2265                                  * of -110 dBm to -40 dBm, the quality value is derived
2266                                  * by adding 110 to the signal level */
2267                                 if (rssi < -110)
2268                                         rssi = -110;
2269                                 else if (rssi > -40)
2270                                         rssi = -40;
2271
2272                                 e->quality = (rssi + 110);
2273                         }
2274                         else
2275                         {
2276                                 e->quality = rssi;
2277                         }
2278
2279                         /* Max. Quality */
2280                         e->quality_max = qmax;
2281
2282                         /* Crypto */
2283                         nl80211_get_scancrypto(flags, &e->crypto);
2284
2285                         count++;
2286                         e++;
2287                 }
2288
2289                 *len = count * sizeof(struct iwinfo_scanlist_entry);
2290         }
2291
2292         close(sock);
2293         unlink(local.sun_path);
2294
2295         return (count >= 0) ? 0 : -1;
2296 }
2297
2298 static int nl80211_get_scanlist(const char *ifname, char *buf, int *len)
2299 {
2300         char *res;
2301         int rv, mode;
2302
2303         *len = 0;
2304
2305         /* Got a radioX pseudo interface, find some interface on it or create one */
2306         if (!strncmp(ifname, "radio", 5))
2307         {
2308                 /* Reuse existing interface */
2309                 if ((res = nl80211_phy2ifname(ifname)) != NULL)
2310                 {
2311                         return nl80211_get_scanlist(res, buf, len);
2312                 }
2313
2314                 /* Need to spawn a temporary iface for scanning */
2315                 else if ((res = nl80211_ifadd(ifname)) != NULL)
2316                 {
2317                         rv = nl80211_get_scanlist(res, buf, len);
2318                         nl80211_ifdel(res);
2319                         return rv;
2320                 }
2321         }
2322
2323         /* WPA supplicant */
2324         if (!nl80211_get_scanlist_wpactl(ifname, buf, len))
2325         {
2326                 return 0;
2327         }
2328
2329         /* station / ad-hoc / monitor scan */
2330         else if (!nl80211_get_mode(ifname, &mode) &&
2331                  (mode == IWINFO_OPMODE_ADHOC ||
2332                   mode == IWINFO_OPMODE_MASTER ||
2333                   mode == IWINFO_OPMODE_CLIENT ||
2334                   mode == IWINFO_OPMODE_MONITOR) &&
2335                  iwinfo_ifup(ifname))
2336         {
2337                 return nl80211_get_scanlist_nl(ifname, buf, len);
2338         }
2339
2340         /* AP scan */
2341         else
2342         {
2343                 /* Got a temp interface, don't create yet another one */
2344                 if (!strncmp(ifname, "tmp.", 4))
2345                 {
2346                         if (!iwinfo_ifup(ifname))
2347                                 return -1;
2348
2349                         rv = nl80211_get_scanlist_nl(ifname, buf, len);
2350                         iwinfo_ifdown(ifname);
2351                         return rv;
2352                 }
2353
2354                 /* Spawn a new scan interface */
2355                 else
2356                 {
2357                         if (!(res = nl80211_ifadd(ifname)))
2358                                 return -1;
2359
2360                         iwinfo_ifmac(res);
2361
2362                         /* if we can take the new interface up, the driver supports an
2363                          * additional interface and there's no need to tear down the ap */
2364                         if (iwinfo_ifup(res))
2365                         {
2366                                 rv = nl80211_get_scanlist_nl(res, buf, len);
2367                                 iwinfo_ifdown(res);
2368                         }
2369
2370                         /* driver cannot create secondary interface, take down ap
2371                          * during scan */
2372                         else if (iwinfo_ifdown(ifname) && iwinfo_ifup(res))
2373                         {
2374                                 rv = nl80211_get_scanlist_nl(res, buf, len);
2375                                 iwinfo_ifdown(res);
2376                                 iwinfo_ifup(ifname);
2377                                 nl80211_hostapd_hup(ifname);
2378                         }
2379
2380                         nl80211_ifdel(res);
2381                         return rv;
2382                 }
2383         }
2384
2385         return -1;
2386 }
2387
2388 static int nl80211_get_freqlist_cb(struct nl_msg *msg, void *arg)
2389 {
2390         int bands_remain, freqs_remain;
2391
2392         struct nl80211_array_buf *arr = arg;
2393         struct iwinfo_freqlist_entry *e = arr->buf;
2394
2395         struct nlattr **attr = nl80211_parse(msg);
2396         struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
2397         struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
2398         struct nlattr *band, *freq;
2399
2400         nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
2401         {
2402                 nla_parse(bands, NL80211_BAND_ATTR_MAX,
2403                           nla_data(band), nla_len(band), NULL);
2404
2405                 nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
2406                 {
2407                         nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
2408                                   nla_data(freq), nla_len(freq), NULL);
2409
2410                         if (!freqs[NL80211_FREQUENCY_ATTR_FREQ] ||
2411                             freqs[NL80211_FREQUENCY_ATTR_DISABLED])
2412                                 continue;
2413
2414                         e->mhz = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]);
2415                         e->channel = nl80211_freq2channel(e->mhz);
2416
2417                         e->restricted = (
2418                                 freqs[NL80211_FREQUENCY_ATTR_NO_IR] &&
2419                                 !freqs[NL80211_FREQUENCY_ATTR_RADAR]
2420                         ) ? 1 : 0;
2421
2422                         e++;
2423                         arr->count++;
2424                 }
2425         }
2426
2427         return NL_SKIP;
2428 }
2429
2430 static int nl80211_get_freqlist(const char *ifname, char *buf, int *len)
2431 {
2432         struct nl80211_msg_conveyor *req;
2433         struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
2434
2435         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
2436         if (req)
2437         {
2438                 nl80211_send(req, nl80211_get_freqlist_cb, &arr);
2439                 nl80211_free(req);
2440         }
2441
2442         if (arr.count > 0)
2443         {
2444                 *len = arr.count * sizeof(struct iwinfo_freqlist_entry);
2445                 return 0;
2446         }
2447
2448         return -1;
2449 }
2450
2451 static int nl80211_get_country_cb(struct nl_msg *msg, void *arg)
2452 {
2453         char *buf = arg;
2454         struct nlattr **attr = nl80211_parse(msg);
2455
2456         if (attr[NL80211_ATTR_REG_ALPHA2])
2457                 memcpy(buf, nla_data(attr[NL80211_ATTR_REG_ALPHA2]), 2);
2458         else
2459                 buf[0] = 0;
2460
2461         return NL_SKIP;
2462 }
2463
2464 static int nl80211_get_country(const char *ifname, char *buf)
2465 {
2466         int rv = -1;
2467         struct nl80211_msg_conveyor *req;
2468
2469         req = nl80211_msg(ifname, NL80211_CMD_GET_REG, 0);
2470         if (req)
2471         {
2472                 nl80211_send(req, nl80211_get_country_cb, buf);
2473                 nl80211_free(req);
2474
2475                 if (buf[0])
2476                         rv = 0;
2477         }
2478
2479         return rv;
2480 }
2481
2482 static int nl80211_get_countrylist(const char *ifname, char *buf, int *len)
2483 {
2484         int count;
2485         struct iwinfo_country_entry *e = (struct iwinfo_country_entry *)buf;
2486         const struct iwinfo_iso3166_label *l;
2487
2488         for (l = IWINFO_ISO3166_NAMES, count = 0; l->iso3166; l++, e++, count++)
2489         {
2490                 e->iso3166 = l->iso3166;
2491                 e->ccode[0] = (l->iso3166 / 256);
2492                 e->ccode[1] = (l->iso3166 % 256);
2493                 e->ccode[2] = 0;
2494         }
2495
2496         *len = (count * sizeof(struct iwinfo_country_entry));
2497         return 0;
2498 }
2499
2500
2501 struct nl80211_modes
2502 {
2503         bool ok;
2504         uint32_t hw;
2505         uint32_t ht;
2506 };
2507
2508 static int nl80211_get_modelist_cb(struct nl_msg *msg, void *arg)
2509 {
2510         struct nl80211_modes *m = arg;
2511         int bands_remain, freqs_remain;
2512         uint16_t caps = 0;
2513         uint32_t vht_caps = 0;
2514         struct nlattr **attr = nl80211_parse(msg);
2515         struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
2516         struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
2517         struct nlattr *band, *freq;
2518
2519         if (attr[NL80211_ATTR_WIPHY_BANDS])
2520         {
2521                 nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
2522                 {
2523                         nla_parse(bands, NL80211_BAND_ATTR_MAX,
2524                                   nla_data(band), nla_len(band), NULL);
2525
2526                         if (bands[NL80211_BAND_ATTR_HT_CAPA])
2527                                 caps = nla_get_u16(bands[NL80211_BAND_ATTR_HT_CAPA]);
2528
2529                         /* Treat any nonzero capability as 11n */
2530                         if (caps > 0)
2531                         {
2532                                 m->hw |= IWINFO_80211_N;
2533                                 m->ht |= IWINFO_HTMODE_HT20;
2534
2535                                 if (caps & (1 << 1))
2536                                         m->ht |= IWINFO_HTMODE_HT40;
2537                         }
2538
2539                         nla_for_each_nested(freq, bands[NL80211_BAND_ATTR_FREQS],
2540                                             freqs_remain)
2541                         {
2542                                 nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
2543                                           nla_data(freq), nla_len(freq), NULL);
2544
2545                                 if (!freqs[NL80211_FREQUENCY_ATTR_FREQ])
2546                                         continue;
2547
2548                                 if (nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) < 2485)
2549                                 {
2550                                         m->hw |= IWINFO_80211_B;
2551                                         m->hw |= IWINFO_80211_G;
2552                                 }
2553                                 else if (bands[NL80211_BAND_ATTR_VHT_CAPA])
2554                                 {
2555                                         vht_caps = nla_get_u32(bands[NL80211_BAND_ATTR_VHT_CAPA]);
2556
2557                                         /* Treat any nonzero capability as 11ac */
2558                                         if (vht_caps > 0)
2559                                         {
2560                                                 m->hw |= IWINFO_80211_AC;
2561                                                 m->ht |= IWINFO_HTMODE_VHT20 | IWINFO_HTMODE_VHT40 | IWINFO_HTMODE_VHT80;
2562
2563                                                 switch ((vht_caps >> 2) & 3)
2564                                                 {
2565                                                 case 2:
2566                                                         m->ht |= IWINFO_HTMODE_VHT80_80;
2567                                                         /* fall through */
2568
2569                                                 case 1:
2570                                                         m->ht |= IWINFO_HTMODE_VHT160;
2571                                                 }
2572                                         }
2573                                 }
2574                                 else if (!(m->hw & IWINFO_80211_AC))
2575                                 {
2576                                         m->hw |= IWINFO_80211_A;
2577                                 }
2578                         }
2579                 }
2580
2581                 m->ok = 1;
2582         }
2583
2584         return NL_SKIP;
2585 }
2586
2587 static int nl80211_get_hwmodelist(const char *ifname, int *buf)
2588 {
2589         struct nl80211_msg_conveyor *req;
2590         struct nl80211_modes m = { 0 };
2591
2592         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
2593         if (req)
2594         {
2595                 nl80211_send(req, nl80211_get_modelist_cb, &m);
2596                 nl80211_free(req);
2597         }
2598
2599         if (m.ok)
2600         {
2601                 *buf = m.hw;
2602                 return 0;
2603         }
2604
2605         return -1;
2606 }
2607
2608 static int nl80211_get_htmodelist(const char *ifname, int *buf)
2609 {
2610         struct nl80211_msg_conveyor *req;
2611         struct nl80211_modes m = { 0 };
2612
2613         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
2614         if (req)
2615         {
2616                 nl80211_send(req, nl80211_get_modelist_cb, &m);
2617                 nl80211_free(req);
2618         }
2619
2620         if (m.ok)
2621         {
2622                 *buf = m.ht;
2623                 return 0;
2624         }
2625
2626         return -1;
2627 }
2628
2629
2630 static int nl80211_get_ifcomb_cb(struct nl_msg *msg, void *arg)
2631 {
2632         struct nlattr **attr = nl80211_parse(msg);
2633         struct nlattr *comb;
2634         int *ret = arg;
2635         int comb_rem, limit_rem, mode_rem;
2636
2637         *ret = 0;
2638         if (!attr[NL80211_ATTR_INTERFACE_COMBINATIONS])
2639                 return NL_SKIP;
2640
2641         nla_for_each_nested(comb, attr[NL80211_ATTR_INTERFACE_COMBINATIONS], comb_rem)
2642         {
2643                 static struct nla_policy iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
2644                         [NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
2645                         [NL80211_IFACE_COMB_MAXNUM] = { .type = NLA_U32 },
2646                 };
2647                 struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB+1];
2648                 static struct nla_policy iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
2649                         [NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
2650                         [NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
2651                 };
2652                 struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT+1];
2653                 struct nlattr *limit;
2654
2655                 nla_parse_nested(tb_comb, NUM_NL80211_IFACE_COMB, comb, iface_combination_policy);
2656
2657                 if (!tb_comb[NL80211_IFACE_COMB_LIMITS])
2658                         continue;
2659
2660                 nla_for_each_nested(limit, tb_comb[NL80211_IFACE_COMB_LIMITS], limit_rem)
2661                 {
2662                         struct nlattr *mode;
2663
2664                         nla_parse_nested(tb_limit, NUM_NL80211_IFACE_LIMIT, limit, iface_limit_policy);
2665
2666                         if (!tb_limit[NL80211_IFACE_LIMIT_TYPES] ||
2667                             !tb_limit[NL80211_IFACE_LIMIT_MAX])
2668                                 continue;
2669
2670                         if (nla_get_u32(tb_limit[NL80211_IFACE_LIMIT_MAX]) < 2)
2671                                 continue;
2672
2673                         nla_for_each_nested(mode, tb_limit[NL80211_IFACE_LIMIT_TYPES], mode_rem) {
2674                                 if (nla_type(mode) == NL80211_IFTYPE_AP)
2675                                         *ret = 1;
2676                         }
2677                 }
2678         }
2679
2680         return NL_SKIP;
2681 }
2682
2683 static int nl80211_get_mbssid_support(const char *ifname, int *buf)
2684 {
2685         struct nl80211_msg_conveyor *req;
2686
2687         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
2688         if (!req)
2689                 return -1;
2690
2691         nl80211_send(req, nl80211_get_ifcomb_cb, buf);
2692         nl80211_free(req);
2693         return 0;
2694 }
2695
2696 static int nl80211_get_hardware_id(const char *ifname, char *buf)
2697 {
2698         int rv = -1;
2699         char *res;
2700
2701         /* Got a radioX pseudo interface, find some interface on it or create one */
2702         if (!strncmp(ifname, "radio", 5))
2703         {
2704                 /* Reuse existing interface */
2705                 if ((res = nl80211_phy2ifname(ifname)) != NULL)
2706                 {
2707                         rv = wext_ops.hardware_id(res, buf);
2708                 }
2709
2710                 /* Need to spawn a temporary iface for finding IDs */
2711                 else if ((res = nl80211_ifadd(ifname)) != NULL)
2712                 {
2713                         rv = wext_ops.hardware_id(res, buf);
2714                         nl80211_ifdel(res);
2715                 }
2716         }
2717         else
2718         {
2719                 rv = wext_ops.hardware_id(ifname, buf);
2720         }
2721
2722         /* Failed to obtain hardware IDs, search board config */
2723         if (rv)
2724         {
2725                 rv = iwinfo_hardware_id_from_mtd((struct iwinfo_hardware_id *)buf);
2726         }
2727
2728         return rv;
2729 }
2730
2731 static const struct iwinfo_hardware_entry *
2732 nl80211_get_hardware_entry(const char *ifname)
2733 {
2734         struct iwinfo_hardware_id id;
2735
2736         if (nl80211_get_hardware_id(ifname, (char *)&id))
2737                 return NULL;
2738
2739         return iwinfo_hardware(&id);
2740 }
2741
2742 static int nl80211_get_hardware_name(const char *ifname, char *buf)
2743 {
2744         const struct iwinfo_hardware_entry *hw;
2745
2746         if (!(hw = nl80211_get_hardware_entry(ifname)))
2747                 sprintf(buf, "Generic MAC80211");
2748         else
2749                 sprintf(buf, "%s %s", hw->vendor_name, hw->device_name);
2750
2751         return 0;
2752 }
2753
2754 static int nl80211_get_txpower_offset(const char *ifname, int *buf)
2755 {
2756         const struct iwinfo_hardware_entry *hw;
2757
2758         if (!(hw = nl80211_get_hardware_entry(ifname)))
2759                 return -1;
2760
2761         *buf = hw->txpower_offset;
2762         return 0;
2763 }
2764
2765 static int nl80211_get_frequency_offset(const char *ifname, int *buf)
2766 {
2767         const struct iwinfo_hardware_entry *hw;
2768
2769         if (!(hw = nl80211_get_hardware_entry(ifname)))
2770                 return -1;
2771
2772         *buf = hw->frequency_offset;
2773         return 0;
2774 }
2775
2776 static int nl80211_lookup_phyname(const char *section, char *buf)
2777 {
2778         int idx;
2779
2780         if ((idx = nl80211_phy_idx_from_uci(section)) < 0)
2781                 return -1;
2782
2783         sprintf(buf, "phy%d", idx);
2784         return 0;
2785 }
2786
2787 const struct iwinfo_ops nl80211_ops = {
2788         .name             = "nl80211",
2789         .probe            = nl80211_probe,
2790         .channel          = nl80211_get_channel,
2791         .frequency        = nl80211_get_frequency,
2792         .frequency_offset = nl80211_get_frequency_offset,
2793         .txpower          = nl80211_get_txpower,
2794         .txpower_offset   = nl80211_get_txpower_offset,
2795         .bitrate          = nl80211_get_bitrate,
2796         .signal           = nl80211_get_signal,
2797         .noise            = nl80211_get_noise,
2798         .quality          = nl80211_get_quality,
2799         .quality_max      = nl80211_get_quality_max,
2800         .mbssid_support   = nl80211_get_mbssid_support,
2801         .hwmodelist       = nl80211_get_hwmodelist,
2802         .htmodelist       = nl80211_get_htmodelist,
2803         .mode             = nl80211_get_mode,
2804         .ssid             = nl80211_get_ssid,
2805         .bssid            = nl80211_get_bssid,
2806         .country          = nl80211_get_country,
2807         .hardware_id      = nl80211_get_hardware_id,
2808         .hardware_name    = nl80211_get_hardware_name,
2809         .encryption       = nl80211_get_encryption,
2810         .phyname          = nl80211_get_phyname,
2811         .assoclist        = nl80211_get_assoclist,
2812         .txpwrlist        = nl80211_get_txpwrlist,
2813         .scanlist         = nl80211_get_scanlist,
2814         .freqlist         = nl80211_get_freqlist,
2815         .countrylist      = nl80211_get_countrylist,
2816         .lookup_phy       = nl80211_lookup_phyname,
2817         .close            = nl80211_close
2818 };