4 Copyright (C) 2006-2009 Jonathan Zarate
13 #ifndef WL_BSS_INFO_VERSION
14 #error WL_BSS_INFO_VERSION
16 #if WL_BSS_INFO_VERSION < 108
17 #error WL_BSS_INFO_VERSION < 108
22 static int subunit
= 0;
24 static void check_wl_unit(const char *unitarg
)
26 char ifname
[12], *wlunit
;
27 unit
= 0; subunit
= 0;
29 wlunit
= (unitarg
&& *unitarg
) ? (char *)unitarg
:
30 webcgi_safeget("_wl_unit", nvram_safe_get("wl_unit"));
31 snprintf(ifname
, sizeof(ifname
), "wl%s", wlunit
);
32 get_ifname_unit(ifname
, &unit
, &subunit
);
34 _dprintf("check_wl_unit: unitarg: %s, _wl_unit: %s, ifname: %s, unit: %d, subunit: %d\n",
35 unitarg
, webcgi_safeget("_wl_unit", nvram_safe_get("wl_unit")), ifname
, unit
, subunit
);
38 static void wl_restore(char *wif
, int unit
, int ap
, int radio
, int scan_time
)
41 wl_ioctl(wif
, WLC_SET_AP
, &ap
, sizeof(ap
));
43 if (!radio
) set_radio(1, unit
);
44 eval("wl", "-i", wif
, "up"); // without this the router may reboot
45 #if WL_BSS_INFO_VERSION >= 108
46 // no idea why this voodoo sequence works to wake up wl -- zzz
47 eval("wl", "-i", wif
, "ssid", "");
48 eval("wl", "-i", wif
, "ssid", nvram_safe_get(wl_nvname("ssid", unit
, 0)));
51 #ifdef WLC_SET_SCAN_CHANNEL_TIME
53 // restore original scan channel time
54 wl_ioctl(wif
, WLC_SET_SCAN_CHANNEL_TIME
, &scan_time
, sizeof(scan_time
));
57 set_radio(radio
, unit
);
60 // allow to scan using up to MAX_WLIF_SCAN wireless ifaces
61 #define MAX_WLIF_SCAN 3
73 static int start_scan(int idx
, int unit
, int subunit
, void *param
)
75 scan_list_t
*rp
= param
;
80 #ifdef WLC_SET_SCAN_CHANNEL_TIME
84 if ((idx
>= MAX_WLIF_SCAN
) || (rp
->unit_filter
>= 0 && rp
->unit_filter
!= unit
)) return 0;
86 wif
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
88 memset(&sp
, 0xff, sizeof(sp
)); // most default to -1
90 sp
.bss_type
= DOT11_BSSTYPE_ANY
; // =2
93 if (wl_ioctl(wif
, WLC_GET_AP
, &(rp
->wif
[idx
].ap
), sizeof(rp
->wif
[idx
].ap
)) < 0) {
94 // Unable to get AP mode
97 if (rp
->wif
[idx
].ap
> 0) {
98 wl_ioctl(wif
, WLC_SET_AP
, &zero
, sizeof(zero
));
101 // set scan type based on the ap mode
102 sp
.scan_type
= rp
->wif
[idx
].ap
? DOT11_SCANTYPE_PASSIVE
: -1 /* default */;
104 #ifdef WLC_SET_SCAN_CHANNEL_TIME
105 // extend scan channel time to get more AP probe resp
106 wl_ioctl(wif
, WLC_GET_SCAN_CHANNEL_TIME
, &(rp
->wif
[idx
].scan_time
), sizeof(rp
->wif
[idx
].scan_time
));
107 if (rp
->wif
[idx
].scan_time
< scan_time
) {
108 wl_ioctl(wif
, WLC_SET_SCAN_CHANNEL_TIME
, &scan_time
, sizeof(scan_time
));
112 rp
->wif
[idx
].radio
= get_radio(unit
);
113 if (!(rp
->wif
[idx
].radio
)) set_radio(1, unit
);
117 if (wl_ioctl(wif
, WLC_SCAN
, &sp
, WL_SCAN_PARAMS_FIXED_SIZE
) == 0)
119 if (retry
) usleep(100000);
122 // Unable to start scan
123 wl_restore(wif
, unit
, rp
->wif
[idx
].ap
, rp
->wif
[idx
].radio
, rp
->wif
[idx
].scan_time
);
127 static int get_scan_results(int idx
, int unit
, int subunit
, void *param
)
129 scan_list_t
*rp
= param
;
131 if ((idx
>= MAX_WLIF_SCAN
) || (rp
->unit_filter
>= 0 && rp
->unit_filter
!= unit
)) return 0;
136 wl_scan_results_t
*results
;
141 wif
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
143 results
= malloc(WLC_IOCTL_MAXLEN
+ sizeof(*results
));
146 wl_restore(wif
, unit
, rp
->wif
[idx
].ap
, rp
->wif
[idx
].radio
, rp
->wif
[idx
].scan_time
);
149 results
->buflen
= WLC_IOCTL_MAXLEN
;
150 results
->version
= WL_BSS_INFO_VERSION
;
152 // Keep trying to obtain scan results for up to 4 secs
153 // Passive scan may require more time, although 1 extra sec is almost always enough.
157 r
= wl_ioctl(wif
, WLC_SCAN_RESULTS
, results
, WLC_IOCTL_MAXLEN
);
162 wl_restore(wif
, unit
, rp
->wif
[idx
].ap
, rp
->wif
[idx
].radio
, rp
->wif
[idx
].scan_time
);
166 // Unable to obtain scan results
170 // format for javascript
181 bssi
= &results
->bss_info
[0];
182 for (i
= 0; i
< results
->count
; ++i
) {
184 channel
= CHSPEC_CHANNEL(bssi
->chanspec
);
185 if (CHSPEC_IS40(bssi
->chanspec
))
186 channel
= channel
+ (CHSPEC_SB_LOWER(bssi
->chanspec
) ? -2 : 2);
191 if (nvram_get_int("wlx_scrubssid")) {
192 for (k
= j
- 1; k
>= 0; --k
) {
194 if (!isprint(c
)) c
= '?';
199 memcpy(ssid
, bssi
->SSID
, j
);
202 ssidj
= js_string(ssid
);
204 web_printf("%c['%s','%s',%u,%u,%d,%d,[", rp
->comma
,
205 ether_etoa(bssi
->BSSID
.octet
, mac
), ssidj
? ssidj
: "",
207 bssi
->capability
, bssi
->RSSI
, bssi
->phy_noise
);
211 for (j
= 0; j
< bssi
->rateset
.count
; ++j
) {
212 web_printf("%s%u", j
? "," : "", bssi
->rateset
.rates
[j
]);
215 web_printf("],%d,%d,%d]",
218 bssi
->n_cap
? (CHSPEC_IS40(bssi
->chanspec
) ? 40 : (CHSPEC_IS20(bssi
->chanspec
) ? 20 : 10)) : 0);
220 bssi
= (wl_bss_info_t
*)((uint8
*)bssi
+ bssi
->length
);
227 // returns: ['bssid','ssid',channel,capabilities,rssi,noise,[rates,]], or [null,'error message']
228 void asp_wlscan(int argc
, char **argv
)
232 memset(&rp
, 0, sizeof(rp
));
234 rp
.unit_filter
= (argc
> 0) ? atoi(argv
[0]) : (-1);
236 web_puts("\nwlscandata = [");
240 if (foreach_wif(0, &rp
, start_scan
) == 0) {
241 web_puts("[null,'Unable to start scan.']];\n");
248 if (foreach_wif(0, &rp
, get_scan_results
) == 0) {
249 web_puts("[null,'Unable to obtain scan results.']];\n");
256 void wo_wlradio(char *url
)
263 parse_asp("saved.asp");
264 if (nvram_get_int(wl_nvname("radio", unit
, 0))) {
265 if ((enable
= webcgi_get("enable")) != NULL
) {
268 sprintf(sunit
, "%d", unit
);
269 eval("radio", atoi(enable
) ? "on" : "off", sunit
);
275 static int read_noise(int unit
)
279 // WLC_GET_PHY_NOISE = 135
280 if (wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit
, 0)), 135, &v
, sizeof(v
)) == 0) {
283 nvram_set(wl_nvname("tnoise", unit
, 0), s
);
289 static int get_wlnoise(int client
, int unit
)
294 v
= read_noise(unit
);
297 v
= nvram_get_int(wl_nvname("tnoise", unit
, 0));
298 if ((v
>= 0) || (v
< -100)) v
= -99;
303 static int print_wlnoise(int idx
, int unit
, int subunit
, void *param
)
305 web_printf("%c%d", (idx
== 0) ? ' ' : ',', get_wlnoise(wl_client(unit
, 0), unit
));
309 void asp_wlnoise(int argc
, char **argv
)
311 web_puts("\nwlnoise = [");
312 foreach_wif(0, NULL
, print_wlnoise
);
316 void wo_wlmnoise(char *url
)
324 parse_asp("mnoise.asp");
328 int radio
= get_radio(unit
);
330 wif
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
331 if (wl_ioctl(wif
, WLC_GET_AP
, &ap
, sizeof(ap
)) < 0) return;
334 wl_ioctl(wif
, WLC_SET_AP
, &i
, sizeof(i
));
336 for (i
= 10; i
> 0; --i
) {
341 wl_restore(wif
, unit
, ap
, radio
, 0);
344 static int wl_chanfreq(uint ch
, int band
)
346 if ((band
== WLC_BAND_2G
&& (ch
< 1 || ch
> 14)) || (ch
> 200))
348 else if ((band
== WLC_BAND_2G
) && (ch
== 14))
351 return ch
* 5 + ((band
== WLC_BAND_2G
) ? 4814 : 10000) / 2;
354 static int not_wlclient(int idx
, int unit
, int subunit
, void *param
)
356 return (!wl_client(unit
, subunit
));
359 // returns '1' if all wireless interfaces are in client mode, '0' otherwise
360 void asp_wlclient(int argc
, char **argv
)
362 web_puts(foreach_wif(1, NULL
, not_wlclient
) ? "0" : "1");
365 static int print_wlstats(int idx
, int unit
, int subunit
, void *param
)
368 int rate
, client
, nbw
;
369 int chanspec
, channel
, mhz
, band
, scan
;
372 char retbuf
[WLC_IOCTL_SMLEN
];
374 char *ifname
, *ctrlsb
;
376 ifname
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
377 client
= wl_client(unit
, 0);
379 /* Get configured phy type */
380 wl_ioctl(ifname
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
382 if (wl_ioctl(ifname
, WLC_GET_RATE
, &rate
, sizeof(rate
)) < 0)
385 if (wl_ioctl(ifname
, WLC_GET_BAND
, &band
, sizeof(band
)) < 0)
386 band
= nvram_get_int(wl_nvname("nband", unit
, 0));
388 channel
= nvram_get_int(wl_nvname("channel", unit
, 0));
392 if (wl_phytype_n(phytype
)) {
393 if (wl_iovar_getint(ifname
, "chanspec", &chanspec
) != 0) {
394 ctrlsb
= nvram_safe_get(wl_nvname("nctrlsb", unit
, 0));
395 nbw
= nvram_get_int(wl_nvname("nbw", unit
, 0));
398 channel
= CHSPEC_CHANNEL(chanspec
);
399 if (CHSPEC_IS40(chanspec
))
400 channel
= channel
+ (CHSPEC_SB_LOWER(chanspec
) ? -2 : 2);
401 ctrlsb
= CHSPEC_SB_LOWER(chanspec
) ? "lower" : (CHSPEC_SB_UPPER(chanspec
) ? "upper" : "none");
402 nbw
= CHSPEC_IS40(chanspec
) ? 40 : 20;
407 if (wl_ioctl(ifname
, WLC_GET_CHANNEL
, &ch
, sizeof(ch
)) == 0) {
408 scan
= (ch
.scan_channel
> 0);
409 channel
= (scan
) ? ch
.scan_channel
: ch
.hw_channel
;
415 mhz
= (channel
) ? wl_chanfreq(channel
, band
) : 0;
416 if (wl_iovar_getint(ifname
, "chanim_enab", (int*)(void*)&chanim_enab
) != 0)
419 if (wl_iovar_getbuf(ifname
, "chanim_state", &chanspec
, sizeof(chanspec
), retbuf
, WLC_IOCTL_SMLEN
) == 0)
420 interference
= *(int*)retbuf
;
423 memset(&rssi
, 0, sizeof(rssi
));
425 if (wl_ioctl(ifname
, WLC_GET_RSSI
, &rssi
, sizeof(rssi
)) != 0)
429 // [ radio, is_client, channel, freq (mhz), rate, nctrlsb, nbw, rssi, noise, interference ]
430 web_printf("%c{ radio: %d, client: %d, channel: %c%d, mhz: %d, rate: %d, ctrlsb: '%s', nbw: %d, rssi: %d, noise: %d, intf: %d }\n",
431 (idx
== 0) ? ' ' : ',',
432 get_radio(unit
), client
, (scan
? '-' : ' '), channel
, mhz
, rate
, ctrlsb
, nbw
, rssi
.val
, get_wlnoise(client
, unit
), interference
);
437 void asp_wlstats(int argc
, char **argv
)
439 int include_vifs
= (argc
> 0) ? atoi(argv
[0]) : 0;
441 web_puts("\nwlstats = [");
442 foreach_wif(include_vifs
, NULL
, print_wlstats
); // AB multiSSID
446 static void web_print_wlchan(uint chan
, int band
)
449 if ((mhz
= wl_chanfreq(chan
, band
)) > 0)
450 web_printf(",[%d, %d]", chan
, mhz
);
452 web_printf(",[%d, 0]", chan
);
455 static int _wlchanspecs(char *ifname
, char *country
, int band
, int bw
, int ctrlsb
)
457 chanspec_t c
= 0, *chanspec
;
459 wl_uint32_list_t
*list
;
462 char *buf
= (char *)malloc(WLC_IOCTL_MAXLEN
);
466 strcpy(buf
, "chanspecs");
467 buflen
= strlen(buf
) + 1;
469 c
|= (band
== WLC_BAND_5G
) ? WL_CHANSPEC_BAND_5G
: WL_CHANSPEC_BAND_2G
;
470 c
|= (bw
== 20) ? WL_CHANSPEC_BW_20
: WL_CHANSPEC_BW_40
;
472 chanspec
= (chanspec_t
*)(buf
+ buflen
);
474 buflen
+= (sizeof(chanspec_t
));
475 strncpy(buf
+ buflen
, country
, WLC_CNTRY_BUF_SZ
);
476 buflen
+= WLC_CNTRY_BUF_SZ
;
479 list
= (wl_uint32_list_t
*)(buf
+ buflen
);
480 list
->count
= WL_NUMCHANSPECS
;
481 buflen
+= sizeof(uint32
)*(WL_NUMCHANSPECS
+ 1);
483 if (wl_ioctl(ifname
, WLC_GET_VAR
, buf
, buflen
) < 0) {
489 list
= (wl_uint32_list_t
*)buf
;
490 for (i
= 0; i
< list
->count
; i
++) {
491 c
= (chanspec_t
)list
->element
[i
];
492 /* Skip upper.. (take only one of the lower or upper) */
493 if (bw
== 40 && (CHSPEC_CTL_SB(c
) != ctrlsb
))
495 /* Create the actual control channel number from sideband */
496 int chan
= CHSPEC_CHANNEL(c
);
498 chan
+= ((ctrlsb
== WL_CHANSPEC_CTL_SB_UPPER
) ? 2 : -2);
499 web_print_wlchan(chan
, band
);
507 static void _wlchannels(char *ifname
, char *country
, int band
)
510 wl_channels_in_country_t
*cic
;
512 cic
= (wl_channels_in_country_t
*)malloc(WLC_IOCTL_MAXLEN
);
514 cic
->buflen
= WLC_IOCTL_MAXLEN
;
515 strcpy(cic
->country_abbrev
, country
);
518 if (wl_ioctl(ifname
, WLC_GET_CHANNELS_IN_COUNTRY
, cic
, cic
->buflen
) == 0) {
519 for (i
= 0; i
< cic
->count
; i
++) {
520 web_print_wlchan(cic
->channel
[i
], band
);
527 void asp_wlchannels(int argc
, char **argv
)
529 char buf
[WLC_CNTRY_BUF_SZ
];
530 int band
, phytype
, nphy
;
531 int bw
, ctrlsb
, chanspec
;
534 // args: unit, nphy[1|0], bw, band, ctrlsb
536 check_wl_unit(argc
> 0 ? argv
[0] : NULL
);
538 ifname
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
539 wl_ioctl(ifname
, WLC_GET_COUNTRY
, buf
, sizeof(buf
));
540 if (wl_ioctl(ifname
, WLC_GET_BAND
, &band
, sizeof(band
)) != 0)
541 band
= nvram_get_int(wl_nvname("nband", unit
, 0));
542 wl_iovar_getint(ifname
, "chanspec", &chanspec
);
545 nphy
= atoi(argv
[1]);
547 wl_ioctl(ifname
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
548 nphy
= wl_phytype_n(phytype
);
551 bw
= (argc
> 2) ? atoi(argv
[2]) : 0;
552 bw
= bw
? : CHSPEC_IS40(chanspec
) ? 40 : 20;
554 if (argc
> 3) band
= atoi(argv
[3]) ? : band
;
557 if (strcmp(argv
[4], "upper") == 0)
558 ctrlsb
= WL_CHANSPEC_CTL_SB_UPPER
;
560 ctrlsb
= WL_CHANSPEC_CTL_SB_LOWER
;
563 ctrlsb
= CHSPEC_CTL_SB(chanspec
);
565 web_puts("\nwl_channels = [\n[0, 0]");
567 if (!_wlchanspecs(ifname
, buf
, band
, bw
, ctrlsb
) && band
== WLC_BAND_2G
&& bw
== 40)
568 _wlchanspecs(ifname
, buf
, band
, 20, ctrlsb
);
571 _wlchannels(ifname
, buf
, band
);
575 static int print_wlbands(int idx
, int unit
, int subunit
, void *param
)
577 char *phytype
, *phylist
, *ifname
;
579 int list
[WLC_BAND_ALL
];
582 ifname
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
583 phytype
= nvram_safe_get(wl_nvname("phytype", unit
, 0));
585 web_printf("%c[", (idx
== 0) ? ' ' : ',');
587 if (phytype
[0] == 'n' ||
592 /* Get band list. Assume both the bands in case of error */
593 if (wl_ioctl(ifname
, WLC_GET_BANDLIST
, list
, sizeof(list
)) < 0) {
594 for (i
= WLC_BAND_5G
; i
<= WLC_BAND_2G
; i
++) {
595 web_printf("%c'%d'", comma
, i
);
602 for (i
= 1; i
<= list
[0]; i
++) {
603 web_printf("%c'%d'", comma
, list
[i
]);
609 /* Get available phy types of the currently selected wireless interface */
610 phylist
= nvram_safe_get(wl_nvname("phytypes", unit
, 0));
611 for (i
= 0; i
< strlen(phylist
); i
++) {
612 web_printf("%c'%d'", comma
, phylist
[i
] == 'a' ? WLC_BAND_5G
: WLC_BAND_2G
);
622 void asp_wlbands(int argc
, char **argv
)
624 int include_vifs
= (argc
> 0) ? atoi(argv
[0]) : 0;
626 web_puts("\nwl_bands = [");
627 foreach_wif(include_vifs
, NULL
, print_wlbands
); // AB multiSSID
631 static int print_wif(int idx
, int unit
, int subunit
, void *param
)
633 char unit_str
[] = "000000";
637 snprintf(unit_str
, sizeof(unit_str
), "%d.%d", unit
, subunit
);
639 snprintf(unit_str
, sizeof(unit_str
), "%d", unit
);
641 // [ifname, unitstr, unit, subunit, ssid, hwaddr]
642 ssidj
= js_string(nvram_safe_get(wl_nvname("ssid", unit
, subunit
)));
643 web_printf("%c['%s','%s',%d,%d,'%s','%s']", (idx
== 0) ? ' ' : ',',
644 nvram_safe_get(wl_nvname("ifname", unit
, subunit
)),
645 unit_str
, unit
, subunit
, ssidj
,
646 // assume the slave inteface MAC address is the same as the primary interface
647 // nvram_safe_get(wl_nvname("hwaddr", unit, 0))
648 // // virtual inteface MAC address
649 nvram_safe_get(wl_nvname("hwaddr", unit
, subunit
)) // AB multiSSID
656 void asp_wlifaces(int argc
, char **argv
)
658 int include_vifs
= (argc
> 0) ? atoi(argv
[0]) : 0;
660 web_puts("\nwl_ifaces = [");
661 foreach_wif(include_vifs
, NULL
, print_wif
);
665 void asp_wlcountries(int argc
, char **argv
)
667 char s
[128], *p
, *code
, *country
;
671 web_puts("\nwl_countries = [");
672 if ((f
= popen("wl country list", "r")) != NULL
) {
673 // skip the header line
674 fgets(s
, sizeof(s
), f
);
675 while (fgets(s
, sizeof(s
), f
)) {
677 if ((code
= strsep(&p
, " \t\n")) && p
) {
678 country
= strsep(&p
, "\n");
679 if ((country
&& *country
&& strcmp(code
, country
) != 0) ||
680 // special case EU code since the driver may not have a name for it
681 (strcmp(code
, "EU") == 0)) {
682 if (!country
|| *country
== 0) country
= code
;
683 p
= js_string(country
);
684 web_printf("%c['%s', '%s']", i
++ ? ',' : ' ', code
, p
);