e0d016feba3ec1d746aae5951eca995d68462072
[openwrt/openwrt.git] / package / broadcom-wl / src / wlc / wlc.c
1 /*
2 * wlc - Broadcom Wireless Driver Control Utility
3 *
4 * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
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
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <unistd.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <fcntl.h>
24 #include <glob.h>
25 #include <ctype.h>
26
27 #include <typedefs.h>
28 #include <wlutils.h>
29 #include <proto/802.11.h>
30
31 #define VERSION "0.1"
32 #define BUFSIZE 8192
33 #define PTABLE_MAGIC 0xbadc0ded
34 #define PTABLE_SLT1 1
35 #define PTABLE_SLT2 2
36 #define PTABLE_ACKW 3
37 #define PTABLE_ADHM 4
38 #define PTABLE_END 0xffffffff
39
40 /*
41 * Copy each token in wordlist delimited by space into word
42 * Taken from Broadcom shutils.h
43 */
44 #define foreach(word, wordlist, next) \
45 for (next = &wordlist[strspn(wordlist, " ")], \
46 strncpy(word, next, sizeof(word)), \
47 word[strcspn(word, " ")] = '\0', \
48 word[sizeof(word) - 1] = '\0', \
49 next = strchr(next, ' '); \
50 strlen(word); \
51 next = next ? &next[strspn(next, " ")] : "", \
52 strncpy(word, next, sizeof(word)), \
53 word[strcspn(word, " ")] = '\0', \
54 word[sizeof(word) - 1] = '\0', \
55 next = strchr(next, ' '))
56
57 static char wlbuf[8192];
58 static char interface[16] = "wl0";
59 static unsigned long kmem_offset = 0;
60 static int vif = 0, debug = 1, fromstdin = 0;
61
62 typedef enum {
63 NONE = 0x00,
64
65 /* types */
66 PARAM_TYPE = 0x00f,
67 INT = 0x001,
68 STRING = 0x002,
69
70 /* options */
71 PARAM_OPTIONS = 0x0f0,
72 NOARG = 0x010,
73
74 /* modes */
75 PARAM_MODE = 0xf00,
76 GET = 0x100,
77 SET = 0x200,
78 } wlc_param;
79
80 struct wlc_call {
81 const char *name;
82 wlc_param param;
83 int (*handler)(wlc_param param, void *data, void *value);
84 union {
85 int num;
86 char *str;
87 void *ptr;
88 } data;
89 const char *desc;
90 };
91
92 /* can't use the system include because of the stupid broadcom header files */
93 extern struct ether_addr *ether_aton(const char *asc);
94 static inline int my_ether_ntoa(unsigned char *ea, char *buf)
95 {
96 return sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
97 ea[0], ea[1], ea[2], ea[3], ea[4], ea[5]);
98 }
99
100 static int wlc_ioctl(wlc_param param, void *data, void *value)
101 {
102 unsigned int *var = ((unsigned int *) data);
103 unsigned int ioc = *var;
104
105 if (param & NOARG) {
106 return wl_ioctl(interface, ioc, NULL, 0);
107 }
108 switch(param & PARAM_TYPE) {
109 case INT:
110 return wl_ioctl(interface, ((param & SET) ? (ioc) : (ioc >> 16)) & 0xffff, value, sizeof(int));
111 case STRING:
112 return wl_ioctl(interface, ((param & SET) ? (ioc) : (ioc >> 16)) & 0xffff, value, BUFSIZE);
113 }
114 return 0;
115 }
116
117 static int wlc_iovar(wlc_param param, void *data, void *value)
118 {
119 int *val = (int *) value;
120 char *iov = *((char **) data);
121 int ret = 0;
122
123 if (param & SET) {
124 switch(param & PARAM_TYPE) {
125 case INT:
126 ret = wl_iovar_setint(interface, iov, *val);
127 }
128 }
129 if (param & GET) {
130 switch(param & PARAM_TYPE) {
131 case INT:
132 ret = wl_iovar_getint(interface, iov, val);
133 }
134 }
135
136 return ret;
137 }
138
139 static int wlc_bssiovar(wlc_param param, void *data, void *value)
140 {
141 int *val = (int *) value;
142 char *iov = *((char **) data);
143 int ret = 0;
144
145 if (param & SET) {
146 switch(param & PARAM_TYPE) {
147 case INT:
148 ret = wl_bssiovar_setint(interface, iov, vif, *val);
149 }
150 }
151 if (param & GET) {
152 switch(param & PARAM_TYPE) {
153 case INT:
154 ret = wl_bssiovar_getint(interface, iov, vif, val);
155 }
156 }
157
158 return ret;
159 }
160
161 static int wlc_vif_enabled(wlc_param param, void *data, void *value)
162 {
163 int *val = (int *) value;
164 int buf[3];
165 int ret = 0;
166
167 sprintf((char *) buf, "bss");
168 buf[1] = vif;
169 if (param & SET) {
170 buf[2] = (*val ? 1 : 0);
171 ret = wl_ioctl(interface, WLC_SET_VAR, buf, sizeof(buf));
172 } else if (param & GET) {
173 ret = wl_ioctl(interface, WLC_GET_VAR, buf, sizeof(buf));
174 *val = buf[0];
175 }
176
177 return ret;
178 }
179
180 static int wlc_ssid(wlc_param param, void *data, void *value)
181 {
182 int ret = -1, ret2 = -1;
183 char *dest = (char *) value;
184 wlc_ssid_t ssid;
185
186 if ((param & PARAM_MODE) == GET) {
187 ret = wl_bssiovar_get(interface, "ssid", vif, &ssid, sizeof(ssid));
188
189 if (ret)
190 /* if we can't get the ssid through the bssiovar, try WLC_GET_SSID */
191 ret = wl_ioctl(interface, WLC_GET_SSID, &ssid, sizeof(ssid));
192
193 if (!ret) {
194 memcpy(dest, ssid.SSID, ssid.SSID_len);
195 dest[ssid.SSID_len] = 0;
196 }
197 } else if ((param & PARAM_MODE) == SET) {
198 strncpy(ssid.SSID, value, 32);
199 ssid.SSID_len = strlen(value);
200
201 if (ssid.SSID_len > 32)
202 ssid.SSID_len = 32;
203
204 if (vif == 0) {
205 /* for the main interface, also try the WLC_SET_SSID call */
206 ret2 = wl_ioctl(interface, WLC_SET_SSID, &ssid, sizeof(ssid));
207 }
208
209 ret = wl_bssiovar_set(interface, "ssid", vif, &ssid, sizeof(ssid));
210 ret = (!ret2 ? 0 : ret);
211 }
212
213 return ret;
214 }
215
216 static int wlc_int(wlc_param param, void *data, void *value)
217 {
218 int *var = *((int **) data);
219 int *val = (int *) value;
220
221 if ((param & PARAM_MODE) == SET) {
222 *var = *val;
223 } else if ((param & PARAM_MODE) == GET) {
224 *val = *var;
225 }
226
227 return 0;
228 }
229
230 static int wlc_flag(wlc_param param, void *data, void *value)
231 {
232 int *var = *((int **) data);
233
234 *var = 1;
235
236 return 0;
237 }
238
239 static int wlc_string(wlc_param param, void *data, void *value)
240 {
241 char *var = *((char **) data);
242
243 if ((param & PARAM_MODE) == GET) {
244 strcpy(value, var);
245 }
246
247 return 0;
248 }
249
250 static int wlc_afterburner(wlc_param param, void *data, void *value)
251 {
252 int *val = (int *) value;
253 int ret = 0;
254
255 if ((param & PARAM_MODE) == GET) {
256 ret = wl_iovar_getint(interface, "afterburner", val);
257 } else {
258 wl_iovar_setint(interface, "wlfeatureflag", (*val ? 3 : 0));
259 ret = wl_iovar_setint(interface, "afterburner", (*val ? 1 : 0));
260 wl_iovar_setint(interface, "afterburner_override", *val);
261 }
262
263 return ret;
264 }
265
266 static int wlc_maclist(wlc_param param, void *data, void *value)
267 {
268 unsigned int *var = ((unsigned int *) data);
269 unsigned int ioc = *var;
270 int limit = (sizeof(wlbuf) - 4) / sizeof(struct ether_addr);
271 struct maclist *list = (struct maclist *) wlbuf;
272 char *str = (char *) value;
273 char astr[30], *p;
274 struct ether_addr *addr;
275 int isset = 0;
276 int ret;
277
278 if ((param & PARAM_MODE) == GET) {
279 list->count = limit;
280 ret = wl_ioctl(interface, (ioc >> 16) & 0xffff, wlbuf, sizeof(wlbuf));
281
282 if (!ret)
283 while (list->count) {
284 str += sprintf(str, "%s", ((((char *) value) == str) ? "" : " "));
285 str += my_ether_ntoa((unsigned char *) &list->ea[list->count-- - 1], str);
286 }
287
288 return ret;
289 } else {
290 while (*str && isspace(*str))
291 *str++;
292
293 if (*str == '+') {
294 str++;
295
296 list->count = limit;
297 if (wl_ioctl(interface, (ioc >> 16) & 0xffff, wlbuf, sizeof(wlbuf)) == 0)
298 isset = 1;
299
300 while (*str && isspace(*str))
301 str++;
302 }
303
304 if (!isset)
305 memset(wlbuf, 0, sizeof(wlbuf));
306
307 foreach(astr, str, p) {
308 if (list->count >= limit)
309 break;
310
311 if ((addr = ether_aton(astr)) != NULL)
312 memcpy(&list->ea[list->count++], addr, sizeof(struct ether_addr));
313 }
314
315 return wl_ioctl(interface, ioc & 0xffff, wlbuf, sizeof(wlbuf));
316 }
317 }
318
319 static int wlc_radio(wlc_param param, void *data, void *value)
320 {
321 int *val = (int *) value;
322 int ret;
323
324 if ((param & PARAM_MODE) == GET) {
325 ret = wl_ioctl(interface, WLC_GET_RADIO, val, sizeof(int));
326 *val = ((*val & 1) ? 0 : 1);
327 } else {
328 *val = (1 << 16) | (*val ? 0 : 1);
329 ret = wl_ioctl(interface, WLC_SET_RADIO, val, sizeof(int));
330 }
331
332 return ret;
333 }
334
335 static int wlc_wsec_key(wlc_param param, void *null, void *value)
336 {
337 wl_wsec_key_t wsec_key;
338 unsigned char *index = value;
339 unsigned char *key;
340 unsigned char *data;
341 unsigned char hex[3];
342
343 if ((param & PARAM_MODE) != SET)
344 return 0;
345
346 memset(&wsec_key, 0, sizeof(wsec_key));
347 if (index[0] == '=') {
348 wsec_key.flags = WL_PRIMARY_KEY;
349 index++;
350 }
351
352 if ((index[0] < '1') || (index[0] > '4') || (index[1] != ','))
353 return -1;
354
355 key = index + 2;
356 if (strncmp(key, "d:", 2) == 0) { /* delete key */
357 } else if (strncmp(key, "s:", 2) == 0) { /* ascii key */
358 key += 2;
359 wsec_key.len = strlen(key);
360
361 if ((wsec_key.len != 5) && (wsec_key.len != 13))
362 return -1;
363
364 strcpy(wsec_key.data, key);
365 } else { /* hex key */
366 wsec_key.len = strlen(key);
367 if ((wsec_key.len != 10) && (wsec_key.len != 26))
368 return -1;
369
370 wsec_key.len /= 2;
371 data = wsec_key.data;
372 hex[2] = 0;
373 do {
374 hex[0] = *(key++);
375 hex[1] = *(key++);
376 *(data++) = (unsigned char) strtoul(hex, NULL, 16);
377 } while (*key != 0);
378 }
379
380 return wl_bssiovar_set(interface, "wsec_key", vif, &wsec_key, sizeof(wsec_key));
381 }
382
383 static inline int cw2ecw(int cw)
384 {
385 int i;
386 for (cw++, i = 0; cw; i++) cw >>=1;
387 return i - 1;
388 }
389
390 static int wlc_wme_ac(wlc_param param, void *data, void *value)
391 {
392 char *type = *((char **) data);
393 char *settings = (char *) value;
394 char cmd[100], *p, *val;
395 edcf_acparam_t params[AC_COUNT];
396 int ret;
397 int intval;
398 int cur = -1;
399 char *buf = wlbuf;
400
401 if ((param & PARAM_MODE) != SET)
402 return -1;
403
404 memset(params, 0, sizeof(params));
405 ret = wl_iovar_get(interface, type, params, sizeof(params));
406 memset(buf, 0, BUFSIZE);
407 strcpy(buf, type);
408 buf += strlen(buf) + 1;
409
410 foreach(cmd, settings, p) {
411 val = strchr(cmd, '=');
412 if (val == NULL) {
413 if (strcmp(cmd, "be") == 0)
414 cur = AC_BE;
415 else if (strcmp(cmd, "bk") == 0)
416 cur = AC_BK;
417 else if (strcmp(cmd, "vi") == 0)
418 cur = AC_VI;
419 else if (strcmp(cmd, "vo") == 0)
420 cur = AC_VO;
421 else
422 return -1;
423
424 /* just in case */
425 params[cur].ACI = (params[cur].ACI & (0x3 << 5)) | (cur << 5);
426 } else {
427 *(val++) = 0;
428
429 intval = strtoul(val, NULL, 10);
430 if (strcmp(cmd, "cwmin") == 0)
431 params[cur].ECW = (params[cur].ECW & ~(0xf)) | cw2ecw(intval);
432 else if (strcmp(cmd, "ecwmin") == 0)
433 params[cur].ECW = (params[cur].ECW & ~(0xf)) | (intval & 0xf);
434 else if (strcmp(cmd, "cwmax") == 0)
435 params[cur].ECW = (params[cur].ECW & ~(0xf << 4)) | (cw2ecw(intval) << 4);
436 else if (strcmp(cmd, "ecwmax") == 0)
437 params[cur].ECW = (params[cur].ECW & ~(0xf << 4)) | ((intval & 0xf) << 4);
438 else if (strcmp(cmd, "aifsn") == 0)
439 params[cur].ACI = (params[cur].ACI & ~(0xf)) | (intval & 0xf);
440 else if (strcmp(cmd, "txop") == 0)
441 params[cur].TXOP = intval >> 5;
442 else if (strcmp(cmd, "force") == 0)
443 params[cur].ACI = (params[cur].ACI & ~(1 << 4)) | ((intval) ? (1 << 4) : 0);
444 else return -1;
445
446 memcpy(buf, &params[cur], sizeof(edcf_acparam_t));
447 wl_ioctl(interface, WLC_SET_VAR, wlbuf, BUFSIZE);
448 }
449 }
450 return ret;
451 }
452
453 static int wlc_ifname(wlc_param param, void *data, void *value)
454 {
455 char *val = (char *) value;
456 int ret = 0;
457
458 if (param & SET) {
459 if (strlen(val) < 16)
460 strcpy(interface, val);
461 else ret = -1;
462 }
463 if (param & GET) {
464 strcpy(val, interface);
465 }
466
467 return ret;
468 }
469
470 static int wlc_wdsmac(wlc_param param, void *data, void *value)
471 {
472 unsigned char mac[6];
473 int ret = 0;
474
475 ret = wl_ioctl(interface, WLC_WDS_GET_REMOTE_HWADDR, &mac, 6);
476 if (ret == 0)
477 my_ether_ntoa(mac, value);
478
479 return ret;
480 }
481
482 static int wlc_pmk(wlc_param param, void *data, void *value)
483 {
484 int ret = -1;
485 char *str = (char *) value;
486 wsec_pmk_t pmk;
487
488 /* driver doesn't support GET */
489
490 if ((param & PARAM_MODE) == SET) {
491 strncpy(pmk.key, value, WSEC_MAX_PSK_LEN);
492 pmk.key_len = strlen(value);
493
494 if (pmk.key_len > WSEC_MAX_PSK_LEN)
495 pmk.key_len = WSEC_MAX_PSK_LEN;
496
497 pmk.flags = WSEC_PASSPHRASE;
498
499 ret = wl_ioctl(interface, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
500 }
501
502 return ret;
503 }
504
505 static const struct wlc_call wlc_calls[] = {
506 {
507 .name = "version",
508 .param = STRING|NOARG,
509 .handler = wlc_string,
510 .data.str = VERSION,
511 .desc = "Version of this program"
512 },
513 {
514 .name = "debug",
515 .param = INT,
516 .handler = wlc_int,
517 .data.ptr = &debug,
518 .desc = "wlc debug level"
519 },
520 {
521 .name = "stdin",
522 .param = NOARG,
523 .handler = wlc_flag,
524 .data.ptr = &fromstdin,
525 .desc = "Accept input from stdin"
526 },
527 {
528 .name = "ifname",
529 .param = STRING,
530 .handler = wlc_ifname,
531 .desc = "interface to send commands to"
532 },
533 {
534 .name = "up",
535 .param = NOARG,
536 .handler = wlc_ioctl,
537 .data.num = WLC_UP,
538 .desc = "Bring the interface up"
539 },
540 {
541 .name = "down",
542 .param = NOARG,
543 .handler = wlc_ioctl,
544 .data.num = WLC_DOWN,
545 .desc = "Bring the interface down"
546 },
547 {
548 .name = "radio",
549 .param = INT,
550 .handler = wlc_radio,
551 .desc = "Radio enabled flag"
552 },
553 {
554 .name = "ap",
555 .param = INT,
556 .handler = wlc_ioctl,
557 .data.num = ((WLC_GET_AP << 16) | WLC_SET_AP),
558 .desc = "Access Point mode"
559 },
560 {
561 .name = "mssid",
562 .param = INT,
563 .handler = wlc_iovar,
564 .data.str = "mbss",
565 .desc = "Multi-ssid mode"
566 },
567 {
568 .name = "apsta",
569 .param = INT,
570 .handler = wlc_iovar,
571 .data.str = "apsta",
572 .desc = "AP+STA mode"
573 },
574 {
575 .name = "infra",
576 .param = INT,
577 .handler = wlc_ioctl,
578 .data.num = ((WLC_GET_INFRA << 16) | WLC_SET_INFRA),
579 .desc = "Infrastructure mode"
580 },
581 {
582 .name = "wet",
583 .param = INT,
584 .handler = wlc_ioctl,
585 .data.num = ((WLC_GET_WET << 16) | WLC_SET_WET),
586 .desc = "Wireless repeater mode",
587 },
588 {
589 .name = "statimeout",
590 .param = INT,
591 .handler = wlc_iovar,
592 .data.str = "sta_retry_time",
593 .desc = "STA connection timeout"
594 },
595 {
596 .name = "country",
597 .param = STRING,
598 .handler = wlc_ioctl,
599 .data.num = ((WLC_GET_COUNTRY << 16) | WLC_SET_COUNTRY),
600 .desc = "Country code"
601 },
602 {
603 .name = "channel",
604 .param = INT,
605 .handler = wlc_ioctl,
606 .data.num = ((WLC_GET_CHANNEL << 16) | WLC_SET_CHANNEL),
607 .desc = "Channel",
608 },
609 {
610 .name = "vlan_mode",
611 .param = INT,
612 .handler = wlc_bssiovar,
613 .data.str = "vlan_mode",
614 .desc = "Parse 802.1Q tags",
615 },
616 {
617 .name = "vif",
618 .param = INT,
619 .handler = wlc_int,
620 .data.ptr = &vif,
621 .desc = "Current vif index"
622 },
623 {
624 .name = "enabled",
625 .param = INT,
626 .handler = wlc_vif_enabled,
627 .desc = "vif enabled flag"
628 },
629 {
630 .name = "ssid",
631 .param = STRING,
632 .handler = wlc_ssid,
633 .desc = "Interface ESSID"
634 },
635 {
636 .name = "closed",
637 .param = INT,
638 .handler = wlc_bssiovar,
639 .data.str = "closednet",
640 .desc = "Hidden ESSID flag"
641 },
642 {
643 .name = "wsec",
644 .param = INT,
645 .handler = wlc_bssiovar,
646 .data.str = "wsec",
647 .desc = "Security mode flags"
648 },
649 {
650 .name = "wepkey",
651 .param = STRING,
652 .handler = wlc_wsec_key,
653 .desc = "Set/Remove WEP keys"
654 },
655 {
656 .name = "wsec_restrict",
657 .param = INT,
658 .handler = wlc_bssiovar,
659 .data.str = "wsec_restrict",
660 .desc = "Drop unencrypted traffic"
661 },
662 {
663 .name = "eap_restrict",
664 .param = INT,
665 .handler = wlc_bssiovar,
666 .data.str = "eap_restrict",
667 .desc = "Only allow 802.1X traffic until 802.1X authorized"
668 },
669 {
670 .name = "wpa_auth",
671 .param = INT,
672 .handler = wlc_bssiovar,
673 .data.str = "wpa_auth",
674 .desc = "WPA authentication modes"
675 },
676 {
677 .name = "ap_isolate",
678 .param = INT,
679 .handler = wlc_bssiovar,
680 .data.str = "ap_isolate",
681 .desc = "Isolate connected clients"
682 },
683 {
684 .name = "supplicant",
685 .param = INT,
686 .handler = wlc_iovar,
687 .data.str = "sup_wpa",
688 .desc = "Built-in WPA supplicant"
689 },
690 {
691 .name = "passphrase",
692 .param = STRING,
693 .handler = wlc_pmk,
694 .desc = "Passphrase for built-in WPA supplicant",
695 },
696 {
697 .name = "maxassoc",
698 .param = INT,
699 .handler = wlc_iovar,
700 .data.str = "maxassoc",
701 .desc = "Max. number of associated clients",
702 },
703 {
704 .name = "wme",
705 .param = INT,
706 .handler = wlc_iovar,
707 .data.str = "wme",
708 .desc = "WME enabled"
709 },
710 {
711 .name = "wme_ac_ap",
712 .param = STRING,
713 .handler = wlc_wme_ac,
714 .data.str = "wme_ac_ap",
715 .desc = "Set WME AC options for AP mode",
716 },
717 {
718 .name = "wme_ac_sta",
719 .param = STRING,
720 .handler = wlc_wme_ac,
721 .data.str = "wme_ac_sta",
722 .desc = "Set WME AC options for STA mode",
723 },
724 {
725 .name = "wme_noack",
726 .param = INT,
727 .handler = wlc_iovar,
728 .data.str = "wme_noack",
729 .desc = "WME ACK disable request",
730 },
731 {
732 .name = "802.11d",
733 .param = INT,
734 .handler = wlc_ioctl,
735 .data.num = ((WLC_GET_REGULATORY << 16) | WLC_SET_REGULATORY),
736 .desc = "Enable/disable 802.11d regulatory management",
737 },
738 {
739 .name = "802.11h",
740 .param = INT,
741 .handler = wlc_ioctl,
742 .data.num = ((WLC_GET_SPECT_MANAGMENT << 16) | WLC_SET_SPECT_MANAGMENT),
743 .desc = "Enable/disable 802.11h spectrum management",
744 },
745 {
746 .name = "fragthresh",
747 .param = INT,
748 .handler = wlc_iovar,
749 .data.str = "fragthresh",
750 .desc = "Fragmentation threshold",
751 },
752 {
753 .name = "rtsthresh",
754 .param = INT,
755 .handler = wlc_iovar,
756 .data.str = "rtsthresh",
757 .desc = "RTS threshold"
758 },
759 {
760 .name = "slottime",
761 .param = INT,
762 .handler = wlc_iovar,
763 .data.str = "acktiming",
764 .desc = "Slot time"
765 },
766 {
767 .name = "rxant",
768 .param = INT,
769 .handler = wlc_ioctl,
770 .data.num = ((WLC_GET_ANTDIV << 16) | WLC_SET_ANTDIV),
771 .desc = "Rx antenna selection"
772 },
773 {
774 .name = "txant",
775 .param = INT,
776 .handler = wlc_ioctl,
777 .data.num = ((WLC_GET_TXANT << 16) | WLC_SET_TXANT),
778 .desc = "Tx antenna selection"
779 },
780 {
781 .name = "dtim",
782 .param = INT,
783 .handler = wlc_ioctl,
784 .data.num = ((WLC_GET_DTIMPRD << 16) | WLC_SET_DTIMPRD),
785 .desc = "DTIM period",
786 },
787 {
788 .name = "bcn",
789 .param = INT,
790 .handler = wlc_ioctl,
791 .data.num = ((WLC_GET_BCNPRD << 16) | WLC_SET_BCNPRD),
792 .desc = "Beacon interval"
793 },
794 {
795 .name = "frameburst",
796 .param = INT,
797 .handler = wlc_ioctl,
798 .data.num = ((WLC_GET_FAKEFRAG << 16) | WLC_SET_FAKEFRAG),
799 .desc = "Framebursting"
800 },
801 {
802 .name = "monitor",
803 .param = INT,
804 .handler = wlc_ioctl,
805 .data.num = ((WLC_GET_MONITOR << 16) | WLC_SET_MONITOR),
806 .desc = "Monitor mode"
807 },
808 {
809 .name = "passive",
810 .param = INT,
811 .handler = wlc_ioctl,
812 .data.num = ((WLC_GET_PASSIVE << 16) | WLC_SET_PASSIVE),
813 .desc = "Passive mode"
814 },
815 {
816 .name = "macfilter",
817 .param = INT,
818 .handler = wlc_ioctl,
819 .data.num = ((WLC_GET_MACMODE << 16) | WLC_SET_MACMODE),
820 .desc = "MAC filter mode (0:disabled, 1:deny, 2:allow)"
821 },
822 {
823 .name = "maclist",
824 .param = STRING,
825 .data.num = ((WLC_GET_MACLIST << 16) | WLC_SET_MACLIST),
826 .handler = wlc_maclist,
827 .desc = "MAC filter list"
828 },
829 {
830 .name = "autowds",
831 .param = INT,
832 .handler = wlc_ioctl,
833 .data.num = ((WLC_GET_LAZYWDS << 16) | WLC_SET_LAZYWDS),
834 .desc = "Automatic WDS"
835 },
836 {
837 .name = "wds",
838 .param = STRING,
839 .data.num = ((WLC_GET_WDSLIST << 16) | WLC_SET_WDSLIST),
840 .handler = wlc_maclist,
841 .desc = "WDS connection list"
842 },
843 {
844 .name = "wdstimeout",
845 .param = INT,
846 .handler = wlc_iovar,
847 .data.str = "wdstimeout",
848 .desc = "WDS link detection timeout"
849 },
850 {
851 .name = "wdsmac",
852 .param = STRING|NOARG,
853 .handler = wlc_wdsmac,
854 .desc = "MAC of the remote WDS endpoint (only with wds0.* interfaces)"
855 },
856 {
857 .name = "afterburner",
858 .param = INT,
859 .handler = wlc_afterburner,
860 .desc = "Broadcom Afterburner"
861 },
862 };
863 #define wlc_calls_size (sizeof(wlc_calls) / sizeof(struct wlc_call))
864
865 static void usage(char *cmd)
866 {
867 int i;
868 fprintf(stderr, "Usage: %s <command> [<argument> ...]\n"
869 "\n"
870 "Available commands:\n", cmd);
871 for (i = 0; i < wlc_calls_size; i++) {
872 fprintf(stderr, "\t%-16s\t%s\n", wlc_calls[i].name ?: "", wlc_calls[i].desc ?: "");
873 }
874 fprintf(stderr, "\n");
875 exit(1);
876 }
877
878 static int do_command(const struct wlc_call *cmd, char *arg)
879 {
880 static char buf[BUFSIZE];
881 int set;
882 int ret = 0;
883 char *format, *end;
884 int intval;
885
886 if (debug >= 10) {
887 fprintf(stderr, "do_command %-16s\t'%s'\n", cmd->name, arg);
888 }
889
890 if ((arg == NULL) && ((cmd->param & PARAM_TYPE) != NONE)) {
891 set = 0;
892 ret = cmd->handler(cmd->param | GET, (void *) &cmd->data, (void *) buf);
893 if (ret == 0) {
894 switch(cmd->param & PARAM_TYPE) {
895 case INT:
896 intval = *((int *) buf);
897
898 if (intval > 65535)
899 format = "0x%08x\n";
900 else if (intval > 255)
901 format = "0x%04x\n";
902 else
903 format = "%d\n";
904
905 fprintf(stdout, format, intval);
906 break;
907 case STRING:
908 fprintf(stdout, "%s\n", buf);
909 }
910 }
911 } else { /* SET */
912 set = 1;
913 switch(cmd->param & PARAM_TYPE) {
914 case INT:
915 intval = strtoul(arg, &end, 10);
916 if (end && !(*end)) {
917 memcpy(buf, &intval, sizeof(intval));
918 } else {
919 fprintf(stderr, "%s: Invalid argument\n", cmd->name);
920 return -1;
921 }
922 break;
923 case STRING:
924 strncpy(buf, arg, BUFSIZE);
925 buf[BUFSIZE - 1] = 0;
926 }
927
928 ret = cmd->handler(cmd->param | SET, (void *) &cmd->data, (void *) buf);
929 }
930
931 if ((debug > 0) && (ret != 0))
932 fprintf(stderr, "Command '%s %s' failed: %d\n", (set == 1 ? "set" : "get"), cmd->name, ret);
933
934 return ret;
935 }
936
937 static struct wlc_call *find_cmd(char *name)
938 {
939 int found = 0, i = 0;
940
941 while (!found && (i < wlc_calls_size)) {
942 if (strcmp(name, wlc_calls[i].name) == 0)
943 found = 1;
944 else
945 i++;
946 }
947
948 return (struct wlc_call *) (found ? &wlc_calls[i] : NULL);
949 }
950
951 int main(int argc, char **argv)
952 {
953 static char buf[BUFSIZE];
954 char *s, *s2;
955 char *cmd = argv[0];
956 struct wlc_call *call;
957 int ret = 0;
958
959 if (argc < 2)
960 usage(argv[0]);
961
962 for(interface[2] = '0'; (interface[2] < '3') && (wl_probe(interface) != 0); interface[2]++);
963 if (interface[2] == '3') {
964 fprintf(stderr, "No Broadcom wl interface found!\n");
965 return -1;
966 }
967
968 argv++;
969 argc--;
970 while ((argc > 0) && (argv[0] != NULL)) {
971 if ((call = find_cmd(argv[0])) == NULL) {
972 fprintf(stderr, "Invalid command: %s\n\n", argv[0]);
973 usage(cmd);
974 }
975 if ((argc > 1) && (!(call->param & NOARG))) {
976 ret = do_command(call, argv[1]);
977 argv += 2;
978 argc -= 2;
979 } else {
980 ret = do_command(call, NULL);
981 argv++;
982 argc--;
983 }
984 }
985
986 while (fromstdin && !feof(stdin)) {
987 *buf = 0;
988 fgets(buf, BUFSIZE - 1, stdin);
989
990 if (*buf == 0)
991 continue;
992
993 if ((s = strchr(buf, '\r')) != NULL)
994 *s = 0;
995 if ((s = strchr(buf, '\n')) != NULL)
996 *s = 0;
997
998 s = buf;
999 while (isspace(*s))
1000 s++;
1001
1002 if (!*s)
1003 continue;
1004
1005 if ((s2 = strchr(buf, ' ')) != NULL)
1006 *(s2++) = 0;
1007
1008 while (s2 && isspace(*s2))
1009 s2++;
1010
1011 if ((call = find_cmd(buf)) == NULL) {
1012 fprintf(stderr, "Invalid command: %s\n", buf);
1013 ret = -1;
1014 } else
1015 ret = do_command(call, ((call->param & NOARG) ? NULL : s2));
1016 }
1017
1018 return ret;
1019 }