ioctl.c 27 KB

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