root/luci/trunk/contrib/package/iwinfo/src/iwinfo_nl80211.c @ 6606

Revision 6606, 33.2 KB (checked in by jow, 2 years ago)

libiwinfo: fix scan issues in nl80211, encryption detection fixes for madwifi

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