source: src/router/services/tools/site_survey_broadcom.c @ 19056

Last change on this file since 19056 was 19056, checked in by BrainSlayer, 13 months ago

extended rate display

File size: 12.7 KB
Line 
1/*
2 * site_survey_broadcom.c
3 *
4 * Copyright (C) 2006 Sebastian Gottschall <gottschall@dd-wrt.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19 *
20 * $Id:
21 */
22
23#include <stdio.h>
24#include <string.h>
25#include <unistd.h>
26#include <signal.h>
27
28#include <typedefs.h>
29#include <bcmnvram.h>
30#include <shutils.h>
31#include <wlioctl.h>
32#include <wlutils.h>
33#include <utils.h>
34#include <bcmutils.h>
35
36#define sys_restart() kill(1, SIGHUP)
37
38int write_site_survey(void);
39static int open_site_survey(void);
40int write_site_survey(void);
41
42struct site_survey_list site_survey_lists[SITE_SURVEY_NUM];
43
44/* 802.11i/WPA RSN IE parsing utilities */
45typedef struct {
46        uint16 version;
47        wpa_suite_mcast_t *mcast;
48        wpa_suite_ucast_t *ucast;
49        wpa_suite_auth_key_mgmt_t *akm;
50        uint8 *capabilities;
51} rsn_parse_info_t;
52
53static int wlu_bcmp(const void *b1, const void *b2, int len)
54{
55        return (memcmp(b1, b2, len));
56}
57
58static INLINE uint16 ltoh16_ua(void *bytes)
59{
60        return (((uint8 *) bytes)[1] << 8) + ((uint8 *) bytes)[0];
61}
62
63static bool wlu_is_wpa_ie(uint8 ** wpaie, uint8 ** tlvs, uint * tlvs_len)
64{
65        uint8 *ie = *wpaie;
66
67        /* If the contents match the WPA_OUI and type=1 */
68        if ((ie[1] >= 6) && !wlu_bcmp(&ie[2], WPA_OUI "\x01", 4)) {
69                return TRUE;
70        }
71
72        /* point to the next ie */
73        ie += ie[1] + 2;
74        /* calculate the length of the rest of the buffer */
75        *tlvs_len -= (int)(ie - *tlvs);
76        /* update the pointer to the start of the buffer */
77        *tlvs = ie;
78
79        return FALSE;
80}
81
82static int
83wl_rsn_ie_parse_info(uint8 * rsn_buf, uint len, rsn_parse_info_t * rsn)
84{
85        uint16 count;
86
87        memset(rsn, 0, sizeof(rsn_parse_info_t));
88
89        /* version */
90        if (len < sizeof(uint16))
91                return 1;
92
93        rsn->version = ltoh16_ua(rsn_buf);
94        len -= sizeof(uint16);
95        rsn_buf += sizeof(uint16);
96
97        /* Multicast Suite */
98        if (len < sizeof(wpa_suite_mcast_t))
99                return 0;
100
101        rsn->mcast = (wpa_suite_mcast_t *) rsn_buf;
102        len -= sizeof(wpa_suite_mcast_t);
103        rsn_buf += sizeof(wpa_suite_mcast_t);
104
105        /* Unicast Suite */
106        if (len < sizeof(uint16))
107                return 0;
108
109        count = ltoh16_ua(rsn_buf);
110
111        if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t)))
112                return 1;
113
114        rsn->ucast = (wpa_suite_ucast_t *) rsn_buf;
115        len -= (sizeof(uint16) + count * sizeof(wpa_suite_t));
116        rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t));
117
118        /* AKM Suite */
119        if (len < sizeof(uint16))
120                return 0;
121
122        count = ltoh16_ua(rsn_buf);
123
124        if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t)))
125                return 1;
126
127        rsn->akm = (wpa_suite_auth_key_mgmt_t *) rsn_buf;
128        len -= (sizeof(uint16) + count * sizeof(wpa_suite_t));
129        rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t));
130
131        /* Capabilites */
132        if (len < sizeof(uint16))
133                return 0;
134
135        rsn->capabilities = rsn_buf;
136
137        return 0;
138}
139
140static void wl_rsn_ie_dump(bcm_tlv_t * ie, char *sum)
141{
142        int i;
143        int rsn;
144        wpa_ie_fixed_t *wpa = NULL;
145        rsn_parse_info_t rsn_info;
146        wpa_suite_t *suite;
147        uint8 std_oui[3];
148        int unicast_count = 0;
149        int akm_count = 0;
150        uint16 capabilities;
151        uint cntrs;
152        int err;
153
154        if (ie->id == DOT11_MNG_RSN_ID) {
155                rsn = TRUE;
156                memcpy(std_oui, WPA2_OUI, WPA_OUI_LEN);
157                err = wl_rsn_ie_parse_info(ie->data, ie->len, &rsn_info);
158        } else {
159                rsn = FALSE;
160                memcpy(std_oui, WPA_OUI, WPA_OUI_LEN);
161                wpa = (wpa_ie_fixed_t *) ie;
162                err =
163                    wl_rsn_ie_parse_info((uint8 *) & wpa->version,
164                                         wpa->length - WPA_IE_OUITYPE_LEN,
165                                         &rsn_info);
166        }
167        if (err || rsn_info.version != WPA_VERSION) {
168                strcat(sum, "WEP ");
169                return;
170        }
171
172        /* Check for multicast suite */
173        if (rsn_info.mcast) {
174                if (!wlu_bcmp(rsn_info.mcast->oui, std_oui, 3)) {
175                        switch (rsn_info.mcast->type) {
176                        case WPA_CIPHER_NONE:
177                                break;
178                        case WPA_CIPHER_WEP_40:
179                                strcat(sum, "Group-WEP64 ");
180                                break;
181                        case WPA_CIPHER_WEP_104:
182                                strcat(sum, "Group-WEP128 ");
183                                break;
184                        case WPA_CIPHER_TKIP:
185                                strcat(sum, "Group-TKIP ");
186                                break;
187                        case WPA_CIPHER_AES_OCB:
188                                strcat(sum, "Group-AES-OCB ");
189                                break;
190                        case WPA_CIPHER_AES_CCM:
191                                strcat(sum, "Group-AES-CCMP ");
192                                break;
193                        default:
194                                sprintf(sum, "Unknown-%s(#%d) ",
195                                        rsn ? "WPA2" : "WPA",
196                                        rsn_info.mcast->type);
197                                break;
198                        }
199                } else {
200                        sprintf(sum, "%s Unknown-%02X:%02X:%02X(#%d) ",
201                                sum, rsn_info.mcast->oui[0],
202                                rsn_info.mcast->oui[1], rsn_info.mcast->oui[2],
203                                rsn_info.mcast->type);
204                }
205        }
206
207        /* Check for unicast suite(s) */
208        if (rsn_info.ucast) {
209                unicast_count = ltoh16_ua(&rsn_info.ucast->count);
210                for (i = 0; i < unicast_count; i++) {
211                        suite = &rsn_info.ucast->list[i];
212                        if (!wlu_bcmp(suite->oui, std_oui, 3)) {
213                                switch (suite->type) {
214                                case WPA_CIPHER_NONE:
215                                        strcat(sum, "Pair-NONE ");
216                                        break;
217                                case WPA_CIPHER_WEP_40:
218                                        strcat(sum, "Pair-WEP64 ");
219                                        break;
220                                case WPA_CIPHER_WEP_104:
221                                        strcat(sum, "Pair-WEP128 ");
222                                        break;
223                                case WPA_CIPHER_TKIP:
224                                        strcat(sum, "Pair-TKIP ");
225                                        break;
226                                case WPA_CIPHER_AES_OCB:
227                                        strcat(sum, "Pair-AES-OCB ");
228                                        break;
229                                case WPA_CIPHER_AES_CCM:
230                                        strcat(sum, "Pair-AES-CCMP ");
231                                        break;
232                                default:
233                                        sprintf(sum, "WPA-Unknown-%s(#%d) ",
234                                                rsn ? "WPA2" : "WPA",
235                                                suite->type);
236                                        break;
237                                }
238                        } else {
239                                sprintf(sum, "%s Unknown-%02X:%02X:%02X(#%d) ",
240                                        sum, suite->oui[0], suite->oui[1],
241                                        suite->oui[2], suite->type);
242                        }
243                }
244                printf("\n");
245        }
246        /* Authentication Key Management */
247        if (rsn_info.akm) {
248                akm_count = ltoh16_ua(&rsn_info.akm->count);
249                for (i = 0; i < akm_count; i++) {
250                        suite = &rsn_info.akm->list[i];
251                        if (!wlu_bcmp(suite->oui, std_oui, 3)) {
252                                switch (suite->type) {
253                                case RSN_AKM_NONE:
254                                        strcat(sum, "None ");
255                                        break;
256                                case RSN_AKM_UNSPECIFIED:
257                                        if (rsn)
258                                                strcat(sum, "WPA2 ");
259                                        else
260                                                strcat(sum, "WPA ");
261                                        break;
262                                case RSN_AKM_PSK:
263                                        if (rsn)
264                                                strcat(sum, "WPA2-PSK ");
265                                        else
266                                                strcat(sum, "WPA-PSK ");
267                                        break;
268                                default:
269                                        sprintf(sum, "Unknown-%s(#%d)  ",
270                                                rsn ? "WPA2" : "WPA",
271                                                suite->type);
272                                        break;
273                                }
274                        } else {
275                                sprintf(sum, "%s Unknown-%02X:%02X:%02X(#%d)  ",
276                                        sum, suite->oui[0], suite->oui[1],
277                                        suite->oui[2], suite->type);
278                        }
279                }
280        }
281}
282
283static uint8 *wlu_parse_tlvs(uint8 * tlv_buf, int buflen, uint key)
284{
285        uint8 *cp;
286        int totlen;
287
288        cp = tlv_buf;
289        totlen = buflen;
290
291        /* find tagged parameter */
292        while (totlen >= 2) {
293                uint tag;
294                int len;
295
296                tag = *cp;
297                len = *(cp + 1);
298
299                /* validate remaining totlen */
300                if ((tag == key) && (totlen >= (len + 2)))
301                        return (cp);
302
303                cp += (len + 2);
304                totlen -= (len + 2);
305        }
306
307        return NULL;
308}
309
310static char *wl_dump_wpa_rsn_ies(uint8 * cp, uint len)
311{
312        uint8 *parse = cp;
313        uint parse_len = len;
314        uint8 *wpaie;
315        uint8 *rsnie;
316        static char sum[128] = { 0 };
317        memset(sum, 0, sizeof(sum));
318
319        while ((wpaie = wlu_parse_tlvs(parse, parse_len, DOT11_MNG_WPA_ID)))
320                if (wlu_is_wpa_ie(&wpaie, &parse, &parse_len))
321                        break;
322        if (wpaie)
323                wl_rsn_ie_dump((bcm_tlv_t *) wpaie, sum);
324
325        rsnie = wlu_parse_tlvs(cp, len, DOT11_MNG_RSN_ID);
326        if (rsnie)
327                wl_rsn_ie_dump((bcm_tlv_t *) rsnie, sum);
328        if (wpaie || rsnie)
329                return sum;
330
331        return "WEP";
332}
333
334static char *getEncInfo(wl_bss_info_t * bi)
335{
336        if (bi->capability & DOT11_CAP_PRIVACY) {
337                if (bi->ie_length)
338                        return
339                            wl_dump_wpa_rsn_ies((uint8 *) (((uint8 *) bi) +
340                                                           bi->ie_offset),
341                                                bi->ie_length);
342                else
343                        return "WEP";
344        } else
345                return "Open";
346}
347
348static int get_mcs_max(const unsigned char *mcs)
349{
350        unsigned int mcs_bit, prev_bit = -2, prev_cont = 0;
351
352        for (mcs_bit = 0; mcs_bit < 16 * 8; mcs_bit++) {
353                unsigned int mcs_octet = mcs_bit / 8;
354                unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8;
355                bool mcs_rate_idx_set;
356
357                mcs_rate_idx_set = !!(mcs[mcs_octet] & MCS_RATE_BIT);
358
359                if (!mcs_rate_idx_set)
360                        break;
361
362                if (prev_bit != mcs_bit - 1) {
363                        prev_cont = 0;
364                } else if (!prev_cont) {
365                        prev_cont = 1;
366                }
367
368                prev_bit = mcs_bit;
369        }
370        if (prev_cont) {
371                if (prev_bit == 7)
372                        return 150;
373                if (prev_bit == 15)
374                        return 300;
375                if (prev_bit == 23)
376                        return 450;
377                if (prev_bit == 31)
378                        return 600;
379        }
380        return 0;
381}
382
383int get_legacy(unsigned char *rates, int count)
384{
385        int r, b, i;
386        int maxrate = 0;
387        for (i = 0; i < count; i++) {
388                r = rates[i] & 0x7f;
389                //b = rates[i] & 0x80;
390                if (r == 0)
391                        break;
392                if (r > maxrate)
393                        maxrate = r;
394        }
395        return maxrate / 2;
396}
397
398int site_survey_main(int argc, char *argv[])
399{
400        char tmp[32];
401        sprintf(tmp, "%s_ifname", nvram_safe_get("wifi_display"));
402        char *name = nvram_safe_get(tmp);
403
404        unsigned char buf[10000];
405        wl_scan_results_t *scan_res = (wl_scan_results_t *) buf;
406        wl_bss_info_t *bss_info;
407        unsigned char mac[20];
408        int i;
409        char *dev = name;
410
411        unlink(SITE_SURVEY_DB);
412        int ap = 0, oldap = 0;
413        wl_scan_params_t params;
414
415        memset(&params, 0, sizeof(params));
416
417        /*
418         * use defaults (same parameters as wl scan)
419         */
420
421        memset(&params.bssid, 0xff, sizeof(params.bssid));
422        if (argc > 1) {
423                params.ssid.SSID_len = strlen(argv[1]);
424                strcpy(params.ssid.SSID, argv[1]);
425        }
426        params.bss_type = DOT11_BSSTYPE_ANY;
427        params.scan_type = 0;
428        params.nprobes = -1;
429        params.active_time = -1;
430        params.passive_time = -1;
431        params.home_time = -1;
432        params.channel_num = 0;
433
434        /*
435         * can only scan in STA mode
436         */
437        if (wl_ioctl(dev, WLC_SCAN, &params, 64) < 0) {
438                fprintf(stderr, "scan failed\n");
439                return -1;
440        }
441        int count = 10;
442        int ret = 0;
443        while ((count--) > 0)   //scan for max 5 seconds
444        {
445                usleep(500 * 1000);
446
447                bzero(buf, sizeof(buf));
448                scan_res->buflen = sizeof(buf);
449                ret = wl_ioctl(dev, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN);
450                if (!ret)
451                        break;
452        }
453        if (ret < 0) {
454                fprintf(stderr, "scan failed with errorcode %d\n", ret);
455        }
456
457        fprintf(stderr, "buflen=[%d] version=[%d] count=[%d]\n",
458                scan_res->buflen, scan_res->version, scan_res->count);
459
460        if (scan_res->count == 0) {
461                cprintf("Can't find any wireless device\n");
462                goto endss;
463        }
464
465        bss_info = &scan_res->bss_info[0];
466        for (i = 0; i < scan_res->count; i++) {
467                strcpy(site_survey_lists[i].SSID, bss_info->SSID);
468                strcpy(site_survey_lists[i].BSSID,
469                       ether_etoa(bss_info->BSSID.octet, mac));
470#ifndef HAVE_RB500
471                site_survey_lists[i].channel = bss_info->chanspec & 0xff;
472#endif
473                site_survey_lists[i].frequency = ieee80211_ieee2mhz(site_survey_lists[i].channel);
474#ifdef WL_CHANSPEC_BW_80
475                switch(bss_info->chanspec & 0x3800)
476                {
477                case WL_CHANSPEC_BW_80:
478                site_survey_lists[i].channel&=0x1000;
479                break;
480                case WL_CHANSPEC_BW_8080:
481                site_survey_lists[i].channel&=0x1100;
482                break;
483                case WL_CHANSPEC_BW_160:
484                site_survey_lists[i].channel&=0x1200;
485                break;
486#endif
487
488                site_survey_lists[i].RSSI = bss_info->RSSI;
489                site_survey_lists[i].phy_noise = bss_info->phy_noise;
490                site_survey_lists[i].beacon_period = bss_info->beacon_period;
491                site_survey_lists[i].capability = bss_info->capability;
492                site_survey_lists[i].rate_count =
493                    get_mcs_max(bss_info->basic_mcs);
494                if (!site_survey_lists[i].rate_count)
495                        site_survey_lists[i].rate_count =
496                            get_legacy(bss_info->rateset.rates,
497                                       bss_info->rateset.count);
498
499                site_survey_lists[i].dtim_period = bss_info->dtim_period;
500                strcpy(site_survey_lists[i].ENCINFO, getEncInfo(bss_info));
501
502                bss_info =
503                    (wl_bss_info_t *) ((uint32) bss_info + bss_info->length);
504        }
505        write_site_survey();
506        open_site_survey();
507        for (i = 0; i < SITE_SURVEY_NUM && site_survey_lists[i].SSID[0]; i++) {
508                fprintf(stderr,
509                        "[%2d] SSID[%20s] BSSID[%s] channel[%2d] frequency[%4d] rssi[%d] noise[%d] beacon[%d] cap[%x] dtim[%d] rate[%d] enc[%s]\n",
510                        i, site_survey_lists[i].SSID,
511                        site_survey_lists[i].BSSID,
512                        site_survey_lists[i].channel,
513                        site_survey_lists[i].frequency,
514                        site_survey_lists[i].RSSI,
515                        site_survey_lists[i].phy_noise,
516                        site_survey_lists[i].beacon_period,
517                        site_survey_lists[i].capability,
518                        site_survey_lists[i].dtim_period,
519                        site_survey_lists[i].rate_count,
520                        site_survey_lists[i].ENCINFO);
521        }
522
523endss:
524
525        C_led(0);
526        eval("wl", "-i", name, "up");
527        return 0;
528}
529
530int write_site_survey(void)
531{
532        FILE *fp;
533
534        if ((fp = fopen(SITE_SURVEY_DB, "w"))) {
535                fwrite(&site_survey_lists[0], sizeof(site_survey_lists), 1, fp);
536                fclose(fp);
537                return FALSE;
538        }
539        return TRUE;
540}
541
542static int open_site_survey(void)
543{
544        FILE *fp;
545
546        bzero(site_survey_lists, sizeof(site_survey_lists));
547
548        if ((fp = fopen(SITE_SURVEY_DB, "r"))) {
549                fread(&site_survey_lists[0], sizeof(site_survey_lists), 1, fp);
550                fclose(fp);
551                return TRUE;
552        }
553        return FALSE;
554}
555
556#ifdef TEST
557
558void main(int argc, char *argv[])
559{
560        site_survey_main(argc, argv);
561
562}
563
564#endif
Note: See TracBrowser for help on using the repository browser.