wlc.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181
  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 int wlc_cap(wlc_param param, void *data, void *value)
  329. {
  330. char *iov = *((char **) data);
  331. if (param & GET)
  332. return wl_iovar_get(interface, iov, value, BUFSIZE);
  333. return -1;
  334. }
  335. static int wlc_bssmax(wlc_param param, void *data, void *value)
  336. {
  337. int *val = (int *) value;
  338. char *iov = *((char **) data);
  339. int ret = -1;
  340. if (param & GET) {
  341. ret = wl_iovar_get(interface, iov, wlbuf, BUFSIZE);
  342. if (!ret) {
  343. if (strstr(wlbuf, "mbss4"))
  344. *val = 4;
  345. else if (strstr(wlbuf, "mbss16"))
  346. *val = 16;
  347. else
  348. *val = 1;
  349. }
  350. }
  351. return ret;
  352. }
  353. static inline int cw2ecw(int cw)
  354. {
  355. int i;
  356. for (cw++, i = 0; cw; i++) cw >>=1;
  357. return i - 1;
  358. }
  359. static int wlc_wme_ac(wlc_param param, void *data, void *value)
  360. {
  361. char *type = *((char **) data);
  362. char *settings = (char *) value;
  363. char cmd[100], *p, *val;
  364. edcf_acparam_t params[AC_COUNT];
  365. int ret;
  366. int intval;
  367. int cur = -1;
  368. char *buf = wlbuf;
  369. if ((param & PARAM_MODE) != SET)
  370. return -1;
  371. memset(params, 0, sizeof(params));
  372. ret = wl_iovar_get(interface, type, params, sizeof(params));
  373. memset(buf, 0, BUFSIZE);
  374. strcpy(buf, type);
  375. buf += strlen(buf) + 1;
  376. foreach(cmd, settings, p) {
  377. val = strchr(cmd, '=');
  378. if (val == NULL) {
  379. if (strcmp(cmd, "be") == 0)
  380. cur = AC_BE;
  381. else if (strcmp(cmd, "bk") == 0)
  382. cur = AC_BK;
  383. else if (strcmp(cmd, "vi") == 0)
  384. cur = AC_VI;
  385. else if (strcmp(cmd, "vo") == 0)
  386. cur = AC_VO;
  387. else
  388. return -1;
  389. /* just in case */
  390. params[cur].ACI = (params[cur].ACI & (0x3 << 5)) | (cur << 5);
  391. } else {
  392. *(val++) = 0;
  393. intval = strtoul(val, NULL, 10);
  394. if (strcmp(cmd, "cwmin") == 0)
  395. params[cur].ECW = (params[cur].ECW & ~(0xf)) | cw2ecw(intval);
  396. else if (strcmp(cmd, "ecwmin") == 0)
  397. params[cur].ECW = (params[cur].ECW & ~(0xf)) | (intval & 0xf);
  398. else if (strcmp(cmd, "cwmax") == 0)
  399. params[cur].ECW = (params[cur].ECW & ~(0xf << 4)) | (cw2ecw(intval) << 4);
  400. else if (strcmp(cmd, "ecwmax") == 0)
  401. params[cur].ECW = (params[cur].ECW & ~(0xf << 4)) | ((intval & 0xf) << 4);
  402. else if (strcmp(cmd, "aifsn") == 0)
  403. params[cur].ACI = (params[cur].ACI & ~(0xf)) | (intval & 0xf);
  404. else if (strcmp(cmd, "txop") == 0)
  405. params[cur].TXOP = intval >> 5;
  406. else if (strcmp(cmd, "force") == 0)
  407. params[cur].ACI = (params[cur].ACI & ~(1 << 4)) | ((intval) ? (1 << 4) : 0);
  408. else return -1;
  409. memcpy(buf, &params[cur], sizeof(edcf_acparam_t));
  410. wl_ioctl(interface, WLC_SET_VAR, wlbuf, BUFSIZE);
  411. }
  412. }
  413. return ret;
  414. }
  415. static int wlc_ifname(wlc_param param, void *data, void *value)
  416. {
  417. char *val = (char *) value;
  418. int ret = 0;
  419. if (param & SET) {
  420. if (strlen(val) < 16)
  421. strcpy(interface, val);
  422. else ret = -1;
  423. }
  424. if (param & GET) {
  425. strcpy(val, interface);
  426. }
  427. return ret;
  428. }
  429. static int wlc_wdsmac(wlc_param param, void *data, void *value)
  430. {
  431. unsigned char mac[6];
  432. int ret = 0;
  433. ret = wl_ioctl(interface, WLC_WDS_GET_REMOTE_HWADDR, &mac, 6);
  434. if (ret == 0)
  435. my_ether_ntoa(mac, value);
  436. return ret;
  437. }
  438. static int wlc_pmk(wlc_param param, void *data, void *value)
  439. {
  440. int ret = -1;
  441. char *str = (char *) value;
  442. wsec_pmk_t pmk;
  443. /* driver doesn't support GET */
  444. if ((param & PARAM_MODE) == SET) {
  445. strncpy(pmk.key, str, WSEC_MAX_PSK_LEN);
  446. pmk.key_len = strlen(str);
  447. if (pmk.key_len > WSEC_MAX_PSK_LEN)
  448. pmk.key_len = WSEC_MAX_PSK_LEN;
  449. pmk.flags = WSEC_PASSPHRASE;
  450. ret = wl_ioctl(interface, WLC_SET_WSEC_PMK, &pmk, sizeof(pmk));
  451. }
  452. return ret;
  453. }
  454. static const struct wlc_call wlc_calls[] = {
  455. {
  456. .name = "version",
  457. .param = STRING|NOARG,
  458. .handler = wlc_string,
  459. .data.str = VERSION,
  460. .desc = "Version of this program"
  461. },
  462. {
  463. .name = "debug",
  464. .param = INT,
  465. .handler = wlc_int,
  466. .data.ptr = &debug,
  467. .desc = "wlc debug level"
  468. },
  469. {
  470. .name = "stdin",
  471. .param = NOARG,
  472. .handler = wlc_flag,
  473. .data.ptr = &fromstdin,
  474. .desc = "Accept input from stdin"
  475. },
  476. {
  477. .name = "ifname",
  478. .param = STRING,
  479. .handler = wlc_ifname,
  480. .desc = "interface to send commands to"
  481. },
  482. {
  483. .name = "up",
  484. .param = NOARG,
  485. .handler = wlc_ioctl,
  486. .data.num = WLC_UP,
  487. .desc = "Bring the interface up"
  488. },
  489. {
  490. .name = "down",
  491. .param = NOARG,
  492. .handler = wlc_ioctl,
  493. .data.num = WLC_DOWN,
  494. .desc = "Bring the interface down"
  495. },
  496. {
  497. .name = "radio",
  498. .param = INT,
  499. .handler = wlc_radio,
  500. .desc = "Radio enabled flag"
  501. },
  502. {
  503. .name = "ap",
  504. .param = INT,
  505. .handler = wlc_ioctl,
  506. .data.num = ((WLC_GET_AP << 16) | WLC_SET_AP),
  507. .desc = "Access Point mode"
  508. },
  509. {
  510. .name = "mssid",
  511. .param = INT,
  512. .handler = wlc_iovar,
  513. .data.str = "mbss",
  514. .desc = "Multi-ssid mode"
  515. },
  516. {
  517. .name = "apsta",
  518. .param = INT,
  519. .handler = wlc_iovar,
  520. .data.str = "apsta",
  521. .desc = "AP+STA mode"
  522. },
  523. {
  524. .name = "infra",
  525. .param = INT,
  526. .handler = wlc_ioctl,
  527. .data.num = ((WLC_GET_INFRA << 16) | WLC_SET_INFRA),
  528. .desc = "Infrastructure mode"
  529. },
  530. {
  531. .name = "wet",
  532. .param = INT,
  533. .handler = wlc_ioctl,
  534. .data.num = ((WLC_GET_WET << 16) | WLC_SET_WET),
  535. .desc = "Wireless repeater mode",
  536. },
  537. {
  538. .name = "statimeout",
  539. .param = INT,
  540. .handler = wlc_iovar,
  541. .data.str = "sta_retry_time",
  542. .desc = "STA connection timeout"
  543. },
  544. {
  545. .name = "country",
  546. .param = STRING,
  547. .handler = wlc_ioctl,
  548. .data.num = ((WLC_GET_COUNTRY << 16) | WLC_SET_COUNTRY),
  549. .desc = "Country code"
  550. },
  551. {
  552. .name = "channel",
  553. .param = INT,
  554. .handler = wlc_ioctl,
  555. .data.num = ((WLC_GET_CHANNEL << 16) | WLC_SET_CHANNEL),
  556. .desc = "Channel",
  557. },
  558. {
  559. .name = "vlan_mode",
  560. .param = INT,
  561. .handler = wlc_bssiovar,
  562. .data.str = "vlan_mode",
  563. .desc = "Parse 802.1Q tags",
  564. },
  565. {
  566. .name = "vif",
  567. .param = INT,
  568. .handler = wlc_int,
  569. .data.ptr = &vif,
  570. .desc = "Current vif index"
  571. },
  572. {
  573. .name = "enabled",
  574. .param = INT,
  575. .handler = wlc_vif_enabled,
  576. .desc = "vif enabled flag"
  577. },
  578. {
  579. .name = "ssid",
  580. .param = STRING,
  581. .handler = wlc_ssid,
  582. .desc = "Interface ESSID"
  583. },
  584. {
  585. .name = "closed",
  586. .param = INT,
  587. .handler = wlc_bssiovar,
  588. .data.str = "closednet",
  589. .desc = "Hidden ESSID flag"
  590. },
  591. {
  592. .name = "wsec",
  593. .param = INT,
  594. .handler = wlc_bssiovar,
  595. .data.str = "wsec",
  596. .desc = "Security mode flags"
  597. },
  598. {
  599. .name = "wepkey",
  600. .param = STRING,
  601. .handler = wlc_wsec_key,
  602. .desc = "Set/Remove WEP keys"
  603. },
  604. {
  605. .name = "wepauth",
  606. .param = INT,
  607. .handler = wlc_ioctl,
  608. .data.num = ((WLC_GET_AUTH << 16) | WLC_SET_AUTH),
  609. .desc = "WEP authentication type. 0 = OpenSystem, 1 = SharedKey"
  610. },
  611. {
  612. .name = "wsec_restrict",
  613. .param = INT,
  614. .handler = wlc_bssiovar,
  615. .data.str = "wsec_restrict",
  616. .desc = "Drop unencrypted traffic"
  617. },
  618. {
  619. .name = "eap_restrict",
  620. .param = INT,
  621. .handler = wlc_bssiovar,
  622. .data.str = "eap_restrict",
  623. .desc = "Only allow 802.1X traffic until 802.1X authorized"
  624. },
  625. {
  626. .name = "wpa_auth",
  627. .param = INT,
  628. .handler = wlc_bssiovar,
  629. .data.str = "wpa_auth",
  630. .desc = "WPA authentication modes"
  631. },
  632. {
  633. .name = "ap_isolate",
  634. .param = INT,
  635. .handler = wlc_bssiovar,
  636. .data.str = "ap_isolate",
  637. .desc = "Isolate connected clients"
  638. },
  639. {
  640. .name = "supplicant",
  641. .param = INT,
  642. .handler = wlc_iovar,
  643. .data.str = "sup_wpa",
  644. .desc = "Built-in WPA supplicant"
  645. },
  646. {
  647. .name = "passphrase",
  648. .param = STRING,
  649. .handler = wlc_pmk,
  650. .desc = "Passphrase for built-in WPA supplicant",
  651. },
  652. {
  653. .name = "maxassoc",
  654. .param = INT,
  655. .handler = wlc_iovar,
  656. .data.str = "maxassoc",
  657. .desc = "Max. number of associated clients",
  658. },
  659. {
  660. .name = "wme",
  661. .param = INT,
  662. .handler = wlc_iovar,
  663. .data.str = "wme",
  664. .desc = "WME enabled"
  665. },
  666. {
  667. .name = "wme_ac_ap",
  668. .param = STRING,
  669. .handler = wlc_wme_ac,
  670. .data.str = "wme_ac_ap",
  671. .desc = "Set WME AC options for AP mode",
  672. },
  673. {
  674. .name = "wme_ac_sta",
  675. .param = STRING,
  676. .handler = wlc_wme_ac,
  677. .data.str = "wme_ac_sta",
  678. .desc = "Set WME AC options for STA mode",
  679. },
  680. {
  681. .name = "wme_noack",
  682. .param = INT,
  683. .handler = wlc_iovar,
  684. .data.str = "wme_noack",
  685. .desc = "WME ACK disable request",
  686. },
  687. {
  688. .name = "802.11d",
  689. .param = INT,
  690. .handler = wlc_ioctl,
  691. .data.num = ((WLC_GET_REGULATORY << 16) | WLC_SET_REGULATORY),
  692. .desc = "Enable/disable 802.11d regulatory management",
  693. },
  694. {
  695. .name = "802.11h",
  696. .param = INT,
  697. .handler = wlc_ioctl,
  698. .data.num = ((WLC_GET_SPECT_MANAGMENT << 16) | WLC_SET_SPECT_MANAGMENT),
  699. .desc = "Enable/disable 802.11h spectrum management",
  700. },
  701. {
  702. .name = "fragthresh",
  703. .param = INT,
  704. .handler = wlc_iovar,
  705. .data.str = "fragthresh",
  706. .desc = "Fragmentation threshold",
  707. },
  708. {
  709. .name = "rtsthresh",
  710. .param = INT,
  711. .handler = wlc_iovar,
  712. .data.str = "rtsthresh",
  713. .desc = "RTS threshold"
  714. },
  715. {
  716. .name = "slottime",
  717. .param = INT,
  718. .handler = wlc_iovar,
  719. .data.str = "acktiming",
  720. .desc = "Slot time"
  721. },
  722. {
  723. .name = "rxant",
  724. .param = INT,
  725. .handler = wlc_ioctl,
  726. .data.num = ((WLC_GET_ANTDIV << 16) | WLC_SET_ANTDIV),
  727. .desc = "Rx antenna selection"
  728. },
  729. {
  730. .name = "txant",
  731. .param = INT,
  732. .handler = wlc_ioctl,
  733. .data.num = ((WLC_GET_TXANT << 16) | WLC_SET_TXANT),
  734. .desc = "Tx antenna selection"
  735. },
  736. {
  737. .name = "dtim",
  738. .param = INT,
  739. .handler = wlc_ioctl,
  740. .data.num = ((WLC_GET_DTIMPRD << 16) | WLC_SET_DTIMPRD),
  741. .desc = "DTIM period",
  742. },
  743. {
  744. .name = "bcn",
  745. .param = INT,
  746. .handler = wlc_ioctl,
  747. .data.num = ((WLC_GET_BCNPRD << 16) | WLC_SET_BCNPRD),
  748. .desc = "Beacon interval"
  749. },
  750. {
  751. .name = "frameburst",
  752. .param = INT,
  753. .handler = wlc_ioctl,
  754. .data.num = ((WLC_GET_FAKEFRAG << 16) | WLC_SET_FAKEFRAG),
  755. .desc = "Framebursting"
  756. },
  757. {
  758. .name = "monitor",
  759. .param = INT,
  760. .handler = wlc_ioctl,
  761. .data.num = ((WLC_GET_MONITOR << 16) | WLC_SET_MONITOR),
  762. .desc = "Monitor mode"
  763. },
  764. {
  765. .name = "passive_scan",
  766. .param = INT,
  767. .handler = wlc_ioctl,
  768. .data.num = ((WLC_GET_PASSIVE_SCAN << 16) | WLC_SET_PASSIVE_SCAN),
  769. .desc = "Passive scan mode"
  770. },
  771. {
  772. .name = "macfilter",
  773. .param = INT,
  774. .handler = wlc_ioctl,
  775. .data.num = ((WLC_GET_MACMODE << 16) | WLC_SET_MACMODE),
  776. .desc = "MAC filter mode (0:disabled, 1:deny, 2:allow)"
  777. },
  778. {
  779. .name = "maclist",
  780. .param = STRING,
  781. .data.num = ((WLC_GET_MACLIST << 16) | WLC_SET_MACLIST),
  782. .handler = wlc_maclist,
  783. .desc = "MAC filter list"
  784. },
  785. {
  786. .name = "autowds",
  787. .param = INT,
  788. .handler = wlc_ioctl,
  789. .data.num = ((WLC_GET_LAZYWDS << 16) | WLC_SET_LAZYWDS),
  790. .desc = "Automatic WDS"
  791. },
  792. {
  793. .name = "wds",
  794. .param = STRING,
  795. .data.num = ((WLC_GET_WDSLIST << 16) | WLC_SET_WDSLIST),
  796. .handler = wlc_maclist,
  797. .desc = "WDS connection list"
  798. },
  799. {
  800. .name = "wdstimeout",
  801. .param = INT,
  802. .handler = wlc_iovar,
  803. .data.str = "wdstimeout",
  804. .desc = "WDS link detection timeout"
  805. },
  806. {
  807. .name = "wdsmac",
  808. .param = STRING|NOARG,
  809. .handler = wlc_wdsmac,
  810. .desc = "MAC of the remote WDS endpoint (only with wds0.* interfaces)"
  811. },
  812. {
  813. .name = "afterburner",
  814. .param = INT,
  815. .handler = wlc_afterburner,
  816. .desc = "Broadcom Afterburner"
  817. },
  818. {
  819. .name = "ibss_merge",
  820. .param = INT,
  821. .handler = wlc_iovar,
  822. .data.str = "ibss_coalesce_allowed",
  823. .desc = "Allow IBSS merges"
  824. },
  825. {
  826. .name = "bssid",
  827. .param = MAC,
  828. .handler = wlc_ioctl,
  829. .data.num = ((WLC_GET_BSSID << 16) | WLC_SET_BSSID),
  830. .desc = "BSSID"
  831. },
  832. {
  833. .name = "cur_etheraddr",
  834. .param = MAC,
  835. .handler = wlc_iovar,
  836. .data.str = "cur_etheraddr",
  837. .desc = "Current MAC Address"
  838. },
  839. {
  840. .name = "default_bssid",
  841. .param = MAC,
  842. .handler = wlc_iovar,
  843. .data.str = "perm_etheraddr",
  844. .desc = "Default BSSID (read-only)"
  845. },
  846. {
  847. .name = "assoclist",
  848. .param = STRING,
  849. .data.num = (WLC_GET_ASSOCLIST << 16),
  850. .handler = wlc_maclist,
  851. .desc = "MACs of associated stations"
  852. },
  853. {
  854. .name = "gmode",
  855. .param = INT,
  856. .data.num = ((WLC_GET_GMODE << 16) | WLC_SET_GMODE),
  857. .handler = wlc_ioctl,
  858. .desc = "G Mode"
  859. },
  860. {
  861. .name = "phytype",
  862. .param = INT,
  863. .data.num = (WLC_GET_PHYTYPE << 16),
  864. .handler = wlc_ioctl,
  865. .desc = "PHY Type (read-only)"
  866. },
  867. {
  868. .name = "nmode",
  869. .param = INT,
  870. .handler = wlc_iovar,
  871. .data.str = "nmode",
  872. .desc = "N Mode"
  873. },
  874. {
  875. .name = "nreqd",
  876. .param = INT,
  877. .handler = wlc_iovar,
  878. .data.str = "nreqd",
  879. .desc = "N Mode required"
  880. },
  881. {
  882. .name = "chanspec",
  883. .param = INT,
  884. .handler = wlc_iovar,
  885. .data.str = "chanspec",
  886. .desc = "Channel Spec (See bcmwifi.h)"
  887. },
  888. {
  889. .name = "band",
  890. .param = INT,
  891. .data.num = ((WLC_GET_BAND << 16) | WLC_SET_BAND),
  892. .handler = wlc_ioctl,
  893. .desc = "Band (0=auto, 1=5Ghz, 2=2.4GHz)"
  894. },
  895. {
  896. .name = "cap",
  897. .param = STRING|NOARG,
  898. .handler = wlc_cap,
  899. .data.str = "cap",
  900. .desc = "Capabilities"
  901. },
  902. {
  903. .name = "bssmax",
  904. .param = INT|NOARG,
  905. .handler = wlc_bssmax,
  906. .data.str = "cap",
  907. .desc = "Number of VIF's supported"
  908. },
  909. {
  910. .name = "leddc",
  911. .param = INT,
  912. .handler = wlc_iovar,
  913. .data.str = "leddc",
  914. .desc = "LED Duty Cycle"
  915. },
  916. };
  917. #define wlc_calls_size (sizeof(wlc_calls) / sizeof(struct wlc_call))
  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. static int do_command(const struct wlc_call *cmd, char *arg)
  931. {
  932. static char buf[BUFSIZE];
  933. int set;
  934. int ret = 0;
  935. char *format, *end;
  936. int intval;
  937. void *ptr = (void *) buf;
  938. if (debug >= 10) {
  939. fprintf(stderr, "do_command %-16s\t'%s'\n", cmd->name, arg);
  940. }
  941. if ((arg == NULL) && ((cmd->param & PARAM_TYPE) != NONE)) {
  942. set = 0;
  943. ret = cmd->handler(cmd->param | GET, (void *) &cmd->data, (void *) buf);
  944. if (ret == 0) {
  945. switch(cmd->param & PARAM_TYPE) {
  946. case INT:
  947. intval = *((int *) buf);
  948. if (intval > 65535)
  949. format = "0x%08x\n";
  950. else if (intval > 255)
  951. format = "0x%04x\n";
  952. else
  953. format = "%d\n";
  954. fprintf(stdout, format, intval);
  955. break;
  956. case STRING:
  957. fprintf(stdout, "%s\n", buf);
  958. break;
  959. case MAC:
  960. my_ether_ntoa(buf, buf + 6);
  961. fprintf(stdout, "%s\n", buf + 6);
  962. break;
  963. }
  964. }
  965. } else { /* SET */
  966. set = 1;
  967. switch(cmd->param & PARAM_TYPE) {
  968. case INT:
  969. intval = strtoul(arg, &end, 0);
  970. if (end && !(*end)) {
  971. memcpy(buf, &intval, sizeof(intval));
  972. } else {
  973. fprintf(stderr, "%s: Invalid argument\n", cmd->name);
  974. return -1;
  975. }
  976. break;
  977. case STRING:
  978. strncpy(buf, arg, BUFSIZE);
  979. buf[BUFSIZE - 1] = 0;
  980. break;
  981. case MAC:
  982. ptr = ether_aton(arg);
  983. if (!ptr) {
  984. fprintf(stderr, "%s: Invalid mac address '%s'\n", cmd->name, arg);
  985. return -1;
  986. }
  987. break;
  988. }
  989. ret = cmd->handler(cmd->param | SET, (void *) &cmd->data, ptr);
  990. }
  991. if ((debug > 0) && (ret != 0))
  992. fprintf(stderr, "Command '%s %s' failed: %d\n", (set == 1 ? "set" : "get"), cmd->name, ret);
  993. return ret;
  994. }
  995. static struct wlc_call *find_cmd(char *name)
  996. {
  997. int found = 0, i = 0;
  998. while (!found && (i < wlc_calls_size)) {
  999. if (strcmp(name, wlc_calls[i].name) == 0)
  1000. found = 1;
  1001. else
  1002. i++;
  1003. }
  1004. return (struct wlc_call *) (found ? &wlc_calls[i] : NULL);
  1005. }
  1006. int main(int argc, char **argv)
  1007. {
  1008. static char buf[BUFSIZE];
  1009. char *s, *s2;
  1010. char *cmd = argv[0];
  1011. struct wlc_call *call;
  1012. int ret = 0;
  1013. if (argc < 2)
  1014. usage(argv[0]);
  1015. for(interface[2] = '0'; (interface[2] < '3') && (wl_probe(interface) != 0); interface[2]++);
  1016. if (interface[2] == '3') {
  1017. fprintf(stderr, "No Broadcom wl interface found!\n");
  1018. return -1;
  1019. }
  1020. argv++;
  1021. argc--;
  1022. while ((argc > 0) && (argv[0] != NULL)) {
  1023. if ((call = find_cmd(argv[0])) == NULL) {
  1024. fprintf(stderr, "Invalid command: %s\n\n", argv[0]);
  1025. usage(cmd);
  1026. }
  1027. if ((argc > 1) && (!(call->param & NOARG))) {
  1028. ret = do_command(call, argv[1]);
  1029. argv += 2;
  1030. argc -= 2;
  1031. } else {
  1032. ret = do_command(call, NULL);
  1033. argv++;
  1034. argc--;
  1035. }
  1036. }
  1037. while (fromstdin && !feof(stdin)) {
  1038. *buf = 0;
  1039. fgets(buf, BUFSIZE - 1, stdin);
  1040. if (*buf == 0)
  1041. continue;
  1042. if ((s = strchr(buf, '\r')) != NULL)
  1043. *s = 0;
  1044. if ((s = strchr(buf, '\n')) != NULL)
  1045. *s = 0;
  1046. s = buf;
  1047. while (isspace(*s))
  1048. s++;
  1049. if (!*s)
  1050. continue;
  1051. if ((s2 = strchr(s, ' ')) != NULL)
  1052. *(s2++) = 0;
  1053. while (s2 && isspace(*s2))
  1054. s2++;
  1055. if ((call = find_cmd(s)) == NULL) {
  1056. fprintf(stderr, "Invalid command: %s\n", s);
  1057. ret = -1;
  1058. } else
  1059. ret = do_command(call, ((call->param & NOARG) ? NULL : s2));
  1060. }
  1061. return ret;
  1062. }