blob: 5a5863239067ec27ae96d7d6360b83703fa7733e [file] [log] [blame]
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001/**
2 * This file contains ioctl functions
3 */
4
5#include <linux/ctype.h>
6#include <linux/delay.h>
7#include <linux/if.h>
8#include <linux/if_arp.h>
9#include <linux/wireless.h>
10
11#include <net/iw_handler.h>
12#include <net/ieee80211.h>
13
14#include "host.h"
15#include "radiotap.h"
16#include "decl.h"
17#include "defs.h"
18#include "dev.h"
19#include "join.h"
20#include "wext.h"
21
22#define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \
23 IW_ESSID_MAX_SIZE + \
24 IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \
25 IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \
26 IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */
27
28#define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ)
29
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020030static int wlan_set_region(wlan_private * priv, u16 region_code)
31{
32 int i;
Holger Schurig9012b282007-05-25 11:27:16 -040033 int ret = 0;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020034
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) {
Holger Schurig9012b282007-05-25 11:27:16 -040046 lbs_deb_ioctl("region Code not identified\n");
47 ret = -1;
48 goto done;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020049 }
50
51 if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) {
Holger Schurig9012b282007-05-25 11:27:16 -040052 ret = -EINVAL;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020053 }
54
Holger Schurig9012b282007-05-25 11:27:16 -040055done:
56 lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
57 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020058}
59
Marcelo Tosatti876c9d32007-02-10 12:25:27 -020060static 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 */
78static 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) */
104static 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 */
124static 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];
Holger Schurig9012b282007-05-25 11:27:16 -0400130 int ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200131
Holger Schurig9012b282007-05-25 11:27:16 -0400132 lbs_deb_enter(LBS_DEB_IOCTL);
133
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200134 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
Holger Schurig9012b282007-05-25 11:27:16 -0400143 lbs_deb_ioctl("BT: adding %s\n", ethaddrs_str);
144 ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200145 cmd_act_bt_access_add,
Holger Schurig9012b282007-05-25 11:27:16 -0400146 cmd_option_waitforrsp, 0, ethaddr);
147 lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
148 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200149}
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 */
157static 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
Holger Schurig9012b282007-05-25 11:27:16 -0400164 lbs_deb_enter(LBS_DEB_IOCTL);
165
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200166 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
Holger Schurig9012b282007-05-25 11:27:16 -0400175 lbs_deb_ioctl("BT: deleting %s\n", ethaddrs_str);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200176
177 return (libertas_prepare_and_send_command(priv,
178 cmd_bt_access,
179 cmd_act_bt_access_del,
180 cmd_option_waitforrsp, 0, ethaddr));
Holger Schurig9012b282007-05-25 11:27:16 -0400181
182 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200183 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 */
191static int wlan_bt_reset_ioctl(wlan_private * priv)
192{
Holger Schurig9012b282007-05-25 11:27:16 -0400193 lbs_deb_enter(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200194
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
Holger Schurig9012b282007-05-25 11:27:16 -0400202 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200203 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 */
212static 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
Holger Schurig9012b282007-05-25 11:27:16 -0400226 lbs_deb_enter(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200227
228 if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) {
Holger Schurig9012b282007-05-25 11:27:16 -0400229 lbs_deb_ioctl("Copy from user failed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200230 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
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400244 pos = sprintf(pbuf, "BT includes node ");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200245 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)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400256 lbs_deb_ioctl("BT_LIST: Copy to user failed!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200257 return -EFAULT;
258 }
259
Holger Schurig9012b282007-05-25 11:27:16 -0400260 lbs_deb_leave(LBS_DEB_IOCTL);
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400261 return 0 ;
262}
263
264/**
265 * @brief Sets inverted state of blacklist (non-zero if inverted)
266 * @param priv A pointer to wlan_private structure
267 * @param req A pointer to ifreq structure
268 * @return 0 --success, otherwise fail
269 */
270static int wlan_bt_set_invert_ioctl(wlan_private * priv, struct ifreq *req)
271{
272 int ret;
273 struct iwreq *wrq = (struct iwreq *)req;
274 union {
275 int id;
276 char addr1addr2[2 * ETH_ALEN];
277 } param;
278
279 lbs_deb_enter(LBS_DEB_IOCTL);
280
281 param.id = SUBCMD_DATA(wrq) ;
282 ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
283 cmd_act_bt_access_set_invert,
284 cmd_option_waitforrsp, 0,
285 (char *)&param);
286 if (ret != 0)
287 return -EFAULT;
288 lbs_deb_leave(LBS_DEB_IOCTL);
289 return 0;
290}
291
292/**
293 * @brief Gets inverted state of blacklist (non-zero if inverted)
294 * @param priv A pointer to wlan_private structure
295 * @param req A pointer to ifreq structure
296 * @return 0 --success, otherwise fail
297 */
298static int wlan_bt_get_invert_ioctl(wlan_private * priv, struct ifreq *req)
299{
300 int ret;
301 union {
302 int id;
303 char addr1addr2[2 * ETH_ALEN];
304 } param;
305
306 lbs_deb_enter(LBS_DEB_IOCTL);
307
308 ret = libertas_prepare_and_send_command(priv, cmd_bt_access,
309 cmd_act_bt_access_get_invert,
310 cmd_option_waitforrsp, 0,
311 (char *)&param);
312
313 if (ret == 0)
314 req->ifr_data = (char *)(le32_to_cpu(param.id));
315 else
316 return -EFAULT;
317
318 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200319 return 0;
320}
321
322/**
323 * @brief Find the next parameter in an input string
324 * @param ptr A pointer to the input parameter string
325 * @return A pointer to the next parameter, or 0 if no parameters left.
326 */
327static char * next_param(char * ptr)
328{
329 if (!ptr) return NULL;
330 while (*ptr == ' ' || *ptr == '\t') ++ptr;
331 return (*ptr == '\0') ? NULL : ptr;
332}
333
334/**
335 * @brief Add an entry to the FWT table
336 * @param priv A pointer to wlan_private structure
337 * @param req A pointer to ifreq structure
338 * @return 0 --success, otherwise fail
339 */
340static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req)
341{
342 struct iwreq *wrq = (struct iwreq *)req;
343 char in_str[128];
344 static struct cmd_ds_fwt_access fwt_access;
345 char *ptr;
Holger Schurig9012b282007-05-25 11:27:16 -0400346 int ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200347
Holger Schurig9012b282007-05-25 11:27:16 -0400348 lbs_deb_enter(LBS_DEB_IOCTL);
349
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200350 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
351 return -EFAULT;
352
353 if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
354 lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n");
355 return -EINVAL;
356 }
357
358 if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
359 lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n");
360 return -EINVAL;
361 }
362
363 if ((ptr = next_param(ptr)))
364 fwt_access.metric =
365 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
366 else
367 fwt_access.metric = FWT_DEFAULT_METRIC;
368
369 if ((ptr = next_param(ptr)))
370 fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
371 else
372 fwt_access.dir = FWT_DEFAULT_DIR;
373
374 if ((ptr = next_param(ptr)))
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400375 fwt_access.rate = (u8) simple_strtoul(ptr, &ptr, 10);
376 else
377 fwt_access.rate = FWT_DEFAULT_RATE;
378
379 if ((ptr = next_param(ptr)))
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200380 fwt_access.ssn =
381 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
382 else
383 fwt_access.ssn = FWT_DEFAULT_SSN;
384
385 if ((ptr = next_param(ptr)))
386 fwt_access.dsn =
387 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
388 else
389 fwt_access.dsn = FWT_DEFAULT_DSN;
390
391 if ((ptr = next_param(ptr)))
392 fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10);
393 else
394 fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT;
395
396 if ((ptr = next_param(ptr)))
397 fwt_access.ttl = simple_strtoul(ptr, &ptr, 10);
398 else
399 fwt_access.ttl = FWT_DEFAULT_TTL;
400
401 if ((ptr = next_param(ptr)))
402 fwt_access.expiration =
403 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
404 else
405 fwt_access.expiration = FWT_DEFAULT_EXPIRATION;
406
407 if ((ptr = next_param(ptr)))
408 fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10);
409 else
410 fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE;
411
412 if ((ptr = next_param(ptr)))
413 fwt_access.snr =
414 cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
415 else
416 fwt_access.snr = FWT_DEFAULT_SNR;
417
418#ifdef DEBUG
419 {
420 char ethaddr1_str[18], ethaddr2_str[18];
421 eth_addr2str(fwt_access.da, ethaddr1_str);
422 eth_addr2str(fwt_access.ra, ethaddr2_str);
Holger Schurig9012b282007-05-25 11:27:16 -0400423 lbs_deb_ioctl("FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200424 fwt_access.dir, ethaddr2_str);
Holger Schurig9012b282007-05-25 11:27:16 -0400425 lbs_deb_ioctl("FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n",
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200426 fwt_access.ssn, fwt_access.dsn, fwt_access.metric,
427 fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration,
428 fwt_access.sleepmode, fwt_access.snr);
429 }
430#endif
431
Holger Schurig9012b282007-05-25 11:27:16 -0400432 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
433 cmd_act_fwt_access_add,
434 cmd_option_waitforrsp, 0,
435 (void *)&fwt_access);
436
437 lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
438 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200439}
440
441/**
442 * @brief Delete an entry from the FWT table
443 * @param priv A pointer to wlan_private structure
444 * @param req A pointer to ifreq structure
445 * @return 0 --success, otherwise fail
446 */
447static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req)
448{
449 struct iwreq *wrq = (struct iwreq *)req;
450 char in_str[64];
451 static struct cmd_ds_fwt_access fwt_access;
452 char *ptr;
Holger Schurig9012b282007-05-25 11:27:16 -0400453 int ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200454
Holger Schurig9012b282007-05-25 11:27:16 -0400455 lbs_deb_enter(LBS_DEB_IOCTL);
456
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200457 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
458 return -EFAULT;
459
460 if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
461 lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n");
462 return -EINVAL;
463 }
464
465 if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) {
466 lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n");
467 return -EINVAL;
468 }
469
470 if ((ptr = next_param(ptr)))
471 fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10);
472 else
473 fwt_access.dir = FWT_DEFAULT_DIR;
474
475#ifdef DEBUG
476 {
477 char ethaddr1_str[18], ethaddr2_str[18];
Holger Schurig9012b282007-05-25 11:27:16 -0400478 lbs_deb_ioctl("FWT_DEL: line is %s\n", in_str);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200479 eth_addr2str(fwt_access.da, ethaddr1_str);
480 eth_addr2str(fwt_access.ra, ethaddr2_str);
Holger Schurig9012b282007-05-25 11:27:16 -0400481 lbs_deb_ioctl("FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str,
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200482 ethaddr2_str, fwt_access.dir);
483 }
484#endif
485
Holger Schurig9012b282007-05-25 11:27:16 -0400486 ret = libertas_prepare_and_send_command(priv,
487 cmd_fwt_access,
488 cmd_act_fwt_access_del,
489 cmd_option_waitforrsp, 0,
490 (void *)&fwt_access);
491 lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
492 return ret;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200493}
494
495
496/**
497 * @brief Print route parameters
498 * @param fwt_access struct cmd_ds_fwt_access with route info
499 * @param buf destination buffer for route info
500 */
501static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf)
502{
503 buf += sprintf(buf, " ");
504 buf += eth_addr2str(fwt_access.da, buf);
505 buf += sprintf(buf, " ");
506 buf += eth_addr2str(fwt_access.ra, buf);
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400507 buf += sprintf(buf, " %u", fwt_access.valid);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200508 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric));
509 buf += sprintf(buf, " %u", fwt_access.dir);
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400510 buf += sprintf(buf, " %u", fwt_access.rate);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200511 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn));
512 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn));
513 buf += sprintf(buf, " %u", fwt_access.hopcount);
514 buf += sprintf(buf, " %u", fwt_access.ttl);
515 buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration));
516 buf += sprintf(buf, " %u", fwt_access.sleepmode);
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400517 buf += sprintf(buf, " %u ", le32_to_cpu(fwt_access.snr));
518 buf += eth_addr2str(fwt_access.prec, buf);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200519}
520
521/**
522 * @brief Lookup an entry in the FWT table
523 * @param priv A pointer to wlan_private structure
524 * @param req A pointer to ifreq structure
525 * @return 0 --success, otherwise fail
526 */
527static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req)
528{
529 struct iwreq *wrq = (struct iwreq *)req;
530 char in_str[64];
531 char *ptr;
532 static struct cmd_ds_fwt_access fwt_access;
533 static char out_str[128];
534 int ret;
535
Holger Schurig9012b282007-05-25 11:27:16 -0400536 lbs_deb_enter(LBS_DEB_IOCTL);
537
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200538 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
539 return -EFAULT;
540
541 if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) {
542 lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n");
543 return -EINVAL;
544 }
545
546#ifdef DEBUG
547 {
548 char ethaddr1_str[18];
Holger Schurig9012b282007-05-25 11:27:16 -0400549 lbs_deb_ioctl("FWT_LOOKUP: line is %s\n", in_str);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200550 eth_addr2str(fwt_access.da, ethaddr1_str);
Holger Schurig9012b282007-05-25 11:27:16 -0400551 lbs_deb_ioctl("FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200552 }
553#endif
554
555 ret = libertas_prepare_and_send_command(priv,
556 cmd_fwt_access,
557 cmd_act_fwt_access_lookup,
558 cmd_option_waitforrsp, 0,
559 (void *)&fwt_access);
560
561 if (ret == 0)
562 print_route(fwt_access, out_str);
563 else
564 sprintf(out_str, "(null)");
565
566 wrq->u.data.length = strlen(out_str);
567 if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
568 wrq->u.data.length)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400569 lbs_deb_ioctl("FWT_LOOKUP: Copy to user failed!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200570 return -EFAULT;
571 }
572
Holger Schurig9012b282007-05-25 11:27:16 -0400573 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200574 return 0;
575}
576
577/**
578 * @brief Reset all entries from the FWT table
579 * @param priv A pointer to wlan_private structure
580 * @return 0 --success, otherwise fail
581 */
582static int wlan_fwt_reset_ioctl(wlan_private * priv)
583{
Holger Schurig9012b282007-05-25 11:27:16 -0400584 lbs_deb_ioctl("FWT: resetting\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200585
586 return (libertas_prepare_and_send_command(priv,
587 cmd_fwt_access,
588 cmd_act_fwt_access_reset,
589 cmd_option_waitforrsp, 0, NULL));
590}
591
592/**
593 * @brief List an entry from the FWT table
594 * @param priv A pointer to wlan_private structure
595 * @param req A pointer to ifreq structure
596 * @return 0 --success, otherwise fail
597 */
598static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req)
599{
600 struct iwreq *wrq = (struct iwreq *)req;
601 char in_str[8];
602 static struct cmd_ds_fwt_access fwt_access;
603 char *ptr = in_str;
604 static char out_str[128];
605 char *pbuf = out_str;
606 int ret;
607
Holger Schurig9012b282007-05-25 11:27:16 -0400608 lbs_deb_enter(LBS_DEB_IOCTL);
609
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200610 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
611 return -EFAULT;
612
613 fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
614
615#ifdef DEBUG
616 {
Holger Schurig9012b282007-05-25 11:27:16 -0400617 lbs_deb_ioctl("FWT_LIST: line is %s\n", in_str);
618 lbs_deb_ioctl("FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200619 }
620#endif
621
622 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
623 cmd_act_fwt_access_list,
624 cmd_option_waitforrsp, 0, (void *)&fwt_access);
625
626 if (ret == 0)
627 print_route(fwt_access, pbuf);
628 else
629 pbuf += sprintf(pbuf, " (null)");
630
631 wrq->u.data.length = strlen(out_str);
632 if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
633 wrq->u.data.length)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400634 lbs_deb_ioctl("FWT_LIST: Copy to user failed!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200635 return -EFAULT;
636 }
637
Holger Schurig9012b282007-05-25 11:27:16 -0400638 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200639 return 0;
640}
641
642/**
643 * @brief List an entry from the FRT table
644 * @param priv A pointer to wlan_private structure
645 * @param req A pointer to ifreq structure
646 * @return 0 --success, otherwise fail
647 */
648static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req)
649{
650 struct iwreq *wrq = (struct iwreq *)req;
651 char in_str[64];
652 static struct cmd_ds_fwt_access fwt_access;
653 char *ptr = in_str;
654 static char out_str[128];
655 char *pbuf = out_str;
656 int ret;
657
Holger Schurig9012b282007-05-25 11:27:16 -0400658 lbs_deb_enter(LBS_DEB_IOCTL);
659
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200660 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
661 return -EFAULT;
662
663 fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
664
665#ifdef DEBUG
666 {
Holger Schurig9012b282007-05-25 11:27:16 -0400667 lbs_deb_ioctl("FWT_LIST_ROUTE: line is %s\n", in_str);
668 lbs_deb_ioctl("FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200669 }
670#endif
671
672 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
673 cmd_act_fwt_access_list_route,
674 cmd_option_waitforrsp, 0, (void *)&fwt_access);
675
676 if (ret == 0) {
677 pbuf += sprintf(pbuf, " ");
678 pbuf += eth_addr2str(fwt_access.da, pbuf);
679 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric));
680 pbuf += sprintf(pbuf, " %u", fwt_access.dir);
681 /* note that the firmware returns the nid in the id field */
682 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id));
683 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn));
684 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn));
685 pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount);
686 pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl);
687 pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration));
688 } else
689 pbuf += sprintf(pbuf, " (null)");
690
691 wrq->u.data.length = strlen(out_str);
692 if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
693 wrq->u.data.length)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400694 lbs_deb_ioctl("FWT_LIST_ROUTE: Copy to user failed!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200695 return -EFAULT;
696 }
697
Holger Schurig9012b282007-05-25 11:27:16 -0400698 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200699 return 0;
700}
701
702/**
703 * @brief List an entry from the FNT table
704 * @param priv A pointer to wlan_private structure
705 * @param req A pointer to ifreq structure
706 * @return 0 --success, otherwise fail
707 */
708static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req)
709{
710 struct iwreq *wrq = (struct iwreq *)req;
711 char in_str[8];
712 static struct cmd_ds_fwt_access fwt_access;
713 char *ptr = in_str;
714 static char out_str[128];
715 char *pbuf = out_str;
716 int ret;
717
Holger Schurig9012b282007-05-25 11:27:16 -0400718 lbs_deb_enter(LBS_DEB_IOCTL);
719
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200720 if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str)))
721 return -EFAULT;
722
723 memset(&fwt_access, 0, sizeof(fwt_access));
724 fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10));
725
726#ifdef DEBUG
727 {
Holger Schurig9012b282007-05-25 11:27:16 -0400728 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: line is %s\n", in_str);
729 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id));
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200730 }
731#endif
732
733 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
734 cmd_act_fwt_access_list_neighbor,
735 cmd_option_waitforrsp, 0,
736 (void *)&fwt_access);
737
738 if (ret == 0) {
739 pbuf += sprintf(pbuf, " ra ");
740 pbuf += eth_addr2str(fwt_access.ra, pbuf);
741 pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode);
742 pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr));
743 pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references));
744 } else
745 pbuf += sprintf(pbuf, " (null)");
746
747 wrq->u.data.length = strlen(out_str);
748 if (copy_to_user(wrq->u.data.pointer, (char *)out_str,
749 wrq->u.data.length)) {
Holger Schurig9012b282007-05-25 11:27:16 -0400750 lbs_deb_ioctl("FWT_LIST_NEIGHBOR: Copy to user failed!\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200751 return -EFAULT;
752 }
753
Holger Schurig9012b282007-05-25 11:27:16 -0400754 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200755 return 0;
756}
757
758/**
759 * @brief Cleans up the route (FRT) and neighbor (FNT) tables
760 * (Garbage Collection)
761 * @param priv A pointer to wlan_private structure
762 * @param req A pointer to ifreq structure
763 * @return 0 --success, otherwise fail
764 */
765static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req)
766{
Dan Williamsc4aa7052007-05-10 23:09:33 -0400767 struct iwreq *wrq = (struct iwreq *)req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200768 static struct cmd_ds_fwt_access fwt_access;
769 int ret;
770
Holger Schurig9012b282007-05-25 11:27:16 -0400771 lbs_deb_enter(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200772
Holger Schurig9012b282007-05-25 11:27:16 -0400773 lbs_deb_ioctl("FWT: cleaning up\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200774
775 memset(&fwt_access, 0, sizeof(fwt_access));
776
777 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
778 cmd_act_fwt_access_cleanup,
779 cmd_option_waitforrsp, 0,
780 (void *)&fwt_access);
781
782 if (ret == 0)
Dan Williamsc4aa7052007-05-10 23:09:33 -0400783 wrq->u.param.value = le32_to_cpu(fwt_access.references);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200784 else
785 return -EFAULT;
786
Holger Schurig9012b282007-05-25 11:27:16 -0400787 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200788 return 0;
789}
790
791/**
792 * @brief Gets firmware internal time (debug purposes)
793 * @param priv A pointer to wlan_private structure
794 * @param req A pointer to ifreq structure
795 * @return 0 --success, otherwise fail
796 */
797static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req)
798{
Dan Williamsc4aa7052007-05-10 23:09:33 -0400799 struct iwreq *wrq = (struct iwreq *)req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200800 static struct cmd_ds_fwt_access fwt_access;
801 int ret;
802
Holger Schurig9012b282007-05-25 11:27:16 -0400803 lbs_deb_enter(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200804
Holger Schurig9012b282007-05-25 11:27:16 -0400805 lbs_deb_ioctl("FWT: getting time\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200806
807 memset(&fwt_access, 0, sizeof(fwt_access));
808
809 ret = libertas_prepare_and_send_command(priv, cmd_fwt_access,
810 cmd_act_fwt_access_time,
811 cmd_option_waitforrsp, 0,
812 (void *)&fwt_access);
813
814 if (ret == 0)
Dan Williamsc4aa7052007-05-10 23:09:33 -0400815 wrq->u.param.value = le32_to_cpu(fwt_access.references);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200816 else
817 return -EFAULT;
818
Holger Schurig9012b282007-05-25 11:27:16 -0400819 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200820 return 0;
821}
822
823/**
824 * @brief Gets mesh ttl from firmware
825 * @param priv A pointer to wlan_private structure
826 * @param req A pointer to ifreq structure
827 * @return 0 --success, otherwise fail
828 */
829static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req)
830{
Dan Williamsc4aa7052007-05-10 23:09:33 -0400831 struct iwreq *wrq = (struct iwreq *)req;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200832 struct cmd_ds_mesh_access mesh_access;
833 int ret;
834
Holger Schurig9012b282007-05-25 11:27:16 -0400835 lbs_deb_enter(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200836
837 memset(&mesh_access, 0, sizeof(mesh_access));
838
839 ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
840 cmd_act_mesh_get_ttl,
841 cmd_option_waitforrsp, 0,
842 (void *)&mesh_access);
843
Dan Williamsc4aa7052007-05-10 23:09:33 -0400844 if (ret == 0)
845 wrq->u.param.value = le32_to_cpu(mesh_access.data[0]);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200846 else
847 return -EFAULT;
848
Holger Schurig9012b282007-05-25 11:27:16 -0400849 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200850 return 0;
851}
852
853/**
854 * @brief Gets mesh ttl from firmware
855 * @param priv A pointer to wlan_private structure
856 * @param ttl New ttl value
857 * @return 0 --success, otherwise fail
858 */
859static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl)
860{
861 struct cmd_ds_mesh_access mesh_access;
862 int ret;
863
Holger Schurig9012b282007-05-25 11:27:16 -0400864 lbs_deb_enter(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200865
866 if( (ttl > 0xff) || (ttl < 0) )
867 return -EINVAL;
868
869 memset(&mesh_access, 0, sizeof(mesh_access));
870 mesh_access.data[0] = ttl;
871
872 ret = libertas_prepare_and_send_command(priv, cmd_mesh_access,
873 cmd_act_mesh_set_ttl,
874 cmd_option_waitforrsp, 0,
875 (void *)&mesh_access);
876
877 if (ret != 0)
878 ret = -EFAULT;
879
Holger Schurig9012b282007-05-25 11:27:16 -0400880 lbs_deb_leave(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200881 return ret;
882}
883
884/**
885 * @brief ioctl function - entry point
886 *
887 * @param dev A pointer to net_device structure
888 * @param req A pointer to ifreq structure
889 * @param cmd command
890 * @return 0--success, otherwise fail
891 */
892int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
893{
894 int subcmd = 0;
895 int idata = 0;
896 int *pdata;
897 int ret = 0;
898 wlan_private *priv = dev->priv;
899 wlan_adapter *adapter = priv->adapter;
900 struct iwreq *wrq = (struct iwreq *)req;
901
Holger Schurig9012b282007-05-25 11:27:16 -0400902 lbs_deb_enter(LBS_DEB_IOCTL);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200903
Holger Schurig9012b282007-05-25 11:27:16 -0400904 lbs_deb_ioctl("libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200905 switch (cmd) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200906 case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */
907 switch (wrq->u.data.flags) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200908 case WLAN_SUBCMD_BT_RESET: /* bt_reset */
909 wlan_bt_reset_ioctl(priv);
910 break;
911 case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */
912 wlan_fwt_reset_ioctl(priv);
913 break;
914 } /* End of switch */
915 break;
916
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200917 case WLAN_SETONEINT_GETNONE:
918 /* The first 4 bytes of req->ifr_data is sub-ioctl number
919 * after 4 bytes sits the payload.
920 */
Dan Williamsc4aa7052007-05-10 23:09:33 -0400921 subcmd = wrq->u.data.flags;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200922 if (!subcmd)
Dan Williamsc4aa7052007-05-10 23:09:33 -0400923 subcmd = (int)wrq->u.param.value;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200924
925 switch (subcmd) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200926 case WLANSETREGION:
927 idata = SUBCMD_DATA(wrq);
928 ret = wlan_set_region(priv, (u16) idata);
929 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200930 case WLAN_SUBCMD_MESH_SET_TTL:
931 idata = SUBCMD_DATA(wrq);
932 ret = wlan_mesh_set_ttl_ioctl(priv, idata);
933 break;
934
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400935 case WLAN_SUBCMD_BT_SET_INVERT:
936 ret = wlan_bt_set_invert_ioctl(priv, req);
937 break ;
938
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200939 default:
940 ret = -EOPNOTSUPP;
941 break;
942 }
943
944 break;
945
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200946 case WLAN_SET128CHAR_GET128CHAR:
947 switch ((int)wrq->u.data.flags) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200948 case WLAN_SUBCMD_BT_ADD:
949 ret = wlan_bt_add_ioctl(priv, req);
950 break;
951 case WLAN_SUBCMD_BT_DEL:
952 ret = wlan_bt_del_ioctl(priv, req);
953 break;
954 case WLAN_SUBCMD_BT_LIST:
955 ret = wlan_bt_list_ioctl(priv, req);
956 break;
957 case WLAN_SUBCMD_FWT_ADD:
958 ret = wlan_fwt_add_ioctl(priv, req);
959 break;
960 case WLAN_SUBCMD_FWT_DEL:
961 ret = wlan_fwt_del_ioctl(priv, req);
962 break;
963 case WLAN_SUBCMD_FWT_LOOKUP:
964 ret = wlan_fwt_lookup_ioctl(priv, req);
965 break;
966 case WLAN_SUBCMD_FWT_LIST_NEIGHBOR:
967 ret = wlan_fwt_list_neighbor_ioctl(priv, req);
968 break;
969 case WLAN_SUBCMD_FWT_LIST:
970 ret = wlan_fwt_list_ioctl(priv, req);
971 break;
972 case WLAN_SUBCMD_FWT_LIST_ROUTE:
973 ret = wlan_fwt_list_route_ioctl(priv, req);
974 break;
975 }
976 break;
977
978 case WLAN_SETNONE_GETONEINT:
Dan Williamsc4aa7052007-05-10 23:09:33 -0400979 switch (wrq->u.param.value) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200980 case WLANGETREGION:
981 pdata = (int *)wrq->u.name;
982 *pdata = (int)adapter->regioncode;
983 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -0200984 case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */
985 ret = wlan_fwt_cleanup_ioctl(priv, req);
986 break;
987
988 case WLAN_SUBCMD_FWT_TIME: /* fwt_time */
989 ret = wlan_fwt_time_ioctl(priv, req);
990 break;
991
992 case WLAN_SUBCMD_MESH_GET_TTL:
993 ret = wlan_mesh_get_ttl_ioctl(priv, req);
994 break;
995
Luis Carlos Cobo90e8eaf2007-05-25 13:53:26 -0400996 case WLAN_SUBCMD_BT_GET_INVERT:
997 ret = wlan_bt_get_invert_ioctl(priv, req);
998 break ;
999
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001000 default:
1001 ret = -EOPNOTSUPP;
1002
1003 }
1004
1005 break;
1006
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001007 case WLAN_SET_GET_SIXTEEN_INT:
1008 switch ((int)wrq->u.data.flags) {
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001009 case WLAN_LED_GPIO_CTRL:
1010 {
1011 int i;
1012 int data[16];
1013
1014 struct cmd_ds_802_11_led_ctrl ctrl;
1015 struct mrvlietypes_ledgpio *gpio =
1016 (struct mrvlietypes_ledgpio *) ctrl.data;
1017
1018 memset(&ctrl, 0, sizeof(ctrl));
1019 if (wrq->u.data.length > MAX_LEDS * 2)
1020 return -ENOTSUPP;
1021 if ((wrq->u.data.length % 2) != 0)
1022 return -ENOTSUPP;
1023 if (wrq->u.data.length == 0) {
1024 ctrl.action =
1025 cpu_to_le16
1026 (cmd_act_get);
1027 } else {
1028 if (copy_from_user
1029 (data, wrq->u.data.pointer,
1030 sizeof(int) *
1031 wrq->u.data.length)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001032 lbs_deb_ioctl(
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001033 "Copy from user failed\n");
1034 return -EFAULT;
1035 }
1036
1037 ctrl.action =
1038 cpu_to_le16
1039 (cmd_act_set);
1040 ctrl.numled = cpu_to_le16(0);
1041 gpio->header.type =
1042 cpu_to_le16(TLV_TYPE_LED_GPIO);
1043 gpio->header.len = wrq->u.data.length;
1044 for (i = 0; i < wrq->u.data.length;
1045 i += 2) {
1046 gpio->ledpin[i / 2].led =
1047 data[i];
1048 gpio->ledpin[i / 2].pin =
1049 data[i + 1];
1050 }
1051 }
1052 ret =
1053 libertas_prepare_and_send_command(priv,
1054 cmd_802_11_led_gpio_ctrl,
1055 0,
1056 cmd_option_waitforrsp,
1057 0, (void *)&ctrl);
1058 for (i = 0; i < gpio->header.len; i += 2) {
1059 data[i] = gpio->ledpin[i / 2].led;
1060 data[i + 1] = gpio->ledpin[i / 2].pin;
1061 }
1062 if (copy_to_user(wrq->u.data.pointer, data,
1063 sizeof(int) *
1064 gpio->header.len)) {
Holger Schurig9012b282007-05-25 11:27:16 -04001065 lbs_deb_ioctl("Copy to user failed\n");
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001066 return -EFAULT;
1067 }
1068
1069 wrq->u.data.length = gpio->header.len;
1070 }
1071 break;
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001072 }
1073 break;
1074
1075 default:
1076 ret = -EINVAL;
1077 break;
1078 }
Holger Schurig9012b282007-05-25 11:27:16 -04001079
1080 lbs_deb_leave_args(LBS_DEB_IOCTL, "ret %d", ret);
Marcelo Tosatti876c9d32007-02-10 12:25:27 -02001081 return ret;
1082}
1083
1084