Changes to update Tomato RAF.
[tomato.git] / release / src / router / httpd / wl.c
blob0cfcaa704f58cba99ea10c58c3650dd9e6c9a5c8
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
8 #include "tomato.h"
10 #include <ctype.h>
11 #include <wlutils.h>
12 #include <sys/ioctl.h>
14 #ifndef WL_BSS_INFO_VERSION
15 #error WL_BSS_INFO_VERSION
16 #endif
17 #if WL_BSS_INFO_VERSION < 108
18 #error WL_BSS_INFO_VERSION < 108
19 #endif
22 static int unit = 0;
23 static int subunit = 0;
25 static void check_wl_unit(const char *unitarg)
27 char ifname[12], *wlunit;
28 unit = 0; subunit = 0;
30 wlunit = (unitarg && *unitarg) ? (char *)unitarg :
31 webcgi_safeget("_wl_unit", nvram_safe_get("wl_unit"));
32 snprintf(ifname, sizeof(ifname), "wl%s", wlunit);
33 get_ifname_unit(ifname, &unit, &subunit);
35 _dprintf("check_wl_unit: unitarg: %s, _wl_unit: %s, ifname: %s, unit: %d, subunit: %d\n",
36 unitarg, webcgi_safeget("_wl_unit", nvram_safe_get("wl_unit")), ifname, unit, subunit);
39 static void wl_restore(char *wif, int unit, int ap, int radio, int scan_time)
41 if (ap > 0) {
42 wl_ioctl(wif, WLC_SET_AP, &ap, sizeof(ap));
44 if (!radio) set_radio(1, unit);
45 eval("wl", "-i", wif, "up"); // without this the router may reboot
46 #if WL_BSS_INFO_VERSION >= 108
47 // no idea why this voodoo sequence works to wake up wl -- zzz
48 eval("wl", "-i", wif, "ssid", "");
49 eval("wl", "-i", wif, "ssid", nvram_safe_get(wl_nvname("ssid", unit, 0)));
50 #endif
52 #ifdef WLC_SET_SCAN_CHANNEL_TIME
53 if (scan_time > 0) {
54 // restore original scan channel time
55 wl_ioctl(wif, WLC_SET_SCAN_CHANNEL_TIME, &scan_time, sizeof(scan_time));
57 #endif
58 set_radio(radio, unit);
61 // allow to scan using up to MAX_WLIF_SCAN wireless ifaces
62 #define MAX_WLIF_SCAN 3
64 typedef struct {
65 int unit_filter;
66 char comma;
67 struct {
68 int ap;
69 int radio;
70 int scan_time;
71 } wif[MAX_WLIF_SCAN];
72 } scan_list_t;
74 static int start_scan(int idx, int unit, int subunit, void *param)
76 scan_list_t *rp = param;
77 wl_scan_params_t sp;
78 char *wif;
79 int zero = 0;
80 int retry;
81 #ifdef WLC_SET_SCAN_CHANNEL_TIME
82 int scan_time = 40;
83 #endif
85 if ((idx >= MAX_WLIF_SCAN) || (rp->unit_filter >= 0 && rp->unit_filter != unit)) return 0;
87 wif = nvram_safe_get(wl_nvname("ifname", unit, 0));
89 memset(&sp, 0xff, sizeof(sp)); // most default to -1
90 sp.ssid.SSID_len = 0;
91 sp.bss_type = DOT11_BSSTYPE_ANY; // =2
92 sp.channel_num = 0;
94 if (wl_ioctl(wif, WLC_GET_AP, &(rp->wif[idx].ap), sizeof(rp->wif[idx].ap)) < 0) {
95 // Unable to get AP mode
96 return 0;
98 if (rp->wif[idx].ap > 0) {
99 wl_ioctl(wif, WLC_SET_AP, &zero, sizeof(zero));
102 // set scan type based on the ap mode
103 sp.scan_type = rp->wif[idx].ap ? DOT11_SCANTYPE_PASSIVE : -1 /* default */;
105 #ifdef WLC_SET_SCAN_CHANNEL_TIME
106 // extend scan channel time to get more AP probe resp
107 wl_ioctl(wif, WLC_GET_SCAN_CHANNEL_TIME, &(rp->wif[idx].scan_time), sizeof(rp->wif[idx].scan_time));
108 if (rp->wif[idx].scan_time < scan_time) {
109 wl_ioctl(wif, WLC_SET_SCAN_CHANNEL_TIME, &scan_time, sizeof(scan_time));
111 #endif
113 rp->wif[idx].radio = get_radio(unit);
114 if (!(rp->wif[idx].radio)) set_radio(1, unit);
116 retry = 3 * 10;
117 while (retry--) {
118 if (wl_ioctl(wif, WLC_SCAN, &sp, WL_SCAN_PARAMS_FIXED_SIZE) == 0)
119 return 1;
120 if (retry) usleep(100000);
123 // Unable to start scan
124 wl_restore(wif, unit, rp->wif[idx].ap, rp->wif[idx].radio, rp->wif[idx].scan_time);
125 return 0;
128 static int get_scan_results(int idx, int unit, int subunit, void *param)
130 scan_list_t *rp = param;
132 if ((idx >= MAX_WLIF_SCAN) || (rp->unit_filter >= 0 && rp->unit_filter != unit)) return 0;
134 // get results
136 char *wif;
137 wl_scan_results_t *results;
138 wl_bss_info_t *bssi;
139 int r;
140 int retry;
142 wif = nvram_safe_get(wl_nvname("ifname", unit, 0));
144 results = malloc(WLC_IOCTL_MAXLEN + sizeof(*results));
145 if (!results) {
146 // Not enough memory
147 wl_restore(wif, unit, rp->wif[idx].ap, rp->wif[idx].radio, rp->wif[idx].scan_time);
148 return 0;
150 results->buflen = WLC_IOCTL_MAXLEN;
151 results->version = WL_BSS_INFO_VERSION;
153 // Keep trying to obtain scan results for up to 4 secs
154 // Passive scan may require more time, although 1 extra sec is almost always enough.
155 retry = 4 * 10;
156 r = -1;
157 while (retry--) {
158 r = wl_ioctl(wif, WLC_SCAN_RESULTS, results, WLC_IOCTL_MAXLEN);
159 if (r >= 0) break;
160 usleep(100000);
163 wl_restore(wif, unit, rp->wif[idx].ap, rp->wif[idx].radio, rp->wif[idx].scan_time);
165 if (r < 0) {
166 free(results);
167 // Unable to obtain scan results
168 return 0;
171 // format for javascript
173 int i;
174 int j;
175 int k;
176 char c;
177 char ssid[64];
178 char mac[32];
179 char *ssidj;
180 int channel;
182 bssi = &results->bss_info[0];
183 for (i = 0; i < results->count; ++i) {
185 channel = CHSPEC_CHANNEL(bssi->chanspec);
186 if (CHSPEC_IS40(bssi->chanspec))
187 channel = channel + (CHSPEC_SB_LOWER(bssi->chanspec) ? -2 : 2);
189 j = bssi->SSID_len;
190 if (j < 0) j = 0;
191 if (j > 32) j = 32;
192 if (nvram_get_int("wlx_scrubssid")) {
193 for (k = j - 1; k >= 0; --k) {
194 c = bssi->SSID[k];
195 if (!isprint(c)) c = '?';
196 ssid[k] = c;
199 else {
200 memcpy(ssid, bssi->SSID, j);
202 ssid[j] = 0;
203 ssidj = js_string(ssid);
205 web_printf("%c['%s','%s',%u,%u,%d,%d,[", rp->comma,
206 ether_etoa(bssi->BSSID.octet, mac), ssidj ? ssidj : "",
207 channel,
208 bssi->capability, bssi->RSSI, bssi->phy_noise);
209 rp->comma = ',';
210 free(ssidj);
212 for (j = 0; j < bssi->rateset.count; ++j) {
213 web_printf("%s%u", j ? "," : "", bssi->rateset.rates[j]);
216 web_printf("],%d,%d,%d]",
217 bssi->n_cap,
218 bssi->nbss_cap,
219 bssi->n_cap ? (CHSPEC_IS40(bssi->chanspec) ? 40 : (CHSPEC_IS20(bssi->chanspec) ? 20 : 10)) : 0);
221 bssi = (wl_bss_info_t*)((uint8*)bssi + bssi->length);
223 free(results);
225 return 1;
228 // returns: ['bssid','ssid',channel,capabilities,rssi,noise,[rates,]], or [null,'error message']
229 void asp_wlscan(int argc, char **argv)
231 scan_list_t rp;
233 memset(&rp, 0, sizeof(rp));
234 rp.comma = ' ';
235 rp.unit_filter = (argc > 0) ? atoi(argv[0]) : (-1);
237 web_puts("\nwlscandata = [");
239 // scan
241 if (foreach_wif(0, &rp, start_scan) == 0) {
242 web_puts("[null,'Unable to start scan.']];\n");
243 return;
245 sleep(1);
247 // get results
249 if (foreach_wif(0, &rp, get_scan_results) == 0) {
250 web_puts("[null,'Unable to obtain scan results.']];\n");
251 return;
254 web_puts("];\n");
257 void wo_wlradio(char *url)
259 char *enable;
260 char sunit[10];
262 check_wl_unit(NULL);
264 parse_asp("saved.asp");
265 if (nvram_get_int(wl_nvname("radio", unit, 0))) {
266 if ((enable = webcgi_get("enable")) != NULL) {
267 web_close();
268 sleep(2);
269 sprintf(sunit, "%d", unit);
270 eval("radio", atoi(enable) ? "on" : "off", sunit);
271 return;
276 static int read_noise(int unit)
278 int v;
280 // WLC_GET_PHY_NOISE = 135
281 if (wl_ioctl(nvram_safe_get(wl_nvname("ifname", unit, 0)), 135, &v, sizeof(v)) == 0) {
282 char s[32];
283 sprintf(s, "%d", v);
284 nvram_set(wl_nvname("tnoise", unit, 0), s);
285 return v;
287 return -99;
290 static int get_wlnoise(int client, int unit)
292 int v;
294 if (client) {
295 v = read_noise(unit);
297 else {
298 v = nvram_get_int(wl_nvname("tnoise", unit, 0));
299 if ((v >= 0) || (v < -100)) v = -99;
301 return v;
304 static int print_wlnoise(int idx, int unit, int subunit, void *param)
306 web_printf("%c%d", (idx == 0) ? ' ' : ',', get_wlnoise(wl_client(unit, 0), unit));
307 return 0;
310 void asp_wlnoise(int argc, char **argv)
312 web_puts("\nwlnoise = [");
313 foreach_wif(0, NULL, print_wlnoise);
314 web_puts(" ];\n");
317 void wo_wlmnoise(char *url)
319 int ap;
320 int i;
321 char *wif;
323 check_wl_unit(NULL);
325 parse_asp("mnoise.asp");
326 web_close();
327 sleep(3);
329 int radio = get_radio(unit);
331 wif = nvram_safe_get(wl_nvname("ifname", unit, 0));
332 if (wl_ioctl(wif, WLC_GET_AP, &ap, sizeof(ap)) < 0) return;
334 i = 0;
335 wl_ioctl(wif, WLC_SET_AP, &i, sizeof(i));
337 for (i = 10; i > 0; --i) {
338 sleep(1);
339 read_noise(unit);
342 wl_restore(wif, unit, ap, radio, 0);
345 static int wl_chanfreq(uint ch, int band)
347 if ((band == WLC_BAND_2G && (ch < 1 || ch > 14)) || (ch > 200))
348 return -1;
349 else if ((band == WLC_BAND_2G) && (ch == 14))
350 return 2484;
351 else
352 return ch * 5 + ((band == WLC_BAND_2G) ? 4814 : 10000) / 2;
355 static int not_wlclient(int idx, int unit, int subunit, void *param)
357 return (!wl_client(unit, subunit));
360 // returns '1' if all wireless interfaces are in client mode, '0' otherwise
361 void asp_wlclient(int argc, char **argv)
363 web_puts(foreach_wif(1, NULL, not_wlclient) ? "0" : "1");
366 static int print_wlstats(int idx, int unit, int subunit, void *param)
368 int phytype;
369 int rate, client, nbw;
370 int chanspec, channel, mhz, band, scan;
371 int chanim_enab;
372 int interference;
373 char retbuf[WLC_IOCTL_SMLEN];
374 scb_val_t rssi;
375 char *ifname, *ctrlsb;
377 ifname = nvram_safe_get(wl_nvname("ifname", unit, 0));
378 client = wl_client(unit, 0);
380 /* Get configured phy type */
381 wl_ioctl(ifname, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
383 if (wl_ioctl(ifname, WLC_GET_RATE, &rate, sizeof(rate)) < 0)
384 rate = 0;
386 if (wl_ioctl(ifname, WLC_GET_BAND, &band, sizeof(band)) < 0)
387 band = nvram_get_int(wl_nvname("nband", unit, 0));
389 channel = nvram_get_int(wl_nvname("channel", unit, 0));
390 scan = 0;
391 interference = -1;
393 if (wl_phytype_n(phytype)) {
394 if (wl_iovar_getint(ifname, "chanspec", &chanspec) != 0) {
395 ctrlsb = nvram_safe_get(wl_nvname("nctrlsb", unit, 0));
396 nbw = nvram_get_int(wl_nvname("nbw", unit, 0));
398 else {
399 channel = CHSPEC_CHANNEL(chanspec);
400 if (CHSPEC_IS40(chanspec))
401 channel = channel + (CHSPEC_SB_LOWER(chanspec) ? -2 : 2);
402 ctrlsb = CHSPEC_SB_LOWER(chanspec) ? "lower" : (CHSPEC_SB_UPPER(chanspec) ? "upper" : "none");
403 nbw = CHSPEC_IS40(chanspec) ? 40 : 20;
406 else {
407 channel_info_t ch;
408 if (wl_ioctl(ifname, WLC_GET_CHANNEL, &ch, sizeof(ch)) == 0) {
409 scan = (ch.scan_channel > 0);
410 channel = (scan) ? ch.scan_channel : ch.hw_channel;
412 ctrlsb = "";
413 nbw = 20;
416 mhz = (channel) ? wl_chanfreq(channel, band) : 0;
417 if (wl_iovar_getint(ifname, "chanim_enab", (int*)(void*)&chanim_enab) != 0)
418 chanim_enab = 0;
419 if (chanim_enab) {
420 if (wl_iovar_getbuf(ifname, "chanim_state", &chanspec, sizeof(chanspec), retbuf, WLC_IOCTL_SMLEN) == 0)
421 interference = *(int*)retbuf;
424 memset(&rssi, 0, sizeof(rssi));
425 if (client) {
426 if (wl_ioctl(ifname, WLC_GET_RSSI, &rssi, sizeof(rssi)) != 0)
427 rssi.val = -100;
430 // [ radio, is_client, channel, freq (mhz), rate, nctrlsb, nbw, rssi, noise, interference ]
431 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",
432 (idx == 0) ? ' ' : ',',
433 get_radio(unit), client, (scan ? '-' : ' '), channel, mhz, rate, ctrlsb, nbw, rssi.val, get_wlnoise(client, unit), interference);
435 return 0;
438 void asp_wlstats(int argc, char **argv)
440 int include_vifs = (argc > 0) ? atoi(argv[0]) : 0;
442 web_puts("\nwlstats = [");
443 foreach_wif(include_vifs, NULL, print_wlstats); // AB multiSSID
444 web_puts("];\n");
447 static void web_print_wlchan(uint chan, int band)
449 int mhz;
450 if ((mhz = wl_chanfreq(chan, band)) > 0)
451 web_printf(",[%d, %d]", chan, mhz);
452 else
453 web_printf(",[%d, 0]", chan);
456 static int _wlchanspecs(char *ifname, char *country, int band, int bw, int ctrlsb)
458 chanspec_t c = 0, *chanspec;
459 int buflen;
460 wl_uint32_list_t *list;
461 int count, i = 0;
463 char *buf = (char *)malloc(WLC_IOCTL_MAXLEN);
464 if (!buf)
465 return 0;
467 strcpy(buf, "chanspecs");
468 buflen = strlen(buf) + 1;
470 c |= (band == WLC_BAND_5G) ? WL_CHANSPEC_BAND_5G : WL_CHANSPEC_BAND_2G;
471 c |= (bw == 20) ? WL_CHANSPEC_BW_20 : WL_CHANSPEC_BW_40;
473 chanspec = (chanspec_t *)(buf + buflen);
474 *chanspec = c;
475 buflen += (sizeof(chanspec_t));
476 strncpy(buf + buflen, country, WLC_CNTRY_BUF_SZ);
477 buflen += WLC_CNTRY_BUF_SZ;
479 /* Add list */
480 list = (wl_uint32_list_t *)(buf + buflen);
481 list->count = WL_NUMCHANSPECS;
482 buflen += sizeof(uint32)*(WL_NUMCHANSPECS + 1);
484 if (wl_ioctl(ifname, WLC_GET_VAR, buf, buflen) < 0) {
485 free((void *)buf);
486 return 0;
489 count = 0;
490 list = (wl_uint32_list_t *)buf;
491 for (i = 0; i < list->count; i++) {
492 c = (chanspec_t)list->element[i];
493 /* Skip upper.. (take only one of the lower or upper) */
494 if (bw == 40 && (CHSPEC_CTL_SB(c) != ctrlsb))
495 continue;
496 /* Create the actual control channel number from sideband */
497 int chan = CHSPEC_CHANNEL(c);
498 if (bw == 40)
499 chan += ((ctrlsb == WL_CHANSPEC_CTL_SB_UPPER) ? 2 : -2);
500 web_print_wlchan(chan, band);
501 count++;
504 free((void *)buf);
505 return count;
508 static void _wlchannels(char *ifname, char *country, int band)
510 int i;
511 wl_channels_in_country_t *cic;
513 cic = (wl_channels_in_country_t *)malloc(WLC_IOCTL_MAXLEN);
514 if (cic) {
515 cic->buflen = WLC_IOCTL_MAXLEN;
516 strcpy(cic->country_abbrev, country);
517 cic->band = band;
519 if (wl_ioctl(ifname, WLC_GET_CHANNELS_IN_COUNTRY, cic, cic->buflen) == 0) {
520 for (i = 0; i < cic->count; i++) {
521 web_print_wlchan(cic->channel[i], band);
524 free((void *)cic);
528 void asp_wlchannels(int argc, char **argv)
530 char buf[WLC_CNTRY_BUF_SZ];
531 int band, phytype, nphy;
532 int bw, ctrlsb, chanspec;
533 char *ifname;
535 // args: unit, nphy[1|0], bw, band, ctrlsb
537 check_wl_unit(argc > 0 ? argv[0] : NULL);
539 ifname = nvram_safe_get(wl_nvname("ifname", unit, 0));
540 wl_ioctl(ifname, WLC_GET_COUNTRY, buf, sizeof(buf));
541 if (wl_ioctl(ifname, WLC_GET_BAND, &band, sizeof(band)) != 0)
542 band = nvram_get_int(wl_nvname("nband", unit, 0));
543 wl_iovar_getint(ifname, "chanspec", &chanspec);
545 if (argc > 1)
546 nphy = atoi(argv[1]);
547 else {
548 wl_ioctl(ifname, WLC_GET_PHYTYPE, &phytype, sizeof(phytype));
549 nphy = wl_phytype_n(phytype);
552 bw = (argc > 2) ? atoi(argv[2]) : 0;
553 bw = bw ? : CHSPEC_IS40(chanspec) ? 40 : 20;
555 if (argc > 3) band = atoi(argv[3]) ? : band;
557 if (argc > 4) {
558 if (strcmp(argv[4], "upper") == 0)
559 ctrlsb = WL_CHANSPEC_CTL_SB_UPPER;
560 else
561 ctrlsb = WL_CHANSPEC_CTL_SB_LOWER;
563 else
564 ctrlsb = CHSPEC_CTL_SB(chanspec);
566 web_puts("\nwl_channels = [\n[0, 0]");
567 if (nphy) {
568 if (!_wlchanspecs(ifname, buf, band, bw, ctrlsb) && band == WLC_BAND_2G && bw == 40)
569 _wlchanspecs(ifname, buf, band, 20, ctrlsb);
571 else
572 _wlchannels(ifname, buf, band);
573 web_puts("];\n");
576 static int print_wlbands(int idx, int unit, int subunit, void *param)
578 char *phytype, *phylist, *ifname;
579 char comma = ' ';
580 int list[WLC_BAND_ALL];
581 int i;
583 ifname = nvram_safe_get(wl_nvname("ifname", unit, 0));
584 phytype = nvram_safe_get(wl_nvname("phytype", unit, 0));
586 web_printf("%c[", (idx == 0) ? ' ' : ',');
588 if (phytype[0] == 'n' ||
589 phytype[0] == 'l' ||
590 phytype[0] == 's' ||
591 phytype[0] == 'c' ||
592 phytype[0] == 'h') {
593 /* Get band list. Assume both the bands in case of error */
594 if (wl_ioctl(ifname, WLC_GET_BANDLIST, list, sizeof(list)) < 0) {
595 for (i = WLC_BAND_5G; i <= WLC_BAND_2G; i++) {
596 web_printf("%c'%d'", comma, i);
597 comma = ',';
600 else {
601 if (list[0] > 2)
602 list[0] = 2;
603 for (i = 1; i <= list[0]; i++) {
604 web_printf("%c'%d'", comma, list[i]);
605 comma = ',';
609 else {
610 /* Get available phy types of the currently selected wireless interface */
611 phylist = nvram_safe_get(wl_nvname("phytypes", unit, 0));
612 for (i = 0; i < strlen(phylist); i++) {
613 web_printf("%c'%d'", comma, phylist[i] == 'a' ? WLC_BAND_5G : WLC_BAND_2G);
614 comma = ',';
618 web_puts("]");
620 return 0;
623 void asp_wlbands(int argc, char **argv)
625 int include_vifs = (argc > 0) ? atoi(argv[0]) : 0;
627 web_puts("\nwl_bands = [");
628 foreach_wif(include_vifs, NULL, print_wlbands); // AB multiSSID
629 web_puts(" ];\n");
632 static int print_wif(int idx, int unit, int subunit, void *param)
634 char unit_str[] = "000000";
635 char *ssidj;
637 char *next;
638 char cap[WLC_IOCTL_SMLEN];
639 char caps[WLC_IOCTL_SMLEN];
640 int max_no_vifs = 0;
642 if (subunit > 0) {
643 snprintf(unit_str, sizeof(unit_str), "%d.%d", unit, subunit);
644 } else {
645 snprintf(unit_str, sizeof(unit_str), "%d", unit);
647 // wl_iovar_get(wl_nvname("ifname", unit, 0), "cap", (void *)caps, WLC_IOCTL_SMLEN);
648 // wl_iovar_get("eth1", "cap", (void *)caps, WLC_IOCTL_SMLEN);
649 max_no_vifs = 1;
650 wl_iovar_get(nvram_safe_get(wl_nvname("ifname", unit, 0)), "cap", (void *)caps, WLC_IOCTL_SMLEN);
651 foreach(cap, caps, next) {
652 if (!strcmp(cap, "mbss16"))
653 max_no_vifs = 16;
654 if (!strcmp(cap, "mbss4"))
655 max_no_vifs = 4;
660 int up = 0;
661 int sfd;
662 struct ifreq ifr;
664 if ((sfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
665 _dprintf("[%s %d]: error opening socket %m\n", __FUNCTION__, __LINE__);
668 if (sfd >= 0) {
669 strcpy(ifr.ifr_name, nvram_safe_get(wl_nvname("ifname", unit, subunit)));
670 if (ioctl(sfd, SIOCGIFFLAGS, &ifr) == 0)
671 if (ifr.ifr_flags & (IFF_UP | IFF_RUNNING))
672 up = 1;
673 close(sfd);
676 char *ifname;
677 ifname = nvram_safe_get(wl_nvname("ifname", unit, subunit));
678 struct ether_addr bssid;
680 wl_ioctl(ifname, WLC_GET_BSSID, &bssid, ETHER_ADDR_LEN);
682 // [ifname, unitstr, unit, subunit, ssid, hwaddr, up, wmode, bssid]
683 ssidj = js_string(nvram_safe_get(wl_nvname("ssid", unit, subunit)));
684 web_printf("%c['%s','%s',%d,%d,'%s','%s',%d,%d,'%s','%02X:%02X:%02X:%02X:%02X:%02X']", (idx == 0) ? ' ' : ',',
685 nvram_safe_get(wl_nvname("ifname", unit, subunit)),
686 unit_str, unit, subunit, ssidj,
687 // // virtual inteface MAC address
688 nvram_safe_get(wl_nvname("hwaddr", unit, subunit)), up, max_no_vifs, // AB multiSSID
689 nvram_safe_get(wl_nvname("mode", unit, subunit)),
690 bssid.octet[0], bssid.octet[1], bssid.octet[2], bssid.octet[3], bssid.octet[4], bssid.octet[5]
692 free(ssidj);
694 return 0;
697 void asp_wlifaces(int argc, char **argv)
699 int include_vifs = (argc > 0) ? atoi(argv[0]) : 0;
701 web_puts("\nwl_ifaces = [");
702 foreach_wif(include_vifs, NULL, print_wif);
703 web_puts("];\n");
706 void asp_wlcountries(int argc, char **argv)
708 char s[128], *p, *code, *country;
709 FILE *f;
710 int i = 0;
712 web_puts("\nwl_countries = [");
713 if ((f = popen("wl country list", "r")) != NULL) {
714 // skip the header line
715 fgets(s, sizeof(s), f);
716 while (fgets(s, sizeof(s), f)) {
717 p = s;
718 if ((code = strsep(&p, " \t\n")) && p) {
719 country = strsep(&p, "\n");
720 if ((country && *country && strcmp(code, country) != 0) ||
721 // special case EU code since the driver may not have a name for it
722 (strcmp(code, "EU") == 0)) {
723 if (!country || *country == 0) country = code;
724 p = js_string(country);
725 web_printf("%c['%s', '%s']", i++ ? ',' : ' ', code, p);
726 free(p);
730 fclose(f);
732 web_puts("];\n");