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