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

Last change on this file since 32590 was 32590, checked in by brainslayer, 3 weeks ago

format code

File size: 13.2 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;
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 wl_rsn_ie_parse_info(uint8 * rsn_buf, uint len, rsn_parse_info_t * rsn)
83{
84        uint16 count;
85
86        bzero(rsn, sizeof(rsn_parse_info_t));
87
88        /* version */
89        if (len < sizeof(uint16))
90                return 1;
91
92        rsn->version = ltoh16_ua(rsn_buf);
93        len -= sizeof(uint16);
94        rsn_buf += sizeof(uint16);
95
96        /* Multicast Suite */
97        if (len < sizeof(wpa_suite_mcast_t))
98                return 0;
99
100        rsn->mcast = (wpa_suite_mcast_t *) rsn_buf;
101        len -= sizeof(wpa_suite_mcast_t);
102        rsn_buf += sizeof(wpa_suite_mcast_t);
103
104        /* Unicast Suite */
105        if (len < sizeof(uint16))
106                return 0;
107
108        count = ltoh16_ua(rsn_buf);
109
110        if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t)))
111                return 1;
112
113        rsn->ucast = (wpa_suite_ucast_t *) rsn_buf;
114        len -= (sizeof(uint16) + count * sizeof(wpa_suite_t));
115        rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t));
116
117        /* AKM Suite */
118        if (len < sizeof(uint16))
119                return 0;
120
121        count = ltoh16_ua(rsn_buf);
122
123        if (len < (sizeof(uint16) + count * sizeof(wpa_suite_t)))
124                return 1;
125
126        rsn->akm = (wpa_suite_auth_key_mgmt_t *) rsn_buf;
127        len -= (sizeof(uint16) + count * sizeof(wpa_suite_t));
128        rsn_buf += (sizeof(uint16) + count * sizeof(wpa_suite_t));
129
130        /* Capabilites */
131        if (len < sizeof(uint16))
132                return 0;
133
134        rsn->capabilities = rsn_buf;
135
136        return 0;
137}
138
139static void wl_rsn_ie_dump(bcm_tlv_t * ie, char *sum)
140{
141        int i;
142        int rsn;
143        wpa_ie_fixed_t *wpa = NULL;
144        rsn_parse_info_t rsn_info;
145        wpa_suite_t *suite;
146        uint8 std_oui[3];
147        int unicast_count = 0;
148        int akm_count = 0;
149        uint16 capabilities;
150        uint cntrs;
151        int err;
152
153        if (ie->id == DOT11_MNG_RSN_ID) {
154                rsn = TRUE;
155                memcpy(std_oui, WPA2_OUI, WPA_OUI_LEN);
156                err = wl_rsn_ie_parse_info(ie->data, ie->len, &rsn_info);
157        } else {
158                rsn = FALSE;
159                memcpy(std_oui, WPA_OUI, WPA_OUI_LEN);
160                wpa = (wpa_ie_fixed_t *) ie;
161                err = wl_rsn_ie_parse_info((uint8 *) & wpa->version, wpa->length - WPA_IE_OUITYPE_LEN, &rsn_info);
162        }
163        if (err || rsn_info.version != WPA_VERSION) {
164                strcat(sum, "WEP ");
165                return;
166        }
167
168        /* Check for multicast suite */
169        if (rsn_info.mcast) {
170                if (!wlu_bcmp(rsn_info.mcast->oui, std_oui, 3)) {
171                        switch (rsn_info.mcast->type) {
172                        case WPA_CIPHER_NONE:
173                                break;
174                        case WPA_CIPHER_WEP_40:
175                                strcat(sum, "Group-WEP64 ");
176                                break;
177                        case WPA_CIPHER_WEP_104:
178                                strcat(sum, "Group-WEP128 ");
179                                break;
180                        case WPA_CIPHER_TKIP:
181                                strcat(sum, "Group-TKIP ");
182                                break;
183                        case WPA_CIPHER_AES_OCB:
184                                strcat(sum, "Group-AES-OCB ");
185                                break;
186                        case WPA_CIPHER_AES_CCM:
187                                strcat(sum, "Group-AES-CCMP ");
188                                break;
189                        default:
190                                sprintf(sum, "Unknown-%s(#%d) ", rsn ? "WPA2" : "WPA", rsn_info.mcast->type);
191                                break;
192                        }
193                } else {
194                        sprintf(sum, "%s Unknown-%02X:%02X:%02X(#%d) ", sum, rsn_info.mcast->oui[0], rsn_info.mcast->oui[1], rsn_info.mcast->oui[2], rsn_info.mcast->type);
195                }
196        }
197
198        /* Check for unicast suite(s) */
199        if (rsn_info.ucast) {
200                unicast_count = ltoh16_ua(&rsn_info.ucast->count);
201                for (i = 0; i < unicast_count; i++) {
202                        suite = &rsn_info.ucast->list[i];
203                        if (!wlu_bcmp(suite->oui, std_oui, 3)) {
204                                switch (suite->type) {
205                                case WPA_CIPHER_NONE:
206                                        strcat(sum, "Pair-NONE ");
207                                        break;
208                                case WPA_CIPHER_WEP_40:
209                                        strcat(sum, "Pair-WEP64 ");
210                                        break;
211                                case WPA_CIPHER_WEP_104:
212                                        strcat(sum, "Pair-WEP128 ");
213                                        break;
214                                case WPA_CIPHER_TKIP:
215                                        strcat(sum, "Pair-TKIP ");
216                                        break;
217                                case WPA_CIPHER_AES_OCB:
218                                        strcat(sum, "Pair-AES-OCB ");
219                                        break;
220                                case WPA_CIPHER_AES_CCM:
221                                        strcat(sum, "Pair-AES-CCMP ");
222                                        break;
223                                default:
224                                        sprintf(sum, "WPA-Unknown-%s(#%d) ", rsn ? "WPA2" : "WPA", suite->type);
225                                        break;
226                                }
227                        } else {
228                                sprintf(sum, "%s Unknown-%02X:%02X:%02X(#%d) ", sum, suite->oui[0], suite->oui[1], suite->oui[2], suite->type);
229                        }
230                }
231                printf("\n");
232        }
233        /* Authentication Key Management */
234        if (rsn_info.akm) {
235                akm_count = ltoh16_ua(&rsn_info.akm->count);
236                for (i = 0; i < akm_count; i++) {
237                        suite = &rsn_info.akm->list[i];
238                        if (!wlu_bcmp(suite->oui, std_oui, 3)) {
239                                switch (suite->type) {
240                                case RSN_AKM_NONE:
241                                        strcat(sum, "None ");
242                                        break;
243                                case RSN_AKM_UNSPECIFIED:
244                                        if (rsn)
245                                                strcat(sum, "WPA2 ");
246                                        else
247                                                strcat(sum, "WPA ");
248                                        break;
249                                case RSN_AKM_PSK:
250                                        if (rsn)
251                                                strcat(sum, "WPA2-PSK ");
252                                        else
253                                                strcat(sum, "WPA-PSK ");
254                                        break;
255                                default:
256                                        sprintf(sum, "Unknown-%s(#%d)  ", rsn ? "WPA2" : "WPA", suite->type);
257                                        break;
258                                }
259                        } else {
260                                sprintf(sum, "%s Unknown-%02X:%02X:%02X(#%d)  ", sum, suite->oui[0], suite->oui[1], suite->oui[2], suite->type);
261                        }
262                }
263        }
264}
265
266static uint8 *wlu_parse_tlvs(uint8 * tlv_buf, int buflen, uint key)
267{
268        uint8 *cp;
269        int totlen;
270
271        cp = tlv_buf;
272        totlen = buflen;
273
274        /* find tagged parameter */
275        while (totlen >= 2) {
276                uint tag;
277                int len;
278
279                tag = *cp;
280                len = *(cp + 1);
281
282                /* validate remaining totlen */
283                if ((tag == key) && (totlen >= (len + 2)))
284                        return (cp);
285
286                cp += (len + 2);
287                totlen -= (len + 2);
288        }
289
290        return NULL;
291}
292
293static char *wl_dump_wpa_rsn_ies(uint8 * cp, uint len)
294{
295        uint8 *parse = cp;
296        uint parse_len = len;
297        uint8 *wpaie;
298        uint8 *rsnie;
299        static char sum[128] = { 0 };
300        bzero(sum, sizeof(sum));
301
302        while ((wpaie = wlu_parse_tlvs(parse, parse_len, DOT11_MNG_WPA_ID)))
303                if (wlu_is_wpa_ie(&wpaie, &parse, &parse_len))
304                        break;
305        if (wpaie)
306                wl_rsn_ie_dump((bcm_tlv_t *) wpaie, sum);
307
308        rsnie = wlu_parse_tlvs(cp, len, DOT11_MNG_RSN_ID);
309        if (rsnie)
310                wl_rsn_ie_dump((bcm_tlv_t *) rsnie, sum);
311        if (wpaie || rsnie)
312                return sum;
313
314        return "WEP";
315}
316
317static char *getEncInfo(wl_bss_info_t * bi)
318{
319        if (bi->capability & DOT11_CAP_PRIVACY) {
320                if (bi->ie_length)
321                        return wl_dump_wpa_rsn_ies((uint8 *) (((uint8 *) bi) + bi->ie_offset), bi->ie_length);
322                else
323                        return "WEP";
324        } else
325                return "Open";
326}
327
328static int get_mcs_max(const unsigned char *mcs)
329{
330        unsigned int mcs_bit, prev_bit = -2, prev_cont = 0;
331
332        for (mcs_bit = 0; mcs_bit < 16 * 8; mcs_bit++) {
333                unsigned int mcs_octet = mcs_bit / 8;
334                unsigned int MCS_RATE_BIT = 1 << mcs_bit % 8;
335                bool mcs_rate_idx_set;
336
337                mcs_rate_idx_set = ! !(mcs[mcs_octet] & MCS_RATE_BIT);
338
339                if (!mcs_rate_idx_set)
340                        break;
341
342                if (prev_bit != mcs_bit - 1) {
343                        prev_cont = 0;
344                } else if (!prev_cont) {
345                        prev_cont = 1;
346                }
347
348                prev_bit = mcs_bit;
349        }
350        if (prev_cont) {
351                if (prev_bit == 7)
352                        return 150;
353                if (prev_bit == 15)
354                        return 300;
355                if (prev_bit == 23)
356                        return 450;
357                if (prev_bit == 31)
358                        return 600;
359        }
360        return 0;
361}
362
363int get_legacy(unsigned char *rates, int count)
364{
365        int r, b, i;
366        int maxrate = 0;
367        for (i = 0; i < count; i++) {
368                r = rates[i] & 0x7f;
369                //b = rates[i] & 0x80;
370                if (r == 0)
371                        break;
372                if (r > maxrate)
373                        maxrate = r;
374        }
375        return maxrate / 2;
376}
377
378int site_survey_main(int argc, char *argv[])
379{
380        site_survey_lists = calloc(sizeof(struct site_survey_list) * SITE_SURVEY_NUM, 1);
381
382        char tmp[32];
383        sprintf(tmp, "%s_ifname", nvram_safe_get("wifi_display"));
384        char *name = nvram_safe_get(tmp);
385
386        unsigned char buf[10000];
387        wl_scan_results_t *scan_res = (wl_scan_results_t *) buf;
388        wl_bss_info_t *bss_info;
389        unsigned char mac[20];
390        int i;
391        char *dev = name;
392
393        unlink(SITE_SURVEY_DB);
394        int ap = 0, oldap = 0;
395        wl_scan_params_t params;
396
397        bzero(&params, sizeof(params));
398
399        /*
400         * use defaults (same parameters as wl scan)
401         */
402
403        memset(&params.bssid, 0xff, sizeof(params.bssid));
404        if (argc > 1) {
405                params.ssid.SSID_len = strlen(argv[1]);
406                strcpy(params.ssid.SSID, argv[1]);
407        }
408        params.bss_type = DOT11_BSSTYPE_ANY;
409        params.scan_type = 0;
410        params.nprobes = -1;
411        params.active_time = -1;
412        params.passive_time = -1;
413        params.home_time = -1;
414        params.channel_num = 0;
415
416        /*
417         * can only scan in STA mode
418         */
419        if (wl_ioctl(dev, WLC_SCAN, &params, 64) < 0) {
420                fprintf(stderr, "scan failed\n");
421                return -1;
422        }
423        int count = 10;
424        int ret = 0;
425        while ((count--) > 0)   //scan for max 5 seconds
426        {
427                usleep(1000 * 1000);
428
429                bzero(buf, sizeof(buf));
430                scan_res->buflen = sizeof(buf);
431                ret = wl_ioctl(dev, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN);
432                if (!ret)
433                        break;
434        }
435        if (ret < 0) {
436                fprintf(stderr, "scan failed with errorcode %d\n", ret);
437        }
438
439        fprintf(stderr, "buflen=[%d] version=[%d] count=[%d]\n", scan_res->buflen, scan_res->version, scan_res->count);
440
441        if (scan_res->count == 0) {
442                cprintf("Can't find any wireless device\n");
443                goto endss;
444        }
445
446        bss_info = &scan_res->bss_info[0];
447        for (i = 0; i < scan_res->count; i++) {
448                strcpy(site_survey_lists[i].SSID, bss_info->SSID);
449                strcpy(site_survey_lists[i].BSSID, ether_etoa(bss_info->BSSID.octet, mac));
450                site_survey_lists[i].channel = bss_info->chanspec & 0xff;
451                switch ((bss_info->chanspec & 0x3800)) {
452                case 0:
453                case 0x800:
454                case 0x1000:
455                        site_survey_lists[i].channel = bss_info->chanspec & 0xff;
456                        break;
457                case 0x0C00:    // for older version
458                case 0x1800:
459                        site_survey_lists[i].channel = bss_info->ctl_ch | 0x2000;
460                        break;
461                case 0x2000:
462                case 0x2800:
463                case 0x3000:
464                        site_survey_lists[i].channel = bss_info->ctl_ch;
465                }
466
467#ifdef WL_CHANSPEC_BW_80
468                switch (bss_info->chanspec & 0x3800) {
469                case WL_CHANSPEC_BW_80:
470                        site_survey_lists[i].channel |= 0x1000;
471                        break;
472                case WL_CHANSPEC_BW_8080:
473                        site_survey_lists[i].channel |= 0x1100;
474                        break;
475                case WL_CHANSPEC_BW_160:
476                        site_survey_lists[i].channel |= 0x1200;
477                        break;
478                }
479#endif
480                site_survey_lists[i].frequency = ieee80211_ieee2mhz(site_survey_lists[i].channel & 0xff);
481
482                site_survey_lists[i].RSSI = bss_info->RSSI;
483                site_survey_lists[i].phy_noise = bss_info->phy_noise;
484                site_survey_lists[i].beacon_period = bss_info->beacon_period;
485                site_survey_lists[i].capability = bss_info->capability;
486                site_survey_lists[i].rate_count = get_mcs_max(bss_info->basic_mcs);
487                if (!site_survey_lists[i].rate_count)
488                        site_survey_lists[i].rate_count = get_legacy(bss_info->rateset.rates, bss_info->rateset.count);
489
490                site_survey_lists[i].dtim_period = bss_info->dtim_period;
491                strcpy(site_survey_lists[i].ENCINFO, getEncInfo(bss_info));
492
493                bss_info = (wl_bss_info_t *) ((uint32) bss_info + bss_info->length);
494        }
495        write_site_survey();
496        open_site_survey();
497        // modded by ascott and fractal, may 17th, 2012 to show "hidden" SSIDS
498        for (i = 0; i < SITE_SURVEY_NUM && site_survey_lists[i].BSSID[0]; i++) {
499                if (site_survey_lists[i].SSID[0] == 0) {
500                        strcpy(site_survey_lists[i].SSID, "hidden");
501                }
502                fprintf(stderr,
503                        "[%2d] SSID[%20s] BSSID[%s] channel[%2d] frequency[%4d] rssi[%d] noise[%d] beacon[%d] cap[%x] dtim[%d] rate[%d] enc[%s]\n",
504                        i, site_survey_lists[i].SSID,
505                        site_survey_lists[i].BSSID,
506                        site_survey_lists[i].channel & 0xff,
507                        site_survey_lists[i].frequency,
508                        site_survey_lists[i].RSSI,
509                        site_survey_lists[i].phy_noise,
510                        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);
511        }
512
513endss:
514
515        C_led(0);
516        eval("wl", "-i", name, "up");
517        free(site_survey_lists);
518        return 0;
519}
520
521int write_site_survey(void)
522{
523        FILE *fp;
524
525        if ((fp = fopen(SITE_SURVEY_DB, "w"))) {
526                fwrite(&site_survey_lists[0], sizeof(struct site_survey_list) * SITE_SURVEY_NUM, 1, fp);
527                fclose(fp);
528                return FALSE;
529        }
530        return TRUE;
531}
532
533static int open_site_survey(void)
534{
535        FILE *fp;
536
537        bzero(site_survey_lists, sizeof(site_survey_lists));
538
539        if ((fp = fopen(SITE_SURVEY_DB, "r"))) {
540                fread(&site_survey_lists[0], sizeof(struct site_survey_list) * SITE_SURVEY_NUM, 1, fp);
541                fclose(fp);
542                return TRUE;
543        }
544        return FALSE;
545}
546
547#ifdef TEST
548
549void main(int argc, char *argv[])
550{
551        site_survey_main(argc, argv);
552
553}
554
555#endif
Note: See TracBrowser for help on using the repository browser.