2 * This file contains ioctl functions
5 #include <linux/ctype.h>
6 #include <linux/delay.h>
8 #include <linux/if_arp.h>
9 #include <linux/wireless.h>
11 #include <net/iw_handler.h>
12 #include <net/ieee80211.h>
23 #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \
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 */
29 #define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
31 static int lbs_set_region(struct lbs_private
* priv
, u16 region_code
)
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
;
44 // if it's unidentified region code
45 if (i
>= MRVDRV_MAX_REGION_CODE
) {
46 lbs_deb_ioctl("region Code not identified\n");
51 if (lbs_set_regiontable(priv
, priv
->regioncode
, 0)) {
56 lbs_deb_leave_args(LBS_DEB_IOCTL
, "ret %d", ret
);
60 static inline int hex2int(char c
)
62 if (c
>= '0' && c
<= '9')
64 if (c
>= 'a' && c
<= 'f')
65 return (c
- 'a' + 10);
66 if (c
>= 'A' && c
<= 'F')
67 return (c
- 'A' + 10);
71 /* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx")
72 into binary format (6 bytes).
74 This function expects that each byte is represented with 2 characters
75 (e.g., 11:2:11:11:11:11 is invalid)
78 static char *eth_str2addr(char *ethstr
, u8
* addr
)
83 /* get rid of initial blanks */
84 while (*pos
== ' ' || *pos
== '\t')
87 for (i
= 0; i
< 6; i
++) {
88 val
= hex2int(*pos
++);
91 val2
= hex2int(*pos
++);
94 addr
[i
] = (val
* 16 + val2
) & 0xff;
96 if (i
< 5 && *pos
++ != ':')
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
)
109 for (i
= 0; i
< 6; i
++) {
110 sprintf(pos
, "%02x", addr
[i
] & 0xff);
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
124 static int lbs_bt_add_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
126 struct iwreq
*wrq
= (struct iwreq
*)req
;
127 char ethaddrs_str
[18];
129 u8 ethaddr
[ETH_ALEN
];
132 lbs_deb_enter(LBS_DEB_IOCTL
);
134 if (copy_from_user(ethaddrs_str
, wrq
->u
.data
.pointer
,
135 sizeof(ethaddrs_str
)))
138 if ((pos
= eth_str2addr(ethaddrs_str
, ethaddr
)) == NULL
) {
139 lbs_pr_info("BT_ADD: Invalid MAC address\n");
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
);
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
157 static int lbs_bt_del_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
159 struct iwreq
*wrq
= (struct iwreq
*)req
;
160 char ethaddrs_str
[18];
161 u8 ethaddr
[ETH_ALEN
];
164 lbs_deb_enter(LBS_DEB_IOCTL
);
166 if (copy_from_user(ethaddrs_str
, wrq
->u
.data
.pointer
,
167 sizeof(ethaddrs_str
)))
170 if ((pos
= eth_str2addr(ethaddrs_str
, ethaddr
)) == NULL
) {
171 lbs_pr_info("Invalid MAC address\n");
175 lbs_deb_ioctl("BT: deleting %s\n", ethaddrs_str
);
177 return (lbs_prepare_and_send_command(priv
,
179 CMD_ACT_BT_ACCESS_DEL
,
180 CMD_OPTION_WAITFORRSP
, 0, ethaddr
));
182 lbs_deb_leave(LBS_DEB_IOCTL
);
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
191 static int lbs_bt_reset_ioctl(struct lbs_private
* priv
)
193 lbs_deb_enter(LBS_DEB_IOCTL
);
195 lbs_pr_alert( "BT: resetting\n");
197 return (lbs_prepare_and_send_command(priv
,
199 CMD_ACT_BT_ACCESS_RESET
,
200 CMD_OPTION_WAITFORRSP
, 0, NULL
));
202 lbs_deb_leave(LBS_DEB_IOCTL
);
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
212 static int lbs_bt_list_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
216 struct iwreq
*wrq
= (struct iwreq
*)req
;
217 /* used to pass id and store the bt entry returned by the FW */
220 char addr1addr2
[2 * ETH_ALEN
];
222 static char outstr
[64];
226 lbs_deb_enter(LBS_DEB_IOCTL
);
228 if (copy_from_user(outstr
, wrq
->u
.data
.pointer
, sizeof(outstr
))) {
229 lbs_deb_ioctl("Copy from user failed\n");
232 param
.id
= simple_strtoul(outstr
, NULL
, 10);
233 pos
= sprintf(pbuf
, "%d: ", param
.id
);
236 ret
= lbs_prepare_and_send_command(priv
, CMD_BT_ACCESS
,
237 CMD_ACT_BT_ACCESS_LIST
,
238 CMD_OPTION_WAITFORRSP
, 0,
242 addr1
= param
.addr1addr2
;
244 pos
= sprintf(pbuf
, "BT includes node ");
246 pos
= eth_addr2str(addr1
, pbuf
);
249 sprintf(pbuf
, "(null)");
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");
260 lbs_deb_leave(LBS_DEB_IOCTL
);
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
270 static int lbs_bt_set_invert_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
273 struct iwreq
*wrq
= (struct iwreq
*)req
;
276 char addr1addr2
[2 * ETH_ALEN
];
279 lbs_deb_enter(LBS_DEB_IOCTL
);
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,
288 lbs_deb_leave(LBS_DEB_IOCTL
);
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
298 static int lbs_bt_get_invert_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
300 struct iwreq
*wrq
= (struct iwreq
*)req
;
304 char addr1addr2
[2 * ETH_ALEN
];
307 lbs_deb_enter(LBS_DEB_IOCTL
);
309 ret
= lbs_prepare_and_send_command(priv
, CMD_BT_ACCESS
,
310 CMD_ACT_BT_ACCESS_GET_INVERT
,
311 CMD_OPTION_WAITFORRSP
, 0,
315 wrq
->u
.param
.value
= le32_to_cpu(param
.id
);
319 lbs_deb_leave(LBS_DEB_IOCTL
);
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.
328 static char * next_param(char * ptr
)
330 if (!ptr
) return NULL
;
331 while (*ptr
== ' ' || *ptr
== '\t') ++ptr
;
332 return (*ptr
== '\0') ? NULL
: ptr
;
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
341 static int lbs_fwt_add_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
343 struct iwreq
*wrq
= (struct iwreq
*)req
;
345 static struct cmd_ds_fwt_access fwt_access
;
349 lbs_deb_enter(LBS_DEB_IOCTL
);
351 if (copy_from_user(in_str
, wrq
->u
.data
.pointer
, sizeof(in_str
)))
354 if ((ptr
= eth_str2addr(in_str
, fwt_access
.da
)) == NULL
) {
355 lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
359 if ((ptr
= eth_str2addr(ptr
, fwt_access
.ra
)) == NULL
) {
360 lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
364 if ((ptr
= next_param(ptr
)))
366 cpu_to_le32(simple_strtoul(ptr
, &ptr
, 10));
368 fwt_access
.metric
= cpu_to_le32(FWT_DEFAULT_METRIC
);
370 if ((ptr
= next_param(ptr
)))
371 fwt_access
.dir
= (u8
)simple_strtoul(ptr
, &ptr
, 10);
373 fwt_access
.dir
= FWT_DEFAULT_DIR
;
375 if ((ptr
= next_param(ptr
)))
376 fwt_access
.rate
= (u8
) simple_strtoul(ptr
, &ptr
, 10);
378 fwt_access
.rate
= FWT_DEFAULT_RATE
;
380 if ((ptr
= next_param(ptr
)))
382 cpu_to_le32(simple_strtoul(ptr
, &ptr
, 10));
384 fwt_access
.ssn
= cpu_to_le32(FWT_DEFAULT_SSN
);
386 if ((ptr
= next_param(ptr
)))
388 cpu_to_le32(simple_strtoul(ptr
, &ptr
, 10));
390 fwt_access
.dsn
= cpu_to_le32(FWT_DEFAULT_DSN
);
392 if ((ptr
= next_param(ptr
)))
393 fwt_access
.hopcount
= simple_strtoul(ptr
, &ptr
, 10);
395 fwt_access
.hopcount
= FWT_DEFAULT_HOPCOUNT
;
397 if ((ptr
= next_param(ptr
)))
398 fwt_access
.ttl
= simple_strtoul(ptr
, &ptr
, 10);
400 fwt_access
.ttl
= FWT_DEFAULT_TTL
;
402 if ((ptr
= next_param(ptr
)))
403 fwt_access
.expiration
=
404 cpu_to_le32(simple_strtoul(ptr
, &ptr
, 10));
406 fwt_access
.expiration
= cpu_to_le32(FWT_DEFAULT_EXPIRATION
);
408 if ((ptr
= next_param(ptr
)))
409 fwt_access
.sleepmode
= (u8
)simple_strtoul(ptr
, &ptr
, 10);
411 fwt_access
.sleepmode
= FWT_DEFAULT_SLEEPMODE
;
413 if ((ptr
= next_param(ptr
)))
415 cpu_to_le32(simple_strtoul(ptr
, &ptr
, 10));
417 fwt_access
.snr
= cpu_to_le32(FWT_DEFAULT_SNR
);
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
);
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
);
438 lbs_deb_leave_args(LBS_DEB_IOCTL
, "ret %d", ret
);
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
448 static int lbs_fwt_del_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
450 struct iwreq
*wrq
= (struct iwreq
*)req
;
452 static struct cmd_ds_fwt_access fwt_access
;
456 lbs_deb_enter(LBS_DEB_IOCTL
);
458 if (copy_from_user(in_str
, wrq
->u
.data
.pointer
, sizeof(in_str
)))
461 if ((ptr
= eth_str2addr(in_str
, fwt_access
.da
)) == NULL
) {
462 lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
466 if ((ptr
= eth_str2addr(ptr
, fwt_access
.ra
)) == NULL
) {
467 lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
471 if ((ptr
= next_param(ptr
)))
472 fwt_access
.dir
= (u8
)simple_strtoul(ptr
, &ptr
, 10);
474 fwt_access
.dir
= FWT_DEFAULT_DIR
;
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
);
487 ret
= lbs_prepare_and_send_command(priv
,
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
);
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
502 static void print_route(struct cmd_ds_fwt_access fwt_access
, char *buf
)
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
);
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
528 static int lbs_fwt_lookup_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
530 struct iwreq
*wrq
= (struct iwreq
*)req
;
533 static struct cmd_ds_fwt_access fwt_access
;
534 static char out_str
[128];
537 lbs_deb_enter(LBS_DEB_IOCTL
);
539 if (copy_from_user(in_str
, wrq
->u
.data
.pointer
, sizeof(in_str
)))
542 if ((ptr
= eth_str2addr(in_str
, fwt_access
.da
)) == NULL
) {
543 lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
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
);
556 ret
= lbs_prepare_and_send_command(priv
,
558 CMD_ACT_FWT_ACCESS_LOOKUP
,
559 CMD_OPTION_WAITFORRSP
, 0,
560 (void *)&fwt_access
);
563 print_route(fwt_access
, out_str
);
565 sprintf(out_str
, "(null)");
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");
574 lbs_deb_leave(LBS_DEB_IOCTL
);
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
583 static int lbs_fwt_reset_ioctl(struct lbs_private
* priv
)
585 lbs_deb_ioctl("FWT: resetting\n");
587 return (lbs_prepare_and_send_command(priv
,
589 CMD_ACT_FWT_ACCESS_RESET
,
590 CMD_OPTION_WAITFORRSP
, 0, NULL
));
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
599 static int lbs_fwt_list_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
601 struct iwreq
*wrq
= (struct iwreq
*)req
;
603 static struct cmd_ds_fwt_access fwt_access
;
605 static char out_str
[128];
606 char *pbuf
= out_str
;
609 lbs_deb_enter(LBS_DEB_IOCTL
);
611 if (copy_from_user(in_str
, wrq
->u
.data
.pointer
, sizeof(in_str
))) {
616 fwt_access
.id
= cpu_to_le32(simple_strtoul(ptr
, &ptr
, 10));
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
));
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
);
630 print_route(fwt_access
, pbuf
);
632 pbuf
+= sprintf(pbuf
, " (null)");
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");
645 lbs_deb_leave(LBS_DEB_IOCTL
);
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
655 static int lbs_fwt_list_route_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
657 struct iwreq
*wrq
= (struct iwreq
*)req
;
659 static struct cmd_ds_fwt_access fwt_access
;
661 static char out_str
[128];
662 char *pbuf
= out_str
;
665 lbs_deb_enter(LBS_DEB_IOCTL
);
667 if (copy_from_user(in_str
, wrq
->u
.data
.pointer
, sizeof(in_str
)))
670 fwt_access
.id
= cpu_to_le32(simple_strtoul(ptr
, &ptr
, 10));
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
));
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
);
684 print_route(fwt_access
, pbuf
);
686 pbuf
+= sprintf(pbuf
, " (null)");
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");
695 lbs_deb_leave(LBS_DEB_IOCTL
);
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
705 static int lbs_fwt_list_neighbor_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
707 struct iwreq
*wrq
= (struct iwreq
*)req
;
709 static struct cmd_ds_fwt_access fwt_access
;
711 static char out_str
[128];
712 char *pbuf
= out_str
;
715 lbs_deb_enter(LBS_DEB_IOCTL
);
717 if (copy_from_user(in_str
, wrq
->u
.data
.pointer
, sizeof(in_str
)))
720 memset(&fwt_access
, 0, sizeof(fwt_access
));
721 fwt_access
.id
= cpu_to_le32(simple_strtoul(ptr
, &ptr
, 10));
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
));
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
);
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
));
742 pbuf
+= sprintf(pbuf
, " (null)");
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");
751 lbs_deb_leave(LBS_DEB_IOCTL
);
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
762 static int lbs_fwt_cleanup_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
764 struct iwreq
*wrq
= (struct iwreq
*)req
;
765 static struct cmd_ds_fwt_access fwt_access
;
768 lbs_deb_enter(LBS_DEB_IOCTL
);
770 lbs_deb_ioctl("FWT: cleaning up\n");
772 memset(&fwt_access
, 0, sizeof(fwt_access
));
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
);
780 wrq
->u
.param
.value
= le32_to_cpu(fwt_access
.references
);
784 lbs_deb_leave(LBS_DEB_IOCTL
);
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
794 static int lbs_fwt_time_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
796 struct iwreq
*wrq
= (struct iwreq
*)req
;
797 static struct cmd_ds_fwt_access fwt_access
;
800 lbs_deb_enter(LBS_DEB_IOCTL
);
802 lbs_deb_ioctl("FWT: getting time\n");
804 memset(&fwt_access
, 0, sizeof(fwt_access
));
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
);
812 wrq
->u
.param
.value
= le32_to_cpu(fwt_access
.references
);
816 lbs_deb_leave(LBS_DEB_IOCTL
);
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
831 static int lbs_mesh_ioctl(struct lbs_private
* priv
, struct iwreq
* wrq
,
834 struct cmd_ds_mesh_access mesh_access
;
840 lbs_deb_enter(LBS_DEB_IOCTL
);
842 memset(&mesh_access
, 0, sizeof(mesh_access
));
844 if (cmd
== LBS_SETONEINT_GETNONE
) {
845 parameter
= SUBCMD_DATA(wrq
);
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
);
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
)))
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))
865 ret
= lbs_mesh_access(priv
, subcmd
, &mesh_access
);
870 if (cmd
== LBS_SETNONE_GETONEINT
) {
871 u32 data
= le32_to_cpu(mesh_access
.data
[0]);
873 if (subcmd
== CMD_ACT_MESH_GET_BCAST_RATE
)
874 wrq
->u
.param
.value
= lbs_fw_index_to_data_rate(data
);
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
);
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");
889 lbs_deb_leave(LBS_DEB_IOCTL
);
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
899 static int lbs_bcn_ioctl(struct lbs_private
* priv
, struct iwreq
*wrq
)
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
,
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");
917 #define GET_TWO_INT 2
918 wrq
->u
.data
.length
= GET_TWO_INT
;
920 lbs_deb_ioctl("Set beacon control\n");
921 if (wrq
->u
.data
.length
> 2)
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");
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
))
933 priv
->beacon_period
= data
[1];
935 ret
= lbs_prepare_and_send_command(priv
,
936 CMD_802_11_BEACON_CTRL
,
938 CMD_OPTION_WAITFORRSP
, 0, NULL
);
943 static int lbs_led_gpio_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
945 struct iwreq
*wrq
= (struct iwreq
*)req
;
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
;
952 if ((len
> MAX_LEDS
* 2) || (len
% 2 != 0))
955 memset(&ctrl
, 0, sizeof(ctrl
));
957 ctrl
.action
= cpu_to_le16(CMD_ACT_GET
);
959 if (copy_from_user(data
, wrq
->u
.data
.pointer
, sizeof(int) * len
)) {
960 lbs_deb_ioctl("Copy from user failed\n");
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];
975 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_LED_GPIO_CTRL
,
976 0, CMD_OPTION_WAITFORRSP
, 0, (void *)&ctrl
);
978 lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret
);
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
;
987 if (copy_to_user(wrq
->u
.data
.pointer
, data
, sizeof(int) * len
)) {
988 lbs_deb_ioctl("Copy to user failed\n");
993 wrq
->u
.data
.length
= len
;
1000 static int lbs_led_bhv_ioctl(struct lbs_private
* priv
, struct ifreq
*req
)
1002 struct iwreq
*wrq
= (struct iwreq
*)req
;
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
;
1010 if ((len
> MAX_LEDS
* 4) ||(len
== 0) )
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");
1020 ctrl
.action
= cpu_to_le16(CMD_ACT_GET
);
1021 firmwarestate
= data
[0];
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];
1039 ret
= lbs_prepare_and_send_command(priv
, CMD_802_11_LED_GPIO_CTRL
,
1040 0, CMD_OPTION_WAITFORRSP
, 0, (void *)&ctrl
);
1042 lbs_deb_ioctl("Error doing LED GPIO control: %d\n", ret
);
1046 /* Get LED behavior IE, we have received gpio control as well when len
1049 bhv
= (struct mrvlietypes_ledbhv
*)
1050 ((unsigned char *)bhv
->ledbhv
+ le16_to_cpu(bhv
->header
.len
));
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
;
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
;
1070 len
= le16_to_cpu(bhv
->header
.len
);
1073 if (copy_to_user(wrq
->u
.data
.pointer
, data
,
1074 sizeof(int) * len
)) {
1075 lbs_deb_ioctl("Copy to user failed\n");
1080 wrq
->u
.data
.length
= len
;
1087 * @brief ioctl function - entry point
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
1094 int lbs_do_ioctl(struct net_device
*dev
, struct ifreq
*req
, int cmd
)
1098 struct lbs_private
*priv
= dev
->priv
;
1099 struct iwreq
*wrq
= (struct iwreq
*)req
;
1101 lbs_deb_enter(LBS_DEB_IOCTL
);
1103 lbs_deb_ioctl("lbs_do_ioctl: ioctl cmd = 0x%x\n", cmd
);
1105 case LBS_SETNONE_GETNONE
:
1106 switch (wrq
->u
.data
.flags
) {
1107 case LBS_SUBCMD_BT_RESET
:
1108 lbs_bt_reset_ioctl(priv
);
1110 case LBS_SUBCMD_FWT_RESET
:
1111 lbs_fwt_reset_ioctl(priv
);
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
));
1121 case LBS_SUBCMD_MESH_SET_TTL
:
1122 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1123 CMD_ACT_MESH_SET_TTL
);
1125 case LBS_SUBCMD_MESH_SET_BCAST_RATE
:
1126 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1127 CMD_ACT_MESH_SET_BCAST_RATE
);
1129 case LBS_SUBCMD_MESH_SET_RREQ_DELAY
:
1130 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1131 CMD_ACT_MESH_SET_RREQ_DELAY
);
1133 case LBS_SUBCMD_MESH_SET_ROUTE_EXP
:
1134 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1135 CMD_ACT_MESH_SET_ROUTE_EXP
);
1137 case LBS_SUBCMD_BT_SET_INVERT
:
1138 ret
= lbs_bt_set_invert_ioctl(priv
, req
);
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
);
1151 case LBS_SUBCMD_BT_DEL
:
1152 ret
= lbs_bt_del_ioctl(priv
, req
);
1154 case LBS_SUBCMD_BT_LIST
:
1155 ret
= lbs_bt_list_ioctl(priv
, req
);
1157 case LBS_SUBCMD_FWT_ADD
:
1158 ret
= lbs_fwt_add_ioctl(priv
, req
);
1160 case LBS_SUBCMD_FWT_DEL
:
1161 ret
= lbs_fwt_del_ioctl(priv
, req
);
1163 case LBS_SUBCMD_FWT_LOOKUP
:
1164 ret
= lbs_fwt_lookup_ioctl(priv
, req
);
1166 case LBS_SUBCMD_FWT_LIST_NEIGHBOR
:
1167 ret
= lbs_fwt_list_neighbor_ioctl(priv
, req
);
1169 case LBS_SUBCMD_FWT_LIST
:
1170 ret
= lbs_fwt_list_ioctl(priv
, req
);
1172 case LBS_SUBCMD_FWT_LIST_ROUTE
:
1173 ret
= lbs_fwt_list_route_ioctl(priv
, req
);
1175 case LBS_SUBCMD_MESH_SET_LINK_COSTS
:
1176 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1177 CMD_ACT_MESH_SET_LINK_COSTS
);
1179 case LBS_SUBCMD_MESH_GET_LINK_COSTS
:
1180 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1181 CMD_ACT_MESH_GET_LINK_COSTS
);
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
;
1192 case LBS_SUBCMD_FWT_CLEANUP
:
1193 ret
= lbs_fwt_cleanup_ioctl(priv
, req
);
1195 case LBS_SUBCMD_FWT_TIME
:
1196 ret
= lbs_fwt_time_ioctl(priv
, req
);
1198 case LBS_SUBCMD_MESH_GET_TTL
:
1199 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1200 CMD_ACT_MESH_GET_TTL
);
1202 case LBS_SUBCMD_MESH_GET_BCAST_RATE
:
1203 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1204 CMD_ACT_MESH_GET_BCAST_RATE
);
1206 case LBS_SUBCMD_MESH_GET_RREQ_DELAY
:
1207 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1208 CMD_ACT_MESH_GET_RREQ_DELAY
);
1210 case LBS_SUBCMD_MESH_GET_ROUTE_EXP
:
1211 ret
= lbs_mesh_ioctl(priv
, wrq
, cmd
,
1212 CMD_ACT_MESH_GET_ROUTE_EXP
);
1214 case LBS_SUBCMD_BT_GET_INVERT
:
1215 ret
= lbs_bt_get_invert_ioctl(priv
, req
);
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
);
1228 ret
= lbs_bcn_ioctl(priv
,wrq
);
1230 case LBS_LED_BEHAVIOR_CTRL
:
1231 ret
= lbs_led_bhv_ioctl(priv
, req
);
1241 lbs_deb_leave_args(LBS_DEB_IOCTL
, "ret %d", ret
);