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
)
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 set_radio(radio
, unit
);
54 // allow to scan using up to MAX_WLIF_SCAN wireless ifaces
55 #define MAX_WLIF_SCAN 3
66 static int start_scan(int idx
, int unit
, int subunit
, void *param
)
68 scan_list_t
*rp
= param
;
74 if ((idx
>= MAX_WLIF_SCAN
) || (rp
->unit_filter
>= 0 && rp
->unit_filter
!= unit
)) return 0;
76 wif
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
77 memset(&sp
, 0xff, sizeof(sp
)); // most default to -1
79 sp
.bss_type
= DOT11_BSSTYPE_ANY
; // =2
82 if (wl_ioctl(wif
, WLC_GET_AP
, &(rp
->wif
[idx
].ap
), sizeof(rp
->wif
[idx
].ap
)) < 0) {
83 // Unable to get AP mode
86 if (rp
->wif
[idx
].ap
> 0) {
87 wl_ioctl(wif
, WLC_SET_AP
, &zero
, sizeof(zero
));
90 // set scan type based on the ap mode
91 sp
.scan_type
= rp
->wif
[idx
].ap
? DOT11_SCANTYPE_PASSIVE
: -1 /* default */;
93 rp
->wif
[idx
].radio
= get_radio(unit
);
94 if (!(rp
->wif
[idx
].radio
)) set_radio(1, unit
);
98 if (wl_ioctl(wif
, WLC_SCAN
, &sp
, WL_SCAN_PARAMS_FIXED_SIZE
) == 0)
100 if (retry
) usleep(100000);
103 // Unable to start scan
104 wl_restore(wif
, unit
, rp
->wif
[idx
].ap
, rp
->wif
[idx
].radio
);
108 static int get_scan_results(int idx
, int unit
, int subunit
, void *param
)
110 scan_list_t
*rp
= param
;
112 if ((idx
>= MAX_WLIF_SCAN
) || (rp
->unit_filter
>= 0 && rp
->unit_filter
!= unit
)) return 0;
117 wl_scan_results_t
*results
;
122 wif
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
124 results
= malloc(WLC_IOCTL_MAXLEN
+ sizeof(*results
));
127 wl_restore(wif
, unit
, rp
->wif
[idx
].ap
, rp
->wif
[idx
].radio
);
130 results
->buflen
= WLC_IOCTL_MAXLEN
;
131 results
->version
= WL_BSS_INFO_VERSION
;
133 // Keep trying to obtain scan results for up to 4 secs
134 // Passive scan may require more time, although 1 extra sec is almost always enough.
138 r
= wl_ioctl(wif
, WLC_SCAN_RESULTS
, results
, WLC_IOCTL_MAXLEN
);
143 wl_restore(wif
, unit
, rp
->wif
[idx
].ap
, rp
->wif
[idx
].radio
);
147 // Unable to obtain scan results
151 // format for javascript
162 bssi
= &results
->bss_info
[0];
163 for (i
= 0; i
< results
->count
; ++i
) {
165 channel
= CHSPEC_CHANNEL(bssi
->chanspec
);
166 if (CHSPEC_IS40(bssi
->chanspec
))
167 channel
= channel
+ (CHSPEC_SB_LOWER(bssi
->chanspec
) ? -2 : 2);
172 if (nvram_get_int("wlx_scrubssid")) {
173 for (k
= j
- 1; k
>= 0; --k
) {
175 if (!isprint(c
)) c
= '?';
180 memcpy(ssid
, bssi
->SSID
, j
);
183 ssidj
= js_string(ssid
);
185 web_printf("%c['%s','%s',%u,%u,%d,%d,[", rp
->comma
,
186 ether_etoa(bssi
->BSSID
.octet
, mac
), ssidj
? ssidj
: "",
188 bssi
->capability
, bssi
->RSSI
, bssi
->phy_noise
);
192 for (j
= 0; j
< bssi
->rateset
.count
; ++j
) {
193 web_printf("%s%u", j
? "," : "", bssi
->rateset
.rates
[j
]);
195 web_printf("],%d,%d]", bssi
->n_cap
, bssi
->nbss_cap
);
197 bssi
= (wl_bss_info_t
*)((uint8
*)bssi
+ bssi
->length
);
204 // returns: ['bssid','ssid',channel,capabilities,rssi,noise,[rates,]], or [null,'error message']
205 void asp_wlscan(int argc
, char **argv
)
209 memset(&rp
, 0, sizeof(rp
));
211 rp
.unit_filter
= (argc
> 0) ? atoi(argv
[0]) : (-1);
213 web_puts("\nwlscandata = [");
217 if (foreach_wif(0, &rp
, start_scan
) == 0) {
218 web_puts("[null,'Unable to start scan.']];\n");
225 if (foreach_wif(0, &rp
, get_scan_results
) == 0) {
226 web_puts("[null,'Unable to obtain scan results.']];\n");
233 void wo_wlradio(char *url
)
240 parse_asp("saved.asp");
241 if (nvram_get_int(wl_nvname("radio", unit
, 0))) {
242 if ((enable
= webcgi_get("enable")) != NULL
) {
245 sprintf(sunit
, "%d", unit
);
246 eval("radio", atoi(enable
) ? "on" : "off", sunit
);
252 static int read_noise(int unit
)
256 // WLC_GET_PHY_NOISE = 135
257 if (wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit
, 0)), 135, &v
, sizeof(v
)) == 0) {
260 nvram_set(wl_nvname("tnoise", unit
, 0), s
);
266 static int get_wlnoise(int client
, int unit
)
271 v
= read_noise(unit
);
274 v
= nvram_get_int(wl_nvname("tnoise", unit
, 0));
275 if ((v
>= 0) || (v
< -100)) v
= -99;
280 static int print_wlnoise(int idx
, int unit
, int subunit
, void *param
)
282 web_printf("%c%d", (idx
== 0) ? ' ' : ',', get_wlnoise(wl_client(unit
, 0), unit
));
286 void asp_wlnoise(int argc
, char **argv
)
288 web_puts("\nwlnoise = [");
289 foreach_wif(0, NULL
, print_wlnoise
);
293 void wo_wlmnoise(char *url
)
301 parse_asp("mnoise.asp");
305 int radio
= get_radio(unit
);
307 wif
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
308 if (wl_ioctl(wif
, WLC_GET_AP
, &ap
, sizeof(ap
)) < 0) return;
311 wl_ioctl(wif
, WLC_SET_AP
, &i
, sizeof(i
));
313 for (i
= 10; i
> 0; --i
) {
318 wl_restore(wif
, unit
, ap
, radio
);
321 static int wl_chanfreq(uint ch
, int band
)
323 if ((band
== WLC_BAND_2G
&& (ch
< 1 || ch
> 14)) || (ch
> 200))
325 else if ((band
== WLC_BAND_2G
) && (ch
== 14))
328 return ch
* 5 + ((band
== WLC_BAND_2G
) ? 4814 : 10000) / 2;
331 static int not_wlclient(int idx
, int unit
, int subunit
, void *param
)
333 return (!wl_client(unit
, subunit
));
336 // returns '1' if all wireless interfaces are in client mode, '0' otherwise
337 void asp_wlclient(int argc
, char **argv
)
339 web_puts(foreach_wif(1, NULL
, not_wlclient
) ? "0" : "1");
342 static int print_wlstats(int idx
, int unit
, int subunit
, void *param
)
345 int rate
, client
, nbw
;
346 int chanspec
, channel
, mhz
, band
, scan
;
349 char retbuf
[WLC_IOCTL_SMLEN
];
351 char *ifname
, *ctrlsb
;
353 ifname
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
354 client
= wl_client(unit
, 0);
356 /* Get configured phy type */
357 wl_ioctl(ifname
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
359 if (wl_ioctl(ifname
, WLC_GET_RATE
, &rate
, sizeof(rate
)) < 0)
362 if (wl_ioctl(ifname
, WLC_GET_BAND
, &band
, sizeof(band
)) < 0)
363 band
= nvram_get_int(wl_nvname("nband", unit
, 0));
365 channel
= nvram_get_int(wl_nvname("channel", unit
, 0));
369 if (wl_phytype_n(phytype
)) {
370 if (wl_iovar_getint(ifname
, "chanspec", &chanspec
) != 0) {
371 ctrlsb
= nvram_safe_get(wl_nvname("nctrlsb", unit
, 0));
372 nbw
= nvram_get_int(wl_nvname("nbw", unit
, 0));
375 channel
= CHSPEC_CHANNEL(chanspec
);
376 if (CHSPEC_IS40(chanspec
))
377 channel
= channel
+ (CHSPEC_SB_LOWER(chanspec
) ? -2 : 2);
378 ctrlsb
= CHSPEC_SB_LOWER(chanspec
) ? "lower" : (CHSPEC_SB_UPPER(chanspec
) ? "upper" : "none");
379 nbw
= CHSPEC_IS40(chanspec
) ? 40 : 20;
384 if (wl_ioctl(ifname
, WLC_GET_CHANNEL
, &ch
, sizeof(ch
)) == 0) {
385 scan
= (ch
.scan_channel
> 0);
386 channel
= (scan
) ? ch
.scan_channel
: ch
.hw_channel
;
392 mhz
= (channel
) ? wl_chanfreq(channel
, band
) : 0;
393 if (wl_iovar_getint(ifname
, "chanim_enab", (int*)(void*)&chanim_enab
) != 0)
396 if (wl_iovar_getbuf(ifname
, "chanim_state", &chanspec
, sizeof(chanspec
), retbuf
, WLC_IOCTL_SMLEN
) == 0)
397 interference
= *(int*)retbuf
;
400 memset(&rssi
, 0, sizeof(rssi
));
402 if (wl_ioctl(ifname
, WLC_GET_RSSI
, &rssi
, sizeof(rssi
)) != 0)
406 // [ radio, is_client, channel, freq (mhz), rate, nctrlsb, nbw, rssi, noise, interference ]
407 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",
408 (idx
== 0) ? ' ' : ',',
409 get_radio(unit
), client
, (scan
? '-' : ' '), channel
, mhz
, rate
, ctrlsb
, nbw
, rssi
.val
, get_wlnoise(client
, unit
), interference
);
414 void asp_wlstats(int argc
, char **argv
)
416 int include_vifs
= (argc
> 0) ? atoi(argv
[0]) : 0;
418 web_puts("\nwlstats = [");
419 foreach_wif(include_vifs
, NULL
, print_wlstats
); // AB multiSSID
423 static void web_print_wlchan(uint chan
, int band
)
426 if ((mhz
= wl_chanfreq(chan
, band
)) > 0)
427 web_printf(",[%d, %d]", chan
, mhz
);
429 web_printf(",[%d, 0]", chan
);
432 static int _wlchanspecs(char *ifname
, char *country
, int band
, int bw
, int ctrlsb
)
434 chanspec_t c
= 0, *chanspec
;
436 wl_uint32_list_t
*list
;
439 char *buf
= (char *)malloc(WLC_IOCTL_MAXLEN
);
443 strcpy(buf
, "chanspecs");
444 buflen
= strlen(buf
) + 1;
446 c
|= (band
== WLC_BAND_5G
) ? WL_CHANSPEC_BAND_5G
: WL_CHANSPEC_BAND_2G
;
447 c
|= (bw
== 20) ? WL_CHANSPEC_BW_20
: WL_CHANSPEC_BW_40
;
449 chanspec
= (chanspec_t
*)(buf
+ buflen
);
451 buflen
+= (sizeof(chanspec_t
));
452 strncpy(buf
+ buflen
, country
, WLC_CNTRY_BUF_SZ
);
453 buflen
+= WLC_CNTRY_BUF_SZ
;
456 list
= (wl_uint32_list_t
*)(buf
+ buflen
);
457 list
->count
= WL_NUMCHANSPECS
;
458 buflen
+= sizeof(uint32
)*(WL_NUMCHANSPECS
+ 1);
460 if (wl_ioctl(ifname
, WLC_GET_VAR
, buf
, buflen
) < 0) {
466 list
= (wl_uint32_list_t
*)buf
;
467 for (i
= 0; i
< list
->count
; i
++) {
468 c
= (chanspec_t
)list
->element
[i
];
469 /* Skip upper.. (take only one of the lower or upper) */
470 if (bw
== 40 && (CHSPEC_CTL_SB(c
) != ctrlsb
))
472 /* Create the actual control channel number from sideband */
473 int chan
= CHSPEC_CHANNEL(c
);
475 chan
+= ((ctrlsb
== WL_CHANSPEC_CTL_SB_UPPER
) ? 2 : -2);
476 web_print_wlchan(chan
, band
);
484 static void _wlchannels(char *ifname
, char *country
, int band
)
487 wl_channels_in_country_t
*cic
;
489 cic
= (wl_channels_in_country_t
*)malloc(WLC_IOCTL_MAXLEN
);
491 cic
->buflen
= WLC_IOCTL_MAXLEN
;
492 strcpy(cic
->country_abbrev
, country
);
495 if (wl_ioctl(ifname
, WLC_GET_CHANNELS_IN_COUNTRY
, cic
, cic
->buflen
) == 0) {
496 for (i
= 0; i
< cic
->count
; i
++) {
497 web_print_wlchan(cic
->channel
[i
], band
);
504 void asp_wlchannels(int argc
, char **argv
)
506 char buf
[WLC_CNTRY_BUF_SZ
];
507 int band
, phytype
, nphy
;
508 int bw
, ctrlsb
, chanspec
;
511 // args: unit, nphy[1|0], bw, band, ctrlsb
513 check_wl_unit(argc
> 0 ? argv
[0] : NULL
);
515 ifname
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
516 wl_ioctl(ifname
, WLC_GET_COUNTRY
, buf
, sizeof(buf
));
517 if (wl_ioctl(ifname
, WLC_GET_BAND
, &band
, sizeof(band
)) != 0)
518 band
= nvram_get_int(wl_nvname("nband", unit
, 0));
519 wl_iovar_getint(ifname
, "chanspec", &chanspec
);
522 nphy
= atoi(argv
[1]);
524 wl_ioctl(ifname
, WLC_GET_PHYTYPE
, &phytype
, sizeof(phytype
));
525 nphy
= wl_phytype_n(phytype
);
528 bw
= (argc
> 2) ? atoi(argv
[2]) : 0;
529 bw
= bw
? : CHSPEC_IS40(chanspec
) ? 40 : 20;
531 if (argc
> 3) band
= atoi(argv
[3]) ? : band
;
534 if (strcmp(argv
[4], "upper") == 0)
535 ctrlsb
= WL_CHANSPEC_CTL_SB_UPPER
;
537 ctrlsb
= WL_CHANSPEC_CTL_SB_LOWER
;
540 ctrlsb
= CHSPEC_CTL_SB(chanspec
);
542 web_puts("\nwl_channels = [\n[0, 0]");
544 if (!_wlchanspecs(ifname
, buf
, band
, bw
, ctrlsb
) && band
== WLC_BAND_2G
&& bw
== 40)
545 _wlchanspecs(ifname
, buf
, band
, 20, ctrlsb
);
548 _wlchannels(ifname
, buf
, band
);
552 static int print_wlbands(int idx
, int unit
, int subunit
, void *param
)
554 char *phytype
, *phylist
, *ifname
;
556 int list
[WLC_BAND_ALL
];
559 ifname
= nvram_safe_get(wl_nvname("ifname", unit
, 0));
560 phytype
= nvram_safe_get(wl_nvname("phytype", unit
, 0));
562 web_printf("%c[", (idx
== 0) ? ' ' : ',');
564 if (phytype
[0] == 'n' ||
569 /* Get band list. Assume both the bands in case of error */
570 if (wl_ioctl(ifname
, WLC_GET_BANDLIST
, list
, sizeof(list
)) < 0) {
571 for (i
= WLC_BAND_5G
; i
<= WLC_BAND_2G
; i
++) {
572 web_printf("%c'%d'", comma
, i
);
579 for (i
= 1; i
<= list
[0]; i
++) {
580 web_printf("%c'%d'", comma
, list
[i
]);
586 /* Get available phy types of the currently selected wireless interface */
587 phylist
= nvram_safe_get(wl_nvname("phytypes", unit
, 0));
588 for (i
= 0; i
< strlen(phylist
); i
++) {
589 web_printf("%c'%d'", comma
, phylist
[i
] == 'a' ? WLC_BAND_5G
: WLC_BAND_2G
);
599 void asp_wlbands(int argc
, char **argv
)
601 int include_vifs
= (argc
> 0) ? atoi(argv
[0]) : 0;
603 web_puts("\nwl_bands = [");
604 foreach_wif(include_vifs
, NULL
, print_wlbands
); // AB multiSSID
608 static int print_wif(int idx
, int unit
, int subunit
, void *param
)
610 char unit_str
[] = "000000";
614 snprintf(unit_str
, sizeof(unit_str
), "%d.%d", unit
, subunit
);
616 snprintf(unit_str
, sizeof(unit_str
), "%d", unit
);
618 // [ifname, unitstr, unit, subunit, ssid, hwaddr]
619 ssidj
= js_string(nvram_safe_get(wl_nvname("ssid", unit
, subunit
)));
620 web_printf("%c['%s','%s',%d,%d,'%s','%s']", (idx
== 0) ? ' ' : ',',
621 nvram_safe_get(wl_nvname("ifname", unit
, subunit
)),
622 unit_str
, unit
, subunit
, ssidj
,
623 // assume the slave inteface MAC address is the same as the primary interface
624 // nvram_safe_get(wl_nvname("hwaddr", unit, 0))
625 // // virtual inteface MAC address
626 nvram_safe_get(wl_nvname("hwaddr", unit
, subunit
)) // AB multiSSID
633 void asp_wlifaces(int argc
, char **argv
)
635 int include_vifs
= (argc
> 0) ? atoi(argv
[0]) : 0;
637 web_puts("\nwl_ifaces = [");
638 foreach_wif(include_vifs
, NULL
, print_wif
);
642 void asp_wlcountries(int argc
, char **argv
)
644 char s
[128], *p
, *code
, *country
;
648 web_puts("\nwl_countries = [");
649 if ((f
= popen("wl country list", "r")) != NULL
) {
650 // skip the header line
651 fgets(s
, sizeof(s
), f
);
652 while (fgets(s
, sizeof(s
), f
)) {
654 if ((code
= strsep(&p
, " \t\n")) && p
) {
655 country
= strsep(&p
, "\n");
656 if ((country
&& *country
&& strcmp(code
, country
) != 0) ||
657 // special case EU code since the driver may not have a name for it
658 (strcmp(code
, "EU") == 0)) {
659 if (!country
|| *country
== 0) country
= code
;
660 p
= js_string(country
);
661 web_printf("%c['%s', '%s']", i
++ ? ',' : ' ', code
, p
);