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