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