dba67077a3e09062b7ae5f727e0872e1a497a065
[project/luci.git] / contrib / package / iwinfo / src / iwinfo_nl80211.c
1 /*
2  * iwinfo - Wireless Information Library - NL80211 Backend
3  *
4  *   Copyright (C) 2010 Jo-Philipp Wich <xm@subsignal.org>
5  *
6  * The iwinfo library is free software: you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License version 2
8  * as published by the Free Software Foundation.
9  *
10  * The iwinfo library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13  * See the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with the iwinfo library. If not, see http://www.gnu.org/licenses/.
17  *
18  * The signal handling code is derived from the official madwifi tools,
19  * wlanconfig.c in particular. The encryption property handling was
20  * inspired by the hostapd madwifi driver.
21  *
22  * Parts of this code are derived from the Linux iw utility.
23  */
24
25 #include "iwinfo_nl80211.h"
26 #include "iwinfo_wext.h"
27
28 #define min(x, y) ((x) < (y)) ? (x) : (y)
29
30 extern struct iwinfo_iso3166_label ISO3166_Names[];
31 static struct nl80211_state *nls = NULL;
32
33 static int nl80211_init(void)
34 {
35         int err, fd;
36
37         if (!nls)
38         {
39                 nls = malloc(sizeof(struct nl80211_state));
40                 if (!nls) {
41                         err = -ENOMEM;
42                         goto err;
43                 }
44
45                 nls->nl_sock = nl_socket_alloc();
46                 if (!nls->nl_sock) {
47                         err = -ENOMEM;
48                         goto err;
49                 }
50
51                 if( genl_connect(nls->nl_sock)) {
52                         err = -ENOLINK;
53                         goto err;
54                 }
55
56                 fd = nl_socket_get_fd(nls->nl_sock);
57                 if (fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC) < 0)
58                 {
59                         err = -EINVAL;
60                         goto err;
61                 }
62
63                 if( genl_ctrl_alloc_cache(nls->nl_sock, &nls->nl_cache)) {
64                         err = -ENOMEM;
65                         goto err;
66                 }
67
68                 nls->nl80211 = genl_ctrl_search_by_name(nls->nl_cache, "nl80211");
69                 if (!nls->nl80211)
70                 {
71                         err = -ENOENT;
72                         goto err;
73                 }
74         }
75
76         return 0;
77
78
79 err:
80         nl80211_close();
81         return err;
82 }
83
84 static int nl80211_msg_error(struct sockaddr_nl *nla,
85         struct nlmsgerr *err, void *arg)
86 {
87         int *ret = arg;
88         *ret = err->error;
89         return NL_STOP;
90 }
91
92 static int nl80211_msg_finish(struct nl_msg *msg, void *arg)
93 {
94         int *ret = arg;
95         *ret = 0;
96         return NL_SKIP;
97 }
98
99 static int nl80211_msg_ack(struct nl_msg *msg, void *arg)
100 {
101         int *ret = arg;
102         *ret = 0;
103         return NL_STOP;
104 }
105
106 static int nl80211_msg_response(struct nl_msg *msg, void *arg)
107 {
108         return NL_SKIP;
109 }
110
111 static void nl80211_free(struct nl80211_msg_conveyor *cv)
112 {
113         if (cv)
114         {
115                 if (cv->cb)
116                         nl_cb_put(cv->cb);
117
118                 if (cv->msg)
119                         nlmsg_free(cv->msg);
120
121                 cv->cb  = NULL;
122                 cv->msg = NULL;
123         }
124 }
125
126 static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname, int cmd, int flags)
127 {
128         static struct nl80211_msg_conveyor cv;
129
130         int ifidx = -1, phyidx = -1;
131         struct nl_msg *req = NULL;
132         struct nl_cb *cb = NULL;
133
134         if (nl80211_init() < 0)
135                 goto err;
136
137         if (!strncmp(ifname, "phy", 3))
138                 phyidx = atoi(&ifname[3]);
139         else if (!strncmp(ifname, "radio", 5))
140                 phyidx = atoi(&ifname[5]);
141         else if (!strncmp(ifname, "mon.", 4))
142                 ifidx = if_nametoindex(&ifname[4]);
143         else
144                 ifidx = if_nametoindex(ifname);
145
146         if ((ifidx < 0) && (phyidx < 0))
147                 return NULL;
148
149         req = nlmsg_alloc();
150         if (!req)
151                 goto err;
152
153         cb = nl_cb_alloc(NL_CB_DEFAULT);
154         if (!cb)
155                 goto err;
156
157         genlmsg_put(req, 0, 0, genl_family_get_id(nls->nl80211), 0,
158                 flags, cmd, 0);
159
160         if (ifidx > -1)
161                 NLA_PUT_U32(req, NL80211_ATTR_IFINDEX, ifidx);
162
163         if (phyidx > -1)
164                 NLA_PUT_U32(req, NL80211_ATTR_WIPHY, phyidx);
165
166         cv.msg       = req;
167         cv.cb        = cb;
168         cv.custom_cb = 0;
169
170         return &cv;
171
172 err:
173 nla_put_failure:
174         if (cb)
175                 nl_cb_put(cb);
176
177         if (req)
178                 nlmsg_free(req);
179
180         return NULL;
181 }
182
183 static void nl80211_cb(struct nl80211_msg_conveyor *cv,
184         int (*cb)(struct nl_msg *, void *), void *arg)
185 {
186         cv->custom_cb = 1;
187         nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, cb, arg);
188 }
189
190 static struct nl80211_msg_conveyor * nl80211_send(struct nl80211_msg_conveyor *cv)
191 {
192         static struct nl80211_msg_conveyor rcv;
193         int err = 1;
194
195         if (!cv->custom_cb)
196                 nl_cb_set(cv->cb, NL_CB_VALID, NL_CB_CUSTOM, nl80211_msg_response, &rcv);
197
198         if (nl_send_auto_complete(nls->nl_sock, cv->msg) < 0)
199                 goto err;
200
201         nl_cb_err(cv->cb,               NL_CB_CUSTOM, nl80211_msg_error,  &err);
202         nl_cb_set(cv->cb, NL_CB_FINISH, NL_CB_CUSTOM, nl80211_msg_finish, &err);
203         nl_cb_set(cv->cb, NL_CB_ACK,    NL_CB_CUSTOM, nl80211_msg_ack,    &err);
204
205         while (err > 0)
206                 nl_recvmsgs(nls->nl_sock, cv->cb);
207
208         return &rcv;
209
210 err:
211         nl_cb_put(cv->cb);
212         nlmsg_free(cv->msg);
213
214         return NULL;
215 }
216
217 static struct nlattr ** nl80211_parse(struct nl_msg *msg)
218 {
219         struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
220         static struct nlattr *attr[NL80211_ATTR_MAX + 1];
221
222         nla_parse(attr, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
223                 genlmsg_attrlen(gnlh, 0), NULL);
224
225         return attr;
226 }
227
228 static int nl80211_freq2channel(int freq)
229 {
230     if (freq == 2484)
231         return 14;
232
233     if (freq < 2484)
234         return (freq - 2407) / 5;
235
236     return (freq / 5) - 1000;
237 }
238
239 static char * nl80211_getval(const char *ifname, const char *buf, const char *key)
240 {
241         int i, len;
242         char lkey[64] = { 0 };
243         const char *ln = buf;
244         static char lval[256] = { 0 };
245
246         int matched_if = ifname ? 0 : 1;
247
248
249         for( i = 0, len = strlen(buf); i < len; i++ )
250         {
251                 if (!lkey[0] && (buf[i] == ' ' || buf[i] == '\t'))
252                 {
253                         ln++;
254                 }
255                 else if (!lkey[0] && (buf[i] == '='))
256                 {
257                         if ((&buf[i] - ln) > 0)
258                                 memcpy(lkey, ln, min(sizeof(lkey) - 1, &buf[i] - ln));
259                 }
260                 else if (buf[i] == '\n')
261                 {
262                         if (lkey[0])
263                         {
264                                 memcpy(lval, ln + strlen(lkey) + 1,
265                                         min(sizeof(lval) - 1, &buf[i] - ln - strlen(lkey) - 1));
266
267                                 if ((ifname != NULL) &&
268                                     (!strcmp(lkey, "interface") || !strcmp(lkey, "bss")) )
269                                 {
270                                         matched_if = !strcmp(lval, ifname);
271                                 }
272                                 else if (matched_if && !strcmp(lkey, key))
273                                 {
274                                         return lval;
275                                 }
276                         }
277
278                         ln = &buf[i+1];
279                         memset(lkey, 0, sizeof(lkey));
280                         memset(lval, 0, sizeof(lval));
281                 }
282         }
283
284         return NULL;
285 }
286
287 static int nl80211_ifname2phy_cb(struct nl_msg *msg, void *arg)
288 {
289         char *buf = arg;
290         struct nlattr **attr = nl80211_parse(msg);
291
292         if (attr[NL80211_ATTR_WIPHY_NAME])
293                 sprintf(buf, "%s", nla_data(attr[NL80211_ATTR_WIPHY_NAME]));
294         else
295                 buf[0] = 0;
296
297         return NL_SKIP;
298 }
299
300 static char * nl80211_ifname2phy(const char *ifname)
301 {
302         static char phy[32] = { 0 };
303         struct nl80211_msg_conveyor *req;
304
305         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
306         if (req)
307         {
308                 nl80211_cb(req, nl80211_ifname2phy_cb, phy);
309                 nl80211_send(req);
310                 nl80211_free(req);
311         }
312
313         return phy[0] ? phy : NULL;
314 }
315
316 static char * nl80211_hostapd_info(const char *ifname)
317 {
318         char *phy;
319         char path[32] = { 0 };
320         static char buf[4096] = { 0 };
321         FILE *conf;
322
323         if ((phy = nl80211_ifname2phy(ifname)) != NULL)
324         {
325                 snprintf(path, sizeof(path), "/var/run/hostapd-%s.conf", phy);
326
327                 if ((conf = fopen(path, "r")) != NULL)
328                 {
329                         fread(buf, sizeof(buf) - 1, 1, conf);
330                         fclose(conf);
331
332                         return buf;
333                 }
334         }
335
336         return NULL;
337 }
338
339 static inline int nl80211_wpactl_recv(int sock, char *buf, int blen)
340 {
341         fd_set rfds;
342         struct timeval tv = { 2, 0 };
343
344         FD_ZERO(&rfds);
345         FD_SET(sock, &rfds);
346
347         memset(buf, 0, blen);
348
349
350         if (select(sock + 1, &rfds, NULL, NULL, &tv) < 0)
351                 return -1;
352
353         if (!FD_ISSET(sock, &rfds))
354                 return -1;
355
356         return recv(sock, buf, blen, 0);
357 }
358
359 static char * nl80211_wpactl_info(const char *ifname, const char *cmd,
360                                                                    const char *event)
361 {
362         int numtry = 0;
363         int sock = -1;
364         char *rv = NULL;
365         size_t remote_length, local_length;
366         static char buffer[10240] = { 0 };
367
368         struct sockaddr_un local = { 0 };
369         struct sockaddr_un remote = { 0 };
370
371
372         sock = socket(PF_UNIX, SOCK_DGRAM, 0);
373         if (sock < 0)
374                 return NULL;
375
376         remote.sun_family = AF_UNIX;
377         remote_length = sizeof(remote.sun_family) + sprintf(remote.sun_path,
378                 "/var/run/wpa_supplicant-%s/%s", ifname, ifname);
379
380         if (fcntl(sock, F_SETFD, fcntl(sock, F_GETFD) | FD_CLOEXEC) < 0)
381                 goto out;
382
383         if (connect(sock, (struct sockaddr *) &remote, remote_length))
384                 goto out;
385
386         local.sun_family = AF_UNIX;
387         local_length = sizeof(local.sun_family) + sprintf(local.sun_path,
388                 "/var/run/iwinfo-%s-%d", ifname, getpid());
389
390         if (bind(sock, (struct sockaddr *) &local, local_length))
391                 goto out;
392
393
394         send(sock, "ATTACH", 6, 0);
395
396         if (nl80211_wpactl_recv(sock, buffer, sizeof(buffer)) <= 0)
397                 goto out;
398
399
400         send(sock, cmd, strlen(cmd), 0);
401
402         while( numtry++ < 5 )
403         {
404                 if (nl80211_wpactl_recv(sock, buffer, sizeof(buffer)) <= 0)
405                 {
406                         if (event)
407                                 continue;
408
409                         break;
410                 }
411
412                 if ((!event && buffer[0] != '<') || strstr(buffer, event))
413                         break;
414         }
415
416         rv = buffer;
417
418 out:
419         close(sock);
420
421         if (local.sun_family)
422                 unlink(local.sun_path);
423
424         return rv;
425 }
426
427 static inline int nl80211_readint(const char *path)
428 {
429         int fd;
430         int rv = -1;
431         char buffer[16];
432
433         if ((fd = open(path, O_RDONLY)) > -1)
434         {
435                 if (read(fd, buffer, sizeof(buffer)) > 0)
436                         rv = atoi(buffer);
437
438                 close(fd);
439         }
440
441         return rv;
442 }
443
444 static char * nl80211_phy2ifname(const char *ifname)
445 {
446         int fd, ifidx = -1, cifidx = -1, phyidx = -1;
447         char buffer[64];
448         static char nif[IFNAMSIZ] = { 0 };
449
450         DIR *d;
451         struct dirent *e;
452
453         if (!ifname)
454                 return NULL;
455         else if (!strncmp(ifname, "phy", 3))
456                 phyidx = atoi(&ifname[3]);
457         else if (!strncmp(ifname, "radio", 5))
458                 phyidx = atoi(&ifname[5]);
459
460         if (phyidx > -1)
461         {
462                 if ((d = opendir("/sys/class/net")) != NULL)
463                 {
464                         while( (e = readdir(d)) != NULL )
465                         {
466                                 snprintf(buffer, sizeof(buffer),
467                                         "/sys/class/net/%s/phy80211/index", e->d_name);
468
469                                 if (nl80211_readint(buffer) == phyidx)
470                                 {
471                                         snprintf(buffer, sizeof(buffer),
472                                                 "/sys/class/net/%s/ifindex", e->d_name);
473
474                                         if( (cifidx = nl80211_readint(buffer)) >= 0 &&
475                                             ((ifidx < 0) || (cifidx < ifidx)) )
476                                         {
477                                                 ifidx = cifidx;
478                                                 strncpy(nif, e->d_name, sizeof(nif));
479                                         }
480                                 }
481                         }
482
483                         closedir(d);
484                 }
485         }
486
487         return nif[0] ? nif : NULL;
488 }
489
490 static char * nl80211_ifadd(const char *ifname)
491 {
492         int phyidx;
493         char *rv = NULL;
494         static char nif[IFNAMSIZ] = { 0 };
495         struct nl80211_msg_conveyor *req, *res;
496
497         req = nl80211_msg(ifname, NL80211_CMD_NEW_INTERFACE, 0);
498         if (req)
499         {
500                 snprintf(nif, sizeof(nif), "tmp.%s", ifname);
501
502                 NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, nif);
503                 NLA_PUT_U32(req->msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_STATION);
504
505                 nl80211_send(req);
506
507                 rv = nif;
508
509         nla_put_failure:
510                 nl80211_free(req);
511         }
512
513         return rv;
514 }
515
516 static void nl80211_ifdel(const char *ifname)
517 {
518         struct nl80211_msg_conveyor *req;
519
520         req = nl80211_msg(ifname, NL80211_CMD_DEL_INTERFACE, 0);
521         if (req)
522         {
523                 NLA_PUT_STRING(req->msg, NL80211_ATTR_IFNAME, ifname);
524
525                 nl80211_send(req);
526
527         nla_put_failure:
528                 nl80211_free(req);
529         }
530 }
531
532 static void nl80211_hostapd_hup(const char *ifname)
533 {
534         int fd, pid = 0;
535         char buf[32];
536         char *phy = nl80211_ifname2phy(ifname);
537
538         if (phy)
539         {
540                 snprintf(buf, sizeof(buf), "/var/run/wifi-%s.pid", phy);
541                 if ((fd = open(buf, O_RDONLY)) > 0)
542                 {
543                         if (read(fd, buf, sizeof(buf)) > 0)
544                                 pid = atoi(buf);
545
546                         close(fd);
547                 }
548
549                 if (pid > 0)
550                         kill(pid, 1);
551         }
552 }
553
554
555 int nl80211_probe(const char *ifname)
556 {
557         return !!nl80211_ifname2phy(ifname);
558 }
559
560 void nl80211_close(void)
561 {
562         if (nls)
563         {
564                 if (nls->nl_sock)
565                         nl_socket_free(nls->nl_sock);
566
567                 if (nls->nl_cache)
568                         nl_cache_free(nls->nl_cache);
569
570                 free(nls);
571                 nls = NULL;
572         }
573 }
574
575 int nl80211_get_mode(const char *ifname, char *buf)
576 {
577         return wext_get_mode(ifname, buf);
578 }
579
580 int nl80211_get_ssid(const char *ifname, char *buf)
581 {
582         char *ssid;
583
584         if (!wext_get_ssid(ifname, buf))
585         {
586                 return 0;
587         }
588         else if( (ssid = nl80211_hostapd_info(ifname)) &&
589                  (ssid = nl80211_getval(ifname, ssid, "ssid")) )
590         {
591                 memcpy(buf, ssid, strlen(ssid));
592                 return 0;
593         }
594
595         return -1;
596 }
597
598 int nl80211_get_bssid(const char *ifname, char *buf)
599 {
600         char *bssid;
601         unsigned char mac[6];
602
603         if (!wext_get_bssid(ifname, buf))
604         {
605                 return 0;
606         }
607         else if((bssid = nl80211_hostapd_info(ifname)) &&
608                  (bssid = nl80211_getval(ifname, bssid, "bssid")))
609         {
610                 mac[0] = strtol(&bssid[0],  NULL, 16);
611                 mac[1] = strtol(&bssid[3],  NULL, 16);
612                 mac[2] = strtol(&bssid[6],  NULL, 16);
613                 mac[3] = strtol(&bssid[9],  NULL, 16);
614                 mac[4] = strtol(&bssid[12], NULL, 16);
615                 mac[5] = strtol(&bssid[15], NULL, 16);
616
617                 sprintf(buf, "%02X:%02X:%02X:%02X:%02X:%02X",
618                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
619
620                 return 0;
621         }
622
623         return -1;
624 }
625
626 int nl80211_get_channel(const char *ifname, int *buf)
627 {
628         char *first;
629
630         if (!wext_get_channel(ifname, buf))
631                 return 0;
632
633         else if ((first = nl80211_phy2ifname(nl80211_ifname2phy(ifname))) != NULL)
634                 return wext_get_channel(first, buf);
635
636         return -1;
637 }
638
639 int nl80211_get_frequency(const char *ifname, int *buf)
640 {
641         char *first;
642
643         if (!wext_get_frequency(ifname, buf))
644                 return 0;
645
646         else if ((first = nl80211_phy2ifname(nl80211_ifname2phy(ifname))) != NULL)
647                 return wext_get_frequency(first, buf);
648
649         return -1;
650 }
651
652 int nl80211_get_txpower(const char *ifname, int *buf)
653 {
654         return wext_get_txpower(ifname, buf);
655 }
656
657
658 static int nl80211_fill_signal_cb(struct nl_msg *msg, void *arg)
659 {
660         int8_t dbm;
661         int16_t mbit;
662         struct nl80211_rssi_rate *rr = arg;
663         struct nlattr **attr = nl80211_parse(msg);
664         struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
665         struct nlattr *rinfo[NL80211_RATE_INFO_MAX + 1];
666
667         static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
668                 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32    },
669                 [NL80211_STA_INFO_RX_BYTES]      = { .type = NLA_U32    },
670                 [NL80211_STA_INFO_TX_BYTES]      = { .type = NLA_U32    },
671                 [NL80211_STA_INFO_RX_PACKETS]    = { .type = NLA_U32    },
672                 [NL80211_STA_INFO_TX_PACKETS]    = { .type = NLA_U32    },
673                 [NL80211_STA_INFO_SIGNAL]        = { .type = NLA_U8     },
674                 [NL80211_STA_INFO_TX_BITRATE]    = { .type = NLA_NESTED },
675                 [NL80211_STA_INFO_LLID]          = { .type = NLA_U16    },
676                 [NL80211_STA_INFO_PLID]          = { .type = NLA_U16    },
677                 [NL80211_STA_INFO_PLINK_STATE]   = { .type = NLA_U8     },
678         };
679
680         static struct nla_policy rate_policy[NL80211_RATE_INFO_MAX + 1] = {
681                 [NL80211_RATE_INFO_BITRATE]      = { .type = NLA_U16  },
682                 [NL80211_RATE_INFO_MCS]          = { .type = NLA_U8   },
683                 [NL80211_RATE_INFO_40_MHZ_WIDTH] = { .type = NLA_FLAG },
684                 [NL80211_RATE_INFO_SHORT_GI]     = { .type = NLA_FLAG },
685         };
686
687         if (attr[NL80211_ATTR_STA_INFO])
688         {
689                 if( !nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
690                                 attr[NL80211_ATTR_STA_INFO], stats_policy) )
691                 {
692                         if (sinfo[NL80211_STA_INFO_SIGNAL])
693                         {
694                                 dbm = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
695                                 rr->rssi = rr->rssi ? (int8_t)((rr->rssi + dbm) / 2) : dbm;
696                         }
697
698                         if (sinfo[NL80211_STA_INFO_TX_BITRATE])
699                         {
700                                 if( !nla_parse_nested(rinfo, NL80211_RATE_INFO_MAX,
701                                                 sinfo[NL80211_STA_INFO_TX_BITRATE], rate_policy) )
702                                 {
703                                         if (rinfo[NL80211_RATE_INFO_BITRATE])
704                                         {
705                                                 mbit = nla_get_u16(rinfo[NL80211_RATE_INFO_BITRATE]);
706                                                 rr->rate = rr->rate
707                                                         ? (int16_t)((rr->rate + mbit) / 2) : mbit;
708                                         }
709                                 }
710                         }
711                 }
712         }
713
714         return NL_SKIP;
715 }
716
717 static void nl80211_fill_signal(const char *ifname, struct nl80211_rssi_rate *r)
718 {
719         DIR *d;
720         struct dirent *de;
721         struct nl80211_msg_conveyor *req;
722
723         r->rssi = 0;
724         r->rate = 0;
725
726         if ((d = opendir("/sys/class/net")) != NULL)
727         {
728                 while ((de = readdir(d)) != NULL)
729                 {
730                         if (!strncmp(de->d_name, ifname, strlen(ifname)) &&
731                                 (!de->d_name[strlen(ifname)] ||
732                                  !strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
733                         {
734                                 req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
735                                                                   NLM_F_DUMP);
736
737                                 if (req)
738                                 {
739                                         nl80211_cb(req, nl80211_fill_signal_cb, r);
740                                         nl80211_send(req);
741                                         nl80211_free(req);
742                                 }
743                         }
744                 }
745
746                 closedir(d);
747         }
748 }
749
750 int nl80211_get_bitrate(const char *ifname, int *buf)
751 {
752         struct nl80211_rssi_rate rr;
753
754         if (!wext_get_bitrate(ifname, buf))
755                 return 0;
756
757         nl80211_fill_signal(ifname, &rr);
758
759         if (rr.rate)
760         {
761                 *buf = (rr.rate * 100);
762                 return 0;
763         }
764
765         return -1;
766 }
767
768 int nl80211_get_signal(const char *ifname, int *buf)
769 {
770         struct nl80211_rssi_rate rr;
771
772         if (!wext_get_signal(ifname, buf))
773                 return 0;
774
775         nl80211_fill_signal(ifname, &rr);
776
777         if (rr.rssi)
778         {
779                 *buf = rr.rssi;
780                 return 0;
781         }
782
783         return -1;
784 }
785
786 static int nl80211_get_noise_cb(struct nl_msg *msg, void *arg)
787 {
788         int8_t *noise = arg;
789         struct nlattr **tb = nl80211_parse(msg);
790         struct nlattr *si[NL80211_SURVEY_INFO_MAX + 1];
791
792         static struct nla_policy sp[NL80211_SURVEY_INFO_MAX + 1] = {
793                 [NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
794                 [NL80211_SURVEY_INFO_NOISE]     = { .type = NLA_U8  },
795         };
796
797         if (!tb[NL80211_ATTR_SURVEY_INFO])
798                 return NL_SKIP;
799
800         if (nla_parse_nested(si, NL80211_SURVEY_INFO_MAX,
801                                                  tb[NL80211_ATTR_SURVEY_INFO], sp))
802                 return NL_SKIP;
803
804         if (!si[NL80211_SURVEY_INFO_NOISE])
805                 return NL_SKIP;
806
807         if (!*noise || si[NL80211_SURVEY_INFO_IN_USE])
808                 *noise = (int8_t)nla_get_u8(si[NL80211_SURVEY_INFO_NOISE]);
809
810         return NL_SKIP;
811 }
812
813
814 int nl80211_get_noise(const char *ifname, int *buf)
815 {
816         int8_t noise;
817         struct nl80211_msg_conveyor *req;
818
819         req = nl80211_msg(ifname, NL80211_CMD_GET_SURVEY, NLM_F_DUMP);
820         if (req)
821         {
822                 noise = 0;
823
824                 nl80211_cb(req, nl80211_get_noise_cb, &noise);
825                 nl80211_send(req);
826                 nl80211_free(req);
827
828                 if (noise)
829                 {
830                         *buf = noise;
831                         return 0;
832                 }
833         }
834
835         return -1;
836 }
837
838 int nl80211_get_quality(const char *ifname, int *buf)
839 {
840         int signal;
841
842         if (wext_get_quality(ifname, buf))
843         {
844                 *buf = 0;
845
846                 if (!nl80211_get_signal(ifname, &signal))
847                 {
848                         /* A positive signal level is usually just a quality
849                          * value, pass through as-is */
850                         if (signal >= 0)
851                         {
852                                 *buf = signal;
853                         }
854
855                         /* The cfg80211 wext compat layer assumes a signal range
856                          * of -110 dBm to -40 dBm, the quality value is derived
857                          * by adding 110 to the signal level */
858                         else
859                         {
860                                 if (signal < -110)
861                                         signal = -110;
862                                 else if (signal > -40)
863                                         signal = -40;
864
865                                 *buf = (signal + 110);
866                         }
867                 }
868         }
869
870         return 0;
871 }
872
873 int nl80211_get_quality_max(const char *ifname, int *buf)
874 {
875         if (wext_get_quality_max(ifname, buf))
876                 /* The cfg80211 wext compat layer assumes a maximum
877                  * quality of 70 */
878                 *buf = 70;
879
880         return 0;
881 }
882
883 int nl80211_get_encryption(const char *ifname, char *buf)
884 {
885         int i;
886         char k[9];
887         char *val, *res;
888         struct iwinfo_crypto_entry *c = (struct iwinfo_crypto_entry *)buf;
889
890         /* WPA supplicant */
891         if( (res = nl80211_wpactl_info(ifname, "STATUS", NULL)) &&
892             (val = nl80211_getval(NULL, res, "pairwise_cipher")) )
893         {
894                 /* WEP */
895                 if (strstr(val, "WEP"))
896                 {
897                         if (strstr(val, "WEP-40"))
898                                 c->pair_ciphers |= IWINFO_CIPHER_WEP40;
899
900                         else if (strstr(val, "WEP-104"))
901                                 c->pair_ciphers |= IWINFO_CIPHER_WEP104;
902
903                         c->enabled       = 1;
904                         c->group_ciphers = c->pair_ciphers;
905
906                         c->auth_suites |= IWINFO_KMGMT_NONE;
907                         c->auth_algs   |= IWINFO_AUTH_OPEN; /* XXX: assumption */
908                 }
909
910                 /* WPA */
911                 else
912                 {
913                         if (strstr(val, "TKIP"))
914                                 c->pair_ciphers |= IWINFO_CIPHER_TKIP;
915
916                         else if (strstr(val, "CCMP"))
917                                 c->pair_ciphers |= IWINFO_CIPHER_CCMP;
918
919                         else if (strstr(val, "NONE"))
920                                 c->pair_ciphers |= IWINFO_CIPHER_NONE;
921
922                         else if (strstr(val, "WEP-40"))
923                                 c->pair_ciphers |= IWINFO_CIPHER_WEP40;
924
925                         else if (strstr(val, "WEP-104"))
926                                 c->pair_ciphers |= IWINFO_CIPHER_WEP104;
927
928
929                         if ((val = nl80211_getval(NULL, res, "group_cipher")))
930                         {
931                                 if (strstr(val, "TKIP"))
932                                         c->group_ciphers |= IWINFO_CIPHER_TKIP;
933
934                                 else if (strstr(val, "CCMP"))
935                                         c->group_ciphers |= IWINFO_CIPHER_CCMP;
936
937                                 else if (strstr(val, "NONE"))
938                                         c->group_ciphers |= IWINFO_CIPHER_NONE;
939
940                                 else if (strstr(val, "WEP-40"))
941                                         c->group_ciphers |= IWINFO_CIPHER_WEP40;
942
943                                 else if (strstr(val, "WEP-104"))
944                                         c->group_ciphers |= IWINFO_CIPHER_WEP104;
945                         }
946
947
948                         if ((val = nl80211_getval(NULL, res, "key_mgmt")))
949                         {
950                                 if (strstr(val, "WPA2"))
951                                         c->wpa_version = 2;
952
953                                 else if (strstr(val, "WPA"))
954                                         c->wpa_version = 1;
955
956
957                                 if (strstr(val, "PSK"))
958                                         c->auth_suites |= IWINFO_KMGMT_PSK;
959
960                                 else if (strstr(val, "EAP") || strstr(val, "802.1X"))
961                                         c->auth_suites |= IWINFO_KMGMT_8021x;
962
963                                 else if (strstr(val, "NONE"))
964                                         c->auth_suites |= IWINFO_KMGMT_NONE;
965                         }
966
967                         c->enabled = (c->wpa_version && c->auth_suites) ? 1 : 0;
968                 }
969
970                 return 0;
971         }
972
973         /* Hostapd */
974         else if ((res = nl80211_hostapd_info(ifname)))
975         {
976                 if ((val = nl80211_getval(ifname, res, "wpa")) != NULL)
977                         c->wpa_version = atoi(val);
978
979                 val = nl80211_getval(ifname, res, "wpa_key_mgmt");
980
981                 if (!val || strstr(val, "PSK"))
982                         c->auth_suites |= IWINFO_KMGMT_PSK;
983
984                 if (val && strstr(val, "EAP"))
985                         c->auth_suites |= IWINFO_KMGMT_8021x;
986
987                 if (val && strstr(val, "NONE"))
988                         c->auth_suites |= IWINFO_KMGMT_NONE;
989
990                 if ((val = nl80211_getval(ifname, res, "wpa_pairwise")) != NULL)
991                 {
992                         if (strstr(val, "TKIP"))
993                                 c->pair_ciphers |= IWINFO_CIPHER_TKIP;
994
995                         if (strstr(val, "CCMP"))
996                                 c->pair_ciphers |= IWINFO_CIPHER_CCMP;
997
998                         if (strstr(val, "NONE"))
999                                 c->pair_ciphers |= IWINFO_CIPHER_NONE;
1000                 }
1001
1002                 if ((val = nl80211_getval(ifname, res, "auth_algs")) != NULL)
1003                 {
1004                         switch(atoi(val)) {
1005                                 case 1:
1006                                         c->auth_algs |= IWINFO_AUTH_OPEN;
1007                                         break;
1008
1009                                 case 2:
1010                                         c->auth_algs |= IWINFO_AUTH_SHARED;
1011                                         break;
1012
1013                                 case 3:
1014                                         c->auth_algs |= IWINFO_AUTH_OPEN;
1015                                         c->auth_algs |= IWINFO_AUTH_SHARED;
1016                                         break;
1017
1018                                 default:
1019                                         break;
1020                         }
1021
1022                         for( i = 0; i < 4; i++ )
1023                         {
1024                                 snprintf(k, sizeof(k), "wep_key%d", i);
1025
1026                                 if ((val = nl80211_getval(ifname, res, k)))
1027                                 {
1028                                         if ((strlen(val) == 5) || (strlen(val) == 10))
1029                                                 c->pair_ciphers |= IWINFO_CIPHER_WEP40;
1030
1031                                         else if ((strlen(val) == 13) || (strlen(val) == 26))
1032                                                 c->pair_ciphers |= IWINFO_CIPHER_WEP104;
1033                                 }
1034                         }
1035                 }
1036
1037                 c->group_ciphers = c->pair_ciphers;
1038                 c->enabled = (c->auth_algs || c->auth_suites) ? 1 : 0;
1039
1040                 return 0;
1041         }
1042
1043         return -1;
1044 }
1045
1046
1047 static int nl80211_get_assoclist_cb(struct nl_msg *msg, void *arg)
1048 {
1049         struct nl80211_array_buf *arr = arg;
1050         struct iwinfo_assoclist_entry *e = arr->buf;
1051         struct nlattr **attr = nl80211_parse(msg);
1052         struct nlattr *sinfo[NL80211_STA_INFO_MAX + 1];
1053
1054         static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
1055                 [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32    },
1056                 [NL80211_STA_INFO_RX_BYTES]      = { .type = NLA_U32    },
1057                 [NL80211_STA_INFO_TX_BYTES]      = { .type = NLA_U32    },
1058                 [NL80211_STA_INFO_RX_PACKETS]    = { .type = NLA_U32    },
1059                 [NL80211_STA_INFO_TX_PACKETS]    = { .type = NLA_U32    },
1060                 [NL80211_STA_INFO_SIGNAL]        = { .type = NLA_U8     },
1061                 [NL80211_STA_INFO_TX_BITRATE]    = { .type = NLA_NESTED },
1062                 [NL80211_STA_INFO_LLID]          = { .type = NLA_U16    },
1063                 [NL80211_STA_INFO_PLID]          = { .type = NLA_U16    },
1064                 [NL80211_STA_INFO_PLINK_STATE]   = { .type = NLA_U8     },
1065         };
1066
1067         /* advance to end of array */
1068         e += arr->count;
1069
1070         if (attr[NL80211_ATTR_MAC])
1071                 memcpy(e->mac, nla_data(attr[NL80211_ATTR_MAC]), 6);
1072
1073         if (attr[NL80211_ATTR_STA_INFO])
1074         {
1075                 if (!nla_parse_nested(sinfo, NL80211_STA_INFO_MAX,
1076                                 attr[NL80211_ATTR_STA_INFO], stats_policy))
1077                 {
1078                         if (sinfo[NL80211_STA_INFO_SIGNAL])
1079                                 e->signal = nla_get_u8(sinfo[NL80211_STA_INFO_SIGNAL]);
1080                 }
1081         }
1082
1083         e->noise = 0; /* filled in by caller */
1084         arr->count++;
1085
1086         return NL_SKIP;
1087 }
1088
1089 int nl80211_get_assoclist(const char *ifname, char *buf, int *len)
1090 {
1091         DIR *d;
1092         int i, noise = 0;
1093         struct dirent *de;
1094         struct nl80211_msg_conveyor *req;
1095         struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
1096         struct iwinfo_assoclist_entry *e;
1097
1098         if ((d = opendir("/sys/class/net")) != NULL)
1099         {
1100                 while ((de = readdir(d)) != NULL)
1101                 {
1102                         if (!strncmp(de->d_name, ifname, strlen(ifname)) &&
1103                                 (!de->d_name[strlen(ifname)] ||
1104                                  !strncmp(&de->d_name[strlen(ifname)], ".sta", 4)))
1105                         {
1106                                 req = nl80211_msg(de->d_name, NL80211_CMD_GET_STATION,
1107                                                                   NLM_F_DUMP);
1108
1109                                 if (req)
1110                                 {
1111                                         nl80211_cb(req, nl80211_get_assoclist_cb, &arr);
1112                                         nl80211_send(req);
1113                                         nl80211_free(req);
1114                                 }
1115
1116                                 break;
1117                         }
1118                 }
1119
1120                 closedir(d);
1121
1122                 if (!nl80211_get_noise(ifname, &noise))
1123                         for (i = 0, e = arr.buf; i < arr.count; i++, e++)
1124                                 e->noise = noise;
1125
1126                 *len = (arr.count * sizeof(struct iwinfo_assoclist_entry));
1127                 return 0;
1128         }
1129
1130         return -1;
1131 }
1132
1133 static int nl80211_get_txpwrlist_cb(struct nl_msg *msg, void *arg)
1134 {
1135         int *dbm_max = arg;
1136         int ch_cur, ch_cmp, bands_remain, freqs_remain;
1137
1138         struct nlattr **attr = nl80211_parse(msg);
1139         struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
1140         struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
1141         struct nlattr *band, *freq;
1142
1143         static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
1144                 [NL80211_FREQUENCY_ATTR_FREQ]         = { .type = NLA_U32  },
1145                 [NL80211_FREQUENCY_ATTR_DISABLED]     = { .type = NLA_FLAG },
1146                 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
1147                 [NL80211_FREQUENCY_ATTR_NO_IBSS]      = { .type = NLA_FLAG },
1148                 [NL80211_FREQUENCY_ATTR_RADAR]        = { .type = NLA_FLAG },
1149                 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32  },
1150         };
1151
1152         ch_cur = *dbm_max; /* value int* is initialized with channel by caller */
1153         *dbm_max = -1;
1154
1155         nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
1156         {
1157                 nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band),
1158                           nla_len(band), NULL);
1159
1160                 nla_for_each_nested(freq,
1161                         bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
1162                 {
1163                         nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
1164                                 nla_data(freq), nla_len(freq), freq_policy);
1165
1166                         ch_cmp = nl80211_freq2channel(
1167                                 nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]));
1168
1169                         if( (!ch_cur || (ch_cmp == ch_cur)) &&
1170                                 freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] )
1171                         {
1172                                 *dbm_max = (int)(0.01 * nla_get_u32(
1173                                         freqs[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]));
1174
1175                                 break;
1176                         }
1177                 }
1178         }
1179
1180         return NL_SKIP;
1181 }
1182
1183 int nl80211_get_txpwrlist(const char *ifname, char *buf, int *len)
1184 {
1185         int ch_cur;
1186         int dbm_max = -1, dbm_cur, dbm_cnt;
1187         struct nl80211_msg_conveyor *req;
1188         struct iwinfo_txpwrlist_entry entry;
1189
1190         if (nl80211_get_channel(ifname, &ch_cur))
1191                 ch_cur = 0;
1192
1193         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
1194         if (req)
1195         {
1196                 /* initialize the value pointer with channel for callback */
1197                 dbm_max = ch_cur;
1198
1199                 nl80211_cb(req, nl80211_get_txpwrlist_cb, &dbm_max);
1200                 nl80211_send(req);
1201                 nl80211_free(req);
1202         }
1203
1204         if (dbm_max > -1)
1205         {
1206                 for (dbm_cur = 0, dbm_cnt = 0;
1207                      dbm_cur < dbm_max;
1208                      dbm_cur++, dbm_cnt++)
1209                 {
1210                         entry.dbm = dbm_cur;
1211                         entry.mw  = iwinfo_dbm2mw(dbm_cur);
1212
1213                         memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry));
1214                 }
1215
1216                 entry.dbm = dbm_max;
1217                 entry.mw  = iwinfo_dbm2mw(dbm_max);
1218
1219                 memcpy(&buf[dbm_cnt * sizeof(entry)], &entry, sizeof(entry));
1220                 dbm_cnt++;
1221
1222                 *len = dbm_cnt * sizeof(entry);
1223                 return 0;
1224         }
1225
1226         return -1;
1227 }
1228
1229 static void nl80211_get_scancrypto(const char *spec,
1230         struct iwinfo_crypto_entry *c)
1231 {
1232         if (strstr(spec, "WPA") || strstr(spec, "WEP"))
1233         {
1234                 c->enabled = 1;
1235
1236                 if (strstr(spec, "WPA2-") && strstr(spec, "WPA-"))
1237                         c->wpa_version = 3;
1238
1239                 else if (strstr(spec, "WPA2"))
1240                         c->wpa_version = 2;
1241
1242                 else if (strstr(spec, "WPA"))
1243                         c->wpa_version = 1;
1244
1245                 else if (strstr(spec, "WEP"))
1246                         c->auth_algs = IWINFO_AUTH_OPEN | IWINFO_AUTH_SHARED;
1247
1248
1249                 if (strstr(spec, "PSK"))
1250                         c->auth_suites |= IWINFO_KMGMT_PSK;
1251
1252                 if (strstr(spec, "802.1X") || strstr(spec, "EAP"))
1253                         c->auth_suites |= IWINFO_KMGMT_8021x;
1254
1255                 if (strstr(spec, "WPA-NONE"))
1256                         c->auth_suites |= IWINFO_KMGMT_NONE;
1257
1258
1259                 if (strstr(spec, "TKIP"))
1260                         c->pair_ciphers |= IWINFO_CIPHER_TKIP;
1261
1262                 if (strstr(spec, "CCMP"))
1263                         c->pair_ciphers |= IWINFO_CIPHER_CCMP;
1264
1265                 if (strstr(spec, "WEP-40"))
1266                         c->pair_ciphers |= IWINFO_CIPHER_WEP40;
1267
1268                 if (strstr(spec, "WEP-104"))
1269                         c->pair_ciphers |= IWINFO_CIPHER_WEP104;
1270
1271                 c->group_ciphers = c->pair_ciphers;
1272         }
1273         else
1274         {
1275                 c->enabled = 0;
1276         }
1277 }
1278
1279 int nl80211_get_scanlist(const char *ifname, char *buf, int *len)
1280 {
1281         int freq, rssi, qmax, count;
1282         char *res;
1283         char ssid[128] = { 0 };
1284         char bssid[18] = { 0 };
1285         char cipher[256] = { 0 };
1286
1287         /* Got a radioX pseudo interface, find some interface on it or create one */
1288         if (!strncmp(ifname, "radio", 5))
1289         {
1290                 /* Reuse existing interface */
1291                 if ((res = nl80211_phy2ifname(ifname)) != NULL)
1292                 {
1293                         return nl80211_get_scanlist(res, buf, len);
1294                 }
1295
1296                 /* Need to spawn a temporary iface for scanning */
1297                 else if ((res = nl80211_ifadd(ifname)) != NULL)
1298                 {
1299                         count = nl80211_get_scanlist(res, buf, len);
1300                         nl80211_ifdel(res);
1301                         return count;
1302                 }
1303         }
1304
1305         struct iwinfo_scanlist_entry *e = (struct iwinfo_scanlist_entry *)buf;
1306
1307         /* WPA supplicant */
1308         if ((res = nl80211_wpactl_info(ifname, "SCAN", "CTRL-EVENT-SCAN-RESULTS")))
1309         {
1310                 if ((res = nl80211_wpactl_info(ifname, "SCAN_RESULTS", NULL)))
1311                 {
1312                         nl80211_get_quality_max(ifname, &qmax);
1313
1314                         /* skip header line */
1315                         while( *res++ != '\n' );
1316
1317                         count = 0;
1318
1319                         while( sscanf(res, "%17s %d %d %255s%*[ \t]%127[^\n]\n",
1320                                       bssid, &freq, &rssi, cipher, ssid) > 0 )
1321                         {
1322                                 /* BSSID */
1323                                 e->mac[0] = strtol(&bssid[0],  NULL, 16);
1324                                 e->mac[1] = strtol(&bssid[3],  NULL, 16);
1325                                 e->mac[2] = strtol(&bssid[6],  NULL, 16);
1326                                 e->mac[3] = strtol(&bssid[9],  NULL, 16);
1327                                 e->mac[4] = strtol(&bssid[12], NULL, 16);
1328                                 e->mac[5] = strtol(&bssid[15], NULL, 16);
1329
1330                                 /* SSID */
1331                                 memcpy(e->ssid, ssid,
1332                                         min(strlen(ssid), sizeof(e->ssid) - 1));
1333
1334                                 /* Mode (assume master) */
1335                                 sprintf((char *)e->mode, "Master");
1336
1337                                 /* Channel */
1338                                 e->channel = nl80211_freq2channel(freq);
1339
1340                                 /* Signal */
1341                                 e->signal = rssi;
1342
1343                                 /* Quality */
1344                                 if (rssi < 0)
1345                                 {
1346                                         /* The cfg80211 wext compat layer assumes a signal range
1347                                          * of -110 dBm to -40 dBm, the quality value is derived
1348                                          * by adding 110 to the signal level */
1349                                         if (rssi < -110)
1350                                                 rssi = -110;
1351                                         else if (rssi > -40)
1352                                                 rssi = -40;
1353
1354                                         e->quality = (rssi + 110);
1355                                 }
1356                                 else
1357                                 {
1358                                         e->quality = rssi;
1359                                 }
1360
1361                                 /* Max. Quality */
1362                                 e->quality_max = qmax;
1363
1364                                 /* Crypto */
1365                                 nl80211_get_scancrypto(cipher, &e->crypto);
1366
1367                                 /* advance to next line */
1368                                 while( *res && *res++ != '\n' );
1369
1370                                 count++;
1371                                 e++;
1372
1373                                 memset(ssid, 0, sizeof(ssid));
1374                                 memset(bssid, 0, sizeof(bssid));
1375                                 memset(cipher, 0, sizeof(cipher));
1376                         }
1377
1378                         *len = count * sizeof(struct iwinfo_scanlist_entry);
1379                         return 0;
1380                 }
1381         }
1382
1383         /* AP scan */
1384         else
1385         {
1386                 /* Got a temp interface, don't create yet another one */
1387                 if (!strncmp(ifname, "tmp.", 4))
1388                 {
1389                         if (!iwinfo_ifup(ifname))
1390                                 return -1;
1391
1392                         wext_get_scanlist(ifname, buf, len);
1393                         iwinfo_ifdown(ifname);
1394                         return 0;
1395                 }
1396
1397                 /* Spawn a new scan interface */
1398                 else
1399                 {
1400                         if (!(res = nl80211_ifadd(ifname)))
1401                                 goto out;
1402
1403                         if (!iwinfo_ifmac(res))
1404                                 goto out;
1405
1406                         /* if we can take the new interface up, the driver supports an
1407                          * additional interface and there's no need to tear down the ap */
1408                         if (iwinfo_ifup(res))
1409                         {
1410                                 wext_get_scanlist(res, buf, len);
1411                                 iwinfo_ifdown(res);
1412                         }
1413
1414                         /* driver cannot create secondary interface, take down ap
1415                          * during scan */
1416                         else if (iwinfo_ifdown(ifname) && iwinfo_ifup(res))
1417                         {
1418                                 wext_get_scanlist(res, buf, len);
1419                                 iwinfo_ifdown(res);
1420                                 iwinfo_ifup(ifname);
1421                                 nl80211_hostapd_hup(ifname);
1422                         }
1423
1424                 out:
1425                         nl80211_ifdel(res);
1426                         return 0;
1427                 }
1428         }
1429
1430         return -1;
1431 }
1432
1433 static int nl80211_get_freqlist_cb(struct nl_msg *msg, void *arg)
1434 {
1435         int bands_remain, freqs_remain;
1436
1437         struct nl80211_array_buf *arr = arg;
1438         struct iwinfo_freqlist_entry *e = arr->buf;
1439
1440         struct nlattr **attr = nl80211_parse(msg);
1441         struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
1442         struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
1443         struct nlattr *band, *freq;
1444
1445         static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
1446                 [NL80211_FREQUENCY_ATTR_FREQ]         = { .type = NLA_U32  },
1447                 [NL80211_FREQUENCY_ATTR_DISABLED]     = { .type = NLA_FLAG },
1448                 [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
1449                 [NL80211_FREQUENCY_ATTR_NO_IBSS]      = { .type = NLA_FLAG },
1450                 [NL80211_FREQUENCY_ATTR_RADAR]        = { .type = NLA_FLAG },
1451                 [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32  },
1452         };
1453
1454         nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
1455         {
1456                 nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band),
1457                         nla_len(band), NULL);
1458
1459                 nla_for_each_nested(freq,
1460                         bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
1461                 {
1462                         nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
1463                                 nla_data(freq), nla_len(freq), NULL);
1464
1465                         if( !freqs[NL80211_FREQUENCY_ATTR_FREQ] ||
1466                                 freqs[NL80211_FREQUENCY_ATTR_DISABLED] )
1467                                 continue;
1468
1469                         e->mhz = nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]);
1470                         e->channel = nl80211_freq2channel(e->mhz);
1471
1472                         e->restricted = (
1473                                 freqs[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] ||
1474                                 freqs[NL80211_FREQUENCY_ATTR_NO_IBSS]      ||
1475                                 freqs[NL80211_FREQUENCY_ATTR_RADAR]
1476                         ) ? 1 : 0;
1477
1478                         e++;
1479                         arr->count++;
1480                 }
1481         }
1482
1483         return NL_SKIP;
1484 }
1485
1486 int nl80211_get_freqlist(const char *ifname, char *buf, int *len)
1487 {
1488         struct nl80211_msg_conveyor *req;
1489         struct nl80211_array_buf arr = { .buf = buf, .count = 0 };
1490
1491         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
1492         if (req)
1493         {
1494                 nl80211_cb(req, nl80211_get_freqlist_cb, &arr);
1495                 nl80211_send(req);
1496                 nl80211_free(req);
1497         }
1498
1499         if (arr.count > 0)
1500         {
1501                 *len = arr.count * sizeof(struct iwinfo_freqlist_entry);
1502                 return 0;
1503         }
1504
1505         return -1;
1506 }
1507
1508 static int nl80211_get_country_cb(struct nl_msg *msg, void *arg)
1509 {
1510         char *buf = arg;
1511         struct nlattr **attr = nl80211_parse(msg);
1512
1513         if (attr[NL80211_ATTR_REG_ALPHA2])
1514                 memcpy(buf, nla_data(attr[NL80211_ATTR_REG_ALPHA2]), 2);
1515         else
1516                 buf[0] = 0;
1517
1518         return NL_SKIP;
1519 }
1520
1521 int nl80211_get_country(const char *ifname, char *buf)
1522 {
1523         int rv = -1;
1524         struct nl80211_msg_conveyor *req;
1525
1526         req = nl80211_msg(ifname, NL80211_CMD_GET_REG, 0);
1527         if (req)
1528         {
1529                 nl80211_cb(req, nl80211_get_country_cb, buf);
1530                 nl80211_send(req);
1531                 nl80211_free(req);
1532
1533                 if (buf[0])
1534                         rv = 0;
1535         }
1536
1537         return rv;
1538 }
1539
1540 int nl80211_get_countrylist(const char *ifname, char *buf, int *len)
1541 {
1542         int i, count;
1543         struct iwinfo_iso3166_label *l;
1544         struct iwinfo_country_entry *e = (struct iwinfo_country_entry *)buf;
1545
1546         for( l = ISO3166_Names, count = 0; l->iso3166; l++, e++, count++ )
1547         {
1548                 e->iso3166 = l->iso3166;
1549                 e->ccode[0] = (l->iso3166 / 256);
1550                 e->ccode[1] = (l->iso3166 % 256);
1551         }
1552
1553         *len = (count * sizeof(struct iwinfo_country_entry));
1554         return 0;
1555 }
1556
1557 static int nl80211_get_hwmodelist_cb(struct nl_msg *msg, void *arg)
1558 {
1559         int *modes = arg;
1560         int bands_remain, freqs_remain;
1561         uint16_t caps = 0;
1562         struct nlattr **attr = nl80211_parse(msg);
1563         struct nlattr *bands[NL80211_BAND_ATTR_MAX + 1];
1564         struct nlattr *freqs[NL80211_FREQUENCY_ATTR_MAX + 1];
1565         struct nlattr *band, *freq;
1566
1567         *modes = 0;
1568
1569         if (attr[NL80211_ATTR_WIPHY_BANDS])
1570         {
1571                 nla_for_each_nested(band, attr[NL80211_ATTR_WIPHY_BANDS], bands_remain)
1572                 {
1573                         nla_parse(bands, NL80211_BAND_ATTR_MAX, nla_data(band),
1574                                 nla_len(band), NULL);
1575
1576                         if (bands[NL80211_BAND_ATTR_HT_CAPA])
1577                                 caps = nla_get_u16(bands[NL80211_BAND_ATTR_HT_CAPA]);
1578
1579                         /* Treat any nonzero capability as 11n */
1580                         if (caps > 0)
1581                                 *modes |= IWINFO_80211_N;
1582
1583                         nla_for_each_nested(freq,
1584                                 bands[NL80211_BAND_ATTR_FREQS], freqs_remain)
1585                         {
1586                                 nla_parse(freqs, NL80211_FREQUENCY_ATTR_MAX,
1587                                         nla_data(freq), nla_len(freq), NULL);
1588
1589                                 if (!freqs[NL80211_FREQUENCY_ATTR_FREQ])
1590                                         continue;
1591
1592                                 if (nla_get_u32(freqs[NL80211_FREQUENCY_ATTR_FREQ]) < 2485)
1593                                 {
1594                                         *modes |= IWINFO_80211_B;
1595                                         *modes |= IWINFO_80211_G;
1596                                 }
1597                                 else
1598                                 {
1599                                         *modes |= IWINFO_80211_A;
1600                                 }
1601                         }
1602                 }
1603         }
1604
1605         return NL_SKIP;
1606 }
1607
1608 int nl80211_get_hwmodelist(const char *ifname, int *buf)
1609 {
1610         struct nl80211_msg_conveyor *req;
1611
1612         req = nl80211_msg(ifname, NL80211_CMD_GET_WIPHY, 0);
1613         if (req)
1614         {
1615                 nl80211_cb(req, nl80211_get_hwmodelist_cb, buf);
1616                 nl80211_send(req);
1617                 nl80211_free(req);
1618         }
1619
1620         return *buf ? 0 : -1;
1621 }
1622
1623 int nl80211_get_mbssid_support(const char *ifname, int *buf)
1624 {
1625         /* Test whether we can create another interface */
1626         char *nif = nl80211_ifadd(ifname);
1627
1628         if (nif)
1629         {
1630                 *buf = (iwinfo_ifmac(nif) && iwinfo_ifup(nif));
1631
1632                 iwinfo_ifdown(nif);
1633                 nl80211_ifdel(nif);
1634
1635                 return 0;
1636         }
1637
1638         return -1;
1639 }