ioctl.c 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  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. u32 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. u32 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. struct iwreq *wrq = (struct iwreq *)req;
  254. int ret;
  255. union {
  256. u32 id;
  257. char addr1addr2[2 * ETH_ALEN];
  258. } param;
  259. lbs_deb_enter(LBS_DEB_IOCTL);
  260. ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
  261. cmd_act_bt_access_get_invert,
  262. cmd_option_waitforrsp, 0,
  263. (char *)&param);
  264. if (ret == 0)
  265. wrq->u.param.value = le32_to_cpu(param.id);
  266. else
  267. return -EFAULT;
  268. lbs_deb_leave(LBS_DEB_IOCTL);
  269. return 0;
  270. }
  271. /**
  272. * @brief Find the next parameter in an input string
  273. * @param ptr A pointer to the input parameter string
  274. * @return A pointer to the next parameter, or 0 if no parameters left.
  275. */
  276. static char * next_param(char * ptr)
  277. {
  278. if (!ptr) return NULL;
  279. while (*ptr == ' ' || *ptr == '\t') ++ptr;
  280. return (*ptr == '\0') ? NULL : ptr;
  281. }
  282. /**
  283. * @brief Add an entry to the FWT table
  284. * @param priv A pointer to wlan_private structure
  285. * @param req A pointer to ifreq structure
  286. * @return 0 --success, otherwise fail
  287. */
  288. static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
  289. {
  290. struct iwreq *wrq = (struct iwreq *)req;
  291. char in_str[128];
  292. static struct cmd_ds_fwt_access fwt_access;
  293. char *ptr;
  294. int ret;
  295. lbs_deb_enter(LBS_DEB_IOCTL);
  296. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  297. return -EFAULT;
  298. if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
  299. lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
  300. return -EINVAL;
  301. }
  302. if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
  303. lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
  304. return -EINVAL;
  305. }
  306. if ((ptr = next_param(ptr)))
  307. fwt_access.metric =
  308. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  309. else
  310. fwt_access.metric = cpu_to_le32(FWT_DEFAULT_METRIC);
  311. if ((ptr = next_param(ptr)))
  312. fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
  313. else
  314. fwt_access.dir = FWT_DEFAULT_DIR;
  315. if ((ptr = next_param(ptr)))
  316. fwt_access.rate = (u8) simple_strtoul(ptr, &ptr, 10);
  317. else
  318. fwt_access.rate = FWT_DEFAULT_RATE;
  319. if ((ptr = next_param(ptr)))
  320. fwt_access.ssn =
  321. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  322. else
  323. fwt_access.ssn = cpu_to_le32(FWT_DEFAULT_SSN);
  324. if ((ptr = next_param(ptr)))
  325. fwt_access.dsn =
  326. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  327. else
  328. fwt_access.dsn = cpu_to_le32(FWT_DEFAULT_DSN);
  329. if ((ptr = next_param(ptr)))
  330. fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
  331. else
  332. fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
  333. if ((ptr = next_param(ptr)))
  334. fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
  335. else
  336. fwt_access.ttl = FWT_DEFAULT_TTL;
  337. if ((ptr = next_param(ptr)))
  338. fwt_access.expiration =
  339. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  340. else
  341. fwt_access.expiration = cpu_to_le32(FWT_DEFAULT_EXPIRATION);
  342. if ((ptr = next_param(ptr)))
  343. fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
  344. else
  345. fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
  346. if ((ptr = next_param(ptr)))
  347. fwt_access.snr =
  348. cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  349. else
  350. fwt_access.snr = cpu_to_le32(FWT_DEFAULT_SNR);
  351. #ifdef DEBUG
  352. {
  353. char ethaddr1_str[18], ethaddr2_str[18];
  354. eth_addr2str(fwt_access.da, ethaddr1_str);
  355. eth_addr2str(fwt_access.ra, ethaddr2_str);
  356. lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
  357. fwt_access.dir, ethaddr2_str);
  358. lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
  359. fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
  360. fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
  361. fwt_access.sleepmode, fwt_access.snr);
  362. }
  363. #endif
  364. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  365. cmd_act_fwt_access_add,
  366. cmd_option_waitforrsp, 0,
  367. (void *)&fwt_access);
  368. lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
  369. return ret;
  370. }
  371. /**
  372. * @brief Delete an entry from the FWT table
  373. * @param priv A pointer to wlan_private structure
  374. * @param req A pointer to ifreq structure
  375. * @return 0 --success, otherwise fail
  376. */
  377. static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
  378. {
  379. struct iwreq *wrq = (struct iwreq *)req;
  380. char in_str[64];
  381. static struct cmd_ds_fwt_access fwt_access;
  382. char *ptr;
  383. int ret;
  384. lbs_deb_enter(LBS_DEB_IOCTL);
  385. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  386. return -EFAULT;
  387. if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
  388. lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
  389. return -EINVAL;
  390. }
  391. if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
  392. lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
  393. return -EINVAL;
  394. }
  395. if ((ptr = next_param(ptr)))
  396. fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
  397. else
  398. fwt_access.dir = FWT_DEFAULT_DIR;
  399. #ifdef DEBUG
  400. {
  401. char ethaddr1_str[18], ethaddr2_str[18];
  402. lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str);
  403. eth_addr2str(fwt_access.da, ethaddr1_str);
  404. eth_addr2str(fwt_access.ra, ethaddr2_str);
  405. lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
  406. ethaddr2_str, fwt_access.dir);
  407. }
  408. #endif
  409. ret = libertas_prepare_and_send_command(priv,
  410. cmd_fwt_access,
  411. cmd_act_fwt_access_del,
  412. cmd_option_waitforrsp, 0,
  413. (void *)&fwt_access);
  414. lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
  415. return ret;
  416. }
  417. /**
  418. * @brief Print route parameters
  419. * @param fwt_access struct cmd_ds_fwt_access with route info
  420. * @param buf destination buffer for route info
  421. */
  422. static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
  423. {
  424. buf += sprintf(buf, " ");
  425. buf += eth_addr2str(fwt_access.da, buf);
  426. buf += sprintf(buf, " ");
  427. buf += eth_addr2str(fwt_access.ra, buf);
  428. buf += sprintf(buf, " %u", fwt_access.valid);
  429. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
  430. buf += sprintf(buf, " %u", fwt_access.dir);
  431. buf += sprintf(buf, " %u", fwt_access.rate);
  432. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
  433. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
  434. buf += sprintf(buf, " %u", fwt_access.hopcount);
  435. buf += sprintf(buf, " %u", fwt_access.ttl);
  436. buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
  437. buf += sprintf(buf, " %u", fwt_access.sleepmode);
  438. buf += sprintf(buf, " %u ", le32_to_cpu(fwt_access.snr));
  439. buf += eth_addr2str(fwt_access.prec, buf);
  440. }
  441. /**
  442. * @brief Lookup an entry in the FWT table
  443. * @param priv A pointer to wlan_private structure
  444. * @param req A pointer to ifreq structure
  445. * @return 0 --success, otherwise fail
  446. */
  447. static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
  448. {
  449. struct iwreq *wrq = (struct iwreq *)req;
  450. char in_str[64];
  451. char *ptr;
  452. static struct cmd_ds_fwt_access fwt_access;
  453. static char out_str[128];
  454. int ret;
  455. lbs_deb_enter(LBS_DEB_IOCTL);
  456. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  457. return -EFAULT;
  458. if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
  459. lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
  460. return -EINVAL;
  461. }
  462. #ifdef DEBUG
  463. {
  464. char ethaddr1_str[18];
  465. lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str);
  466. eth_addr2str(fwt_access.da, ethaddr1_str);
  467. lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
  468. }
  469. #endif
  470. ret = libertas_prepare_and_send_command(priv,
  471. cmd_fwt_access,
  472. cmd_act_fwt_access_lookup,
  473. cmd_option_waitforrsp, 0,
  474. (void *)&fwt_access);
  475. if (ret == 0)
  476. print_route(fwt_access, out_str);
  477. else
  478. sprintf(out_str, "(null)");
  479. wrq->u.data.length = strlen(out_str);
  480. if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
  481. wrq->u.data.length)) {
  482. lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n");
  483. return -EFAULT;
  484. }
  485. lbs_deb_leave(LBS_DEB_IOCTL);
  486. return 0;
  487. }
  488. /**
  489. * @brief Reset all entries from the FWT table
  490. * @param priv A pointer to wlan_private structure
  491. * @return 0 --success, otherwise fail
  492. */
  493. static int wlan_fwt_reset_ioctl(wlan_private * priv)
  494. {
  495. lbs_deb_ioctl("FWT: resetting\n");
  496. return (libertas_prepare_and_send_command(priv,
  497. cmd_fwt_access,
  498. cmd_act_fwt_access_reset,
  499. cmd_option_waitforrsp, 0, NULL));
  500. }
  501. /**
  502. * @brief List an entry from the FWT table
  503. * @param priv A pointer to wlan_private structure
  504. * @param req A pointer to ifreq structure
  505. * @return 0 --success, otherwise fail
  506. */
  507. static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
  508. {
  509. struct iwreq *wrq = (struct iwreq *)req;
  510. char in_str[8];
  511. static struct cmd_ds_fwt_access fwt_access;
  512. char *ptr = in_str;
  513. static char out_str[128];
  514. char *pbuf = out_str;
  515. int ret = 0;
  516. lbs_deb_enter(LBS_DEB_IOCTL);
  517. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) {
  518. ret = -EFAULT;
  519. goto out;
  520. }
  521. fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  522. #ifdef DEBUG
  523. {
  524. lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str);
  525. lbs_deb_ioctl("FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
  526. }
  527. #endif
  528. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  529. cmd_act_fwt_access_list,
  530. cmd_option_waitforrsp, 0, (void *)&fwt_access);
  531. if (ret == 0)
  532. print_route(fwt_access, pbuf);
  533. else
  534. pbuf += sprintf(pbuf, " (null)");
  535. wrq->u.data.length = strlen(out_str);
  536. if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
  537. wrq->u.data.length)) {
  538. lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n");
  539. ret = -EFAULT;
  540. goto out;
  541. }
  542. ret = 0;
  543. out:
  544. lbs_deb_leave(LBS_DEB_IOCTL);
  545. return ret;
  546. }
  547. /**
  548. * @brief List an entry from the FRT table
  549. * @param priv A pointer to wlan_private structure
  550. * @param req A pointer to ifreq structure
  551. * @return 0 --success, otherwise fail
  552. */
  553. static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
  554. {
  555. struct iwreq *wrq = (struct iwreq *)req;
  556. char in_str[64];
  557. static struct cmd_ds_fwt_access fwt_access;
  558. char *ptr = in_str;
  559. static char out_str[128];
  560. char *pbuf = out_str;
  561. int ret;
  562. lbs_deb_enter(LBS_DEB_IOCTL);
  563. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  564. return -EFAULT;
  565. fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  566. #ifdef DEBUG
  567. {
  568. lbs_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str);
  569. lbs_deb_ioctl("FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
  570. }
  571. #endif
  572. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  573. cmd_act_fwt_access_list_route,
  574. cmd_option_waitforrsp, 0, (void *)&fwt_access);
  575. if (ret == 0) {
  576. print_route(fwt_access, pbuf);
  577. } else
  578. pbuf += sprintf(pbuf, " (null)");
  579. wrq->u.data.length = strlen(out_str);
  580. if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
  581. wrq->u.data.length)) {
  582. lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n");
  583. return -EFAULT;
  584. }
  585. lbs_deb_leave(LBS_DEB_IOCTL);
  586. return 0;
  587. }
  588. /**
  589. * @brief List an entry from the FNT table
  590. * @param priv A pointer to wlan_private structure
  591. * @param req A pointer to ifreq structure
  592. * @return 0 --success, otherwise fail
  593. */
  594. static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
  595. {
  596. struct iwreq *wrq = (struct iwreq *)req;
  597. char in_str[8];
  598. static struct cmd_ds_fwt_access fwt_access;
  599. char *ptr = in_str;
  600. static char out_str[128];
  601. char *pbuf = out_str;
  602. int ret;
  603. lbs_deb_enter(LBS_DEB_IOCTL);
  604. if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
  605. return -EFAULT;
  606. memset(&fwt_access, 0, sizeof(fwt_access));
  607. fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
  608. #ifdef DEBUG
  609. {
  610. lbs_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str);
  611. lbs_deb_ioctl("FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
  612. }
  613. #endif
  614. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  615. cmd_act_fwt_access_list_neighbor,
  616. cmd_option_waitforrsp, 0,
  617. (void *)&fwt_access);
  618. if (ret == 0) {
  619. pbuf += sprintf(pbuf, " ra ");
  620. pbuf += eth_addr2str(fwt_access.ra, pbuf);
  621. pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode);
  622. pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr));
  623. pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references));
  624. } else
  625. pbuf += sprintf(pbuf, " (null)");
  626. wrq->u.data.length = strlen(out_str);
  627. if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
  628. wrq->u.data.length)) {
  629. lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n");
  630. return -EFAULT;
  631. }
  632. lbs_deb_leave(LBS_DEB_IOCTL);
  633. return 0;
  634. }
  635. /**
  636. * @brief Cleans up the route (FRT) and neighbor (FNT) tables
  637. * (Garbage Collection)
  638. * @param priv A pointer to wlan_private structure
  639. * @param req A pointer to ifreq structure
  640. * @return 0 --success, otherwise fail
  641. */
  642. static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
  643. {
  644. struct iwreq *wrq = (struct iwreq *)req;
  645. static struct cmd_ds_fwt_access fwt_access;
  646. int ret;
  647. lbs_deb_enter(LBS_DEB_IOCTL);
  648. lbs_deb_ioctl("FWT: cleaning up\n");
  649. memset(&fwt_access, 0, sizeof(fwt_access));
  650. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  651. cmd_act_fwt_access_cleanup,
  652. cmd_option_waitforrsp, 0,
  653. (void *)&fwt_access);
  654. if (ret == 0)
  655. wrq->u.param.value = le32_to_cpu(fwt_access.references);
  656. else
  657. return -EFAULT;
  658. lbs_deb_leave(LBS_DEB_IOCTL);
  659. return 0;
  660. }
  661. /**
  662. * @brief Gets firmware internal time (debug purposes)
  663. * @param priv A pointer to wlan_private structure
  664. * @param req A pointer to ifreq structure
  665. * @return 0 --success, otherwise fail
  666. */
  667. static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
  668. {
  669. struct iwreq *wrq = (struct iwreq *)req;
  670. static struct cmd_ds_fwt_access fwt_access;
  671. int ret;
  672. lbs_deb_enter(LBS_DEB_IOCTL);
  673. lbs_deb_ioctl("FWT: getting time\n");
  674. memset(&fwt_access, 0, sizeof(fwt_access));
  675. ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
  676. cmd_act_fwt_access_time,
  677. cmd_option_waitforrsp, 0,
  678. (void *)&fwt_access);
  679. if (ret == 0)
  680. wrq->u.param.value = le32_to_cpu(fwt_access.references);
  681. else
  682. return -EFAULT;
  683. lbs_deb_leave(LBS_DEB_IOCTL);
  684. return 0;
  685. }
  686. /**
  687. * @brief Gets mesh ttl from firmware
  688. * @param priv A pointer to wlan_private structure
  689. * @param req A pointer to ifreq structure
  690. * @return 0 --success, otherwise fail
  691. */
  692. static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
  693. {
  694. struct iwreq *wrq = (struct iwreq *)req;
  695. struct cmd_ds_mesh_access mesh_access;
  696. int ret;
  697. lbs_deb_enter(LBS_DEB_IOCTL);
  698. memset(&mesh_access, 0, sizeof(mesh_access));
  699. ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
  700. cmd_act_mesh_get_ttl,
  701. cmd_option_waitforrsp, 0,
  702. (void *)&mesh_access);
  703. if (ret == 0)
  704. wrq->u.param.value = le32_to_cpu(mesh_access.data[0]);
  705. else
  706. return -EFAULT;
  707. lbs_deb_leave(LBS_DEB_IOCTL);
  708. return 0;
  709. }
  710. /**
  711. * @brief Gets mesh ttl from firmware
  712. * @param priv A pointer to wlan_private structure
  713. * @param ttl New ttl value
  714. * @return 0 --success, otherwise fail
  715. */
  716. static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
  717. {
  718. struct cmd_ds_mesh_access mesh_access;
  719. int ret;
  720. lbs_deb_enter(LBS_DEB_IOCTL);
  721. if( (ttl > 0xff) || (ttl < 0) )
  722. return -EINVAL;
  723. memset(&mesh_access, 0, sizeof(mesh_access));
  724. mesh_access.data[0] = cpu_to_le32(ttl);
  725. ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
  726. cmd_act_mesh_set_ttl,
  727. cmd_option_waitforrsp, 0,
  728. (void *)&mesh_access);
  729. if (ret != 0)
  730. ret = -EFAULT;
  731. lbs_deb_leave(LBS_DEB_IOCTL);
  732. return ret;
  733. }
  734. /**
  735. * @brief ioctl function - entry point
  736. *
  737. * @param dev A pointer to net_device structure
  738. * @param req A pointer to ifreq structure
  739. * @param cmd command
  740. * @return 0--success, otherwise fail
  741. */
  742. int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
  743. {
  744. int subcmd = 0;
  745. int idata = 0;
  746. int *pdata;
  747. int ret = 0;
  748. wlan_private *priv = dev->priv;
  749. wlan_adapter *adapter = priv->adapter;
  750. struct iwreq *wrq = (struct iwreq *)req;
  751. lbs_deb_enter(LBS_DEB_IOCTL);
  752. lbs_deb_ioctl("libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
  753. switch (cmd) {
  754. case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
  755. switch (wrq->u.data.flags) {
  756. case WLAN_SUBCMD_BT_RESET: /* bt_reset */
  757. wlan_bt_reset_ioctl(priv);
  758. break;
  759. case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */
  760. wlan_fwt_reset_ioctl(priv);
  761. break;
  762. } /* End of switch */
  763. break;
  764. case WLAN_SETONEINT_GETNONE:
  765. /* The first 4 bytes of req->ifr_data is sub-ioctl number
  766. * after 4 bytes sits the payload.
  767. */
  768. subcmd = wrq->u.data.flags;
  769. if (!subcmd)
  770. subcmd = (int)wrq->u.param.value;
  771. switch (subcmd) {
  772. case WLANSETREGION:
  773. idata = SUBCMD_DATA(wrq);
  774. ret = wlan_set_region(priv, (u16) idata);
  775. break;
  776. case WLAN_SUBCMD_MESH_SET_TTL:
  777. idata = SUBCMD_DATA(wrq);
  778. ret = wlan_mesh_set_ttl_ioctl(priv, idata);
  779. break;
  780. case WLAN_SUBCMD_BT_SET_INVERT:
  781. ret = wlan_bt_set_invert_ioctl(priv, req);
  782. break ;
  783. default:
  784. ret = -EOPNOTSUPP;
  785. break;
  786. }
  787. break;
  788. case WLAN_SET128CHAR_GET128CHAR:
  789. switch ((int)wrq->u.data.flags) {
  790. case WLAN_SUBCMD_BT_ADD:
  791. ret = wlan_bt_add_ioctl(priv, req);
  792. break;
  793. case WLAN_SUBCMD_BT_DEL:
  794. ret = wlan_bt_del_ioctl(priv, req);
  795. break;
  796. case WLAN_SUBCMD_BT_LIST:
  797. ret = wlan_bt_list_ioctl(priv, req);
  798. break;
  799. case WLAN_SUBCMD_FWT_ADD:
  800. ret = wlan_fwt_add_ioctl(priv, req);
  801. break;
  802. case WLAN_SUBCMD_FWT_DEL:
  803. ret = wlan_fwt_del_ioctl(priv, req);
  804. break;
  805. case WLAN_SUBCMD_FWT_LOOKUP:
  806. ret = wlan_fwt_lookup_ioctl(priv, req);
  807. break;
  808. case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
  809. ret = wlan_fwt_list_neighbor_ioctl(priv, req);
  810. break;
  811. case WLAN_SUBCMD_FWT_LIST:
  812. ret = wlan_fwt_list_ioctl(priv, req);
  813. break;
  814. case WLAN_SUBCMD_FWT_LIST_ROUTE:
  815. ret = wlan_fwt_list_route_ioctl(priv, req);
  816. break;
  817. }
  818. break;
  819. case WLAN_SETNONE_GETONEINT:
  820. switch (wrq->u.param.value) {
  821. case WLANGETREGION:
  822. pdata = (int *)wrq->u.name;
  823. *pdata = (int)adapter->regioncode;
  824. break;
  825. case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */
  826. ret = wlan_fwt_cleanup_ioctl(priv, req);
  827. break;
  828. case WLAN_SUBCMD_FWT_TIME: /* fwt_time */
  829. ret = wlan_fwt_time_ioctl(priv, req);
  830. break;
  831. case WLAN_SUBCMD_MESH_GET_TTL:
  832. ret = wlan_mesh_get_ttl_ioctl(priv, req);
  833. break;
  834. case WLAN_SUBCMD_BT_GET_INVERT:
  835. ret = wlan_bt_get_invert_ioctl(priv, req);
  836. break ;
  837. default:
  838. ret = -EOPNOTSUPP;
  839. }
  840. break;
  841. case WLAN_SET_GET_SIXTEEN_INT:
  842. switch ((int)wrq->u.data.flags) {
  843. case WLAN_LED_GPIO_CTRL:
  844. {
  845. int i;
  846. int data[16];
  847. struct cmd_ds_802_11_led_ctrl ctrl;
  848. struct mrvlietypes_ledgpio *gpio =
  849. (struct mrvlietypes_ledgpio *) ctrl.data;
  850. memset(&ctrl, 0, sizeof(ctrl));
  851. if (wrq->u.data.length > MAX_LEDS * 2)
  852. return -ENOTSUPP;
  853. if ((wrq->u.data.length % 2) != 0)
  854. return -ENOTSUPP;
  855. if (wrq->u.data.length == 0) {
  856. ctrl.action =
  857. cpu_to_le16
  858. (cmd_act_get);
  859. } else {
  860. if (copy_from_user
  861. (data, wrq->u.data.pointer,
  862. sizeof(int) *
  863. wrq->u.data.length)) {
  864. lbs_deb_ioctl(
  865. "Copy from user failed\n");
  866. return -EFAULT;
  867. }
  868. ctrl.action =
  869. cpu_to_le16
  870. (cmd_act_set);
  871. ctrl.numled = cpu_to_le16(0);
  872. gpio->header.type =
  873. cpu_to_le16(TLV_TYPE_LED_GPIO);
  874. gpio->header.len = wrq->u.data.length;
  875. for (i = 0; i < wrq->u.data.length;
  876. i += 2) {
  877. gpio->ledpin[i / 2].led =
  878. data[i];
  879. gpio->ledpin[i / 2].pin =
  880. data[i + 1];
  881. }
  882. }
  883. ret =
  884. libertas_prepare_and_send_command(priv,
  885. cmd_802_11_led_gpio_ctrl,
  886. 0,
  887. cmd_option_waitforrsp,
  888. 0, (void *)&ctrl);
  889. for (i = 0; i < gpio->header.len; i += 2) {
  890. data[i] = gpio->ledpin[i / 2].led;
  891. data[i + 1] = gpio->ledpin[i / 2].pin;
  892. }
  893. if (copy_to_user(wrq->u.data.pointer, data,
  894. sizeof(int) *
  895. gpio->header.len)) {
  896. lbs_deb_ioctl("Copy to user failed\n");
  897. return -EFAULT;
  898. }
  899. wrq->u.data.length = gpio->header.len;
  900. }
  901. break;
  902. }
  903. break;
  904. default:
  905. ret = -EINVAL;
  906. break;
  907. }
  908. lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
  909. return ret;
  910. }