ioctl.c 25 KB

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