]> err.no Git - linux-2.6/blob - drivers/net/wireless/libertas/ioctl.c
[PATCH] libertas: remove unused variables in wlan_dev_t
[linux-2.6] / 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, "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)) {
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          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  */
269 static 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  */
282 static 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;
288         int ret;
289
290         lbs_deb_enter(LBS_DEB_IOCTL);
291
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);
360                 lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
361                        fwt_access.dir, ethaddr2_str);
362                 lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
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
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;
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  */
384 static 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;
390         int ret;
391
392         lbs_deb_enter(LBS_DEB_IOCTL);
393
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];
415                 lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str);
416                 eth_addr2str(fwt_access.da, ethaddr1_str);
417                 eth_addr2str(fwt_access.ra, ethaddr2_str);
418                 lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
419                        ethaddr2_str, fwt_access.dir);
420         }
421 #endif
422
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;
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  */
438 static 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  */
461 static 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
470         lbs_deb_enter(LBS_DEB_IOCTL);
471
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];
483                 lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str);
484                 eth_addr2str(fwt_access.da, ethaddr1_str);
485                 lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
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)) {
503                 lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n");
504                 return -EFAULT;
505         }
506
507         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
516 static int wlan_fwt_reset_ioctl(wlan_private * priv)
517 {
518         lbs_deb_ioctl("FWT: resetting\n");
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  */
532 static 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
542         lbs_deb_enter(LBS_DEB_IOCTL);
543
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         {
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));
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)) {
568                 lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n");
569                 return -EFAULT;
570         }
571
572         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
582 static 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
592         lbs_deb_enter(LBS_DEB_IOCTL);
593
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         {
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));
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)) {
628                 lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n");
629                 return -EFAULT;
630         }
631
632         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
642 static 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
652         lbs_deb_enter(LBS_DEB_IOCTL);
653
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         {
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));
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)) {
684                 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n");
685                 return -EFAULT;
686         }
687
688         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
699 static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
700 {
701         struct iwreq *wrq = (struct iwreq *)req;
702         static struct cmd_ds_fwt_access fwt_access;
703         int ret;
704
705         lbs_deb_enter(LBS_DEB_IOCTL);
706
707         lbs_deb_ioctl("FWT: cleaning up\n");
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)
717                 wrq->u.param.value = le32_to_cpu(fwt_access.references);
718         else
719                 return -EFAULT;
720
721         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
731 static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
732 {
733         struct iwreq *wrq = (struct iwreq *)req;
734         static struct cmd_ds_fwt_access fwt_access;
735         int ret;
736
737         lbs_deb_enter(LBS_DEB_IOCTL);
738
739         lbs_deb_ioctl("FWT: getting time\n");
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)
749                 wrq->u.param.value = le32_to_cpu(fwt_access.references);
750         else
751                 return -EFAULT;
752
753         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
763 static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
764 {
765         struct iwreq *wrq = (struct iwreq *)req;
766         struct cmd_ds_mesh_access mesh_access;
767         int ret;
768
769         lbs_deb_enter(LBS_DEB_IOCTL);
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
778         if (ret == 0)
779                 wrq->u.param.value = le32_to_cpu(mesh_access.data[0]);
780         else
781                 return -EFAULT;
782
783         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
793 static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
794 {
795         struct cmd_ds_mesh_access mesh_access;
796         int ret;
797
798         lbs_deb_enter(LBS_DEB_IOCTL);
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
814         lbs_deb_leave(LBS_DEB_IOCTL);
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  */
826 int 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
836         lbs_deb_enter(LBS_DEB_IOCTL);
837
838         lbs_deb_ioctl("libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
839         switch (cmd) {
840         case WLAN_SETNONE_GETNONE:      /* set WPA mode on/off ioctl #20 */
841                 switch (wrq->u.data.flags) {
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
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                  */
855                 subcmd = wrq->u.data.flags;
856                 if (!subcmd)
857                         subcmd = (int)wrq->u.param.value;
858
859                 switch (subcmd) {
860                 case WLANSETREGION:
861                         idata = SUBCMD_DATA(wrq);
862                         ret = wlan_set_region(priv, (u16) idata);
863                         break;
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
876         case WLAN_SET128CHAR_GET128CHAR:
877                 switch ((int)wrq->u.data.flags) {
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:
909                 switch (wrq->u.param.value) {
910                 case WLANGETREGION:
911                         pdata = (int *)wrq->u.name;
912                         *pdata = (int)adapter->regioncode;
913                         break;
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
933         case WLAN_SET_GET_SIXTEEN_INT:
934                 switch ((int)wrq->u.data.flags) {
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)) {
958                                                 lbs_deb_ioctl(
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)) {
991                                         lbs_deb_ioctl("Copy to user failed\n");
992                                         return -EFAULT;
993                                 }
994
995                                 wrq->u.data.length = gpio->header.len;
996                         }
997                         break;
998                 }
999                 break;
1000
1001         default:
1002                 ret = -EINVAL;
1003                 break;
1004         }
1005
1006         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
1007         return ret;
1008 }
1009
1010