wlc.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121
  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, str, WSEC_MAX_PSK_LEN);
  421. pmk.key_len = strlen(str);
  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. .name = "phytype",
  830. .param = INT,
  831. .data.num = (WLC_GET_PHYTYPE << 16),
  832. .handler = wlc_ioctl,
  833. .desc = "PHY Type"
  834. },
  835. {
  836. .name = "nmode",
  837. .param = INT,
  838. .handler = wlc_iovar,
  839. .data.str = "nmode",
  840. .desc = "N Mode"
  841. },
  842. {
  843. .name = "nreqd",
  844. .param = INT,
  845. .handler = wlc_iovar,
  846. .data.str = "nreqd",
  847. .desc = "N Mode required"
  848. },
  849. {
  850. .name = "chanspec",
  851. .param = INT,
  852. .handler = wlc_iovar,
  853. .data.str = "chanspec",
  854. .desc = "Channel Spec (See bcmwifi.h)"
  855. },
  856. {
  857. .name = "band",
  858. .param = INT,
  859. .data.num = ((WLC_GET_BAND << 16) | WLC_SET_BAND),
  860. .handler = wlc_ioctl,
  861. .desc = "Band"
  862. },
  863. };
  864. #define wlc_calls_size (sizeof(wlc_calls) / sizeof(struct wlc_call))
  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. static int do_command(const struct wlc_call *cmd, char *arg)
  878. {
  879. static char buf[BUFSIZE];
  880. int set;
  881. int ret = 0;
  882. char *format, *end;
  883. int intval;
  884. void *ptr = (void *) buf;
  885. if (debug >= 10) {
  886. fprintf(stderr, "do_command %-16s\t'%s'\n", cmd->name, arg);
  887. }
  888. if ((arg == NULL) && ((cmd->param & PARAM_TYPE) != NONE)) {
  889. set = 0;
  890. ret = cmd->handler(cmd->param | GET, (void *) &cmd->data, (void *) buf);
  891. if (ret == 0) {
  892. switch(cmd->param & PARAM_TYPE) {
  893. case INT:
  894. intval = *((int *) buf);
  895. if (intval > 65535)
  896. format = "0x%08x\n";
  897. else if (intval > 255)
  898. format = "0x%04x\n";
  899. else
  900. format = "%d\n";
  901. fprintf(stdout, format, intval);
  902. break;
  903. case STRING:
  904. fprintf(stdout, "%s\n", buf);
  905. break;
  906. case MAC:
  907. my_ether_ntoa(buf, buf + 6);
  908. fprintf(stdout, "%s\n", buf + 6);
  909. break;
  910. }
  911. }
  912. } else { /* SET */
  913. set = 1;
  914. switch(cmd->param & PARAM_TYPE) {
  915. case INT:
  916. intval = strtoul(arg, &end, 0);
  917. if (end && !(*end)) {
  918. memcpy(buf, &intval, sizeof(intval));
  919. } else {
  920. fprintf(stderr, "%s: Invalid argument\n", cmd->name);
  921. return -1;
  922. }
  923. break;
  924. case STRING:
  925. strncpy(buf, arg, BUFSIZE);
  926. buf[BUFSIZE - 1] = 0;
  927. break;
  928. case MAC:
  929. ptr = ether_aton(arg);
  930. if (!ptr) {
  931. fprintf(stderr, "%s: Invalid mac address '%s'\n", cmd->name, arg);
  932. return -1;
  933. }
  934. break;
  935. }
  936. ret = cmd->handler(cmd->param | SET, (void *) &cmd->data, ptr);
  937. }
  938. if ((debug > 0) && (ret != 0))
  939. fprintf(stderr, "Command '%s %s' failed: %d\n", (set == 1 ? "set" : "get"), cmd->name, ret);
  940. return ret;
  941. }
  942. static struct wlc_call *find_cmd(char *name)
  943. {
  944. int found = 0, i = 0;
  945. while (!found && (i < wlc_calls_size)) {
  946. if (strcmp(name, wlc_calls[i].name) == 0)
  947. found = 1;
  948. else
  949. i++;
  950. }
  951. return (struct wlc_call *) (found ? &wlc_calls[i] : NULL);
  952. }
  953. int main(int argc, char **argv)
  954. {
  955. static char buf[BUFSIZE];
  956. char *s, *s2;
  957. char *cmd = argv[0];
  958. struct wlc_call *call;
  959. int ret = 0;
  960. if (argc < 2)
  961. usage(argv[0]);
  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. argv++;
  968. argc--;
  969. while ((argc > 0) && (argv[0] != NULL)) {
  970. if ((call = find_cmd(argv[0])) == NULL) {
  971. fprintf(stderr, "Invalid command: %s\n\n", argv[0]);
  972. usage(cmd);
  973. }
  974. if ((argc > 1) && (!(call->param & NOARG))) {
  975. ret = do_command(call, argv[1]);
  976. argv += 2;
  977. argc -= 2;
  978. } else {
  979. ret = do_command(call, NULL);
  980. argv++;
  981. argc--;
  982. }
  983. }
  984. while (fromstdin && !feof(stdin)) {
  985. *buf = 0;
  986. fgets(buf, BUFSIZE - 1, stdin);
  987. if (*buf == 0)
  988. continue;
  989. if ((s = strchr(buf, '\r')) != NULL)
  990. *s = 0;
  991. if ((s = strchr(buf, '\n')) != NULL)
  992. *s = 0;
  993. s = buf;
  994. while (isspace(*s))
  995. s++;
  996. if (!*s)
  997. continue;
  998. if ((s2 = strchr(buf, ' ')) != NULL)
  999. *(s2++) = 0;
  1000. while (s2 && isspace(*s2))
  1001. s2++;
  1002. if ((call = find_cmd(buf)) == NULL) {
  1003. fprintf(stderr, "Invalid command: %s\n", buf);
  1004. ret = -1;
  1005. } else
  1006. ret = do_command(call, ((call->param & NOARG) ? NULL : s2));
  1007. }
  1008. return ret;
  1009. }