[iptables] Update layer7 rules
[openwrt.git] / package / libertas / src / 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 "wext.h"
20 #include "cmd.h"
21 #include "ioctl.h"
22
23 #define MAX_SCAN_CELL_SIZE      (IW_EV_ADDR_LEN + \
24                                 IW_ESSID_MAX_SIZE + \
25                                 IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
26                                 IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
27                                 IW_EV_PARAM_LEN + 40)   /* 40 for WPAIE */
28
29 #define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
30
31 static int lbs_set_region(struct lbs_private * priv, u16 region_code)
32 {
33         int i;
34         int ret = 0;
35
36         for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) {
37                 // use the region code to search for the index
38                 if (region_code == lbs_region_code_to_index[i]) {
39                         priv->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 (lbs_set_regiontable(priv, priv->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 struct lbs_private structure
121  *  @param req      A pointer to ifreq structure
122  *  @return         0 --success, otherwise fail
123  */
124 static int lbs_bt_add_ioctl(struct lbs_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 = lbs_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 struct lbs_private structure
154  *  @param req      A pointer to ifreq structure
155  *  @return         0 --success, otherwise fail
156  */
157 static int lbs_bt_del_ioctl(struct lbs_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 (lbs_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 struct lbs_private structure
189  *  @return         0 --success, otherwise fail
190  */
191 static int lbs_bt_reset_ioctl(struct lbs_private * priv)
192 {
193         lbs_deb_enter(LBS_DEB_IOCTL);
194
195         lbs_pr_alert( "BT: resetting\n");
196
197         return (lbs_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 struct lbs_private structure
209  *  @param req      A pointer to ifreq structure
210  *  @return         0 --success, otherwise fail
211  */
212 static int lbs_bt_list_ioctl(struct lbs_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                 u32 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 = lbs_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 struct lbs_private structure
267  *  @param req      A pointer to ifreq structure
268  *  @return         0 --success, otherwise fail
269  */
270 static int lbs_bt_set_invert_ioctl(struct lbs_private * priv, struct ifreq *req)
271 {
272         int ret;
273         struct iwreq *wrq = (struct iwreq *)req;
274         union {
275                 u32 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 = lbs_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 struct lbs_private structure
295  *  @param req      A pointer to ifreq structure
296  *  @return         0 --success, otherwise fail
297  */
298 static int lbs_bt_get_invert_ioctl(struct lbs_private * priv, struct ifreq *req)
299 {
300         struct iwreq *wrq = (struct iwreq *)req;
301         int ret;
302         union {
303                 __le32 id;
304                 char addr1addr2[2 * ETH_ALEN];
305         } param;
306
307         lbs_deb_enter(LBS_DEB_IOCTL);
308
309         ret = lbs_prepare_and_send_command(priv, CMD_BT_ACCESS,
310                                     CMD_ACT_BT_ACCESS_GET_INVERT,
311                                     CMD_OPTION_WAITFORRSP, 0,
312                                     (char *)&param);
313
314         if (ret == 0)
315                 wrq->u.param.value = le32_to_cpu(param.id);
316         else
317                 return -EFAULT;
318
319         lbs_deb_leave(LBS_DEB_IOCTL);
320         return 0;
321 }
322
323 /**
324  *  @brief          Find the next parameter in an input string
325  *  @param ptr      A pointer to the input parameter string
326  *  @return         A pointer to the next parameter, or 0 if no parameters left.
327  */
328 static char * next_param(char * ptr)
329 {
330         if (!ptr) return NULL;
331         while (*ptr == ' ' || *ptr == '\t') ++ptr;
332         return (*ptr == '\0') ? NULL : ptr;
333 }
334
335 /**
336  *  @brief          Add an entry to the FWT table
337  *  @param priv     A pointer to struct lbs_private structure
338  *  @param req      A pointer to ifreq structure
339  *  @return         0 --success, otherwise fail
340  */
341 static int lbs_fwt_add_ioctl(struct lbs_private * priv, struct ifreq *req)
342 {
343         struct iwreq *wrq = (struct iwreq *)req;
344         char in_str[128];
345         static struct cmd_ds_fwt_access fwt_access;
346         char *ptr;
347         int ret;
348
349         lbs_deb_enter(LBS_DEB_IOCTL);
350
351         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
352                 return -EFAULT;
353
354         if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
355                 lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
356                 return -EINVAL;
357         }
358
359         if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
360                 lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
361                 return -EINVAL;
362         }
363
364         if ((ptr = next_param(ptr)))
365                 fwt_access.metric =
366                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
367         else
368                 fwt_access.metric = cpu_to_le32(FWT_DEFAULT_METRIC);
369
370         if ((ptr = next_param(ptr)))
371                 fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
372         else
373                 fwt_access.dir = FWT_DEFAULT_DIR;
374
375         if ((ptr = next_param(ptr)))
376                 fwt_access.rate = (u8) simple_strtoul(ptr, &ptr, 10);
377         else
378                 fwt_access.rate = FWT_DEFAULT_RATE;
379
380         if ((ptr = next_param(ptr)))
381                 fwt_access.ssn =
382                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
383         else
384                 fwt_access.ssn = cpu_to_le32(FWT_DEFAULT_SSN);
385
386         if ((ptr = next_param(ptr)))
387                 fwt_access.dsn =
388                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
389         else
390                 fwt_access.dsn = cpu_to_le32(FWT_DEFAULT_DSN);
391
392         if ((ptr = next_param(ptr)))
393                 fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
394         else
395                 fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
396
397         if ((ptr = next_param(ptr)))
398                 fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
399         else
400                 fwt_access.ttl = FWT_DEFAULT_TTL;
401
402         if ((ptr = next_param(ptr)))
403                 fwt_access.expiration =
404                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
405         else
406                 fwt_access.expiration = cpu_to_le32(FWT_DEFAULT_EXPIRATION);
407
408         if ((ptr = next_param(ptr)))
409                 fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
410         else
411                 fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
412
413         if ((ptr = next_param(ptr)))
414                 fwt_access.snr =
415                         cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
416         else
417                 fwt_access.snr = cpu_to_le32(FWT_DEFAULT_SNR);
418
419 #ifdef DEBUG
420         {
421                 char ethaddr1_str[18], ethaddr2_str[18];
422                 eth_addr2str(fwt_access.da, ethaddr1_str);
423                 eth_addr2str(fwt_access.ra, ethaddr2_str);
424                 lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
425                        fwt_access.dir, ethaddr2_str);
426                 lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
427                        fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
428                        fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
429                        fwt_access.sleepmode, fwt_access.snr);
430         }
431 #endif
432
433         ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
434                                                 CMD_ACT_FWT_ACCESS_ADD,
435                                                 CMD_OPTION_WAITFORRSP, 0,
436                                                 (void *)&fwt_access);
437
438         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
439         return ret;
440 }
441
442 /**
443  *  @brief          Delete an entry from the FWT table
444  *  @param priv     A pointer to struct lbs_private structure
445  *  @param req      A pointer to ifreq structure
446  *  @return         0 --success, otherwise fail
447  */
448 static int lbs_fwt_del_ioctl(struct lbs_private * priv, struct ifreq *req)
449 {
450         struct iwreq *wrq = (struct iwreq *)req;
451         char in_str[64];
452         static struct cmd_ds_fwt_access fwt_access;
453         char *ptr;
454         int ret;
455
456         lbs_deb_enter(LBS_DEB_IOCTL);
457
458         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
459                 return -EFAULT;
460
461         if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
462                 lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
463                 return -EINVAL;
464         }
465
466         if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
467                 lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
468                 return -EINVAL;
469         }
470
471         if ((ptr = next_param(ptr)))
472                 fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
473         else
474                 fwt_access.dir = FWT_DEFAULT_DIR;
475
476 #ifdef DEBUG
477         {
478                 char ethaddr1_str[18], ethaddr2_str[18];
479                 lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str);
480                 eth_addr2str(fwt_access.da, ethaddr1_str);
481                 eth_addr2str(fwt_access.ra, ethaddr2_str);
482                 lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
483                        ethaddr2_str, fwt_access.dir);
484         }
485 #endif
486
487         ret = lbs_prepare_and_send_command(priv,
488                                                 CMD_FWT_ACCESS,
489                                                 CMD_ACT_FWT_ACCESS_DEL,
490                                                 CMD_OPTION_WAITFORRSP, 0,
491                                                 (void *)&fwt_access);
492         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
493         return ret;
494 }
495
496
497 /**
498  *  @brief             Print route parameters
499  *  @param fwt_access  struct cmd_ds_fwt_access with route info
500  *  @param buf         destination buffer for route info
501  */
502 static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
503 {
504         buf += sprintf(buf, " ");
505         buf += eth_addr2str(fwt_access.da, buf);
506         buf += sprintf(buf, " ");
507         buf += eth_addr2str(fwt_access.ra, buf);
508         buf += sprintf(buf, " %u", fwt_access.valid);
509         buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
510         buf += sprintf(buf, " %u", fwt_access.dir);
511         buf += sprintf(buf, " %u", fwt_access.rate);
512         buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
513         buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
514         buf += sprintf(buf, " %u", fwt_access.hopcount);
515         buf += sprintf(buf, " %u", fwt_access.ttl);
516         buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
517         buf += sprintf(buf, " %u", fwt_access.sleepmode);
518         buf += sprintf(buf, " %u ", le32_to_cpu(fwt_access.snr));
519         buf += eth_addr2str(fwt_access.prec, buf);
520 }
521
522 /**
523  *  @brief          Lookup an entry in the FWT table
524  *  @param priv     A pointer to struct lbs_private structure
525  *  @param req      A pointer to ifreq structure
526  *  @return         0 --success, otherwise fail
527  */
528 static int lbs_fwt_lookup_ioctl(struct lbs_private * priv, struct ifreq *req)
529 {
530         struct iwreq *wrq = (struct iwreq *)req;
531         char in_str[64];
532         char *ptr;
533         static struct cmd_ds_fwt_access fwt_access;
534         static char out_str[128];
535         int ret;
536
537         lbs_deb_enter(LBS_DEB_IOCTL);
538
539         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
540                 return -EFAULT;
541
542         if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
543                 lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
544                 return -EINVAL;
545         }
546
547 #ifdef DEBUG
548         {
549                 char ethaddr1_str[18];
550                 lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str);
551                 eth_addr2str(fwt_access.da, ethaddr1_str);
552                 lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
553         }
554 #endif
555
556         ret = lbs_prepare_and_send_command(priv,
557                                                 CMD_FWT_ACCESS,
558                                                 CMD_ACT_FWT_ACCESS_LOOKUP,
559                                                 CMD_OPTION_WAITFORRSP, 0,
560                                                 (void *)&fwt_access);
561
562         if (ret == 0)
563                 print_route(fwt_access, out_str);
564         else
565                 sprintf(out_str, "(null)");
566
567         wrq->u.data.length = strlen(out_str);
568         if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
569                          wrq->u.data.length)) {
570                 lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n");
571                 return -EFAULT;
572         }
573
574         lbs_deb_leave(LBS_DEB_IOCTL);
575         return 0;
576 }
577
578 /**
579  *  @brief          Reset all entries from the FWT table
580  *  @param priv     A pointer to struct lbs_private structure
581  *  @return         0 --success, otherwise fail
582  */
583 static int lbs_fwt_reset_ioctl(struct lbs_private * priv)
584 {
585         lbs_deb_ioctl("FWT: resetting\n");
586
587         return (lbs_prepare_and_send_command(priv,
588                                       CMD_FWT_ACCESS,
589                                       CMD_ACT_FWT_ACCESS_RESET,
590                                       CMD_OPTION_WAITFORRSP, 0, NULL));
591 }
592
593 /**
594  *  @brief          List an entry from the FWT table
595  *  @param priv     A pointer to struct lbs_private structure
596  *  @param req      A pointer to ifreq structure
597  *  @return         0 --success, otherwise fail
598  */
599 static int lbs_fwt_list_ioctl(struct lbs_private * priv, struct ifreq *req)
600 {
601         struct iwreq *wrq = (struct iwreq *)req;
602         char in_str[8];
603         static struct cmd_ds_fwt_access fwt_access;
604         char *ptr = in_str;
605         static char out_str[128];
606         char *pbuf = out_str;
607         int ret = 0;
608
609         lbs_deb_enter(LBS_DEB_IOCTL);
610
611         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) {
612                 ret = -EFAULT;
613                 goto out;
614         }
615
616         fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
617
618 #ifdef DEBUG
619         {
620                 lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str);
621                 lbs_deb_ioctl("FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
622         }
623 #endif
624
625         ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
626                                     CMD_ACT_FWT_ACCESS_LIST,
627                                     CMD_OPTION_WAITFORRSP, 0, (void *)&fwt_access);
628
629         if (ret == 0)
630                 print_route(fwt_access, pbuf);
631         else
632                 pbuf += sprintf(pbuf, " (null)");
633
634         wrq->u.data.length = strlen(out_str);
635         if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
636                          wrq->u.data.length)) {
637                 lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n");
638                 ret = -EFAULT;
639                 goto out;
640         }
641
642         ret = 0;
643
644 out:
645         lbs_deb_leave(LBS_DEB_IOCTL);
646         return ret;
647 }
648
649 /**
650  *  @brief          List an entry from the FRT table
651  *  @param priv     A pointer to struct lbs_private structure
652  *  @param req      A pointer to ifreq structure
653  *  @return         0 --success, otherwise fail
654  */
655 static int lbs_fwt_list_route_ioctl(struct lbs_private * priv, struct ifreq *req)
656 {
657         struct iwreq *wrq = (struct iwreq *)req;
658         char in_str[64];
659         static struct cmd_ds_fwt_access fwt_access;
660         char *ptr = in_str;
661         static char out_str[128];
662         char *pbuf = out_str;
663         int ret;
664
665         lbs_deb_enter(LBS_DEB_IOCTL);
666
667         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
668                 return -EFAULT;
669
670         fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
671
672 #ifdef DEBUG
673         {
674                 lbs_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str);
675                 lbs_deb_ioctl("FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
676         }
677 #endif
678
679         ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
680                                     CMD_ACT_FWT_ACCESS_LIST_ROUTE,
681                                     CMD_OPTION_WAITFORRSP, 0, (void *)&fwt_access);
682
683         if (ret == 0) {
684                 print_route(fwt_access, pbuf);
685         } else
686                 pbuf += sprintf(pbuf, " (null)");
687
688         wrq->u.data.length = strlen(out_str);
689         if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
690                          wrq->u.data.length)) {
691                 lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n");
692                 return -EFAULT;
693         }
694
695         lbs_deb_leave(LBS_DEB_IOCTL);
696         return 0;
697 }
698
699 /**
700  *  @brief          List an entry from the FNT table
701  *  @param priv     A pointer to struct lbs_private structure
702  *  @param req      A pointer to ifreq structure
703  *  @return         0 --success, otherwise fail
704  */
705 static int lbs_fwt_list_neighbor_ioctl(struct lbs_private * priv, struct ifreq *req)
706 {
707         struct iwreq *wrq = (struct iwreq *)req;
708         char in_str[8];
709         static struct cmd_ds_fwt_access fwt_access;
710         char *ptr = in_str;
711         static char out_str[128];
712         char *pbuf = out_str;
713         int ret;
714
715         lbs_deb_enter(LBS_DEB_IOCTL);
716
717         if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
718                 return -EFAULT;
719
720         memset(&fwt_access, 0, sizeof(fwt_access));
721         fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
722
723 #ifdef DEBUG
724         {
725                 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str);
726                 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
727         }
728 #endif
729
730         ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
731                                     CMD_ACT_FWT_ACCESS_LIST_NEIGHBOR,
732                                     CMD_OPTION_WAITFORRSP, 0,
733                                     (void *)&fwt_access);
734
735         if (ret == 0) {
736                 pbuf += sprintf(pbuf, " ra ");
737                 pbuf += eth_addr2str(fwt_access.ra, pbuf);
738                 pbuf += sprintf(pbuf, "  slp %u", fwt_access.sleepmode);
739                 pbuf += sprintf(pbuf, "  snr %u", le32_to_cpu(fwt_access.snr));
740                 pbuf += sprintf(pbuf, "  ref %u", le32_to_cpu(fwt_access.references));
741         } else
742                 pbuf += sprintf(pbuf, " (null)");
743
744         wrq->u.data.length = strlen(out_str);
745         if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
746                          wrq->u.data.length)) {
747                 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n");
748                 return -EFAULT;
749         }
750
751         lbs_deb_leave(LBS_DEB_IOCTL);
752         return 0;
753 }
754
755 /**
756  *  @brief          Cleans up the route (FRT) and neighbor (FNT) tables
757  *                  (Garbage Collection)
758  *  @param priv     A pointer to struct lbs_private structure
759  *  @param req      A pointer to ifreq structure
760  *  @return         0 --success, otherwise fail
761  */
762 static int lbs_fwt_cleanup_ioctl(struct lbs_private * priv, struct ifreq *req)
763 {
764         struct iwreq *wrq = (struct iwreq *)req;
765         static struct cmd_ds_fwt_access fwt_access;
766         int ret;
767
768         lbs_deb_enter(LBS_DEB_IOCTL);
769
770         lbs_deb_ioctl("FWT: cleaning up\n");
771
772         memset(&fwt_access, 0, sizeof(fwt_access));
773
774         ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
775                                     CMD_ACT_FWT_ACCESS_CLEANUP,
776                                     CMD_OPTION_WAITFORRSP, 0,
777                                     (void *)&fwt_access);
778
779         if (ret == 0)
780                 wrq->u.param.value = le32_to_cpu(fwt_access.references);
781         else
782                 return -EFAULT;
783
784         lbs_deb_leave(LBS_DEB_IOCTL);
785         return 0;
786 }
787
788 /**
789  *  @brief          Gets firmware internal time (debug purposes)
790  *  @param priv     A pointer to struct lbs_private structure
791  *  @param req      A pointer to ifreq structure
792  *  @return         0 --success, otherwise fail
793  */
794 static int lbs_fwt_time_ioctl(struct lbs_private * priv, struct ifreq *req)
795 {
796         struct iwreq *wrq = (struct iwreq *)req;
797         static struct cmd_ds_fwt_access fwt_access;
798         int ret;
799
800         lbs_deb_enter(LBS_DEB_IOCTL);
801
802         lbs_deb_ioctl("FWT: getting time\n");
803
804         memset(&fwt_access, 0, sizeof(fwt_access));
805
806         ret = lbs_prepare_and_send_command(priv, CMD_FWT_ACCESS,
807                                     CMD_ACT_FWT_ACCESS_TIME,
808                                     CMD_OPTION_WAITFORRSP, 0,
809                                     (void *)&fwt_access);
810
811         if (ret == 0)
812                 wrq->u.param.value = le32_to_cpu(fwt_access.references);
813         else
814                 return -EFAULT;
815
816         lbs_deb_leave(LBS_DEB_IOCTL);
817         return 0;
818 }
819
820
821 /**
822  *  @brief              Manages all mesh related ioctls
823  *  @param priv         A pointer to struct lbs_private structure
824  *  @param req          A pointer to ifreq structure
825  *  @param cmd          The command type
826  *  @param host_subcmd  The device code for the subcommand
827  *                          0: sets a value in the firmware
828  *                          1: retrieves an int from the firmware
829  *  @return             0 --success, otherwise fail
830  */
831 static int lbs_mesh_ioctl(struct lbs_private * priv, struct iwreq * wrq, 
832                 int cmd, int subcmd)
833 {
834         struct cmd_ds_mesh_access mesh_access;
835         int parameter;
836         char str[128];
837         char *ptr = str;
838         int ret, i;
839
840         lbs_deb_enter(LBS_DEB_IOCTL);
841
842         memset(&mesh_access, 0, sizeof(mesh_access));
843
844         if (cmd == LBS_SETONEINT_GETNONE) {
845                 parameter = SUBCMD_DATA(wrq);
846
847                 /* Convert rate from Mbps -> firmware rate index */
848                 if (subcmd == CMD_ACT_MESH_SET_BCAST_RATE)
849                         parameter = lbs_data_rate_to_fw_index(parameter);
850
851                 if (parameter < 0)
852                         return -EINVAL;
853                 mesh_access.data[0] = cpu_to_le32(parameter);
854         } else if (subcmd == CMD_ACT_MESH_SET_LINK_COSTS) {
855                 if (copy_from_user(str, wrq->u.data.pointer, sizeof(str)))
856                         return -EFAULT;
857
858                 for (i = 0; i < COSTS_LIST_SIZE; i++) {
859                         mesh_access.data[i] = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
860                         if (!(ptr = next_param(ptr)) && i!= (COSTS_LIST_SIZE - 1))
861                                 return -EINVAL;
862                 }
863         }
864
865         ret = lbs_mesh_access(priv, subcmd, &mesh_access);
866
867         if (ret != 0)
868                 return ret;
869
870         if (cmd == LBS_SETNONE_GETONEINT) {
871                 u32 data = le32_to_cpu(mesh_access.data[0]);
872
873                 if (subcmd == CMD_ACT_MESH_GET_BCAST_RATE)
874                         wrq->u.param.value = lbs_fw_index_to_data_rate(data);
875                 else
876                         wrq->u.param.value = data;
877         } else if (subcmd == CMD_ACT_MESH_GET_LINK_COSTS) {
878                 for (i = 0; i < COSTS_LIST_SIZE; i++)
879                         ptr += sprintf (ptr, " %u", le32_to_cpu(mesh_access.data[i]));
880                 wrq->u.data.length = strlen(str);
881
882                 if (copy_to_user(wrq->u.data.pointer, (char *)str,
883                                  wrq->u.data.length)) {
884                         lbs_deb_ioctl("MESH_IOCTL: Copy to user failed!\n");
885                         ret = -EFAULT;
886                 }
887         }
888
889         lbs_deb_leave(LBS_DEB_IOCTL);
890         return ret;
891 }
892
893 /**
894  *  @brief Control Beacon transmissions
895  *  @param priv                 A pointer to struct lbs_private structure
896  *  @param wrq                  A pointer to iwreq structure
897  *  @return                     0 --success, otherwise fail
898  */
899 static int lbs_bcn_ioctl(struct lbs_private * priv, struct iwreq *wrq)
900 {
901         int ret;
902         int data[2];
903
904         memset(data, 0, sizeof(data));
905         if (!wrq->u.data.length) {
906                 lbs_deb_ioctl("Get Beacon control\n");
907                 ret = lbs_prepare_and_send_command(priv,
908                                             CMD_802_11_BEACON_CTRL,
909                                             CMD_ACT_GET,
910                                             CMD_OPTION_WAITFORRSP, 0, NULL);
911                 data[0] = priv->beacon_enable;
912                 data[1] = priv->beacon_period;
913                 if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) {
914                         lbs_deb_ioctl("Copy to user failed\n");
915                         return -EFAULT;
916                 }
917 #define GET_TWO_INT     2
918                 wrq->u.data.length = GET_TWO_INT;
919         } else {
920                 lbs_deb_ioctl("Set beacon control\n");
921                 if (wrq->u.data.length > 2)
922                         return -EINVAL;
923                 if (copy_from_user (data, wrq->u.data.pointer,
924                      sizeof(int) * wrq->u.data.length)) {
925                         lbs_deb_ioctl("Copy from user failed\n");
926                         return -EFAULT;
927                 }
928                 priv->beacon_enable = data[0];
929                 if (wrq->u.data.length > 1) {
930                 if ((data[1] > MRVDRV_MAX_BEACON_INTERVAL)
931                     || (data[1] < MRVDRV_MIN_BEACON_INTERVAL))
932                         return -ENOTSUPP;
933                 priv->beacon_period= data[1];
934                 }
935                 ret = lbs_prepare_and_send_command(priv,
936                                             CMD_802_11_BEACON_CTRL,
937                                             CMD_ACT_SET,
938                                             CMD_OPTION_WAITFORRSP, 0, NULL);
939         }
940         return ret;
941 }
942
943 static int lbs_led_gpio_ioctl(struct lbs_private * priv, struct ifreq *req)
944 {
945         struct iwreq *wrq = (struct iwreq *)req;
946         int i, ret = 0;
947         int data[16];
948         struct cmd_ds_802_11_led_ctrl ctrl;
949         struct mrvlietypes_ledgpio *gpio = (struct mrvlietypes_ledgpio *) ctrl.data;
950         int len = wrq->u.data.length;
951
952         if ((len > MAX_LEDS * 2) || (len % 2 != 0))
953                 return -ENOTSUPP;
954
955         memset(&ctrl, 0, sizeof(ctrl));
956         if (len == 0) {
957                 ctrl.action = cpu_to_le16(CMD_ACT_GET);
958         } else {
959                 if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * len)) {
960                         lbs_deb_ioctl("Copy from user failed\n");
961                         ret = -EFAULT;
962                         goto out;
963                 }
964
965                 ctrl.action = cpu_to_le16(CMD_ACT_SET);
966                 ctrl.numled = cpu_to_le16(0);
967                 gpio->header.type = cpu_to_le16(TLV_TYPE_LED_GPIO);
968                 gpio->header.len = cpu_to_le16(len);
969                 for (i = 0; i < len; i += 2) {
970                         gpio->ledpin[i / 2].led = data[i];
971                         gpio->ledpin[i / 2].pin = data[i + 1];
972                 }
973         }
974
975         ret = lbs_prepare_and_send_command(priv, CMD_802_11_LED_GPIO_CTRL,
976                         0, CMD_OPTION_WAITFORRSP, 0, (void *)&ctrl);
977         if (ret) {
978                 lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret);
979                 goto out;
980         }
981         len = le16_to_cpu(gpio->header.len);
982         for (i = 0; i < len; i += 2) {
983                 data[i] = gpio->ledpin[i / 2].led;
984                 data[i + 1] = gpio->ledpin[i / 2].pin;
985         }
986
987         if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * len)) {
988                 lbs_deb_ioctl("Copy to user failed\n");
989                 ret = -EFAULT;
990                 goto out;
991         }
992
993         wrq->u.data.length = len;
994
995 out:
996         return ret;
997 }
998
999
1000 static int lbs_led_bhv_ioctl(struct lbs_private * priv, struct ifreq *req)
1001 {
1002         struct iwreq *wrq = (struct iwreq *)req;
1003         int i, ret = 0;
1004         int data[MAX_LEDS*4];
1005         int firmwarestate = 0;
1006         struct cmd_ds_802_11_led_ctrl ctrl;
1007         struct mrvlietypes_ledbhv *bhv = (struct mrvlietypes_ledbhv *) ctrl.data;
1008         int len = wrq->u.data.length;
1009
1010         if ((len > MAX_LEDS * 4) ||(len == 0)  )
1011                 return -ENOTSUPP;
1012
1013         memset(&ctrl, 0, sizeof(ctrl));
1014         if (copy_from_user(data, wrq->u.data.pointer, sizeof(int) * len)) {
1015                         lbs_deb_ioctl("Copy from user failed\n");
1016                         ret = -EFAULT;
1017                         goto out;
1018         }
1019         if (len == 1) {
1020                 ctrl.action = cpu_to_le16(CMD_ACT_GET);
1021                 firmwarestate = data[0];
1022         } else {
1023                 
1024                 if (len % 4 != 0 )
1025                         return -ENOTSUPP;
1026
1027                 bhv->header.type = cpu_to_le16(TLV_TYPE_LEDBEHAVIOR);
1028                 bhv->header.len = cpu_to_le16(len);
1029                 ctrl.action = cpu_to_le16(CMD_ACT_SET);
1030                 ctrl.numled = cpu_to_le16(0);
1031                 for (i = 0; i < len; i += 4) {
1032                         bhv->ledbhv[i / 4].firmwarestate = data[i];
1033                         bhv->ledbhv[i / 4].led = data[i + 1];
1034                         bhv->ledbhv[i / 4].ledstate = data[i + 2];
1035                         bhv->ledbhv[i / 4].ledarg = data[i + 3];
1036                 }
1037         }
1038
1039         ret = lbs_prepare_and_send_command(priv, CMD_802_11_LED_GPIO_CTRL,
1040                         0, CMD_OPTION_WAITFORRSP, 0, (void *)&ctrl);
1041         if (ret) {
1042                 lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret);
1043                 goto out;
1044         }
1045
1046         /* Get LED behavior IE, we have received gpio control as well when len 
1047           is equal to 1. */
1048         if (len ==1 ) {
1049                 bhv = (struct mrvlietypes_ledbhv *) 
1050                         ((unsigned char *)bhv->ledbhv + le16_to_cpu(bhv->header.len));
1051                 i = 0;
1052                 while ( i < (MAX_LEDS*4) &&
1053                         (bhv->header.type != cpu_to_le16(MRVL_TERMINATE_TLV_ID)) ) {
1054                         if (bhv->ledbhv[0].firmwarestate == firmwarestate) {
1055                                 data[i++] = bhv->ledbhv[0].firmwarestate;
1056                                 data[i++] = bhv->ledbhv[0].led;
1057                                 data[i++] = bhv->ledbhv[0].ledstate;
1058                                 data[i++] = bhv->ledbhv[0].ledarg;
1059                         }
1060                         bhv++;
1061                 }
1062                 len = i;
1063         } else {
1064                 for (i = 0; i < le16_to_cpu(bhv->header.len); i += 4) {
1065                         data[i] = bhv->ledbhv[i / 4].firmwarestate;
1066                         data[i + 1] = bhv->ledbhv[i / 4].led;
1067                         data[i + 2] = bhv->ledbhv[i / 4].ledstate;
1068                         data[i + 3] = bhv->ledbhv[i / 4].ledarg;
1069                 }
1070                 len = le16_to_cpu(bhv->header.len);
1071         }
1072
1073         if (copy_to_user(wrq->u.data.pointer, data,
1074                          sizeof(int) * len)) {
1075                 lbs_deb_ioctl("Copy to user failed\n");
1076                 ret = -EFAULT;
1077                 goto out;
1078         }
1079
1080         wrq->u.data.length = len;
1081
1082 out:
1083         return ret;
1084 }
1085
1086 /**
1087  *  @brief ioctl function - entry point
1088  *
1089  *  @param dev          A pointer to net_device structure
1090  *  @param req          A pointer to ifreq structure
1091  *  @param cmd          command
1092  *  @return             0--success, otherwise fail
1093  */
1094 int lbs_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
1095 {
1096         int *pdata;
1097         int ret = 0;
1098         struct lbs_private *priv = dev->priv;
1099         struct iwreq *wrq = (struct iwreq *)req;
1100
1101         lbs_deb_enter(LBS_DEB_IOCTL);
1102
1103         lbs_deb_ioctl("lbs_do_ioctl: ioctl cmd = 0x%x\n", cmd);
1104         switch (cmd) {
1105         case LBS_SETNONE_GETNONE:
1106                 switch (wrq->u.data.flags) {
1107                 case LBS_SUBCMD_BT_RESET:
1108                         lbs_bt_reset_ioctl(priv);
1109                         break;
1110                 case LBS_SUBCMD_FWT_RESET:
1111                         lbs_fwt_reset_ioctl(priv);
1112                         break;
1113                 }
1114                 break;
1115
1116         case LBS_SETONEINT_GETNONE:
1117                 switch (wrq->u.mode) {
1118                 case LBS_SUBCMD_SET_REGION:
1119                         ret = lbs_set_region(priv, (u16) SUBCMD_DATA(wrq));
1120                         break;
1121                 case LBS_SUBCMD_MESH_SET_TTL:
1122                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1123                                         CMD_ACT_MESH_SET_TTL);
1124                         break;
1125                 case LBS_SUBCMD_MESH_SET_BCAST_RATE:
1126                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1127                                         CMD_ACT_MESH_SET_BCAST_RATE);
1128                         break;
1129                 case LBS_SUBCMD_MESH_SET_RREQ_DELAY:
1130                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1131                                         CMD_ACT_MESH_SET_RREQ_DELAY);
1132                         break;
1133                 case LBS_SUBCMD_MESH_SET_ROUTE_EXP:
1134                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1135                                         CMD_ACT_MESH_SET_ROUTE_EXP);
1136                         break;
1137                 case LBS_SUBCMD_BT_SET_INVERT:
1138                         ret = lbs_bt_set_invert_ioctl(priv, req);
1139                         break;
1140                 default:
1141                         ret = -EOPNOTSUPP;
1142                         break;
1143                 }
1144                 break;
1145
1146         case LBS_SET128CHAR_GET128CHAR:
1147                 switch ((int)wrq->u.data.flags) {
1148                 case LBS_SUBCMD_BT_ADD:
1149                         ret = lbs_bt_add_ioctl(priv, req);
1150                         break;
1151                 case LBS_SUBCMD_BT_DEL:
1152                         ret = lbs_bt_del_ioctl(priv, req);
1153                         break;
1154                 case LBS_SUBCMD_BT_LIST:
1155                         ret = lbs_bt_list_ioctl(priv, req);
1156                         break;
1157                 case LBS_SUBCMD_FWT_ADD:
1158                         ret = lbs_fwt_add_ioctl(priv, req);
1159                         break;
1160                 case LBS_SUBCMD_FWT_DEL:
1161                         ret = lbs_fwt_del_ioctl(priv, req);
1162                         break;
1163                 case LBS_SUBCMD_FWT_LOOKUP:
1164                         ret = lbs_fwt_lookup_ioctl(priv, req);
1165                         break;
1166                 case LBS_SUBCMD_FWT_LIST_NEIGHBOR:
1167                         ret = lbs_fwt_list_neighbor_ioctl(priv, req);
1168                         break;
1169                 case LBS_SUBCMD_FWT_LIST:
1170                         ret = lbs_fwt_list_ioctl(priv, req);
1171                         break;
1172                 case LBS_SUBCMD_FWT_LIST_ROUTE:
1173                         ret = lbs_fwt_list_route_ioctl(priv, req);
1174                         break;
1175                 case LBS_SUBCMD_MESH_SET_LINK_COSTS:
1176                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1177                                         CMD_ACT_MESH_SET_LINK_COSTS);
1178                         break ;
1179                 case LBS_SUBCMD_MESH_GET_LINK_COSTS:
1180                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1181                                         CMD_ACT_MESH_GET_LINK_COSTS);
1182                         break;
1183                 }
1184                 break;
1185
1186         case LBS_SETNONE_GETONEINT:
1187                 switch (wrq->u.mode) {
1188                 case LBS_SUBCMD_GET_REGION:
1189                         pdata = (int *)wrq->u.name;
1190                         *pdata = (int)priv->regioncode;
1191                         break;
1192                 case LBS_SUBCMD_FWT_CLEANUP:
1193                         ret = lbs_fwt_cleanup_ioctl(priv, req);
1194                         break;
1195                 case LBS_SUBCMD_FWT_TIME:
1196                         ret = lbs_fwt_time_ioctl(priv, req);
1197                         break;
1198                 case LBS_SUBCMD_MESH_GET_TTL:
1199                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1200                                         CMD_ACT_MESH_GET_TTL);
1201                         break;
1202                 case LBS_SUBCMD_MESH_GET_BCAST_RATE:
1203                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1204                                         CMD_ACT_MESH_GET_BCAST_RATE);
1205                         break;
1206                 case LBS_SUBCMD_MESH_GET_RREQ_DELAY:
1207                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1208                                         CMD_ACT_MESH_GET_RREQ_DELAY);
1209                         break;
1210                 case LBS_SUBCMD_MESH_GET_ROUTE_EXP:
1211                         ret = lbs_mesh_ioctl(priv, wrq, cmd,
1212                                         CMD_ACT_MESH_GET_ROUTE_EXP);
1213                         break;
1214                 case LBS_SUBCMD_BT_GET_INVERT:
1215                         ret = lbs_bt_get_invert_ioctl(priv, req);
1216                         break;
1217                 default:
1218                         ret = -EOPNOTSUPP;
1219                 }
1220                 break;
1221
1222         case LBS_SET_GET_SIXTEEN_INT:
1223                 switch ((int)wrq->u.data.flags) {
1224                 case LBS_LED_GPIO_CTRL:
1225                         ret = lbs_led_gpio_ioctl(priv, req);
1226                         break;
1227                 case LBS_BCN_CTRL:
1228                         ret = lbs_bcn_ioctl(priv,wrq);
1229                         break;
1230                 case LBS_LED_BEHAVIOR_CTRL:
1231                         ret = lbs_led_bhv_ioctl(priv, req);
1232                         break;
1233                 }
1234                 break;
1235
1236         default:
1237                 ret = -EINVAL;
1238                 break;
1239         }
1240
1241         lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
1242         return ret;
1243 }