wlc.c 23 KB

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