source: trunk/package/iwinfo/src/iwinfo_nl80211.c @ 29403

Last change on this file since 29403 was 29403, checked in by jow, 5 years ago

[package] add libiwinfo (moved from LuCI trunk)

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