ioctl.c 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. /**
  2. * This file contains ioctl functions
  3. */
  4. #include <linux/ctype.h>
  5. #include <linux/delay.h>
  6. #include <linux/if.h>
  7. #include <linux/if_arp.h>
  8. #include <linux/wireless.h>
  9. #include <net/iw_handler.h>
  10. #include <net/ieee80211.h>
  11. #include "host.h"
  12. #include "radiotap.h"
  13. #include "decl.h"
  14. #include "defs.h"
  15. #include "dev.h"
  16. #include "join.h"
  17. #include "wext.h"
  18. #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \
  19. IW_ESSID_MAX_SIZE + \
  20. IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
  21. IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
  22. IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
  23. #define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
  24. static int wlan_set_region(wlan_private * priv, u16 region_code)
  25. {
  26. int i;
  27. for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
  28. // use the region code to search for the index
  29. if (region_code == libertas_region_code_to_index[i]) {
  30. priv->adapter->regiontableindex = (u16) i;
  31. priv->adapter->regioncode = region_code;
  32. break;
  33. }
  34. }
  35. // if it's unidentified region code
  36. if (i >= MRVDRV_MAX_REGION_CODE) {
  37. lbs_pr_debug(1, "region Code not identified\n");
  38. LEAVE();
  39. return -1;
  40. }
  41. if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
  42. LEAVE();
  43. return -EINVAL;
  44. }
  45. return 0;
  46. }
  47. static inline int hex2int(char c)
  48. {
  49. if (c >= '0' && c <= '9')
  50. return (c - '0');
  51. if (c >= 'a' && c <= 'f')
  52. return (c - 'a' + 10);
  53. if (c >= 'A' && c <= 'F')
  54. return (c - 'A' + 10);
  55. return -1;
  56. }
  57. /* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
  58. into binary format (6 bytes).
  59. This function expects that each byte is represented with 2 characters
  60. (e.g., 11:2:11:11:11:11 is invalid)
  61. */
  62. static char *eth_str2addr(char *ethstr, u8 * addr)
  63. {
  64. int i, val, val2;
  65. char *pos = ethstr;
  66. /* get rid of initial blanks */
  67. while (*pos == ' ' || *pos == '\t')
  68. ++pos;
  69. for (i = 0; i < 6; i++) {
  70. val = hex2int(*pos++);
  71. if (val < 0)
  72. return NULL;
  73. val2 = hex2int(*pos++);
  74. if (val2 < 0)
  75. return NULL;
  76. addr[i] = (val * 16 + val2) & 0xff;
  77. if (i < 5 && *pos++ != ':')
  78. return NULL;
  79. }
  80. return pos;
  81. }
  82. /* this writes xx:xx:xx:xx:xx:xx into ethstr
  83. (ethstr must have space for 18 chars) */
  84. static int eth_addr2str(u8 * addr, char *ethstr)
  85. {
  86. int i;
  87. char *pos = ethstr;
  88. for (i = 0; i < 6; i++) {
  89. sprintf(pos, "%02x", addr[i] & 0xff);
  90. pos += 2;
  91. if (i < 5)
  92. *pos++ = ':';
  93. }
  94. return 17;
  95. }
  96. /**
  97. * @brief Add an entry to the BT table
  98. * @param priv A pointer to wlan_private structure
  99. * @param req A pointer to ifreq structure
  100. * @return 0 --success, otherwise fail
  101. */
  102. static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req)
  103. {
  104. struct iwreq *wrq = (struct iwreq *)req;
  105. char ethaddrs_str[18];
  106. char *pos;
  107. u8 ethaddr[ETH_ALEN];
  108. ENTER();
  109. if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
  110. sizeof(ethaddrs_str)))
  111. return -EFAULT;
  112. if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
  113. lbs_pr_info("BT_ADD: Invalid MAC address\n");
  114. return -EINVAL;
  115. }
  116. lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str);
  117. LEAVE();
  118. return (libertas_prepare_and_send_command(priv, cmd_bt_access,
  119. cmd_act_bt_access_add,
  120. cmd_option_waitforrsp, 0, ethaddr));
  121. }
  122. /**
  123. * @brief Delete an entry from the BT table
  124. * @param priv A pointer to wlan_private structure
  125. * @param req A pointer to ifreq structure
  126. * @return 0 --success, otherwise fail
  127. */
  128. static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req)
  129. {
  130. struct iwreq *wrq = (struct iwreq *)req;
  131. char ethaddrs_str[18];
  132. u8 ethaddr[ETH_ALEN];
  133. char *pos;
  134. ENTER();
  135. if (copy_from_user(ethaddrs_str, wrq->u.data.pointer,
  136. sizeof(ethaddrs_str)))
  137. return -EFAULT;
  138. if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) {
  139. lbs_pr_info("Invalid MAC address\n");
  140. return -EINVAL;
  141. }
  142. lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str);
  143. return (libertas_prepare_and_send_command(priv,
  144. cmd_bt_access,
  145. cmd_act_bt_access_del,
  146. cmd_option_waitforrsp, 0, ethaddr));
  147. LEAVE();
  148. return 0;
  149. }
  150. /**
  151. * @brief Reset all entries from the BT table
  152. * @param priv A pointer to wlan_private structure
  153. * @return 0 --success, otherwise fail
  154. */
  155. static int wlan_bt_reset_ioctl(wlan_private * priv)
  156. {
  157. ENTER();
  158. lbs_pr_alert( "BT: resetting\n");
  159. return (libertas_prepare_and_send_command(priv,
  160. cmd_bt_access,
  161. cmd_act_bt_access_reset,
  162. cmd_option_waitforrsp, 0, NULL));
  163. LEAVE();
  164. return 0;
  165. }
  166. /**
  167. * @brief List an entry from the BT table
  168. * @param priv A pointer to wlan_private structure
  169. * @param req A pointer to ifreq structure
  170. * @return 0 --success, otherwise fail
  171. */
  172. static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req)
  173. {
  174. int pos;
  175. char *addr1;
  176. struct iwreq *wrq = (struct iwreq *)req;
  177. /* used to pass id and store the bt entry returned by the FW */
  178. union {
  179. int id;
  180. char addr1addr2[2 * ETH_ALEN];
  181. } param;
  182. static char outstr[64];
  183. char *pbuf = outstr;
  184. int ret;
  185. ENTER();
  186. if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
  187. lbs_pr_debug(1, "Copy from user failed\n");
  188. return -1;
  189. }
  190. param.id = simple_strtoul(outstr, NULL, 10);
  191. pos = sprintf(pbuf, "%d: ", param.id);
  192. pbuf += pos;
  193. ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
  194. cmd_act_bt_access_list,
  195. cmd_option_waitforrsp, 0,
  196. (char *)&param);
  197. if (ret == 0) {
  198. addr1 = param.addr1addr2;
  199. pos = sprintf(pbuf, "ignoring traffic from ");
  200. pbuf += pos;
  201. pos = eth_addr2str(addr1, pbuf);
  202. pbuf += pos;
  203. } else {
  204. sprintf(pbuf, "(null)");
  205. pbuf += pos;
  206. }
  207. wrq->u.data.length = strlen(outstr);
  208. if (copy_to_user(wrq->u.data.pointer, (char *)outstr,
  209. wrq->u.data.length)) {
  210. lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n");
  211. return -EFAULT;
  212. }
  213. LEAVE();
  214. return 0;
  215. }
  216. /**
  217. * @brief Find the next parameter in an input string
  218. * @param ptr A pointer to the input parameter string
  219. * @return A pointer to the next parameter, or 0 if no parameters left.
  220. */
  221. static char * next_param(char * ptr)
  222. {
  223. if (!ptr) return NULL;
  224. while (*ptr == ' ' || *ptr == '\t') ++ptr;
  225. return (*ptr == '\0') ? NULL : ptr;
  226. }
  227. /**
  228. * @brief Add an entry to the FWT table
  229. * @param priv A pointer to wlan_private structure
  230. * @param req A pointer to ifreq structure
  231. * @return 0 --success, otherwise fail
  232. */
  233. static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
  234. {
  235. struct iwreq *wrq = (struct iwreq *)req;
  236. char in_str[128];
  237. static struct cmd_ds_fwt_access fwt_access;
  238. char *ptr;
  239. ENTER();
  240. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  241. return -EFAULT;
  242. if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
  243. lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
  244. return -EINVAL;
  245. }
  246. if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
  247. lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
  248. return -EINVAL;
  249. }
  250. if ((ptr = next_param(ptr)))
  251. fwt_access.metric =
  252. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  253. else
  254. fwt_access.metric = FWT_DEFAULT_METRIC;
  255. if ((ptr = next_param(ptr)))
  256. fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
  257. else
  258. fwt_access.dir = FWT_DEFAULT_DIR;
  259. if ((ptr = next_param(ptr)))
  260. fwt_access.ssn =
  261. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  262. else
  263. fwt_access.ssn = FWT_DEFAULT_SSN;
  264. if ((ptr = next_param(ptr)))
  265. fwt_access.dsn =
  266. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  267. else
  268. fwt_access.dsn = FWT_DEFAULT_DSN;
  269. if ((ptr = next_param(ptr)))
  270. fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
  271. else
  272. fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
  273. if ((ptr = next_param(ptr)))
  274. fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
  275. else
  276. fwt_access.ttl = FWT_DEFAULT_TTL;
  277. if ((ptr = next_param(ptr)))
  278. fwt_access.expiration =
  279. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  280. else
  281. fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
  282. if ((ptr = next_param(ptr)))
  283. fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
  284. else
  285. fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
  286. if ((ptr = next_param(ptr)))
  287. fwt_access.snr =
  288. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  289. else
  290. fwt_access.snr = FWT_DEFAULT_SNR;
  291. #ifdef DEBUG
  292. {
  293. char ethaddr1_str[18], ethaddr2_str[18];
  294. eth_addr2str(fwt_access.da, ethaddr1_str);
  295. eth_addr2str(fwt_access.ra, ethaddr2_str);
  296. lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
  297. fwt_access.dir, ethaddr2_str);
  298. lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
  299. fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
  300. fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
  301. fwt_access.sleepmode, fwt_access.snr);
  302. }
  303. #endif
  304. LEAVE();
  305. return (libertas_prepare_and_send_command(priv, cmd_fwt_access,
  306. cmd_act_fwt_access_add,
  307. cmd_option_waitforrsp, 0,
  308. (void *)&fwt_access));
  309. }
  310. /**
  311. * @brief Delete an entry from the FWT table
  312. * @param priv A pointer to wlan_private structure
  313. * @param req A pointer to ifreq structure
  314. * @return 0 --success, otherwise fail
  315. */
  316. static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
  317. {
  318. struct iwreq *wrq = (struct iwreq *)req;
  319. char in_str[64];
  320. static struct cmd_ds_fwt_access fwt_access;
  321. char *ptr;
  322. ENTER();
  323. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  324. return -EFAULT;
  325. if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
  326. lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
  327. return -EINVAL;
  328. }
  329. if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
  330. lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
  331. return -EINVAL;
  332. }
  333. if ((ptr = next_param(ptr)))
  334. fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
  335. else
  336. fwt_access.dir = FWT_DEFAULT_DIR;
  337. #ifdef DEBUG
  338. {
  339. char ethaddr1_str[18], ethaddr2_str[18];
  340. lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str);
  341. eth_addr2str(fwt_access.da, ethaddr1_str);
  342. eth_addr2str(fwt_access.ra, ethaddr2_str);
  343. lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
  344. ethaddr2_str, fwt_access.dir);
  345. }
  346. #endif
  347. LEAVE();
  348. return (libertas_prepare_and_send_command(priv,
  349. cmd_fwt_access,
  350. cmd_act_fwt_access_del,
  351. cmd_option_waitforrsp, 0,
  352. (void *)&fwt_access));
  353. }
  354. /**
  355. * @brief Print route parameters
  356. * @param fwt_access struct cmd_ds_fwt_access with route info
  357. * @param buf destination buffer for route info
  358. */
  359. static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
  360. {
  361. buf += sprintf(buf, " ");
  362. buf += eth_addr2str(fwt_access.da, buf);
  363. buf += sprintf(buf, " ");
  364. buf += eth_addr2str(fwt_access.ra, buf);
  365. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
  366. buf += sprintf(buf, " %u", fwt_access.dir);
  367. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
  368. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
  369. buf += sprintf(buf, " %u", fwt_access.hopcount);
  370. buf += sprintf(buf, " %u", fwt_access.ttl);
  371. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
  372. buf += sprintf(buf, " %u", fwt_access.sleepmode);
  373. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr));
  374. }
  375. /**
  376. * @brief Lookup an entry in the FWT table
  377. * @param priv A pointer to wlan_private structure
  378. * @param req A pointer to ifreq structure
  379. * @return 0 --success, otherwise fail
  380. */
  381. static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
  382. {
  383. struct iwreq *wrq = (struct iwreq *)req;
  384. char in_str[64];
  385. char *ptr;
  386. static struct cmd_ds_fwt_access fwt_access;
  387. static char out_str[128];
  388. int ret;
  389. ENTER();
  390. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  391. return -EFAULT;
  392. if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
  393. lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
  394. return -EINVAL;
  395. }
  396. #ifdef DEBUG
  397. {
  398. char ethaddr1_str[18];
  399. lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str);
  400. eth_addr2str(fwt_access.da, ethaddr1_str);
  401. lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
  402. }
  403. #endif
  404. ret = libertas_prepare_and_send_command(priv,
  405. cmd_fwt_access,
  406. cmd_act_fwt_access_lookup,
  407. cmd_option_waitforrsp, 0,
  408. (void *)&fwt_access);
  409. if (ret == 0)
  410. print_route(fwt_access, out_str);
  411. else
  412. sprintf(out_str, "(null)");
  413. wrq->u.data.length = strlen(out_str);
  414. if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
  415. wrq->u.data.length)) {
  416. lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n");
  417. return -EFAULT;
  418. }
  419. LEAVE();
  420. return 0;
  421. }
  422. /**
  423. * @brief Reset all entries from the FWT table
  424. * @param priv A pointer to wlan_private structure
  425. * @return 0 --success, otherwise fail
  426. */
  427. static int wlan_fwt_reset_ioctl(wlan_private * priv)
  428. {
  429. lbs_pr_debug(1, "FWT: resetting\n");
  430. return (libertas_prepare_and_send_command(priv,
  431. cmd_fwt_access,
  432. cmd_act_fwt_access_reset,
  433. cmd_option_waitforrsp, 0, NULL));
  434. }
  435. /**
  436. * @brief List an entry from the FWT table
  437. * @param priv A pointer to wlan_private structure
  438. * @param req A pointer to ifreq structure
  439. * @return 0 --success, otherwise fail
  440. */
  441. static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
  442. {
  443. struct iwreq *wrq = (struct iwreq *)req;
  444. char in_str[8];
  445. static struct cmd_ds_fwt_access fwt_access;
  446. char *ptr = in_str;
  447. static char out_str[128];
  448. char *pbuf = out_str;
  449. int ret;
  450. ENTER();
  451. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  452. return -EFAULT;
  453. fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  454. #ifdef DEBUG
  455. {
  456. lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str);
  457. lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
  458. }
  459. #endif
  460. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  461. cmd_act_fwt_access_list,
  462. cmd_option_waitforrsp, 0, (void *)&fwt_access);
  463. if (ret == 0)
  464. print_route(fwt_access, pbuf);
  465. else
  466. pbuf += sprintf(pbuf, " (null)");
  467. wrq->u.data.length = strlen(out_str);
  468. if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
  469. wrq->u.data.length)) {
  470. lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n");
  471. return -EFAULT;
  472. }
  473. LEAVE();
  474. return 0;
  475. }
  476. /**
  477. * @brief List an entry from the FRT table
  478. * @param priv A pointer to wlan_private structure
  479. * @param req A pointer to ifreq structure
  480. * @return 0 --success, otherwise fail
  481. */
  482. static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
  483. {
  484. struct iwreq *wrq = (struct iwreq *)req;
  485. char in_str[64];
  486. static struct cmd_ds_fwt_access fwt_access;
  487. char *ptr = in_str;
  488. static char out_str[128];
  489. char *pbuf = out_str;
  490. int ret;
  491. ENTER();
  492. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  493. return -EFAULT;
  494. fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  495. #ifdef DEBUG
  496. {
  497. lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str);
  498. lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
  499. }
  500. #endif
  501. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  502. cmd_act_fwt_access_list_route,
  503. cmd_option_waitforrsp, 0, (void *)&fwt_access);
  504. if (ret == 0) {
  505. pbuf += sprintf(pbuf, " ");
  506. pbuf += eth_addr2str(fwt_access.da, pbuf);
  507. pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
  508. pbuf += sprintf(pbuf, " %u", fwt_access.dir);
  509. /* note that the firmware returns the nid in the id field */
  510. pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
  511. pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
  512. pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
  513. pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount);
  514. pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl);
  515. pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
  516. } else
  517. pbuf += sprintf(pbuf, " (null)");
  518. wrq->u.data.length = strlen(out_str);
  519. if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
  520. wrq->u.data.length)) {
  521. lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n");
  522. return -EFAULT;
  523. }
  524. LEAVE();
  525. return 0;
  526. }
  527. /**
  528. * @brief List an entry from the FNT table
  529. * @param priv A pointer to wlan_private structure
  530. * @param req A pointer to ifreq structure
  531. * @return 0 --success, otherwise fail
  532. */
  533. static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
  534. {
  535. struct iwreq *wrq = (struct iwreq *)req;
  536. char in_str[8];
  537. static struct cmd_ds_fwt_access fwt_access;
  538. char *ptr = in_str;
  539. static char out_str[128];
  540. char *pbuf = out_str;
  541. int ret;
  542. ENTER();
  543. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  544. return -EFAULT;
  545. memset(&fwt_access, 0, sizeof(fwt_access));
  546. fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  547. #ifdef DEBUG
  548. {
  549. lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str);
  550. lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
  551. }
  552. #endif
  553. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  554. cmd_act_fwt_access_list_neighbor,
  555. cmd_option_waitforrsp, 0,
  556. (void *)&fwt_access);
  557. if (ret == 0) {
  558. pbuf += sprintf(pbuf, " ra ");
  559. pbuf += eth_addr2str(fwt_access.ra, pbuf);
  560. pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode);
  561. pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr));
  562. pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references));
  563. } else
  564. pbuf += sprintf(pbuf, " (null)");
  565. wrq->u.data.length = strlen(out_str);
  566. if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
  567. wrq->u.data.length)) {
  568. lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n");
  569. return -EFAULT;
  570. }
  571. LEAVE();
  572. return 0;
  573. }
  574. /**
  575. * @brief Cleans up the route (FRT) and neighbor (FNT) tables
  576. * (Garbage Collection)
  577. * @param priv A pointer to wlan_private structure
  578. * @param req A pointer to ifreq structure
  579. * @return 0 --success, otherwise fail
  580. */
  581. static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
  582. {
  583. struct iwreq *wrq = (struct iwreq *)req;
  584. static struct cmd_ds_fwt_access fwt_access;
  585. int ret;
  586. ENTER();
  587. lbs_pr_debug(1, "FWT: cleaning up\n");
  588. memset(&fwt_access, 0, sizeof(fwt_access));
  589. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  590. cmd_act_fwt_access_cleanup,
  591. cmd_option_waitforrsp, 0,
  592. (void *)&fwt_access);
  593. if (ret == 0)
  594. wrq->u.param.value = le32_to_cpu(fwt_access.references);
  595. else
  596. return -EFAULT;
  597. LEAVE();
  598. return 0;
  599. }
  600. /**
  601. * @brief Gets firmware internal time (debug purposes)
  602. * @param priv A pointer to wlan_private structure
  603. * @param req A pointer to ifreq structure
  604. * @return 0 --success, otherwise fail
  605. */
  606. static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
  607. {
  608. struct iwreq *wrq = (struct iwreq *)req;
  609. static struct cmd_ds_fwt_access fwt_access;
  610. int ret;
  611. ENTER();
  612. lbs_pr_debug(1, "FWT: getting time\n");
  613. memset(&fwt_access, 0, sizeof(fwt_access));
  614. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  615. cmd_act_fwt_access_time,
  616. cmd_option_waitforrsp, 0,
  617. (void *)&fwt_access);
  618. if (ret == 0)
  619. wrq->u.param.value = le32_to_cpu(fwt_access.references);
  620. else
  621. return -EFAULT;
  622. LEAVE();
  623. return 0;
  624. }
  625. /**
  626. * @brief Gets mesh ttl from firmware
  627. * @param priv A pointer to wlan_private structure
  628. * @param req A pointer to ifreq structure
  629. * @return 0 --success, otherwise fail
  630. */
  631. static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
  632. {
  633. struct iwreq *wrq = (struct iwreq *)req;
  634. struct cmd_ds_mesh_access mesh_access;
  635. int ret;
  636. ENTER();
  637. memset(&mesh_access, 0, sizeof(mesh_access));
  638. ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
  639. cmd_act_mesh_get_ttl,
  640. cmd_option_waitforrsp, 0,
  641. (void *)&mesh_access);
  642. if (ret == 0)
  643. wrq->u.param.value = le32_to_cpu(mesh_access.data[0]);
  644. else
  645. return -EFAULT;
  646. LEAVE();
  647. return 0;
  648. }
  649. /**
  650. * @brief Gets mesh ttl from firmware
  651. * @param priv A pointer to wlan_private structure
  652. * @param ttl New ttl value
  653. * @return 0 --success, otherwise fail
  654. */
  655. static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
  656. {
  657. struct cmd_ds_mesh_access mesh_access;
  658. int ret;
  659. ENTER();
  660. if( (ttl > 0xff) || (ttl < 0) )
  661. return -EINVAL;
  662. memset(&mesh_access, 0, sizeof(mesh_access));
  663. mesh_access.data[0] = ttl;
  664. ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
  665. cmd_act_mesh_set_ttl,
  666. cmd_option_waitforrsp, 0,
  667. (void *)&mesh_access);
  668. if (ret != 0)
  669. ret = -EFAULT;
  670. LEAVE();
  671. return ret;
  672. }
  673. /**
  674. * @brief ioctl function - entry point
  675. *
  676. * @param dev A pointer to net_device structure
  677. * @param req A pointer to ifreq structure
  678. * @param cmd command
  679. * @return 0--success, otherwise fail
  680. */
  681. int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
  682. {
  683. int subcmd = 0;
  684. int idata = 0;
  685. int *pdata;
  686. int ret = 0;
  687. wlan_private *priv = dev->priv;
  688. wlan_adapter *adapter = priv->adapter;
  689. struct iwreq *wrq = (struct iwreq *)req;
  690. ENTER();
  691. lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
  692. switch (cmd) {
  693. case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
  694. switch (wrq->u.data.flags) {
  695. case WLAN_SUBCMD_BT_RESET: /* bt_reset */
  696. wlan_bt_reset_ioctl(priv);
  697. break;
  698. case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */
  699. wlan_fwt_reset_ioctl(priv);
  700. break;
  701. } /* End of switch */
  702. break;
  703. case WLAN_SETONEINT_GETNONE:
  704. /* The first 4 bytes of req->ifr_data is sub-ioctl number
  705. * after 4 bytes sits the payload.
  706. */
  707. subcmd = wrq->u.data.flags;
  708. if (!subcmd)
  709. subcmd = (int)wrq->u.param.value;
  710. switch (subcmd) {
  711. case WLANSETREGION:
  712. idata = SUBCMD_DATA(wrq);
  713. ret = wlan_set_region(priv, (u16) idata);
  714. break;
  715. case WLAN_SUBCMD_MESH_SET_TTL:
  716. idata = SUBCMD_DATA(wrq);
  717. ret = wlan_mesh_set_ttl_ioctl(priv, idata);
  718. break;
  719. default:
  720. ret = -EOPNOTSUPP;
  721. break;
  722. }
  723. break;
  724. case WLAN_SET128CHAR_GET128CHAR:
  725. switch ((int)wrq->u.data.flags) {
  726. case WLAN_SUBCMD_BT_ADD:
  727. ret = wlan_bt_add_ioctl(priv, req);
  728. break;
  729. case WLAN_SUBCMD_BT_DEL:
  730. ret = wlan_bt_del_ioctl(priv, req);
  731. break;
  732. case WLAN_SUBCMD_BT_LIST:
  733. ret = wlan_bt_list_ioctl(priv, req);
  734. break;
  735. case WLAN_SUBCMD_FWT_ADD:
  736. ret = wlan_fwt_add_ioctl(priv, req);
  737. break;
  738. case WLAN_SUBCMD_FWT_DEL:
  739. ret = wlan_fwt_del_ioctl(priv, req);
  740. break;
  741. case WLAN_SUBCMD_FWT_LOOKUP:
  742. ret = wlan_fwt_lookup_ioctl(priv, req);
  743. break;
  744. case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
  745. ret = wlan_fwt_list_neighbor_ioctl(priv, req);
  746. break;
  747. case WLAN_SUBCMD_FWT_LIST:
  748. ret = wlan_fwt_list_ioctl(priv, req);
  749. break;
  750. case WLAN_SUBCMD_FWT_LIST_ROUTE:
  751. ret = wlan_fwt_list_route_ioctl(priv, req);
  752. break;
  753. }
  754. break;
  755. case WLAN_SETNONE_GETONEINT:
  756. switch (wrq->u.param.value) {
  757. case WLANGETREGION:
  758. pdata = (int *)wrq->u.name;
  759. *pdata = (int)adapter->regioncode;
  760. break;
  761. case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */
  762. ret = wlan_fwt_cleanup_ioctl(priv, req);
  763. break;
  764. case WLAN_SUBCMD_FWT_TIME: /* fwt_time */
  765. ret = wlan_fwt_time_ioctl(priv, req);
  766. break;
  767. case WLAN_SUBCMD_MESH_GET_TTL:
  768. ret = wlan_mesh_get_ttl_ioctl(priv, req);
  769. break;
  770. default:
  771. ret = -EOPNOTSUPP;
  772. }
  773. break;
  774. case WLAN_SET_GET_SIXTEEN_INT:
  775. switch ((int)wrq->u.data.flags) {
  776. case WLAN_LED_GPIO_CTRL:
  777. {
  778. int i;
  779. int data[16];
  780. struct cmd_ds_802_11_led_ctrl ctrl;
  781. struct mrvlietypes_ledgpio *gpio =
  782. (struct mrvlietypes_ledgpio *) ctrl.data;
  783. memset(&ctrl, 0, sizeof(ctrl));
  784. if (wrq->u.data.length > MAX_LEDS * 2)
  785. return -ENOTSUPP;
  786. if ((wrq->u.data.length % 2) != 0)
  787. return -ENOTSUPP;
  788. if (wrq->u.data.length == 0) {
  789. ctrl.action =
  790. cpu_to_le16
  791. (cmd_act_get);
  792. } else {
  793. if (copy_from_user
  794. (data, wrq->u.data.pointer,
  795. sizeof(int) *
  796. wrq->u.data.length)) {
  797. lbs_pr_debug(1,
  798. "Copy from user failed\n");
  799. return -EFAULT;
  800. }
  801. ctrl.action =
  802. cpu_to_le16
  803. (cmd_act_set);
  804. ctrl.numled = cpu_to_le16(0);
  805. gpio->header.type =
  806. cpu_to_le16(TLV_TYPE_LED_GPIO);
  807. gpio->header.len = wrq->u.data.length;
  808. for (i = 0; i < wrq->u.data.length;
  809. i += 2) {
  810. gpio->ledpin[i / 2].led =
  811. data[i];
  812. gpio->ledpin[i / 2].pin =
  813. data[i + 1];
  814. }
  815. }
  816. ret =
  817. libertas_prepare_and_send_command(priv,
  818. cmd_802_11_led_gpio_ctrl,
  819. 0,
  820. cmd_option_waitforrsp,
  821. 0, (void *)&ctrl);
  822. for (i = 0; i < gpio->header.len; i += 2) {
  823. data[i] = gpio->ledpin[i / 2].led;
  824. data[i + 1] = gpio->ledpin[i / 2].pin;
  825. }
  826. if (copy_to_user(wrq->u.data.pointer, data,
  827. sizeof(int) *
  828. gpio->header.len)) {
  829. lbs_pr_debug(1, "Copy to user failed\n");
  830. return -EFAULT;
  831. }
  832. wrq->u.data.length = gpio->header.len;
  833. }
  834. break;
  835. }
  836. break;
  837. default:
  838. ret = -EINVAL;
  839. break;
  840. }
  841. LEAVE();
  842. return ret;
  843. }