source: src/router/services/tools/site_survey_mac80211.c @ 32668

Last change on this file since 32668 was 32668, checked in by brainslayer, 10 days ago

fixes

File size: 39.0 KB
Line 
1/*
2 * mac80211site_survey.c
3 * Copyright (C) 2011 Christian Scheele <chris@dd-wrt.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 */
14
15/*
16 * mostly copied from iw (scan.c, utils.c, iw.h) thanks that this exists:
17 * Copyright (c) 2007, 2008    Johannes Berg
18 * Copyright (c) 2007      Andy Lutomirski
19 * Copyright (c) 2007      Mike Kershaw
20 * Copyright (c) 2008-2009     Luis R. Rodriguez
21 *
22 * Permission to use, copy, modify, and/or distribute this software for any
23 * purpose with or without fee is hereby granted, provided that the above
24 * copyright notice and this permission notice appear in all copies.
25 *
26 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
27 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
28 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
29 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
30 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
31 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
32 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
33 */
34
35#include <sys/types.h>
36#include <sys/socket.h>
37#include <net/if.h>
38#include <stdint.h>
39#include <unistd.h>
40#include <stdio.h>
41#include <fcntl.h>
42#include <stdbool.h>
43#include <glob.h>
44
45#include "wlutils.h"
46#include "unl.h"
47
48#include <stdio.h>
49#include <string.h>
50#include <fcntl.h>
51#include <errno.h>
52#include <signal.h>
53#include <sys/stat.h>
54#include <stdlib.h>
55#include <unistd.h>
56#include <sys/wait.h>
57#include <ctype.h>
58#include <bcmnvram.h>
59#include <shutils.h>
60#include <wlutils.h>
61
62#include "linux/nl80211.h"
63
64#include "mac80211site_survey.h"
65
66extern struct unl unl;
67extern bool bunl;
68
69static void __attribute__((constructor)) mac80211_init(void)
70{
71        if (!bunl) {
72                unl_genl_init(&unl, "nl80211");
73                bunl = 1;
74        }
75
76}
77
78static int sscount = 0;
79static int rate_count = 0;
80
81static int noise[6075];
82
83static struct scan_params scan_params;
84
85struct ie_print {
86        const char *name;
87        void (*print) (const uint8_t type, uint8_t len, const uint8_t * data);
88        uint8_t minlen, maxlen;
89        uint8_t flags;
90};
91static void print_ssid(const uint8_t type, uint8_t len, const uint8_t * data);
92static void print_supprates(const uint8_t type, uint8_t len, const uint8_t * data);
93static void print_ds(const uint8_t type, uint8_t len, const uint8_t * data);
94static void print_tim(const uint8_t type, uint8_t len, const uint8_t * data);
95static void print_country(const uint8_t type, uint8_t len, const uint8_t * data);
96static void print_powerconstraint(const uint8_t type, uint8_t len, const uint8_t * data);
97static void print_rsn(const uint8_t type, uint8_t len, const uint8_t * data);
98static void print_erp(const uint8_t type, uint8_t len, const uint8_t * data);
99static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t * data);
100static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t * data);
101static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t * data);
102static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t * data);
103static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t * data);
104static int print_bss_handler(struct nl_msg *msg, void *arg);
105static void print_rsn_ie(const char *defcipher, const char *defauth, uint8_t len, const uint8_t * data);
106static void print_ies(unsigned char *ie, int ielen, bool unknown, enum print_ie_type ptype);
107
108static void tab_on_first(bool * first);
109
110static const struct ie_print ieprinters[] = {
111        [0] = {"SSID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK),},
112        [1] = {"Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN),},
113        [3] = {"DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN),},
114        [5] = {"TIM", print_tim, 4, 255, BIT(PRINT_SCAN),},
115        [7] = {"Country", print_country, 3, 255, BIT(PRINT_SCAN),},
116        [32] = {"Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN),},
117        [42] = {"ERP", print_erp, 1, 255, BIT(PRINT_SCAN),},
118        [45] = {"HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN),},
119        [61] = {"HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN),},
120        [48] = {"RSN", print_rsn, 2, 255, BIT(PRINT_SCAN),},
121        [50] = {"Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN),},
122        [191] = {"VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN),},
123        [192] = {"VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN),},
124        [127] = {"Extended capabilities", print_capabilities, 0, 255,
125                 BIT(PRINT_SCAN),},
126};
127
128static void fillENC(const char *text, const char *space)
129{
130        char *buf;
131        buf = site_survey_lists[sscount].ENCINFO;
132        if (strstr(buf, text))
133                return;
134        buf += strlen(buf);
135        buf += sprintf(buf, "%s%s", text, space);
136}
137
138static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
139        [NL80211_SURVEY_INFO_FREQUENCY] = {.type = NLA_U32},
140        [NL80211_SURVEY_INFO_NOISE] = {.type = NLA_U8},
141        [NL80211_SURVEY_INFO_CHANNEL_TIME] = {.type = NLA_U64},
142        [NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY] = {.type = NLA_U64},
143};
144
145static int parse_survey(struct nl_msg *msg, struct nlattr **sinfo)
146{
147        struct nlattr *tb[NL80211_ATTR_MAX + 1];
148        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
149
150        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
151
152        if (!tb[NL80211_ATTR_SURVEY_INFO])
153                return -1;
154
155        if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX, tb[NL80211_ATTR_SURVEY_INFO], survey_policy))
156                return -1;
157
158        if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
159                return -1;
160
161        return 0;
162}
163
164static int cb_survey(struct nl_msg *msg, void *data)
165{
166        struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
167        int freq;
168
169        if (parse_survey(msg, sinfo))
170                goto out;
171
172        freq = nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]);
173        if (sinfo[NL80211_SURVEY_INFO_NOISE]) {
174                int8_t lnoise = nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
175                noise[freq] = lnoise;
176                // int channel=ieee80211_mhz2ieee(freq);
177                // noise[channel] = lnoise;
178        }
179
180out:
181        return NL_SKIP;
182}
183
184static void lgetnoise(int wdev)
185{
186        static struct nl_msg *surveymsg;
187
188        surveymsg = unl_genl_msg(&unl, NL80211_CMD_GET_SURVEY, true);
189        NLA_PUT_U32(surveymsg, NL80211_ATTR_IFINDEX, wdev);
190        unl_genl_request(&unl, surveymsg, cb_survey, NULL);
191        return;
192
193nla_put_failure:
194        nlmsg_free(surveymsg);
195        return;
196}
197
198static __u32 compute_ampdu_length(__u8 exponent)
199{
200        switch (exponent) {
201        case 0:
202                return 8191;    /* (2 ^(13 + 0)) -1 */
203        case 1:
204                return 16383;   /* (2 ^(13 + 1)) -1 */
205        case 2:
206                return 32767;   /* (2 ^(13 + 2)) -1 */
207        case 3:
208                return 65535;   /* (2 ^(13 + 3)) -1 */
209        default:
210                return 0;
211        }
212}
213
214static const char *print_ampdu_space(__u8 space)
215{
216        switch (space) {
217        case 0:
218                return "No restriction";
219        case 1:
220                return "1/4 usec";
221        case 2:
222                return "1/2 usec";
223        case 3:
224                return "1 usec";
225        case 4:
226                return "2 usec";
227        case 5:
228                return "4 usec";
229        case 6:
230                return "8 usec";
231        case 7:
232                return "16 usec";
233        default:
234                return "BUG (spacing more than 3 bits!)";
235        }
236}
237
238void print_ampdu_length(__u8 exponent)
239{
240        __u32 max_ampdu_length;
241
242        max_ampdu_length = compute_ampdu_length(exponent);
243
244        if (max_ampdu_length) {
245                printf("\t\tMaximum RX AMPDU length %d bytes (exponent: 0x0%02x)\n", max_ampdu_length, exponent);
246        } else {
247                printf("\t\tMaximum RX AMPDU length: unrecognized bytes " "(exponent: %d)\n", exponent);
248        }
249}
250
251void print_ampdu_spacing(__u8 spacing)
252{
253        printf("\t\tMinimum RX AMPDU time spacing: %s (0x%02x)\n", print_ampdu_space(spacing), spacing);
254}
255
256static void print_mcs_index(const __u8 *mcs)
257{
258        unsigned int mcs_bit, prev_bit = -2, prev_cont = 0;
259
260        for (mcs_bit = 0; mcs_bit <= 76; mcs_bit++) {
261                unsigned int mcs_octet = mcs_bit / 8;
262                unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8;
263                bool mcs_rate_idx_set;
264
265                mcs_rate_idx_set = ! !(mcs[mcs_octet] & MCS_RATE_BIT);
266
267                if (!mcs_rate_idx_set)
268                        continue;
269
270                if (prev_bit != mcs_bit - 1) {
271                        prev_cont = 0;
272                } else if (!prev_cont) {
273                        prev_cont = 1;
274                }
275                prev_bit = mcs_bit;
276        }
277
278        if (prev_cont) {
279                if (prev_bit == 7)
280                        rate_count = 150;
281                if (prev_bit == 15)
282                        rate_count = 300;
283                if (prev_bit == 23)
284                        rate_count = 450;
285                if (prev_bit == 31)
286                        rate_count = 600;
287        }
288}
289
290static void print_ht_mcs(const __u8 *mcs)
291{
292        /* As defined in 7.3.2.57.4 Supported MCS Set field */
293        unsigned int tx_max_num_spatial_streams, max_rx_supp_data_rate;
294        bool tx_mcs_set_defined, tx_mcs_set_equal, tx_unequal_modulation;
295
296        max_rx_supp_data_rate = ((mcs[10] >> 8) & ((mcs[11] & 0x3) << 8));
297        tx_mcs_set_defined = ! !(mcs[12] & (1 << 0));
298        tx_mcs_set_equal = !(mcs[12] & (1 << 1));
299        tx_max_num_spatial_streams = ((mcs[12] >> 2) & 3) + 1;
300        tx_unequal_modulation = ! !(mcs[12] & (1 << 4));
301
302        if (max_rx_supp_data_rate)
303                printf("\t\tHT Max RX data rate: %d Mbps\n", max_rx_supp_data_rate);
304        /* XXX: else see 9.6.0e.5.3 how to get this I think */
305
306        if (tx_mcs_set_defined) {
307                if (tx_mcs_set_equal) {
308                        printf("\t\tHT TX/RX MCS rate indexes supported:");
309                        print_mcs_index(mcs);
310                } else {
311                        printf("\t\tHT RX MCS rate indexes supported:");
312                        print_mcs_index(mcs);
313
314                        if (tx_unequal_modulation)
315                                printf("\t\tTX unequal modulation supported\n");
316                        else
317                                printf("\t\tTX unequal modulation not supported\n");
318
319                        printf("\t\tHT TX Max spatial streams: %d\n", tx_max_num_spatial_streams);
320
321                        printf("\t\tHT TX MCS rate indexes supported may differ\n");
322                }
323        } else {
324                printf("\t\tHT RX MCS rate indexes supported:");
325                print_mcs_index(mcs);
326                printf("\t\tHT TX MCS rate indexes are undefined\n");
327        }
328}
329
330static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t * data)
331{
332        fillENC("WPA", " ");
333        print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
334}
335
336static bool print_wifi_wmm_param(const uint8_t * data, uint8_t len)
337{
338        int i;
339        static const char *aci_tbl[] = { "BE", "BK", "VI", "VO" };
340
341        if (len < 19)
342                goto invalid;
343
344        if (data[0] != 1) {
345                printf("Parameter: not version 1: ");
346                return false;
347        }
348
349        printf("\t * Parameter version 1");
350
351        data++;
352
353        if (data[0] & 0x80)
354                printf("\n\t\t * u-APSD");
355
356        data += 2;
357
358        for (i = 0; i < 4; i++) {
359                printf("\n\t\t * %s:", aci_tbl[(data[0] >> 5) & 3]);
360                if (data[4] & 0x10)
361                        printf(" acm");
362                printf(" CW %d-%d", (1 << (data[1] & 0xf)) - 1, (1 << (data[1] >> 4)) - 1);
363                printf(", AIFSN %d", data[0] & 0xf);
364                if (data[2] | data[3])
365                        printf(", TXOP %d usec", (data[2] + (data[3] << 8)) * 32);
366                data += 4;
367        }
368
369        printf("\n");
370        return true;
371
372invalid:
373        printf("invalid: ");
374        return false;
375}
376
377static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t * data)
378{
379        int i;
380
381        switch (data[0]) {
382        case 0x00:
383                printf(" information:");
384                break;
385        case 0x01:
386                if (print_wifi_wmm_param(data + 1, len - 1))
387                        return;
388                break;
389        default:
390                printf(" type %d:", data[0]);
391                break;
392        }
393
394        for (i = 1; i < len; i++)
395                printf(" %.02x", data[i]);
396        printf("\n");
397}
398
399static const char *wifi_wps_dev_passwd_id(uint16_t id)
400{
401        switch (id) {
402        case 0:
403                return "Default (PIN)";
404        case 1:
405                return "User-specified";
406        case 2:
407                return "Machine-specified";
408        case 3:
409                return "Rekey";
410        case 4:
411                return "PushButton";
412        case 5:
413                return "Registrar-specified";
414        default:
415                return "??";
416        }
417}
418
419static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t * data)
420{
421        bool first = true;
422        __u16 subtype, sublen;
423
424        while (len >= 4) {
425                subtype = (data[0] << 8) + data[1];
426                sublen = (data[2] << 8) + data[3];
427                if (sublen > len)
428                        break;
429
430                switch (subtype) {
431                case 0x104a:
432                        tab_on_first(&first);
433                        printf("\t * Version: %d.%d\n", data[4] >> 4, data[4] & 0xF);
434                        break;
435                case 0x1011:
436                        tab_on_first(&first);
437                        printf("\t * Device name: %.*s\n", sublen, data + 4);
438                        break;
439                case 0x1012:{
440                                uint16_t id;
441                                tab_on_first(&first);
442                                if (sublen != 2) {
443                                        printf("\t * Device Password ID: (invalid " "length %d)\n", sublen);
444                                        break;
445                                }
446                                id = data[4] << 8 | data[5];
447                                printf("\t * Device Password ID: %u (%s)\n", id, wifi_wps_dev_passwd_id(id));
448                                break;
449                        }
450                case 0x1021:
451                        tab_on_first(&first);
452                        printf("\t * Manufacturer: %.*s\n", sublen, data + 4);
453                        break;
454                case 0x1023:
455                        tab_on_first(&first);
456                        printf("\t * Model: %.*s\n", sublen, data + 4);
457                        break;
458                case 0x1024:
459                        tab_on_first(&first);
460                        printf("\t * Model Number: %.*s\n", sublen, data + 4);
461                        break;
462                case 0x103b:{
463                                __u8 val = data[4];
464                                tab_on_first(&first);
465                                printf("\t * Response Type: %d%s\n", val, val == 3 ? " (AP)" : "");
466                                break;
467                        }
468                case 0x103c:{
469                                __u8 val = data[4];
470                                tab_on_first(&first);
471                                printf("\t * RF Bands: 0x%x\n", val);
472                                break;
473                        }
474                case 0x1041:{
475                                __u8 val = data[4];
476                                tab_on_first(&first);
477                                printf("\t * Selected Registrar: 0x%x\n", val);
478                                break;
479                        }
480                case 0x1042:
481                        tab_on_first(&first);
482                        printf("\t * Serial Number: %.*s\n", sublen, data + 4);
483                        break;
484                case 0x1044:{
485                                __u8 val = data[4];
486                                tab_on_first(&first);
487                                printf("\t * Wi-Fi Protected Setup State: %d%s%s\n", val, val == 1 ? " (Unconfigured)" : "", val == 2 ? " (Configured)" : "");
488                                break;
489                        }
490                case 0x1054:{
491                                tab_on_first(&first);
492                                if (sublen != 8) {
493                                        printf("\t * Primary Device Type: (invalid " "length %d)\n", sublen);
494                                        break;
495                                }
496                                printf("\t * Primary Device Type: " "%u-%02x%02x%02x%02x-%u\n", data[4] << 8 | data[5], data[6], data[7], data[8], data[9], data[10] << 8 | data[11]);
497                                break;
498                        }
499                case 0x1057:{
500                                __u8 val = data[4];
501                                tab_on_first(&first);
502                                printf("\t * AP setup locked: 0x%.2x\n", val);
503                                break;
504                        }
505                case 0x1008:
506                case 0x1053:{
507                                __u16 meth = (data[4] << 8) + data[5];
508                                bool comma = false;
509                                tab_on_first(&first);
510                                printf("\t * %sConfig methods:", subtype == 0x1053 ? "Selected Registrar " : "");
511#define T(bit, name) do {               \
512        if (meth & (1<<bit)) {          \
513                if (comma)              \
514                        printf(",");    \
515                comma = true;           \
516                printf(" " name);       \
517        } } while (0)
518                                T(0, "USB");
519                                T(1, "Ethernet");
520                                T(2, "Label");
521                                T(3, "Display");
522                                T(4, "Ext. NFC");
523                                T(5, "Int. NFC");
524                                T(6, "NFC Intf.");
525                                T(7, "PBC");
526                                T(8, "Keypad");
527                                printf("\n");
528                                break;
529#undef T
530                        }
531                default:{
532                                const __u8 *subdata = data + 4;
533                                __u16 tmplen = sublen;
534
535                                tab_on_first(&first);
536                                printf("\t * Unknown TLV (%#.4x, %d bytes):", subtype, tmplen);
537                                while (tmplen) {
538                                        printf(" %.2x", *subdata);
539                                        subdata++;
540                                        tmplen--;
541                                }
542                                printf("\n");
543                                break;
544                        }
545                }
546
547                data += sublen + 4;
548                len -= sublen + 4;
549        }
550
551        if (len != 0) {
552                printf("\t\t * bogus tail data (%d):", len);
553                while (len) {
554                        printf(" %.2x", *data);
555                        data++;
556                        len--;
557                }
558                printf("\n");
559        }
560}
561
562static void tab_on_first(bool * first)
563{
564        if (!*first)
565                printf("\t");
566        else
567                *first = false;
568}
569
570static void print_ssid(const uint8_t type, uint8_t len, const uint8_t * data)
571{
572        memcpy(site_survey_lists[sscount].SSID, data, len);
573}
574
575static int print_bss_handler(struct nl_msg *msg, void *arg)
576{
577        struct nlattr *tb[NL80211_ATTR_MAX + 1];
578        struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
579        struct nlattr *bss[NL80211_BSS_MAX + 1];
580        char mac_addr[20], dev[20];
581        static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
582                [NL80211_BSS_TSF] = {.type = NLA_U64},
583                [NL80211_BSS_FREQUENCY] = {.type = NLA_U32},
584                [NL80211_BSS_BSSID] = {},
585                [NL80211_BSS_BEACON_INTERVAL] = {.type = NLA_U16},
586                [NL80211_BSS_CAPABILITY] = {.type = NLA_U16},
587                [NL80211_BSS_INFORMATION_ELEMENTS] = {},
588                [NL80211_BSS_SIGNAL_MBM] = {.type = NLA_U32},
589                [NL80211_BSS_SIGNAL_UNSPEC] = {.type = NLA_U8},
590                [NL80211_BSS_STATUS] = {.type = NLA_U32},
591                [NL80211_BSS_SEEN_MS_AGO] = {.type = NLA_U32},
592                [NL80211_BSS_BEACON_IES] = {},
593        };
594        struct scan_params *params = arg;
595        rate_count = 0;
596        bzero(site_survey_lists[sscount].ENCINFO, 128);
597        int show = params->show_both_ie_sets ? 2 : 1;
598
599        nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
600
601        if (!tb[NL80211_ATTR_BSS]) {
602                fprintf(stderr, "bss info missing!\n");
603                return NL_SKIP;
604        }
605        if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS], bss_policy)) {
606                fprintf(stderr, "failed to parse nested attributes!\n");
607                return NL_SKIP;
608        }
609
610        if (!bss[NL80211_BSS_BSSID])
611                return NL_SKIP;
612        ether_etoa(nla_data(bss[NL80211_BSS_BSSID]), mac_addr);
613        if_indextoname(nla_get_u32(tb[NL80211_ATTR_IFINDEX]), dev);
614        printf("BSS %s (on %s)", mac_addr, dev);
615        strcpy(site_survey_lists[sscount].BSSID, mac_addr);
616
617        if (bss[NL80211_BSS_STATUS]) {
618                switch (nla_get_u32(bss[NL80211_BSS_STATUS])) {
619                case NL80211_BSS_STATUS_AUTHENTICATED:
620                        printf(" -- authenticated");
621                        break;
622                case NL80211_BSS_STATUS_ASSOCIATED:
623                        printf(" -- associated");
624                        break;
625                case NL80211_BSS_STATUS_IBSS_JOINED:
626                        printf(" -- joined");
627                        break;
628                default:
629                        printf(" -- unknown status: %d", nla_get_u32(bss[NL80211_BSS_STATUS]));
630                        break;
631                }
632        }
633        printf("\n");
634
635        if (bss[NL80211_BSS_TSF]) {
636                unsigned long long tsf;
637                tsf = (unsigned long long)nla_get_u64(bss[NL80211_BSS_TSF]);
638                printf("\tTSF: %llu usec (%llud, %.2lld:%.2llu:%.2llu)\n", tsf, tsf / 1000 / 1000 / 60 / 60 / 24, (tsf / 1000 / 1000 / 60 / 60) % 24, (tsf / 1000 / 1000 / 60) % 60, (tsf / 1000 / 1000) % 60);
639        }
640        if (bss[NL80211_BSS_FREQUENCY]) {
641                printf("\tfreq: %d\n", nla_get_u32(bss[NL80211_BSS_FREQUENCY]));
642                site_survey_lists[sscount].frequency = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
643        }
644        if (bss[NL80211_BSS_BEACON_INTERVAL]) {
645                printf("\tbeacon interval: %d\n", nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]));
646                site_survey_lists[sscount].beacon_period = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
647        }
648        if (bss[NL80211_BSS_CAPABILITY]) {
649                __u16 capa = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
650                site_survey_lists[sscount].capability = capa;
651                printf("\tcapability:");
652                if (capa & WLAN_CAPABILITY_ESS)
653                        printf(" ESS");
654                if (capa & WLAN_CAPABILITY_IBSS)
655                        printf(" IBSS");
656                if (capa & WLAN_CAPABILITY_PRIVACY)
657                        printf(" Privacy");
658                if (capa & WLAN_CAPABILITY_SHORT_PREAMBLE)
659                        printf(" ShortPreamble");
660                if (capa & WLAN_CAPABILITY_PBCC)
661                        printf(" PBCC");
662                if (capa & WLAN_CAPABILITY_CHANNEL_AGILITY)
663                        printf(" ChannelAgility");
664                if (capa & WLAN_CAPABILITY_SPECTRUM_MGMT)
665                        printf(" SpectrumMgmt");
666                if (capa & WLAN_CAPABILITY_QOS)
667                        printf(" QoS");
668                if (capa & WLAN_CAPABILITY_SHORT_SLOT_TIME)
669                        printf(" ShortSlotTime");
670                if (capa & WLAN_CAPABILITY_APSD)
671                        printf(" APSD");
672                if (capa & WLAN_CAPABILITY_DSSS_OFDM)
673                        printf(" DSSS-OFDM");
674                printf(" (0x%.4x)\n", capa);
675        }
676        if (bss[NL80211_BSS_SIGNAL_MBM]) {
677                int s = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
678                printf("\tsignal: %d.%.2d dBm\n", s / 100, s % 100);
679                site_survey_lists[sscount].RSSI = s / 100;
680        }
681        if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
682                unsigned char s = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
683                printf("\tsignal: %d/100\n", s);
684        }
685        if (bss[NL80211_BSS_SEEN_MS_AGO]) {
686                int age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
687                printf("\tlast seen: %d ms ago\n", age);
688        }
689
690        if (bss[NL80211_BSS_INFORMATION_ELEMENTS] && show--) {
691                if (bss[NL80211_BSS_BEACON_IES])
692                        printf("\tInformation elements from Probe Response " "frame:\n");
693                print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]), nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]), params->unknown, params->type);
694        }
695        if (bss[NL80211_BSS_BEACON_IES] && show--) {
696                printf("\tInformation elements from Beacon frame:\n");
697                print_ies(nla_data(bss[NL80211_BSS_BEACON_IES]), nla_len(bss[NL80211_BSS_BEACON_IES]), params->unknown, params->type);
698        }
699        site_survey_lists[sscount].rate_count = rate_count;
700        int freq = site_survey_lists[sscount].frequency;
701        site_survey_lists[sscount].phy_noise = noise[freq];
702        if ((site_survey_lists[sscount].channel & 0xff) == 0) {
703                site_survey_lists[sscount].channel |= (ieee80211_mhz2ieee(site_survey_lists[sscount].frequency) & 0xff);
704        }
705        sscount++;
706
707        return NL_SKIP;
708}
709
710static const char *country_env_str(char environment)
711{
712        switch (environment) {
713        case 'I':
714                return "Indoor only";
715        case 'O':
716                return "Outdoor only";
717        case ' ':
718                return "Indoor/Outdoor";
719        default:
720                return "bogus";
721        }
722}
723
724static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len, const uint8_t * data)
725{
726        int i;
727
728        if (!p->print)
729                return;
730
731        printf("\t%s:", p->name);
732        if (len < p->minlen || len > p->maxlen) {
733                if (len > 1) {
734                        printf(" <invalid: %d bytes:", len);
735                        for (i = 0; i < len; i++)
736                                printf(" %.02x", data[i]);
737                        printf(">\n");
738                } else if (len)
739                        printf(" <invalid: 1 byte: %.02x>\n", data[0]);
740                else
741                        printf(" <invalid: no data>\n");
742                return;
743        }
744
745        p->print(type, len, data);
746}
747
748static const struct ie_print wifiprinters[] = {
749        [1] = {"WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN),},
750        [2] = {"WMM", print_wifi_wmm, 1, 255, BIT(PRINT_SCAN),},
751        [4] = {"WPS", print_wifi_wps, 0, 255, BIT(PRINT_SCAN),},
752};
753
754static void print_vendor(unsigned char len, unsigned char *data, bool unknown, enum print_ie_type ptype)
755{
756        int i;
757
758        if (len < 3) {
759                printf("\tVendor specific: <too short> data:");
760                for (i = 0; i < len; i++)
761                        printf(" %.02x", data[i]);
762                printf("\n");
763                return;
764        }
765
766        if (len >= 4 && memcmp(data, wifi_oui, 3) == 0) {
767                if (data[3] < ARRAY_SIZE(wifiprinters) && wifiprinters[data[3]].name && wifiprinters[data[3]].flags & BIT(ptype)) {
768                        print_ie(&wifiprinters[data[3]], data[3], len - 4, data + 4);
769                        return;
770                }
771                if (!unknown)
772                        return;
773                printf("\tWiFi OUI %#.2x, data:", data[3]);
774                for (i = 0; i < len - 4; i++)
775                        printf(" %.02x", data[i + 4]);
776                printf("\n");
777                return;
778        }
779
780        if (!unknown)
781                return;
782
783        printf("\tVendor specific: OUI %.2x:%.2x:%.2x, data:", data[0], data[1], data[2]);
784        for (i = 3; i < len; i++)
785                printf(" %.2x", data[i]);
786        printf("\n");
787}
788
789static void print_ies(unsigned char *ie, int ielen, bool unknown, enum print_ie_type ptype)
790{
791        while (ielen >= 2 && ielen >= ie[1]) {
792                if (ie[0] < ARRAY_SIZE(ieprinters) && ieprinters[ie[0]].name && ieprinters[ie[0]].flags & BIT(ptype)) {
793                        print_ie(&ieprinters[ie[0]], ie[0], ie[1], ie + 2);
794                } else if (ie[0] == 221 /* vendor */ ) {
795                        print_vendor(ie[1], ie + 2, unknown, ptype);
796                } else if (unknown) {
797                        int i;
798
799                        printf("\tUnknown IE (%d):", ie[0]);
800                        for (i = 0; i < ie[1]; i++)
801                                printf(" %.2x", ie[2 + i]);
802                        printf("\n");
803                }
804                ielen -= ie[1] + 2;
805                ie += ie[1] + 2;
806        }
807}
808
809static void print_supprates(const uint8_t type, uint8_t len, const uint8_t * data)
810{
811        int i;
812
813        printf(" ");
814
815        for (i = 0; i < len; i++) {
816                int r = data[i] & 0x7f;
817                printf("%d.%d%s _%d_", r / 2, 5 * (r & 1), data[i] & 0x80 ? "*" : "", rate_count);
818                rate_count++;
819        }
820        printf("\n");
821}
822
823static void print_ds(const uint8_t type, uint8_t len, const uint8_t * data)
824{
825        printf(" channel %d\n", data[0]);
826        site_survey_lists[sscount].channel = data[0];
827}
828
829static void print_tim(const uint8_t type, uint8_t len, const uint8_t * data)
830{
831        printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x " "Bitmap[0] 0x%x", data[0], data[1], data[2], data[3]);
832        if (len - 4)
833                printf(" (+ %u octet%s)", len - 4, len - 4 == 1 ? "" : "s");
834        printf("\n");
835        site_survey_lists[sscount].dtim_period = data[1];
836}
837
838static void print_country(const uint8_t type, uint8_t len, const uint8_t * data)
839{
840        printf(" %.*s", 2, data);
841
842        printf("\tEnvironment: %s\n", country_env_str(data[2]));
843
844        data += 3;
845        len -= 3;
846
847        if (len < 3) {
848                printf("\t\tNo country IE triplets present\n");
849                return;
850        }
851
852        while (len >= 3) {
853                int end_channel;
854                union ieee80211_country_ie_triplet *triplet = (void *)data;
855
856                if (triplet->ext.reg_extension_id >= IEEE80211_COUNTRY_EXTENSION_ID) {
857                        printf
858                            ("\t\tExtension ID: %d Regulatory Class: %d Coverage class: %d (up to %dm)\n",
859                             triplet->ext.reg_extension_id, triplet->ext.reg_class, triplet->ext.coverage_class, triplet->ext.coverage_class * 450);
860
861                        data += 3;
862                        len -= 3;
863                        continue;
864                }
865
866                /* 2 GHz */
867                if (triplet->chans.first_channel <= 14)
868                        end_channel = triplet->chans.first_channel + (triplet->chans.num_channels - 1);
869                else
870                        end_channel = triplet->chans.first_channel + (4 * (triplet->chans.num_channels - 1));
871
872                printf("\t\tChannels [%d - %d] @ %d dBm\n", triplet->chans.first_channel, end_channel, triplet->chans.max_power);
873
874                data += 3;
875                len -= 3;
876        }
877
878        return;
879}
880
881static void print_powerconstraint(const uint8_t type, uint8_t len, const uint8_t * data)
882{
883        printf(" %d dB\n", data[0]);
884}
885
886static void print_erp(const uint8_t type, uint8_t len, const uint8_t * data)
887{
888        if (data[0] == 0x00)
889                printf(" <no flags>");
890        if (data[0] & 0x01)
891                printf(" NonERP_Present");
892        if (data[0] & 0x02)
893                printf(" Use_Protection");
894        if (data[0] & 0x04)
895                printf(" Barker_Preamble_Mode");
896        printf("\n");
897}
898
899static void print_cipher(const uint8_t * data)
900{
901        if (memcmp(data, wifi_oui, 3) == 0) {
902                switch (data[3]) {
903                case 0:
904                        printf("Use group cipher suite");
905                        break;
906                case 1:
907                        printf("WEP-40");
908                        fillENC("WEP-40", " ");
909                        break;
910                case 2:
911                        printf("TKIP");
912                        fillENC("TKIP", " ");
913                        break;
914                case 4:
915                        printf("CCMP");
916                        fillENC("CCMP", " ");
917                        break;
918                case 5:
919                        printf("WEP-104");
920                        fillENC("WEP-104", " ");
921                        break;
922                default:
923                        printf("%.02x-%.02x-%.02x:%d", data[0], data[1], data[2], data[3]);
924                        break;
925                }
926        } else if (memcmp(data, ieee80211_oui, 3) == 0) {
927                switch (data[3]) {
928                case 0:
929                        printf("Use group cipher suite");
930                        break;
931                case 1:
932                        printf("WEP-40");
933                        fillENC("WEP-40", " ");
934                        break;
935                case 2:
936                        printf("TKIP");
937                        fillENC("TKIP", " ");
938                        break;
939                case 4:
940                        printf("CCMP");
941                        fillENC("CCMP", " ");
942                        break;
943                case 5:
944                        printf("WEP-104");
945                        fillENC("WEP-104", " ");
946                        break;
947                case 6:
948                        printf("AES-128-CMAC");
949                        fillENC("AES-128-CMAC", " ");
950                        break;
951                default:
952                        printf("%.02x-%.02x-%.02x:%d", data[0], data[1], data[2], data[3]);
953                        break;
954                }
955        } else
956                printf("%.02x-%.02x-%.02x:%d", data[0], data[1], data[2], data[3]);
957}
958
959static void print_auth(const uint8_t * data)
960{
961        if (memcmp(data, wifi_oui, 3) == 0) {
962                switch (data[3]) {
963                case 1:
964                        printf("IEEE 802.1X");
965                        fillENC("IEEE 802.1X", " ");
966                        break;
967                case 2:
968                        printf("PSK");
969                        fillENC("PSK", " ");
970                        break;
971                default:
972                        printf("%.02x-%.02x-%.02x:%d", data[0], data[1], data[2], data[3]);
973                        break;
974                }
975        } else if (memcmp(data, ieee80211_oui, 3) == 0) {
976                switch (data[3]) {
977                case 1:
978                        printf("IEEE 802.1X");
979                        fillENC("IEEE 802.1X", " ");
980                        break;
981                case 2:
982                        printf("PSK");
983                        fillENC("PSK", " ");
984                        break;
985                case 3:
986                        printf("FT/IEEE 802.1X");
987                        fillENC("FT/IEEE 8021X", " ");
988                        break;
989                case 4:
990                        printf("FT/PSK");
991                        fillENC("FT/PSK", " ");
992                        break;
993                case 5:
994                        printf("IEEE 802.1X/SHA-256");
995                        fillENC("IEEE 8021X/SHA-256", " ");
996                        break;
997                case 6:
998                        printf("PSK/SHA-256");
999                        fillENC("PSK/SHA-256", " ");
1000                        break;
1001                default:
1002                        printf("%.02x-%.02x-%.02x:%d", data[0], data[1], data[2], data[3]);
1003                        break;
1004                }
1005        } else
1006                printf("%.02x-%.02x-%.02x:%d", data[0], data[1], data[2], data[3]);
1007}
1008
1009static void print_rsn_ie(const char *defcipher, const char *defauth, uint8_t len, const uint8_t * data)
1010{
1011        bool first = true;
1012        __u16 version, count, capa;
1013        int i;
1014
1015        version = data[0] + (data[1] << 8);
1016        tab_on_first(&first);
1017        printf("\t * Version: %d\n", version);
1018
1019        data += 2;
1020        len -= 2;
1021
1022        if (len < 4) {
1023                tab_on_first(&first);
1024                printf("\t * Group cipher: %s\n", defcipher);
1025                printf("\t * Pairwise ciphers: %s\n", defcipher);
1026                fillENC(defcipher, " ");
1027                return;
1028        }
1029
1030        tab_on_first(&first);
1031        printf("\t * Group cipher: ");
1032        print_cipher(data);
1033        printf("\n");
1034
1035        data += 4;
1036        len -= 4;
1037
1038        if (len < 2) {
1039                tab_on_first(&first);
1040                printf("\t * Pairwise ciphers: %s\n", defcipher);
1041                return;
1042        }
1043
1044        count = data[0] | (data[1] << 8);
1045        if (2 + (count * 4) > len)
1046                goto invalid;
1047
1048        tab_on_first(&first);
1049        printf("\t * Pairwise ciphers:");
1050        for (i = 0; i < count; i++) {
1051                printf(" ");
1052                print_cipher(data + 2 + (i * 4));
1053        }
1054        printf("\n");
1055
1056        data += 2 + (count * 4);
1057        len -= 2 + (count * 4);
1058
1059        if (len < 2) {
1060                tab_on_first(&first);
1061                printf("\t * Authentication suites: %s\n", defauth);
1062                fillENC(defauth, " ");
1063                return;
1064        }
1065
1066        count = data[0] | (data[1] << 8);
1067        if (2 + (count * 4) > len)
1068                goto invalid;
1069
1070        tab_on_first(&first);
1071        printf("\t * Authentication suites:");
1072        for (i = 0; i < count; i++) {
1073                printf(" ");
1074                print_auth(data + 2 + (i * 4));
1075        }
1076        printf("\n");
1077
1078        data += 2 + (count * 4);
1079        len -= 2 + (count * 4);
1080
1081        if (len >= 2) {
1082                capa = data[0] | (data[1] << 8);
1083                tab_on_first(&first);
1084                printf("\t * Capabilities:");
1085                if (capa & 0x0001)
1086                        printf(" PreAuth");
1087                if (capa & 0x0002)
1088                        printf(" NoPairwise");
1089                switch ((capa & 0x000c) >> 2) {
1090                case 0:
1091                        break;
1092                case 1:
1093                        printf(" 2-PTKSA-RC");
1094                        break;
1095                case 2:
1096                        printf(" 4-PTKSA-RC");
1097                        break;
1098                case 3:
1099                        printf(" 16-PTKSA-RC");
1100                        break;
1101                }
1102                switch ((capa & 0x0030) >> 4) {
1103                case 0:
1104                        break;
1105                case 1:
1106                        printf(" 2-GTKSA-RC");
1107                        break;
1108                case 2:
1109                        printf(" 4-GTKSA-RC");
1110                        break;
1111                case 3:
1112                        printf(" 16-GTKSA-RC");
1113                        break;
1114                }
1115                if (capa & 0x0040)
1116                        printf(" MFP-required");
1117                if (capa & 0x0080)
1118                        printf(" MFP-capable");
1119                if (capa & 0x0200)
1120                        printf(" Peerkey-enabled");
1121                if (capa & 0x0400)
1122                        printf(" SPP-AMSDU-capable");
1123                if (capa & 0x0800)
1124                        printf(" SPP-AMSDU-required");
1125                printf(" (0x%.4x)\n", capa);
1126                data += 2;
1127                len -= 2;
1128        }
1129
1130        if (len >= 2) {
1131                int pmkid_count = data[0] | (data[1] << 8);
1132
1133                if (len >= 2 + 16 * pmkid_count) {
1134                        tab_on_first(&first);
1135                        printf("\t * %d PMKIDs\n", pmkid_count);
1136                        /* not printing PMKID values */
1137                        data += 2 + 16 * pmkid_count;
1138                        len -= 2 + 16 * pmkid_count;
1139                } else
1140                        goto invalid;
1141        }
1142
1143        if (len >= 4) {
1144                tab_on_first(&first);
1145                printf("\t * Group mgmt cipher suite: ");
1146                print_cipher(data);
1147                printf("\n");
1148                data += 4;
1149                len -= 4;
1150        }
1151
1152invalid:
1153        if (len != 0) {
1154                printf("\t\t * bogus tail data (%d):", len);
1155                while (len) {
1156                        printf(" %.2x", *data);
1157                        data++;
1158                        len--;
1159                }
1160                printf("\n");
1161        }
1162}
1163
1164static void print_rsn(const uint8_t type, uint8_t len, const uint8_t * data)
1165{
1166        fillENC("WPA2", " ");
1167        print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
1168}
1169
1170void print_vht_info(__u32 capa, const __u8 *mcs)
1171{
1172        __u16 tmp;
1173        int i;
1174
1175        printf("\t\tVHT Capabilities (0x%.8x):\n", capa);
1176
1177#define PRINT_VHT_CAPA(_bit, _str) \
1178        do { \
1179                if (capa & BIT(_bit)) \
1180                        printf("\t\t\t" _str "\n"); \
1181        } while (0)
1182
1183        printf("\t\t\tMax MPDU length: ");
1184        switch (capa & 3) {
1185        case 0:
1186                printf("3895\n");
1187                break;
1188        case 1:
1189                printf("7991\n");
1190                break;
1191        case 2:
1192                printf("11454\n");
1193                break;
1194        case 3:
1195                printf("(reserved)\n");
1196        }
1197        printf("\t\t\tSupported Channel Width: ");
1198        switch ((capa >> 2) & 3) {
1199        case 0:
1200                printf("neither 160 nor 80+80\n");
1201                site_survey_lists[sscount].channel |= 0x1000;
1202                if (capa & BIT(5)) {
1203                        fillENC("VHT80SGI", " ");
1204                } else {
1205                        fillENC("VHT80", " ");
1206                }
1207                break;
1208        case 1:
1209                printf("160 MHz\n");
1210                if (capa & BIT(6)) {
1211                        fillENC("VHT160SGI", " ");
1212                } else {
1213                        fillENC("VHT160", " ");
1214                }
1215                site_survey_lists[sscount].channel |= 0x1100;
1216                break;
1217        case 2:
1218                printf("160 MHz, 80+80 MHz\n");
1219                fillENC("VHT160 VHT80+80", " ");
1220                site_survey_lists[sscount].channel |= 0x1200;
1221                break;
1222        case 3:
1223                printf("(reserved)\n");
1224        }
1225        PRINT_VHT_CAPA(4, "RX LDPC");
1226        PRINT_VHT_CAPA(5, "short GI (80 MHz)");
1227        PRINT_VHT_CAPA(6, "short GI (160 MHz)");
1228        PRINT_VHT_CAPA(7, "TX STBC");
1229        /* RX STBC */
1230        PRINT_VHT_CAPA(11, "SU Beamformer");
1231        PRINT_VHT_CAPA(12, "SU Beamformee");
1232        /* compressed steering */
1233        /* # of sounding dimensions */
1234        PRINT_VHT_CAPA(19, "MU Beamformer");
1235        PRINT_VHT_CAPA(20, "MU Beamformee");
1236        PRINT_VHT_CAPA(21, "VHT TXOP PS");
1237        PRINT_VHT_CAPA(22, "+HTC-VHT");
1238        /* max A-MPDU */
1239        /* VHT link adaptation */
1240        PRINT_VHT_CAPA(28, "RX antenna pattern consistency");
1241        PRINT_VHT_CAPA(29, "TX antenna pattern consistency");
1242
1243        printf("\t\tVHT RX MCS set:\n");
1244        tmp = mcs[0] | (mcs[1] << 8);
1245        for (i = 1; i <= 8; i++) {
1246                printf("\t\t\t%d streams: ", i);
1247                switch ((tmp >> ((i - 1) * 2)) & 3) {
1248                case 0:
1249                        printf("MCS 0-7\n");
1250                        break;
1251                case 1:
1252                        printf("MCS 0-8\n");
1253                        break;
1254                case 2:
1255                        printf("MCS 0-9\n");
1256                        break;
1257                case 3:
1258                        printf("not supported\n");
1259                        break;
1260                }
1261        }
1262        tmp = mcs[2] | (mcs[3] << 8);
1263        printf("\t\tVHT RX highest supported: %d Mbps\n", tmp & 0x1fff);
1264
1265        printf("\t\tVHT TX MCS set:\n");
1266        tmp = mcs[4] | (mcs[5] << 8);
1267        for (i = 1; i <= 8; i++) {
1268                printf("\t\t\t%d streams: ", i);
1269                switch ((tmp >> ((i - 1) * 2)) & 3) {
1270                case 0:
1271                        printf("MCS 0-7\n");
1272                        break;
1273                case 1:
1274                        printf("MCS 0-8\n");
1275                        break;
1276                case 2:
1277                        printf("MCS 0-9\n");
1278                        break;
1279                case 3:
1280                        printf("not supported\n");
1281                        break;
1282                }
1283        }
1284        tmp = mcs[6] | (mcs[7] << 8);
1285        printf("\t\tVHT TX highest supported: %d Mbps\n", tmp & 0x1fff);
1286}
1287
1288static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t * data)
1289{
1290        printf("\n");
1291        print_vht_info(data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24), data + 4);
1292}
1293
1294static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t * data)
1295{
1296        const char *chandwidths[] = {
1297                [0] = "20 or 40 MHz",
1298                [1] = "80 MHz",
1299                [3] = "80+80 MHz",
1300                [2] = "160 MHz",
1301        };
1302
1303        printf("\n");
1304        printf("\t\t * channel width: %d (%s)\n", data[0], data[0] < ARRAY_SIZE(chandwidths) ? chandwidths[data[0]] : "unknown");
1305        printf("\t\t * center freq segment 1: %d\n", data[1]);
1306        printf("\t\t * center freq segment 2: %d\n", data[2]);
1307        printf("\t\t * VHT basic MCS set: 0x%.2x%.2x\n", data[4], data[3]);
1308}
1309
1310static void print_ht_capability(__u16 cap)
1311{
1312#define PRINT_HT_CAP(_cond, _str) \
1313        do { \
1314                if (_cond) \
1315                        printf("\t\t\t" _str "\n"); \
1316        } while (0)
1317
1318        printf("\t\tCapabilities: 0x%02x\n", cap);
1319
1320        PRINT_HT_CAP((cap & BIT(0)), "RX LDPC");
1321        PRINT_HT_CAP((cap & BIT(1)), "HT20/HT40");
1322        if (cap & BIT(1)) {
1323                site_survey_lists[sscount].channel |= 0x2000;
1324                if ((cap & BIT(6))) {
1325                        fillENC("HT40SGI", " ");
1326                } else {
1327                        fillENC("HT40", " ");
1328                }
1329        } else
1330
1331                PRINT_HT_CAP(!(cap & BIT(1)), "HT20");
1332        if (!(cap & BIT(1))) {
1333                if ((cap & BIT(5))) {
1334                        fillENC("HT20SGI", " ");
1335                } else {
1336                        fillENC("HT20", " ");
1337                }
1338        }
1339
1340        PRINT_HT_CAP(((cap >> 2) & 0x3) == 0, "Static SM Power Save");
1341        PRINT_HT_CAP(((cap >> 2) & 0x3) == 1, "Dynamic SM Power Save");
1342        PRINT_HT_CAP(((cap >> 2) & 0x3) == 3, "SM Power Save disabled");
1343
1344        PRINT_HT_CAP((cap & BIT(4)), "RX Greenfield");
1345        PRINT_HT_CAP((cap & BIT(5)), "RX HT20 SGI");
1346        PRINT_HT_CAP((cap & BIT(6)), "RX HT40 SGI");
1347        PRINT_HT_CAP((cap & BIT(7)), "TX STBC");
1348
1349        PRINT_HT_CAP(((cap >> 8) & 0x3) == 0, "No RX STBC");
1350        PRINT_HT_CAP(((cap >> 8) & 0x3) == 1, "RX STBC 1-stream");
1351        PRINT_HT_CAP(((cap >> 8) & 0x3) == 2, "RX STBC 2-streams");
1352        PRINT_HT_CAP(((cap >> 8) & 0x3) == 3, "RX STBC 3-streams");
1353
1354        PRINT_HT_CAP((cap & BIT(10)), "HT Delayed Block Ack");
1355
1356        PRINT_HT_CAP(!(cap & BIT(11)), "Max AMSDU length: 3839 bytes");
1357        PRINT_HT_CAP((cap & BIT(11)), "Max AMSDU length: 7935 bytes");
1358
1359        /*
1360         * For beacons and probe response this would mean the BSS
1361         * does or does not allow the usage of DSSS/CCK HT40.
1362         * Otherwise it means the STA does or does not use
1363         * DSSS/CCK HT40.
1364         */
1365        PRINT_HT_CAP((cap & BIT(12)), "DSSS/CCK HT40");
1366        PRINT_HT_CAP(!(cap & BIT(12)), "No DSSS/CCK HT40");
1367
1368        /* BIT(13) is reserved */
1369
1370        PRINT_HT_CAP((cap & BIT(14)), "40 MHz Intolerant");
1371
1372        PRINT_HT_CAP((cap & BIT(15)), "L-SIG TXOP protection");
1373#undef PRINT_HT_CAP
1374}
1375
1376static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t * data)
1377{
1378        printf("\n");
1379        print_ht_capability(data[0] | (data[1] << 8));
1380        print_ampdu_length(data[2] & 3);
1381        print_ampdu_spacing((data[2] >> 2) & 7);
1382        print_ht_mcs(data + 3);
1383}
1384
1385static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t * data)
1386{
1387        static const char *offset[4] = {
1388                "no secondary",
1389                "above",
1390                "[reserved!]",
1391                "below",
1392        };
1393        static const char *protection[4] = {
1394                "no",
1395                "nonmember",
1396                "20 MHz",
1397                "non-HT mixed",
1398        };
1399        static const char *sta_chan_width[2] = {
1400                "20 MHz",
1401                "any",
1402        };
1403
1404        printf("\n");
1405        printf("\t\t * primary channel: %d\n", data[0]);
1406        printf("\t\t * secondary channel offset: %s\n", offset[data[1] & 0x3]);
1407        printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4) >> 2]);
1408        printf("\t\t * RIFS: %d\n", (data[1] & 0x8) >> 3);
1409        printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
1410        printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
1411        printf("\t\t * OBSS non-GF present: %d\n", (data[2] & 0x10) >> 4);
1412        printf("\t\t * dual beacon: %d\n", (data[4] & 0x40) >> 6);
1413        printf("\t\t * dual CTS protection: %d\n", (data[4] & 0x80) >> 7);
1414        printf("\t\t * STBC beacon: %d\n", data[5] & 0x1);
1415        printf("\t\t * L-SIG TXOP Prot: %d\n", (data[5] & 0x2) >> 1);
1416        printf("\t\t * PCO active: %d\n", (data[5] & 0x4) >> 2);
1417        printf("\t\t * PCO phase: %d\n", (data[5] & 0x8) >> 3);
1418}
1419
1420static void print_capabilities(const uint8_t type, uint8_t len, const uint8_t * data)
1421{
1422        int i, base, bit;
1423        bool first = true;
1424
1425        for (i = 0; i < len; i++) {
1426                base = i * 8;
1427
1428                for (bit = 0; bit < 8; bit++) {
1429                        if (!(data[i] & (1 << bit)))
1430                                continue;
1431
1432                        if (!first)
1433                                printf(",");
1434                        else
1435                                first = false;
1436
1437                        switch (bit + base) {
1438                        case 0:
1439                                printf(" HT Information Exchange Supported");
1440                                break;
1441                        case 1:
1442                                printf(" On-demand Beacon");
1443                                break;
1444                        case 2:
1445                                printf(" Extended Channel Switching");
1446                                break;
1447                        case 3:
1448                                printf(" Wave Indication");
1449                                break;
1450                        case 4:
1451                                printf(" PSMP Capability");
1452                                break;
1453                        case 5:
1454                                printf(" Service Interval Granularity");
1455                                break;
1456                        case 6:
1457                                printf(" S-PSMP Capability");
1458                                break;
1459                        default:
1460                                printf(" %d", bit);
1461                                break;
1462                        }
1463                }
1464        }
1465
1466        printf("\n");
1467}
1468
1469//  end of iw copied code
1470void mac80211_scan(char *interface)
1471{
1472        struct nl_msg *msg;
1473        int wdev;
1474        wdev = if_nametoindex(interface);
1475        lgetnoise(wdev);
1476        bzero(&scan_params, sizeof(scan_params));
1477        scan_params.type = PRINT_SCAN;
1478        msg = unl_genl_msg(&unl, NL80211_CMD_GET_SCAN, true);
1479        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, wdev);
1480        unl_genl_request(&unl, msg, print_bss_handler, &scan_params);
1481        // nlmsg_free(surveymsg);
1482        return;
1483nla_put_failure:
1484        nlmsg_free(msg);
1485}
1486
1487static int write_site_survey(void);
1488static int open_site_survey(void);
1489
1490void mac80211_site_survey(char *interface)
1491{
1492        site_survey_lists = malloc(sizeof(struct site_survey_list) * SITE_SURVEY_NUM);
1493        int i;
1494        int phy, wdev;
1495        char scaninterface[32];
1496        char macaddr[32];
1497        unsigned char hwbuff[16];
1498        bzero(site_survey_lists, sizeof(struct site_survey_list) * SITE_SURVEY_NUM);
1499        eval("iw", "dev", interface, "scan");
1500        mac80211_scan(interface);
1501        write_site_survey();
1502        open_site_survey();
1503        for (i = 0; i < SITE_SURVEY_NUM && site_survey_lists[i].BSSID[0]; i++) {
1504
1505                if (site_survey_lists[i].SSID[0] == 0) {
1506                        strcpy(site_survey_lists[i].SSID, "hidden");
1507                }
1508
1509                fprintf(stderr,
1510                        "[%2d] SSID[%20s] BSSID[%s] channel[%2d/%4d] frequency[%4d] rssi[%d] noise[%d] beacon[%d] cap[%x] dtim[%d] rate[%d] enc[%s]\n",
1511                        i, site_survey_lists[i].SSID,
1512                        site_survey_lists[i].BSSID,
1513                        site_survey_lists[i].channel & 0xff,
1514                        site_survey_lists[i].channel,
1515                        site_survey_lists[i].frequency,
1516                        site_survey_lists[i].RSSI,
1517                        site_survey_lists[i].phy_noise,
1518                        site_survey_lists[i].beacon_period, site_survey_lists[i].capability, site_survey_lists[i].dtim_period, site_survey_lists[i].rate_count, site_survey_lists[i].ENCINFO);
1519        }
1520        free(site_survey_lists);
1521}
1522
1523static int write_site_survey(void)
1524{
1525        FILE *fp;
1526        if ((fp = fopen(SITE_SURVEY_DB, "w"))) {
1527                fwrite(&site_survey_lists[0], sizeof(struct site_survey_list) * SITE_SURVEY_NUM, 1, fp);
1528                fclose(fp);
1529                return 0;
1530        }
1531        return 1;
1532}
1533
1534static int open_site_survey(void)
1535{
1536        FILE *fp;
1537        bzero(site_survey_lists, sizeof(site_survey_lists) * SITE_SURVEY_NUM);
1538        if ((fp = fopen(SITE_SURVEY_DB, "r"))) {
1539                fread(&site_survey_lists[0], sizeof(struct site_survey_list) * SITE_SURVEY_NUM, 1, fp);
1540                fclose(fp);
1541                return 1;
1542        }
1543        return 0;
1544}
1545
1546int site_survey_main_mac802211(int argc, char *argv[])
1547{
1548        unlink(SITE_SURVEY_DB);
1549        char *sta = nvram_safe_get("wifi_display");
1550        mac80211_site_survey(sta);
1551        return 0;
1552}
Note: See TracBrowser for help on using the repository browser.