Root/package/network/utils/iwinfo/src/iwinfo_nl80211.c

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

Archive Download this file



interactive