5a5863239067ec27ae96d7d6360b83703fa7733e
[pandora-kernel.git] / drivers / net / wireless / libertas / ioctl.c
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
30 static int wlan_set_region(wlan_private * priv, u16 region_code)
31 {
32         int i;
33         int ret = 0;
34
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;
40                         break;
41                 }
42         }
43
44         // if it's unidentified region code
45         if (i >= MRVDRV_MAX_REGION_CODE) {
46                 lbs_deb_ioctl("region Code not identified\n");
47                 ret = -1;
48                 goto done;
49         }
50
51         if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
52                 ret = -EINVAL;
53         }
54
55 done:
56         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
57         return ret;
58 }
59
60 static 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  */
78 static 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) */
104 static 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  */
124 static 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];
130         int ret;
131
132         lbs_deb_enter(LBS_DEB_IOCTL);
133
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
143         lbs_deb_ioctl("BT: adding %s\n", ethaddrs_str);
144         ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
145                                       cmd_act_bt_access_add,
146                                       cmd_option_waitforrsp, 0, ethaddr);
147         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
148         return ret;
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  */
157 static 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
164         lbs_deb_enter(LBS_DEB_IOCTL);
165
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
175         lbs_deb_ioctl("BT: deleting %s\n", ethaddrs_str);
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));
181
182         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
191 static int wlan_bt_reset_ioctl(wlan_private * priv)
192 {
193         lbs_deb_enter(LBS_DEB_IOCTL);
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
202         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
212 static 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
226         lbs_deb_enter(LBS_DEB_IOCTL);
227
228         if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
229                 lbs_deb_ioctl("Copy from user failed\n");
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, "BT includes node ");
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)) {
256                 lbs_deb_ioctl("BT_LIST: Copy to user failed!\n");
257                 return -EFAULT;
258         }
259
260         lbs_deb_leave(LBS_DEB_IOCTL);
261         return 0 ;
262 }
263
264 /**
265  *  @brief          Sets inverted state of blacklist (non-zero if inverted)
266  *  @param priv     A pointer to wlan_private structure
267  *  @param req      A pointer to ifreq structure
268  *  @return         0 --success, otherwise fail
269  */
270 static int wlan_bt_set_invert_ioctl(wlan_private * priv, struct ifreq *req)
271 {
272         int ret;
273         struct iwreq *wrq = (struct iwreq *)req;
274         union {
275                 int id;
276                 char addr1addr2[2 * ETH_ALEN];
277         } param;
278
279         lbs_deb_enter(LBS_DEB_IOCTL);
280
281         param.id = SUBCMD_DATA(wrq) ;
282         ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
283                                     cmd_act_bt_access_set_invert,
284                                     cmd_option_waitforrsp, 0,
285                                     (char *)&param);
286         if (ret != 0)
287                 return -EFAULT;
288         lbs_deb_leave(LBS_DEB_IOCTL);
289         return 0;
290 }
291
292 /**
293  *  @brief          Gets inverted state of blacklist (non-zero if inverted)
294  *  @param priv     A pointer to wlan_private structure
295  *  @param req      A pointer to ifreq structure
296  *  @return         0 --success, otherwise fail
297  */
298 static int wlan_bt_get_invert_ioctl(wlan_private * priv, struct ifreq *req)
299 {
300         int ret;
301         union {
302                 int id;
303                 char addr1addr2[2 * ETH_ALEN];
304         } param;
305
306         lbs_deb_enter(LBS_DEB_IOCTL);
307
308         ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
309                                     cmd_act_bt_access_get_invert,
310                                     cmd_option_waitforrsp, 0,
311                                     (char *)&param);
312
313         if (ret == 0)
314                 req->ifr_data = (char *)(le32_to_cpu(param.id));
315         else
316                 return -EFAULT;
317
318         lbs_deb_leave(LBS_DEB_IOCTL);
319         return 0;
320 }
321
322 /**
323  *  @brief          Find the next parameter in an input string
324  *  @param ptr      A pointer to the input parameter string
325  *  @return         A pointer to the next parameter, or 0 if no parameters left.
326  */
327 static char * next_param(char * ptr)
328 {
329         if (!ptr) return NULL;
330         while (*ptr == ' ' || *ptr == '\t') ++ptr;
331         return (*ptr == '\0') ? NULL : ptr;
332 }
333
334 /**
335  *  @brief          Add an entry to the FWT table
336  *  @param priv     A pointer to wlan_private structure
337  *  @param req      A pointer to ifreq structure
338  *  @return         0 --success, otherwise fail
339  */
340 static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
341 {
342         struct iwreq *wrq = (struct iwreq *)req;
343         char in_str[128];
344         static struct cmd_ds_fwt_access fwt_access;
345         char *ptr;
346         int ret;
347
348         lbs_deb_enter(LBS_DEB_IOCTL);
349
350         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
351                 return -EFAULT;
352
353         if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
354                 lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
355                 return -EINVAL;
356         }
357
358         if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
359                 lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
360                 return -EINVAL;
361         }
362
363         if ((ptr = next_param(ptr)))
364                 fwt_access.metric =
365                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
366         else
367                 fwt_access.metric = FWT_DEFAULT_METRIC;
368
369         if ((ptr = next_param(ptr)))
370                 fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
371         else
372                 fwt_access.dir = FWT_DEFAULT_DIR;
373
374         if ((ptr = next_param(ptr)))
375                 fwt_access.rate = (u8) simple_strtoul(ptr, &ptr, 10);
376         else
377                 fwt_access.rate = FWT_DEFAULT_RATE;
378
379         if ((ptr = next_param(ptr)))
380                 fwt_access.ssn =
381                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
382         else
383                 fwt_access.ssn = FWT_DEFAULT_SSN;
384
385         if ((ptr = next_param(ptr)))
386                 fwt_access.dsn =
387                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
388         else
389                 fwt_access.dsn = FWT_DEFAULT_DSN;
390
391         if ((ptr = next_param(ptr)))
392                 fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
393         else
394                 fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
395
396         if ((ptr = next_param(ptr)))
397                 fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
398         else
399                 fwt_access.ttl = FWT_DEFAULT_TTL;
400
401         if ((ptr = next_param(ptr)))
402                 fwt_access.expiration =
403                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
404         else
405                 fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
406
407         if ((ptr = next_param(ptr)))
408                 fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
409         else
410                 fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
411
412         if ((ptr = next_param(ptr)))
413                 fwt_access.snr =
414                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
415         else
416                 fwt_access.snr = FWT_DEFAULT_SNR;
417
418 #ifdef DEBUG
419         {
420                 char ethaddr1_str[18], ethaddr2_str[18];
421                 eth_addr2str(fwt_access.da, ethaddr1_str);
422                 eth_addr2str(fwt_access.ra, ethaddr2_str);
423                 lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
424                        fwt_access.dir, ethaddr2_str);
425                 lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
426                        fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
427                        fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
428                        fwt_access.sleepmode, fwt_access.snr);
429         }
430 #endif
431
432         ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
433                                                 cmd_act_fwt_access_add,
434                                                 cmd_option_waitforrsp, 0,
435                                                 (void *)&fwt_access);
436
437         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
438         return ret;
439 }
440
441 /**
442  *  @brief          Delete an entry from 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_del_ioctl(wlan_private * priv, struct ifreq *req)
448 {
449         struct iwreq *wrq = (struct iwreq *)req;
450         char in_str[64];
451         static struct cmd_ds_fwt_access fwt_access;
452         char *ptr;
453         int ret;
454
455         lbs_deb_enter(LBS_DEB_IOCTL);
456
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_DEL: Invalid MAC address 1\n");
462                 return -EINVAL;
463         }
464
465         if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
466                 lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
467                 return -EINVAL;
468         }
469
470         if ((ptr = next_param(ptr)))
471                 fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
472         else
473                 fwt_access.dir = FWT_DEFAULT_DIR;
474
475 #ifdef DEBUG
476         {
477                 char ethaddr1_str[18], ethaddr2_str[18];
478                 lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str);
479                 eth_addr2str(fwt_access.da, ethaddr1_str);
480                 eth_addr2str(fwt_access.ra, ethaddr2_str);
481                 lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
482                        ethaddr2_str, fwt_access.dir);
483         }
484 #endif
485
486         ret = libertas_prepare_and_send_command(priv,
487                                                 cmd_fwt_access,
488                                                 cmd_act_fwt_access_del,
489                                                 cmd_option_waitforrsp, 0,
490                                                 (void *)&fwt_access);
491         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
492         return ret;
493 }
494
495
496 /**
497  *  @brief             Print route parameters
498  *  @param fwt_access  struct cmd_ds_fwt_access with route info
499  *  @param buf         destination buffer for route info
500  */
501 static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
502 {
503         buf += sprintf(buf, " ");
504         buf += eth_addr2str(fwt_access.da, buf);
505         buf += sprintf(buf, " ");
506         buf += eth_addr2str(fwt_access.ra, buf);
507         buf += sprintf(buf, " %u", fwt_access.valid);
508         buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
509         buf += sprintf(buf, " %u", fwt_access.dir);
510         buf += sprintf(buf, " %u", fwt_access.rate);
511         buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
512         buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
513         buf += sprintf(buf, " %u", fwt_access.hopcount);
514         buf += sprintf(buf, " %u", fwt_access.ttl);
515         buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
516         buf += sprintf(buf, " %u", fwt_access.sleepmode);
517         buf += sprintf(buf, " %u ", le32_to_cpu(fwt_access.snr));
518         buf += eth_addr2str(fwt_access.prec, buf);
519 }
520
521 /**
522  *  @brief          Lookup an entry in the FWT table
523  *  @param priv     A pointer to wlan_private structure
524  *  @param req      A pointer to ifreq structure
525  *  @return         0 --success, otherwise fail
526  */
527 static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
528 {
529         struct iwreq *wrq = (struct iwreq *)req;
530         char in_str[64];
531         char *ptr;
532         static struct cmd_ds_fwt_access fwt_access;
533         static char out_str[128];
534         int ret;
535
536         lbs_deb_enter(LBS_DEB_IOCTL);
537
538         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
539                 return -EFAULT;
540
541         if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
542                 lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
543                 return -EINVAL;
544         }
545
546 #ifdef DEBUG
547         {
548                 char ethaddr1_str[18];
549                 lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str);
550                 eth_addr2str(fwt_access.da, ethaddr1_str);
551                 lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
552         }
553 #endif
554
555         ret = libertas_prepare_and_send_command(priv,
556                                                 cmd_fwt_access,
557                                                 cmd_act_fwt_access_lookup,
558                                                 cmd_option_waitforrsp, 0,
559                                                 (void *)&fwt_access);
560
561         if (ret == 0)
562                 print_route(fwt_access, out_str);
563         else
564                 sprintf(out_str, "(null)");
565
566         wrq->u.data.length = strlen(out_str);
567         if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
568                          wrq->u.data.length)) {
569                 lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n");
570                 return -EFAULT;
571         }
572
573         lbs_deb_leave(LBS_DEB_IOCTL);
574         return 0;
575 }
576
577 /**
578  *  @brief          Reset all entries from the FWT table
579  *  @param priv     A pointer to wlan_private structure
580  *  @return         0 --success, otherwise fail
581  */
582 static int wlan_fwt_reset_ioctl(wlan_private * priv)
583 {
584         lbs_deb_ioctl("FWT: resetting\n");
585
586         return (libertas_prepare_and_send_command(priv,
587                                       cmd_fwt_access,
588                                       cmd_act_fwt_access_reset,
589                                       cmd_option_waitforrsp, 0, NULL));
590 }
591
592 /**
593  *  @brief          List an entry from the FWT table
594  *  @param priv     A pointer to wlan_private structure
595  *  @param req      A pointer to ifreq structure
596  *  @return         0 --success, otherwise fail
597  */
598 static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
599 {
600         struct iwreq *wrq = (struct iwreq *)req;
601         char in_str[8];
602         static struct cmd_ds_fwt_access fwt_access;
603         char *ptr = in_str;
604         static char out_str[128];
605         char *pbuf = out_str;
606         int ret;
607
608         lbs_deb_enter(LBS_DEB_IOCTL);
609
610         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
611                 return -EFAULT;
612
613         fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
614
615 #ifdef DEBUG
616         {
617                 lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str);
618                 lbs_deb_ioctl("FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
619         }
620 #endif
621
622         ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
623                                     cmd_act_fwt_access_list,
624                                     cmd_option_waitforrsp, 0, (void *)&fwt_access);
625
626         if (ret == 0)
627                 print_route(fwt_access, pbuf);
628         else
629                 pbuf += sprintf(pbuf, " (null)");
630
631         wrq->u.data.length = strlen(out_str);
632         if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
633                          wrq->u.data.length)) {
634                 lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n");
635                 return -EFAULT;
636         }
637
638         lbs_deb_leave(LBS_DEB_IOCTL);
639         return 0;
640 }
641
642 /**
643  *  @brief          List an entry from the FRT table
644  *  @param priv     A pointer to wlan_private structure
645  *  @param req      A pointer to ifreq structure
646  *  @return         0 --success, otherwise fail
647  */
648 static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
649 {
650         struct iwreq *wrq = (struct iwreq *)req;
651         char in_str[64];
652         static struct cmd_ds_fwt_access fwt_access;
653         char *ptr = in_str;
654         static char out_str[128];
655         char *pbuf = out_str;
656         int ret;
657
658         lbs_deb_enter(LBS_DEB_IOCTL);
659
660         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
661                 return -EFAULT;
662
663         fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
664
665 #ifdef DEBUG
666         {
667                 lbs_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str);
668                 lbs_deb_ioctl("FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
669         }
670 #endif
671
672         ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
673                                     cmd_act_fwt_access_list_route,
674                                     cmd_option_waitforrsp, 0, (void *)&fwt_access);
675
676         if (ret == 0) {
677                 pbuf += sprintf(pbuf, " ");
678                 pbuf += eth_addr2str(fwt_access.da, pbuf);
679                 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
680                 pbuf += sprintf(pbuf, " %u", fwt_access.dir);
681                 /* note that the firmware returns the nid in the id field */
682                 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
683                 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
684                 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
685                 pbuf += sprintf(pbuf, "  hop %u", fwt_access.hopcount);
686                 pbuf += sprintf(pbuf, "  ttl %u", fwt_access.ttl);
687                 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
688         } else
689                 pbuf += sprintf(pbuf, " (null)");
690
691         wrq->u.data.length = strlen(out_str);
692         if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
693                          wrq->u.data.length)) {
694                 lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n");
695                 return -EFAULT;
696         }
697
698         lbs_deb_leave(LBS_DEB_IOCTL);
699         return 0;
700 }
701
702 /**
703  *  @brief          List an entry from the FNT table
704  *  @param priv     A pointer to wlan_private structure
705  *  @param req      A pointer to ifreq structure
706  *  @return         0 --success, otherwise fail
707  */
708 static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
709 {
710         struct iwreq *wrq = (struct iwreq *)req;
711         char in_str[8];
712         static struct cmd_ds_fwt_access fwt_access;
713         char *ptr = in_str;
714         static char out_str[128];
715         char *pbuf = out_str;
716         int ret;
717
718         lbs_deb_enter(LBS_DEB_IOCTL);
719
720         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
721                 return -EFAULT;
722
723         memset(&fwt_access, 0, sizeof(fwt_access));
724         fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
725
726 #ifdef DEBUG
727         {
728                 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str);
729                 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
730         }
731 #endif
732
733         ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
734                                     cmd_act_fwt_access_list_neighbor,
735                                     cmd_option_waitforrsp, 0,
736                                     (void *)&fwt_access);
737
738         if (ret == 0) {
739                 pbuf += sprintf(pbuf, " ra ");
740                 pbuf += eth_addr2str(fwt_access.ra, pbuf);
741                 pbuf += sprintf(pbuf, "  slp %u", fwt_access.sleepmode);
742                 pbuf += sprintf(pbuf, "  snr %u", le32_to_cpu(fwt_access.snr));
743                 pbuf += sprintf(pbuf, "  ref %u", le32_to_cpu(fwt_access.references));
744         } else
745                 pbuf += sprintf(pbuf, " (null)");
746
747         wrq->u.data.length = strlen(out_str);
748         if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
749                          wrq->u.data.length)) {
750                 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n");
751                 return -EFAULT;
752         }
753
754         lbs_deb_leave(LBS_DEB_IOCTL);
755         return 0;
756 }
757
758 /**
759  *  @brief          Cleans up the route (FRT) and neighbor (FNT) tables
760  *                  (Garbage Collection)
761  *  @param priv     A pointer to wlan_private structure
762  *  @param req      A pointer to ifreq structure
763  *  @return         0 --success, otherwise fail
764  */
765 static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
766 {
767         struct iwreq *wrq = (struct iwreq *)req;
768         static struct cmd_ds_fwt_access fwt_access;
769         int ret;
770
771         lbs_deb_enter(LBS_DEB_IOCTL);
772
773         lbs_deb_ioctl("FWT: cleaning up\n");
774
775         memset(&fwt_access, 0, sizeof(fwt_access));
776
777         ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
778                                     cmd_act_fwt_access_cleanup,
779                                     cmd_option_waitforrsp, 0,
780                                     (void *)&fwt_access);
781
782         if (ret == 0)
783                 wrq->u.param.value = le32_to_cpu(fwt_access.references);
784         else
785                 return -EFAULT;
786
787         lbs_deb_leave(LBS_DEB_IOCTL);
788         return 0;
789 }
790
791 /**
792  *  @brief          Gets firmware internal time (debug purposes)
793  *  @param priv     A pointer to wlan_private structure
794  *  @param req      A pointer to ifreq structure
795  *  @return         0 --success, otherwise fail
796  */
797 static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
798 {
799         struct iwreq *wrq = (struct iwreq *)req;
800         static struct cmd_ds_fwt_access fwt_access;
801         int ret;
802
803         lbs_deb_enter(LBS_DEB_IOCTL);
804
805         lbs_deb_ioctl("FWT: getting time\n");
806
807         memset(&fwt_access, 0, sizeof(fwt_access));
808
809         ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
810                                     cmd_act_fwt_access_time,
811                                     cmd_option_waitforrsp, 0,
812                                     (void *)&fwt_access);
813
814         if (ret == 0)
815                 wrq->u.param.value = le32_to_cpu(fwt_access.references);
816         else
817                 return -EFAULT;
818
819         lbs_deb_leave(LBS_DEB_IOCTL);
820         return 0;
821 }
822
823 /**
824  *  @brief          Gets mesh ttl from firmware
825  *  @param priv     A pointer to wlan_private structure
826  *  @param req      A pointer to ifreq structure
827  *  @return         0 --success, otherwise fail
828  */
829 static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
830 {
831         struct iwreq *wrq = (struct iwreq *)req;
832         struct cmd_ds_mesh_access mesh_access;
833         int ret;
834
835         lbs_deb_enter(LBS_DEB_IOCTL);
836
837         memset(&mesh_access, 0, sizeof(mesh_access));
838
839         ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
840                                     cmd_act_mesh_get_ttl,
841                                     cmd_option_waitforrsp, 0,
842                                     (void *)&mesh_access);
843
844         if (ret == 0)
845                 wrq->u.param.value = le32_to_cpu(mesh_access.data[0]);
846         else
847                 return -EFAULT;
848
849         lbs_deb_leave(LBS_DEB_IOCTL);
850         return 0;
851 }
852
853 /**
854  *  @brief          Gets mesh ttl from firmware
855  *  @param priv     A pointer to wlan_private structure
856  *  @param ttl      New ttl value
857  *  @return         0 --success, otherwise fail
858  */
859 static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
860 {
861         struct cmd_ds_mesh_access mesh_access;
862         int ret;
863
864         lbs_deb_enter(LBS_DEB_IOCTL);
865
866         if( (ttl > 0xff) || (ttl < 0) )
867                 return -EINVAL;
868
869         memset(&mesh_access, 0, sizeof(mesh_access));
870         mesh_access.data[0] = ttl;
871
872         ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
873                                                 cmd_act_mesh_set_ttl,
874                                                 cmd_option_waitforrsp, 0,
875                                                 (void *)&mesh_access);
876
877         if (ret != 0)
878                 ret = -EFAULT;
879
880         lbs_deb_leave(LBS_DEB_IOCTL);
881         return ret;
882 }
883
884 /**
885  *  @brief ioctl function - entry point
886  *
887  *  @param dev          A pointer to net_device structure
888  *  @param req          A pointer to ifreq structure
889  *  @param cmd          command
890  *  @return             0--success, otherwise fail
891  */
892 int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
893 {
894         int subcmd = 0;
895         int idata = 0;
896         int *pdata;
897         int ret = 0;
898         wlan_private *priv = dev->priv;
899         wlan_adapter *adapter = priv->adapter;
900         struct iwreq *wrq = (struct iwreq *)req;
901
902         lbs_deb_enter(LBS_DEB_IOCTL);
903
904         lbs_deb_ioctl("libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
905         switch (cmd) {
906         case WLAN_SETNONE_GETNONE:      /* set WPA mode on/off ioctl #20 */
907                 switch (wrq->u.data.flags) {
908                 case WLAN_SUBCMD_BT_RESET:      /* bt_reset */
909                         wlan_bt_reset_ioctl(priv);
910                         break;
911                 case WLAN_SUBCMD_FWT_RESET:     /* fwt_reset */
912                         wlan_fwt_reset_ioctl(priv);
913                         break;
914                 }               /* End of switch */
915                 break;
916
917         case WLAN_SETONEINT_GETNONE:
918                 /* The first 4 bytes of req->ifr_data is sub-ioctl number
919                  * after 4 bytes sits the payload.
920                  */
921                 subcmd = wrq->u.data.flags;
922                 if (!subcmd)
923                         subcmd = (int)wrq->u.param.value;
924
925                 switch (subcmd) {
926                 case WLANSETREGION:
927                         idata = SUBCMD_DATA(wrq);
928                         ret = wlan_set_region(priv, (u16) idata);
929                         break;
930                 case WLAN_SUBCMD_MESH_SET_TTL:
931                         idata = SUBCMD_DATA(wrq);
932                         ret = wlan_mesh_set_ttl_ioctl(priv, idata);
933                         break;
934
935                 case WLAN_SUBCMD_BT_SET_INVERT:
936                         ret = wlan_bt_set_invert_ioctl(priv, req);
937                         break ;
938
939                 default:
940                         ret = -EOPNOTSUPP;
941                         break;
942                 }
943
944                 break;
945
946         case WLAN_SET128CHAR_GET128CHAR:
947                 switch ((int)wrq->u.data.flags) {
948                 case WLAN_SUBCMD_BT_ADD:
949                         ret = wlan_bt_add_ioctl(priv, req);
950                         break;
951                 case WLAN_SUBCMD_BT_DEL:
952                         ret = wlan_bt_del_ioctl(priv, req);
953                         break;
954                 case WLAN_SUBCMD_BT_LIST:
955                         ret = wlan_bt_list_ioctl(priv, req);
956                         break;
957                 case WLAN_SUBCMD_FWT_ADD:
958                         ret = wlan_fwt_add_ioctl(priv, req);
959                         break;
960                 case WLAN_SUBCMD_FWT_DEL:
961                         ret = wlan_fwt_del_ioctl(priv, req);
962                         break;
963                 case WLAN_SUBCMD_FWT_LOOKUP:
964                         ret = wlan_fwt_lookup_ioctl(priv, req);
965                         break;
966                 case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
967                         ret = wlan_fwt_list_neighbor_ioctl(priv, req);
968                         break;
969                 case WLAN_SUBCMD_FWT_LIST:
970                         ret = wlan_fwt_list_ioctl(priv, req);
971                         break;
972                 case WLAN_SUBCMD_FWT_LIST_ROUTE:
973                         ret = wlan_fwt_list_route_ioctl(priv, req);
974                         break;
975                 }
976                 break;
977
978         case WLAN_SETNONE_GETONEINT:
979                 switch (wrq->u.param.value) {
980                 case WLANGETREGION:
981                         pdata = (int *)wrq->u.name;
982                         *pdata = (int)adapter->regioncode;
983                         break;
984                 case WLAN_SUBCMD_FWT_CLEANUP:   /* fwt_cleanup */
985                         ret = wlan_fwt_cleanup_ioctl(priv, req);
986                         break;
987
988                 case WLAN_SUBCMD_FWT_TIME:      /* fwt_time */
989                         ret = wlan_fwt_time_ioctl(priv, req);
990                         break;
991
992                 case WLAN_SUBCMD_MESH_GET_TTL:
993                         ret = wlan_mesh_get_ttl_ioctl(priv, req);
994                         break;
995
996                 case WLAN_SUBCMD_BT_GET_INVERT:
997                         ret = wlan_bt_get_invert_ioctl(priv, req);
998                         break ;
999
1000                 default:
1001                         ret = -EOPNOTSUPP;
1002
1003                 }
1004
1005                 break;
1006
1007         case WLAN_SET_GET_SIXTEEN_INT:
1008                 switch ((int)wrq->u.data.flags) {
1009                 case WLAN_LED_GPIO_CTRL:
1010                         {
1011                                 int i;
1012                                 int data[16];
1013
1014                                 struct cmd_ds_802_11_led_ctrl ctrl;
1015                                 struct mrvlietypes_ledgpio *gpio =
1016                                     (struct mrvlietypes_ledgpio *) ctrl.data;
1017
1018                                 memset(&ctrl, 0, sizeof(ctrl));
1019                                 if (wrq->u.data.length > MAX_LEDS * 2)
1020                                         return -ENOTSUPP;
1021                                 if ((wrq->u.data.length % 2) != 0)
1022                                         return -ENOTSUPP;
1023                                 if (wrq->u.data.length == 0) {
1024                                         ctrl.action =
1025                                             cpu_to_le16
1026                                             (cmd_act_get);
1027                                 } else {
1028                                         if (copy_from_user
1029                                             (data, wrq->u.data.pointer,
1030                                              sizeof(int) *
1031                                              wrq->u.data.length)) {
1032                                                 lbs_deb_ioctl(
1033                                                        "Copy from user failed\n");
1034                                                 return -EFAULT;
1035                                         }
1036
1037                                         ctrl.action =
1038                                             cpu_to_le16
1039                                             (cmd_act_set);
1040                                         ctrl.numled = cpu_to_le16(0);
1041                                         gpio->header.type =
1042                                             cpu_to_le16(TLV_TYPE_LED_GPIO);
1043                                         gpio->header.len = wrq->u.data.length;
1044                                         for (i = 0; i < wrq->u.data.length;
1045                                              i += 2) {
1046                                                 gpio->ledpin[i / 2].led =
1047                                                     data[i];
1048                                                 gpio->ledpin[i / 2].pin =
1049                                                     data[i + 1];
1050                                         }
1051                                 }
1052                                 ret =
1053                                     libertas_prepare_and_send_command(priv,
1054                                                           cmd_802_11_led_gpio_ctrl,
1055                                                           0,
1056                                                           cmd_option_waitforrsp,
1057                                                           0, (void *)&ctrl);
1058                                 for (i = 0; i < gpio->header.len; i += 2) {
1059                                         data[i] = gpio->ledpin[i / 2].led;
1060                                         data[i + 1] = gpio->ledpin[i / 2].pin;
1061                                 }
1062                                 if (copy_to_user(wrq->u.data.pointer, data,
1063                                                  sizeof(int) *
1064                                                  gpio->header.len)) {
1065                                         lbs_deb_ioctl("Copy to user failed\n");
1066                                         return -EFAULT;
1067                                 }
1068
1069                                 wrq->u.data.length = gpio->header.len;
1070                         }
1071                         break;
1072                 }
1073                 break;
1074
1075         default:
1076                 ret = -EINVAL;
1077                 break;
1078         }
1079
1080         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
1081         return ret;
1082 }
1083
1084