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