diff options
Diffstat (limited to 'drivers/net/wireless/libertas/ioctl.c')
-rw-r--r-- | drivers/net/wireless/libertas/ioctl.c | 2500 |
1 files changed, 2500 insertions, 0 deletions
diff --git a/drivers/net/wireless/libertas/ioctl.c b/drivers/net/wireless/libertas/ioctl.c new file mode 100644 index 000000000000..82b39642423a --- /dev/null +++ b/drivers/net/wireless/libertas/ioctl.c | |||
@@ -0,0 +1,2500 @@ | |||
1 | /** | ||
2 | * This file contains ioctl functions | ||
3 | */ | ||
4 | |||
5 | #include <linux/ctype.h> | ||
6 | #include <linux/delay.h> | ||
7 | #include <linux/if.h> | ||
8 | #include <linux/if_arp.h> | ||
9 | #include <linux/wireless.h> | ||
10 | |||
11 | #include <net/iw_handler.h> | ||
12 | #include <net/ieee80211.h> | ||
13 | |||
14 | #include "host.h" | ||
15 | #include "radiotap.h" | ||
16 | #include "decl.h" | ||
17 | #include "defs.h" | ||
18 | #include "dev.h" | ||
19 | #include "join.h" | ||
20 | #include "wext.h" | ||
21 | |||
22 | #define MAX_SCAN_CELL_SIZE (IW_EV_ADDR_LEN + \ | ||
23 | IW_ESSID_MAX_SIZE + \ | ||
24 | IW_EV_UINT_LEN + IW_EV_FREQ_LEN + \ | ||
25 | IW_EV_QUAL_LEN + IW_ESSID_MAX_SIZE + \ | ||
26 | IW_EV_PARAM_LEN + 40) /* 40 for WPAIE */ | ||
27 | |||
28 | #define WAIT_FOR_SCAN_RRESULT_MAX_TIME (10 * HZ) | ||
29 | |||
30 | static int setrxantenna(wlan_private * priv, int mode) | ||
31 | { | ||
32 | int ret = 0; | ||
33 | wlan_adapter *adapter = priv->adapter; | ||
34 | |||
35 | if (mode != RF_ANTENNA_1 && mode != RF_ANTENNA_2 | ||
36 | && mode != RF_ANTENNA_AUTO) { | ||
37 | return -EINVAL; | ||
38 | } | ||
39 | |||
40 | adapter->rxantennamode = mode; | ||
41 | |||
42 | lbs_pr_debug(1, "SET RX Antenna mode to 0x%04x\n", adapter->rxantennamode); | ||
43 | |||
44 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, | ||
45 | cmd_act_set_rx, | ||
46 | cmd_option_waitforrsp, 0, | ||
47 | &adapter->rxantennamode); | ||
48 | return ret; | ||
49 | } | ||
50 | |||
51 | static int settxantenna(wlan_private * priv, int mode) | ||
52 | { | ||
53 | int ret = 0; | ||
54 | wlan_adapter *adapter = priv->adapter; | ||
55 | |||
56 | if ((mode != RF_ANTENNA_1) && (mode != RF_ANTENNA_2) | ||
57 | && (mode != RF_ANTENNA_AUTO)) { | ||
58 | return -EINVAL; | ||
59 | } | ||
60 | |||
61 | adapter->txantennamode = mode; | ||
62 | |||
63 | lbs_pr_debug(1, "SET TX Antenna mode to 0x%04x\n", adapter->txantennamode); | ||
64 | |||
65 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, | ||
66 | cmd_act_set_tx, | ||
67 | cmd_option_waitforrsp, 0, | ||
68 | &adapter->txantennamode); | ||
69 | |||
70 | return ret; | ||
71 | } | ||
72 | |||
73 | static int getrxantenna(wlan_private * priv, char *buf) | ||
74 | { | ||
75 | int ret = 0; | ||
76 | wlan_adapter *adapter = priv->adapter; | ||
77 | |||
78 | // clear it, so we will know if the value | ||
79 | // returned below is correct or not. | ||
80 | adapter->rxantennamode = 0; | ||
81 | |||
82 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, | ||
83 | cmd_act_get_rx, | ||
84 | cmd_option_waitforrsp, 0, NULL); | ||
85 | |||
86 | if (ret) { | ||
87 | LEAVE(); | ||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | lbs_pr_debug(1, "Get Rx Antenna mode:0x%04x\n", adapter->rxantennamode); | ||
92 | |||
93 | return sprintf(buf, "0x%04x", adapter->rxantennamode) + 1; | ||
94 | } | ||
95 | |||
96 | static int gettxantenna(wlan_private * priv, char *buf) | ||
97 | { | ||
98 | int ret = 0; | ||
99 | wlan_adapter *adapter = priv->adapter; | ||
100 | |||
101 | // clear it, so we will know if the value | ||
102 | // returned below is correct or not. | ||
103 | adapter->txantennamode = 0; | ||
104 | |||
105 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_rf_antenna, | ||
106 | cmd_act_get_tx, | ||
107 | cmd_option_waitforrsp, 0, NULL); | ||
108 | |||
109 | if (ret) { | ||
110 | LEAVE(); | ||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | lbs_pr_debug(1, "Get Tx Antenna mode:0x%04x\n", adapter->txantennamode); | ||
115 | |||
116 | return sprintf(buf, "0x%04x", adapter->txantennamode) + 1; | ||
117 | } | ||
118 | |||
119 | static int wlan_set_region(wlan_private * priv, u16 region_code) | ||
120 | { | ||
121 | int i; | ||
122 | |||
123 | for (i = 0; i < MRVDRV_MAX_REGION_CODE; i++) { | ||
124 | // use the region code to search for the index | ||
125 | if (region_code == libertas_region_code_to_index[i]) { | ||
126 | priv->adapter->regiontableindex = (u16) i; | ||
127 | priv->adapter->regioncode = region_code; | ||
128 | break; | ||
129 | } | ||
130 | } | ||
131 | |||
132 | // if it's unidentified region code | ||
133 | if (i >= MRVDRV_MAX_REGION_CODE) { | ||
134 | lbs_pr_debug(1, "region Code not identified\n"); | ||
135 | LEAVE(); | ||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | if (libertas_set_regiontable(priv, priv->adapter->regioncode, 0)) { | ||
140 | LEAVE(); | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | |||
144 | return 0; | ||
145 | } | ||
146 | |||
147 | /** | ||
148 | * @brief Get/Set Firmware wakeup method | ||
149 | * | ||
150 | * @param priv A pointer to wlan_private structure | ||
151 | * @param wrq A pointer to user data | ||
152 | * @return 0--success, otherwise fail | ||
153 | */ | ||
154 | static int wlan_txcontrol(wlan_private * priv, struct iwreq *wrq) | ||
155 | { | ||
156 | wlan_adapter *adapter = priv->adapter; | ||
157 | int data; | ||
158 | ENTER(); | ||
159 | |||
160 | if ((int)wrq->u.data.length == 0) { | ||
161 | if (copy_to_user | ||
162 | (wrq->u.data.pointer, &adapter->pkttxctrl, sizeof(u32))) { | ||
163 | lbs_pr_alert("copy_to_user failed!\n"); | ||
164 | return -EFAULT; | ||
165 | } | ||
166 | } else { | ||
167 | if ((int)wrq->u.data.length > 1) { | ||
168 | lbs_pr_alert("ioctl too many args!\n"); | ||
169 | return -EFAULT; | ||
170 | } | ||
171 | if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { | ||
172 | lbs_pr_alert("Copy from user failed\n"); | ||
173 | return -EFAULT; | ||
174 | } | ||
175 | |||
176 | adapter->pkttxctrl = (u32) data; | ||
177 | } | ||
178 | |||
179 | wrq->u.data.length = 1; | ||
180 | |||
181 | LEAVE(); | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | /** | ||
186 | * @brief Get/Set NULL Package generation interval | ||
187 | * | ||
188 | * @param priv A pointer to wlan_private structure | ||
189 | * @param wrq A pointer to user data | ||
190 | * @return 0--success, otherwise fail | ||
191 | */ | ||
192 | static int wlan_null_pkt_interval(wlan_private * priv, struct iwreq *wrq) | ||
193 | { | ||
194 | wlan_adapter *adapter = priv->adapter; | ||
195 | int data; | ||
196 | ENTER(); | ||
197 | |||
198 | if ((int)wrq->u.data.length == 0) { | ||
199 | data = adapter->nullpktinterval; | ||
200 | |||
201 | if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { | ||
202 | lbs_pr_alert( "copy_to_user failed!\n"); | ||
203 | return -EFAULT; | ||
204 | } | ||
205 | } else { | ||
206 | if ((int)wrq->u.data.length > 1) { | ||
207 | lbs_pr_alert( "ioctl too many args!\n"); | ||
208 | return -EFAULT; | ||
209 | } | ||
210 | if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { | ||
211 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
212 | return -EFAULT; | ||
213 | } | ||
214 | |||
215 | adapter->nullpktinterval = data; | ||
216 | } | ||
217 | |||
218 | wrq->u.data.length = 1; | ||
219 | |||
220 | LEAVE(); | ||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int wlan_get_rxinfo(wlan_private * priv, struct iwreq *wrq) | ||
225 | { | ||
226 | wlan_adapter *adapter = priv->adapter; | ||
227 | int data[2]; | ||
228 | ENTER(); | ||
229 | data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; | ||
230 | data[1] = adapter->rxpd_rate; | ||
231 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { | ||
232 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
233 | return -EFAULT; | ||
234 | } | ||
235 | wrq->u.data.length = 2; | ||
236 | LEAVE(); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int wlan_get_snr(wlan_private * priv, struct iwreq *wrq) | ||
241 | { | ||
242 | int ret = 0; | ||
243 | wlan_adapter *adapter = priv->adapter; | ||
244 | int data[4]; | ||
245 | |||
246 | ENTER(); | ||
247 | memset(data, 0, sizeof(data)); | ||
248 | if (wrq->u.data.length) { | ||
249 | if (copy_from_user(data, wrq->u.data.pointer, | ||
250 | min_t(size_t, wrq->u.data.length, 4) * sizeof(int))) | ||
251 | return -EFAULT; | ||
252 | } | ||
253 | if ((wrq->u.data.length == 0) || (data[0] == 0) || (data[0] == 1)) { | ||
254 | if (adapter->connect_status == libertas_connected) { | ||
255 | ret = libertas_prepare_and_send_command(priv, | ||
256 | cmd_802_11_rssi, | ||
257 | 0, | ||
258 | cmd_option_waitforrsp, | ||
259 | 0, NULL); | ||
260 | |||
261 | if (ret) { | ||
262 | LEAVE(); | ||
263 | return ret; | ||
264 | } | ||
265 | } | ||
266 | } | ||
267 | |||
268 | if (wrq->u.data.length == 0) { | ||
269 | data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; | ||
270 | data[1] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; | ||
271 | data[2] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; | ||
272 | data[3] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | ||
273 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 4)) | ||
274 | return -EFAULT; | ||
275 | wrq->u.data.length = 4; | ||
276 | } else if (data[0] == 0) { | ||
277 | data[0] = adapter->SNR[TYPE_BEACON][TYPE_NOAVG]; | ||
278 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) | ||
279 | return -EFAULT; | ||
280 | wrq->u.data.length = 1; | ||
281 | } else if (data[0] == 1) { | ||
282 | data[0] = adapter->SNR[TYPE_BEACON][TYPE_AVG]; | ||
283 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) | ||
284 | return -EFAULT; | ||
285 | wrq->u.data.length = 1; | ||
286 | } else if (data[0] == 2) { | ||
287 | data[0] = adapter->SNR[TYPE_RXPD][TYPE_NOAVG]; | ||
288 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) | ||
289 | return -EFAULT; | ||
290 | wrq->u.data.length = 1; | ||
291 | } else if (data[0] == 3) { | ||
292 | data[0] = adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | ||
293 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int))) | ||
294 | return -EFAULT; | ||
295 | wrq->u.data.length = 1; | ||
296 | } else | ||
297 | return -ENOTSUPP; | ||
298 | |||
299 | LEAVE(); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int wlan_beacon_interval(wlan_private * priv, struct iwreq *wrq) | ||
304 | { | ||
305 | int data; | ||
306 | wlan_adapter *adapter = priv->adapter; | ||
307 | |||
308 | if (wrq->u.data.length > 0) { | ||
309 | if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) | ||
310 | return -EFAULT; | ||
311 | |||
312 | lbs_pr_debug(1, "WLAN SET BEACON INTERVAL: %d\n", data); | ||
313 | if ((data > MRVDRV_MAX_BEACON_INTERVAL) | ||
314 | || (data < MRVDRV_MIN_BEACON_INTERVAL)) | ||
315 | return -ENOTSUPP; | ||
316 | adapter->beaconperiod = data; | ||
317 | } | ||
318 | data = adapter->beaconperiod; | ||
319 | if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) | ||
320 | return -EFAULT; | ||
321 | |||
322 | wrq->u.data.length = 1; | ||
323 | |||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static int wlan_get_rssi(wlan_private * priv, struct iwreq *wrq) | ||
328 | { | ||
329 | int ret = 0; | ||
330 | wlan_adapter *adapter = priv->adapter; | ||
331 | int temp; | ||
332 | int data = 0; | ||
333 | int *val; | ||
334 | |||
335 | ENTER(); | ||
336 | data = SUBCMD_DATA(wrq); | ||
337 | if ((data == 0) || (data == 1)) { | ||
338 | ret = libertas_prepare_and_send_command(priv, | ||
339 | cmd_802_11_rssi, | ||
340 | 0, cmd_option_waitforrsp, | ||
341 | 0, NULL); | ||
342 | if (ret) { | ||
343 | LEAVE(); | ||
344 | return ret; | ||
345 | } | ||
346 | } | ||
347 | |||
348 | switch (data) { | ||
349 | case 0: | ||
350 | |||
351 | temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_NOAVG], | ||
352 | adapter->NF[TYPE_BEACON][TYPE_NOAVG]); | ||
353 | break; | ||
354 | case 1: | ||
355 | temp = CAL_RSSI(adapter->SNR[TYPE_BEACON][TYPE_AVG], | ||
356 | adapter->NF[TYPE_BEACON][TYPE_AVG]); | ||
357 | break; | ||
358 | case 2: | ||
359 | temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_NOAVG], | ||
360 | adapter->NF[TYPE_RXPD][TYPE_NOAVG]); | ||
361 | break; | ||
362 | case 3: | ||
363 | temp = CAL_RSSI(adapter->SNR[TYPE_RXPD][TYPE_AVG] / AVG_SCALE, | ||
364 | adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE); | ||
365 | break; | ||
366 | default: | ||
367 | return -ENOTSUPP; | ||
368 | } | ||
369 | val = (int *)wrq->u.name; | ||
370 | *val = temp; | ||
371 | |||
372 | LEAVE(); | ||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int wlan_get_nf(wlan_private * priv, struct iwreq *wrq) | ||
377 | { | ||
378 | int ret = 0; | ||
379 | wlan_adapter *adapter = priv->adapter; | ||
380 | int temp; | ||
381 | int data = 0; | ||
382 | int *val; | ||
383 | |||
384 | data = SUBCMD_DATA(wrq); | ||
385 | if ((data == 0) || (data == 1)) { | ||
386 | ret = libertas_prepare_and_send_command(priv, | ||
387 | cmd_802_11_rssi, | ||
388 | 0, cmd_option_waitforrsp, | ||
389 | 0, NULL); | ||
390 | |||
391 | if (ret) { | ||
392 | LEAVE(); | ||
393 | return ret; | ||
394 | } | ||
395 | } | ||
396 | |||
397 | switch (data) { | ||
398 | case 0: | ||
399 | temp = adapter->NF[TYPE_BEACON][TYPE_NOAVG]; | ||
400 | break; | ||
401 | case 1: | ||
402 | temp = adapter->NF[TYPE_BEACON][TYPE_AVG]; | ||
403 | break; | ||
404 | case 2: | ||
405 | temp = adapter->NF[TYPE_RXPD][TYPE_NOAVG]; | ||
406 | break; | ||
407 | case 3: | ||
408 | temp = adapter->NF[TYPE_RXPD][TYPE_AVG] / AVG_SCALE; | ||
409 | break; | ||
410 | default: | ||
411 | return -ENOTSUPP; | ||
412 | } | ||
413 | |||
414 | temp = CAL_NF(temp); | ||
415 | |||
416 | lbs_pr_debug(1, "%s: temp = %d\n", __FUNCTION__, temp); | ||
417 | val = (int *)wrq->u.name; | ||
418 | *val = temp; | ||
419 | return 0; | ||
420 | } | ||
421 | |||
422 | static int wlan_get_txrate_ioctl(wlan_private * priv, struct ifreq *req) | ||
423 | { | ||
424 | wlan_adapter *adapter = priv->adapter; | ||
425 | int *pdata; | ||
426 | struct iwreq *wrq = (struct iwreq *)req; | ||
427 | int ret = 0; | ||
428 | adapter->txrate = 0; | ||
429 | lbs_pr_debug(1, "wlan_get_txrate_ioctl\n"); | ||
430 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_tx_rate_query, | ||
431 | cmd_act_get, cmd_option_waitforrsp, | ||
432 | 0, NULL); | ||
433 | if (ret) | ||
434 | return ret; | ||
435 | |||
436 | pdata = (int *)wrq->u.name; | ||
437 | *pdata = (int)adapter->txrate; | ||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int wlan_get_adhoc_status_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
442 | { | ||
443 | char status[64]; | ||
444 | wlan_adapter *adapter = priv->adapter; | ||
445 | |||
446 | memset(status, 0, sizeof(status)); | ||
447 | |||
448 | switch (adapter->inframode) { | ||
449 | case wlan802_11ibss: | ||
450 | if (adapter->connect_status == libertas_connected) { | ||
451 | if (adapter->adhoccreate) | ||
452 | memcpy(&status, "AdhocStarted", sizeof(status)); | ||
453 | else | ||
454 | memcpy(&status, "AdhocJoined", sizeof(status)); | ||
455 | } else { | ||
456 | memcpy(&status, "AdhocIdle", sizeof(status)); | ||
457 | } | ||
458 | break; | ||
459 | case wlan802_11infrastructure: | ||
460 | memcpy(&status, "Inframode", sizeof(status)); | ||
461 | break; | ||
462 | default: | ||
463 | memcpy(&status, "AutoUnknownmode", sizeof(status)); | ||
464 | break; | ||
465 | } | ||
466 | |||
467 | lbs_pr_debug(1, "status = %s\n", status); | ||
468 | wrq->u.data.length = strlen(status) + 1; | ||
469 | |||
470 | if (wrq->u.data.pointer) { | ||
471 | if (copy_to_user(wrq->u.data.pointer, | ||
472 | &status, wrq->u.data.length)) | ||
473 | return -EFAULT; | ||
474 | } | ||
475 | |||
476 | LEAVE(); | ||
477 | return 0; | ||
478 | } | ||
479 | |||
480 | /** | ||
481 | * @brief Set/Get WPA IE | ||
482 | * @param priv A pointer to wlan_private structure | ||
483 | * @param req A pointer to ifreq structure | ||
484 | * @return 0 --success, otherwise fail | ||
485 | */ | ||
486 | static int wlan_setwpaie_ioctl(wlan_private * priv, struct ifreq *req) | ||
487 | { | ||
488 | struct iwreq *wrq = (struct iwreq *)req; | ||
489 | wlan_adapter *adapter = priv->adapter; | ||
490 | int ret = 0; | ||
491 | |||
492 | ENTER(); | ||
493 | |||
494 | if (wrq->u.data.length) { | ||
495 | if (wrq->u.data.length > sizeof(adapter->wpa_ie)) { | ||
496 | lbs_pr_debug(1, "failed to copy WPA IE, too big \n"); | ||
497 | return -EFAULT; | ||
498 | } | ||
499 | if (copy_from_user(adapter->wpa_ie, wrq->u.data.pointer, | ||
500 | wrq->u.data.length)) { | ||
501 | lbs_pr_debug(1, "failed to copy WPA IE \n"); | ||
502 | return -EFAULT; | ||
503 | } | ||
504 | adapter->wpa_ie_len = wrq->u.data.length; | ||
505 | lbs_pr_debug(1, "Set wpa_ie_len=%d IE=%#x\n", adapter->wpa_ie_len, | ||
506 | adapter->wpa_ie[0]); | ||
507 | lbs_dbg_hex("wpa_ie", adapter->wpa_ie, adapter->wpa_ie_len); | ||
508 | if (adapter->wpa_ie[0] == WPA_IE) | ||
509 | adapter->secinfo.WPAenabled = 1; | ||
510 | else if (adapter->wpa_ie[0] == WPA2_IE) | ||
511 | adapter->secinfo.WPA2enabled = 1; | ||
512 | else { | ||
513 | adapter->secinfo.WPAenabled = 0; | ||
514 | adapter->secinfo.WPA2enabled = 0; | ||
515 | } | ||
516 | } else { | ||
517 | memset(adapter->wpa_ie, 0, sizeof(adapter->wpa_ie)); | ||
518 | adapter->wpa_ie_len = wrq->u.data.length; | ||
519 | lbs_pr_debug(1, "Reset wpa_ie_len=%d IE=%#x\n", | ||
520 | adapter->wpa_ie_len, adapter->wpa_ie[0]); | ||
521 | adapter->secinfo.WPAenabled = 0; | ||
522 | adapter->secinfo.WPA2enabled = 0; | ||
523 | } | ||
524 | |||
525 | // enable/disable RSN in firmware if WPA is enabled/disabled | ||
526 | // depending on variable adapter->secinfo.WPAenabled is set or not | ||
527 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_enable_rsn, | ||
528 | cmd_act_set, cmd_option_waitforrsp, | ||
529 | 0, NULL); | ||
530 | |||
531 | LEAVE(); | ||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | /** | ||
536 | * @brief Set Auto prescan | ||
537 | * @param priv A pointer to wlan_private structure | ||
538 | * @param wrq A pointer to iwreq structure | ||
539 | * @return 0 --success, otherwise fail | ||
540 | */ | ||
541 | static int wlan_subcmd_setprescan_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
542 | { | ||
543 | int data; | ||
544 | wlan_adapter *adapter = priv->adapter; | ||
545 | int *val; | ||
546 | |||
547 | data = SUBCMD_DATA(wrq); | ||
548 | lbs_pr_debug(1, "WLAN_SUBCMD_SET_PRESCAN %d\n", data); | ||
549 | adapter->prescan = data; | ||
550 | |||
551 | val = (int *)wrq->u.name; | ||
552 | *val = data; | ||
553 | return 0; | ||
554 | } | ||
555 | |||
556 | static int wlan_set_multiple_dtim_ioctl(wlan_private * priv, struct ifreq *req) | ||
557 | { | ||
558 | struct iwreq *wrq = (struct iwreq *)req; | ||
559 | u32 mdtim; | ||
560 | int idata; | ||
561 | int ret = -EINVAL; | ||
562 | |||
563 | ENTER(); | ||
564 | |||
565 | idata = SUBCMD_DATA(wrq); | ||
566 | mdtim = (u32) idata; | ||
567 | if (((mdtim >= MRVDRV_MIN_MULTIPLE_DTIM) | ||
568 | && (mdtim <= MRVDRV_MAX_MULTIPLE_DTIM)) | ||
569 | || (mdtim == MRVDRV_IGNORE_MULTIPLE_DTIM)) { | ||
570 | priv->adapter->multipledtim = mdtim; | ||
571 | ret = 0; | ||
572 | } | ||
573 | if (ret) | ||
574 | lbs_pr_debug(1, "Invalid parameter, multipledtim not changed.\n"); | ||
575 | |||
576 | LEAVE(); | ||
577 | return ret; | ||
578 | } | ||
579 | |||
580 | /** | ||
581 | * @brief Set authentication mode | ||
582 | * @param priv A pointer to wlan_private structure | ||
583 | * @param req A pointer to ifreq structure | ||
584 | * @return 0 --success, otherwise fail | ||
585 | */ | ||
586 | static int wlan_setauthalg_ioctl(wlan_private * priv, struct ifreq *req) | ||
587 | { | ||
588 | int alg; | ||
589 | struct iwreq *wrq = (struct iwreq *)req; | ||
590 | wlan_adapter *adapter = priv->adapter; | ||
591 | |||
592 | if (wrq->u.data.flags == 0) { | ||
593 | //from iwpriv subcmd | ||
594 | alg = SUBCMD_DATA(wrq); | ||
595 | } else { | ||
596 | //from wpa_supplicant subcmd | ||
597 | if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(alg))) { | ||
598 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
599 | return -EFAULT; | ||
600 | } | ||
601 | } | ||
602 | |||
603 | lbs_pr_debug(1, "auth alg is %#x\n", alg); | ||
604 | |||
605 | switch (alg) { | ||
606 | case AUTH_ALG_SHARED_KEY: | ||
607 | adapter->secinfo.authmode = wlan802_11authmodeshared; | ||
608 | break; | ||
609 | case AUTH_ALG_NETWORK_EAP: | ||
610 | adapter->secinfo.authmode = | ||
611 | wlan802_11authmodenetworkEAP; | ||
612 | break; | ||
613 | case AUTH_ALG_OPEN_SYSTEM: | ||
614 | default: | ||
615 | adapter->secinfo.authmode = wlan802_11authmodeopen; | ||
616 | break; | ||
617 | } | ||
618 | return 0; | ||
619 | } | ||
620 | |||
621 | /** | ||
622 | * @brief Set 802.1x authentication mode | ||
623 | * @param priv A pointer to wlan_private structure | ||
624 | * @param req A pointer to ifreq structure | ||
625 | * @return 0 --success, otherwise fail | ||
626 | */ | ||
627 | static int wlan_set8021xauthalg_ioctl(wlan_private * priv, struct ifreq *req) | ||
628 | { | ||
629 | int alg; | ||
630 | struct iwreq *wrq = (struct iwreq *)req; | ||
631 | |||
632 | if (wrq->u.data.flags == 0) { | ||
633 | //from iwpriv subcmd | ||
634 | alg = SUBCMD_DATA(wrq); | ||
635 | } else { | ||
636 | //from wpa_supplicant subcmd | ||
637 | if (copy_from_user(&alg, wrq->u.data.pointer, sizeof(int))) { | ||
638 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
639 | return -EFAULT; | ||
640 | } | ||
641 | } | ||
642 | lbs_pr_debug(1, "802.1x auth alg is %#x\n", alg); | ||
643 | priv->adapter->secinfo.auth1xalg = alg; | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int wlan_setencryptionmode_ioctl(wlan_private * priv, struct ifreq *req) | ||
648 | { | ||
649 | int mode; | ||
650 | struct iwreq *wrq = (struct iwreq *)req; | ||
651 | |||
652 | ENTER(); | ||
653 | |||
654 | if (wrq->u.data.flags == 0) { | ||
655 | //from iwpriv subcmd | ||
656 | mode = SUBCMD_DATA(wrq); | ||
657 | } else { | ||
658 | //from wpa_supplicant subcmd | ||
659 | if (copy_from_user(&mode, wrq->u.data.pointer, sizeof(int))) { | ||
660 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
661 | return -EFAULT; | ||
662 | } | ||
663 | } | ||
664 | lbs_pr_debug(1, "encryption mode is %#x\n", mode); | ||
665 | priv->adapter->secinfo.Encryptionmode = mode; | ||
666 | |||
667 | LEAVE(); | ||
668 | return 0; | ||
669 | } | ||
670 | |||
671 | static void adjust_mtu(wlan_private * priv) | ||
672 | { | ||
673 | int mtu_increment = 0; | ||
674 | |||
675 | if (priv->adapter->linkmode == WLAN_LINKMODE_802_11) | ||
676 | mtu_increment += sizeof(struct ieee80211_hdr_4addr); | ||
677 | |||
678 | if (priv->adapter->radiomode == WLAN_RADIOMODE_RADIOTAP) | ||
679 | mtu_increment += max(sizeof(struct tx_radiotap_hdr), | ||
680 | sizeof(struct rx_radiotap_hdr)); | ||
681 | priv->wlan_dev.netdev->mtu = ETH_FRAME_LEN | ||
682 | - sizeof(struct ethhdr) | ||
683 | + mtu_increment; | ||
684 | } | ||
685 | |||
686 | /** | ||
687 | * @brief Set Link-Layer Layer mode | ||
688 | * @param priv A pointer to wlan_private structure | ||
689 | * @param req A pointer to ifreq structure | ||
690 | * @return 0 --success, otherwise fail | ||
691 | */ | ||
692 | static int wlan_set_linkmode_ioctl(wlan_private * priv, struct ifreq *req) | ||
693 | { | ||
694 | int mode; | ||
695 | |||
696 | mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; | ||
697 | |||
698 | switch (mode) { | ||
699 | case WLAN_LINKMODE_802_3: | ||
700 | priv->adapter->linkmode = mode; | ||
701 | break; | ||
702 | case WLAN_LINKMODE_802_11: | ||
703 | priv->adapter->linkmode = mode; | ||
704 | break; | ||
705 | default: | ||
706 | lbs_pr_info("usb8388-5: invalid link-layer mode (%#x)\n", | ||
707 | mode); | ||
708 | return -EINVAL; | ||
709 | break; | ||
710 | } | ||
711 | lbs_pr_debug(1, "usb8388-5: link-layer mode is %#x\n", mode); | ||
712 | |||
713 | adjust_mtu(priv); | ||
714 | |||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | /** | ||
719 | * @brief Set Radio header mode | ||
720 | * @param priv A pointer to wlan_private structure | ||
721 | * @param req A pointer to ifreq structure | ||
722 | * @return 0 --success, otherwise fail | ||
723 | */ | ||
724 | static int wlan_set_radiomode_ioctl(wlan_private * priv, struct ifreq *req) | ||
725 | { | ||
726 | int mode; | ||
727 | |||
728 | mode = (int)((struct ifreq *)((u8 *) req + 4))->ifr_data; | ||
729 | |||
730 | switch (mode) { | ||
731 | case WLAN_RADIOMODE_NONE: | ||
732 | priv->adapter->radiomode = mode; | ||
733 | break; | ||
734 | case WLAN_RADIOMODE_RADIOTAP: | ||
735 | priv->adapter->radiomode = mode; | ||
736 | break; | ||
737 | default: | ||
738 | lbs_pr_debug(1, "usb8388-5: invalid radio header mode (%#x)\n", | ||
739 | mode); | ||
740 | return -EINVAL; | ||
741 | } | ||
742 | lbs_pr_debug(1, "usb8388-5: radio-header mode is %#x\n", mode); | ||
743 | |||
744 | adjust_mtu(priv); | ||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | /** | ||
749 | * @brief Set Debug header mode | ||
750 | * @param priv A pointer to wlan_private structure | ||
751 | * @param req A pointer to ifreq structure | ||
752 | * @return 0 --success, otherwise fail | ||
753 | */ | ||
754 | static int wlan_set_debugmode_ioctl(wlan_private * priv, struct ifreq *req) | ||
755 | { | ||
756 | priv->adapter->debugmode = (int)((struct ifreq *) | ||
757 | ((u8 *) req + 4))->ifr_data; | ||
758 | return 0; | ||
759 | } | ||
760 | |||
761 | static int wlan_subcmd_getrxantenna_ioctl(wlan_private * priv, | ||
762 | struct ifreq *req) | ||
763 | { | ||
764 | int len; | ||
765 | char buf[8]; | ||
766 | struct iwreq *wrq = (struct iwreq *)req; | ||
767 | |||
768 | lbs_pr_debug(1, "WLAN_SUBCMD_GETRXANTENNA\n"); | ||
769 | len = getrxantenna(priv, buf); | ||
770 | |||
771 | wrq->u.data.length = len; | ||
772 | if (wrq->u.data.pointer) { | ||
773 | if (copy_to_user(wrq->u.data.pointer, &buf, len)) { | ||
774 | lbs_pr_debug(1, "CopyToUser failed\n"); | ||
775 | return -EFAULT; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int wlan_subcmd_gettxantenna_ioctl(wlan_private * priv, | ||
783 | struct ifreq *req) | ||
784 | { | ||
785 | int len; | ||
786 | char buf[8]; | ||
787 | struct iwreq *wrq = (struct iwreq *)req; | ||
788 | |||
789 | lbs_pr_debug(1, "WLAN_SUBCMD_GETTXANTENNA\n"); | ||
790 | len = gettxantenna(priv, buf); | ||
791 | |||
792 | wrq->u.data.length = len; | ||
793 | if (wrq->u.data.pointer) { | ||
794 | if (copy_to_user(wrq->u.data.pointer, &buf, len)) { | ||
795 | lbs_pr_debug(1, "CopyToUser failed\n"); | ||
796 | return -EFAULT; | ||
797 | } | ||
798 | } | ||
799 | return 0; | ||
800 | } | ||
801 | |||
802 | /** | ||
803 | * @brief Get the MAC TSF value from the firmware | ||
804 | * | ||
805 | * @param priv A pointer to wlan_private structure | ||
806 | * @param wrq A pointer to iwreq structure containing buffer | ||
807 | * space to store a TSF value retrieved from the firmware | ||
808 | * | ||
809 | * @return 0 if successful; IOCTL error code otherwise | ||
810 | */ | ||
811 | static int wlan_get_tsf_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
812 | { | ||
813 | u64 tsfval; | ||
814 | int ret; | ||
815 | |||
816 | ret = libertas_prepare_and_send_command(priv, | ||
817 | cmd_get_tsf, | ||
818 | 0, cmd_option_waitforrsp, 0, &tsfval); | ||
819 | |||
820 | lbs_pr_debug(1, "IOCTL: Get TSF = 0x%016llx\n", tsfval); | ||
821 | |||
822 | if (ret != 0) { | ||
823 | lbs_pr_debug(1, "IOCTL: Get TSF; command exec failed\n"); | ||
824 | ret = -EFAULT; | ||
825 | } else { | ||
826 | if (copy_to_user(wrq->u.data.pointer, | ||
827 | &tsfval, | ||
828 | min_t(size_t, wrq->u.data.length, | ||
829 | sizeof(tsfval))) != 0) { | ||
830 | |||
831 | lbs_pr_debug(1, "IOCTL: Get TSF; Copy to user failed\n"); | ||
832 | ret = -EFAULT; | ||
833 | } else { | ||
834 | ret = 0; | ||
835 | } | ||
836 | } | ||
837 | return ret; | ||
838 | } | ||
839 | |||
840 | /** | ||
841 | * @brief Get/Set adapt rate | ||
842 | * @param priv A pointer to wlan_private structure | ||
843 | * @param wrq A pointer to iwreq structure | ||
844 | * @return 0 --success, otherwise fail | ||
845 | */ | ||
846 | static int wlan_adapt_rateset(wlan_private * priv, struct iwreq *wrq) | ||
847 | { | ||
848 | int ret; | ||
849 | wlan_adapter *adapter = priv->adapter; | ||
850 | int data[2]; | ||
851 | |||
852 | memset(data, 0, sizeof(data)); | ||
853 | if (!wrq->u.data.length) { | ||
854 | lbs_pr_debug(1, "Get ADAPT RATE SET\n"); | ||
855 | ret = libertas_prepare_and_send_command(priv, | ||
856 | cmd_802_11_rate_adapt_rateset, | ||
857 | cmd_act_get, | ||
858 | cmd_option_waitforrsp, 0, NULL); | ||
859 | data[0] = adapter->enablehwauto; | ||
860 | data[1] = adapter->ratebitmap; | ||
861 | if (copy_to_user(wrq->u.data.pointer, data, sizeof(int) * 2)) { | ||
862 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
863 | return -EFAULT; | ||
864 | } | ||
865 | #define GET_TWO_INT 2 | ||
866 | wrq->u.data.length = GET_TWO_INT; | ||
867 | } else { | ||
868 | lbs_pr_debug(1, "Set ADAPT RATE SET\n"); | ||
869 | if (wrq->u.data.length > 2) | ||
870 | return -EINVAL; | ||
871 | if (copy_from_user | ||
872 | (data, wrq->u.data.pointer, | ||
873 | sizeof(int) * wrq->u.data.length)) { | ||
874 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
875 | return -EFAULT; | ||
876 | } | ||
877 | |||
878 | adapter->enablehwauto = data[0]; | ||
879 | adapter->ratebitmap = data[1]; | ||
880 | ret = libertas_prepare_and_send_command(priv, | ||
881 | cmd_802_11_rate_adapt_rateset, | ||
882 | cmd_act_set, | ||
883 | cmd_option_waitforrsp, 0, NULL); | ||
884 | } | ||
885 | return ret; | ||
886 | } | ||
887 | |||
888 | /** | ||
889 | * @brief Get/Set inactivity timeout | ||
890 | * @param priv A pointer to wlan_private structure | ||
891 | * @param wrq A pointer to iwreq structure | ||
892 | * @return 0 --success, otherwise fail | ||
893 | */ | ||
894 | static int wlan_inactivity_timeout(wlan_private * priv, struct iwreq *wrq) | ||
895 | { | ||
896 | int ret; | ||
897 | int data = 0; | ||
898 | u16 timeout = 0; | ||
899 | |||
900 | ENTER(); | ||
901 | if (wrq->u.data.length > 1) | ||
902 | return -ENOTSUPP; | ||
903 | |||
904 | if (wrq->u.data.length == 0) { | ||
905 | /* Get */ | ||
906 | ret = libertas_prepare_and_send_command(priv, | ||
907 | cmd_802_11_inactivity_timeout, | ||
908 | cmd_act_get, | ||
909 | cmd_option_waitforrsp, 0, | ||
910 | &timeout); | ||
911 | data = timeout; | ||
912 | if (copy_to_user(wrq->u.data.pointer, &data, sizeof(int))) { | ||
913 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
914 | return -EFAULT; | ||
915 | } | ||
916 | } else { | ||
917 | /* Set */ | ||
918 | if (copy_from_user(&data, wrq->u.data.pointer, sizeof(int))) { | ||
919 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
920 | return -EFAULT; | ||
921 | } | ||
922 | |||
923 | timeout = data; | ||
924 | ret = libertas_prepare_and_send_command(priv, | ||
925 | cmd_802_11_inactivity_timeout, | ||
926 | cmd_act_set, | ||
927 | cmd_option_waitforrsp, 0, | ||
928 | &timeout); | ||
929 | } | ||
930 | |||
931 | wrq->u.data.length = 1; | ||
932 | |||
933 | LEAVE(); | ||
934 | return ret; | ||
935 | } | ||
936 | |||
937 | static int wlan_do_getlog_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
938 | { | ||
939 | int ret; | ||
940 | char buf[GETLOG_BUFSIZE - 1]; | ||
941 | wlan_adapter *adapter = priv->adapter; | ||
942 | |||
943 | lbs_pr_debug(1, " GET STATS\n"); | ||
944 | |||
945 | ret = libertas_prepare_and_send_command(priv, cmd_802_11_get_log, | ||
946 | 0, cmd_option_waitforrsp, 0, NULL); | ||
947 | |||
948 | if (ret) { | ||
949 | return ret; | ||
950 | } | ||
951 | |||
952 | if (wrq->u.data.pointer) { | ||
953 | sprintf(buf, "\n mcasttxframe %u failed %u retry %u " | ||
954 | "multiretry %u framedup %u " | ||
955 | "rtssuccess %u rtsfailure %u ackfailure %u\n" | ||
956 | "rxfrag %u mcastrxframe %u fcserror %u " | ||
957 | "txframe %u wepundecryptable %u ", | ||
958 | adapter->logmsg.mcasttxframe, | ||
959 | adapter->logmsg.failed, | ||
960 | adapter->logmsg.retry, | ||
961 | adapter->logmsg.multiretry, | ||
962 | adapter->logmsg.framedup, | ||
963 | adapter->logmsg.rtssuccess, | ||
964 | adapter->logmsg.rtsfailure, | ||
965 | adapter->logmsg.ackfailure, | ||
966 | adapter->logmsg.rxfrag, | ||
967 | adapter->logmsg.mcastrxframe, | ||
968 | adapter->logmsg.fcserror, | ||
969 | adapter->logmsg.txframe, | ||
970 | adapter->logmsg.wepundecryptable); | ||
971 | wrq->u.data.length = strlen(buf) + 1; | ||
972 | if (copy_to_user(wrq->u.data.pointer, buf, wrq->u.data.length)) { | ||
973 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
974 | return -EFAULT; | ||
975 | } | ||
976 | } | ||
977 | |||
978 | return 0; | ||
979 | } | ||
980 | |||
981 | static int wlan_scan_type_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
982 | { | ||
983 | u8 buf[12]; | ||
984 | u8 *option[] = { "active", "passive", "get", }; | ||
985 | int i, max_options = (sizeof(option) / sizeof(option[0])); | ||
986 | int ret = 0; | ||
987 | wlan_adapter *adapter = priv->adapter; | ||
988 | |||
989 | if (priv->adapter->enable11d) { | ||
990 | lbs_pr_debug(1, "11D: Cannot set scantype when 11D enabled\n"); | ||
991 | return -EFAULT; | ||
992 | } | ||
993 | |||
994 | memset(buf, 0, sizeof(buf)); | ||
995 | |||
996 | if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), | ||
997 | wrq->u.data.length))) | ||
998 | return -EFAULT; | ||
999 | |||
1000 | lbs_pr_debug(1, "Scan type Option = %s\n", buf); | ||
1001 | |||
1002 | buf[sizeof(buf) - 1] = '\0'; | ||
1003 | |||
1004 | for (i = 0; i < max_options; i++) { | ||
1005 | if (!strcmp(buf, option[i])) | ||
1006 | break; | ||
1007 | } | ||
1008 | |||
1009 | switch (i) { | ||
1010 | case 0: | ||
1011 | adapter->scantype = cmd_scan_type_active; | ||
1012 | break; | ||
1013 | case 1: | ||
1014 | adapter->scantype = cmd_scan_type_passive; | ||
1015 | break; | ||
1016 | case 2: | ||
1017 | wrq->u.data.length = strlen(option[adapter->scantype]) + 1; | ||
1018 | |||
1019 | if (copy_to_user(wrq->u.data.pointer, | ||
1020 | option[adapter->scantype], | ||
1021 | wrq->u.data.length)) { | ||
1022 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
1023 | ret = -EFAULT; | ||
1024 | } | ||
1025 | |||
1026 | break; | ||
1027 | default: | ||
1028 | lbs_pr_debug(1, "Invalid Scan type Ioctl Option\n"); | ||
1029 | ret = -EINVAL; | ||
1030 | break; | ||
1031 | } | ||
1032 | |||
1033 | return ret; | ||
1034 | } | ||
1035 | |||
1036 | static int wlan_scan_mode_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
1037 | { | ||
1038 | wlan_adapter *adapter = priv->adapter; | ||
1039 | u8 buf[12]; | ||
1040 | u8 *option[] = { "bss", "ibss", "any", "get" }; | ||
1041 | int i, max_options = (sizeof(option) / sizeof(option[0])); | ||
1042 | int ret = 0; | ||
1043 | |||
1044 | ENTER(); | ||
1045 | |||
1046 | memset(buf, 0, sizeof(buf)); | ||
1047 | |||
1048 | if (copy_from_user(buf, wrq->u.data.pointer, min_t(size_t, sizeof(buf), | ||
1049 | wrq->u.data.length))) { | ||
1050 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
1051 | return -EFAULT; | ||
1052 | } | ||
1053 | |||
1054 | lbs_pr_debug(1, "Scan mode Option = %s\n", buf); | ||
1055 | |||
1056 | buf[sizeof(buf) - 1] = '\0'; | ||
1057 | |||
1058 | for (i = 0; i < max_options; i++) { | ||
1059 | if (!strcmp(buf, option[i])) | ||
1060 | break; | ||
1061 | } | ||
1062 | |||
1063 | switch (i) { | ||
1064 | |||
1065 | case 0: | ||
1066 | adapter->scanmode = cmd_bss_type_bss; | ||
1067 | break; | ||
1068 | case 1: | ||
1069 | adapter->scanmode = cmd_bss_type_ibss; | ||
1070 | break; | ||
1071 | case 2: | ||
1072 | adapter->scanmode = cmd_bss_type_any; | ||
1073 | break; | ||
1074 | case 3: | ||
1075 | |||
1076 | wrq->u.data.length = strlen(option[adapter->scanmode - 1]) + 1; | ||
1077 | |||
1078 | lbs_pr_debug(1, "Get Scan mode Option = %s\n", | ||
1079 | option[adapter->scanmode - 1]); | ||
1080 | |||
1081 | lbs_pr_debug(1, "Scan mode length %d\n", wrq->u.data.length); | ||
1082 | |||
1083 | if (copy_to_user(wrq->u.data.pointer, | ||
1084 | option[adapter->scanmode - 1], | ||
1085 | wrq->u.data.length)) { | ||
1086 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
1087 | ret = -EFAULT; | ||
1088 | } | ||
1089 | lbs_pr_debug(1, "GET Scan type Option after copy = %s\n", | ||
1090 | (char *)wrq->u.data.pointer); | ||
1091 | |||
1092 | break; | ||
1093 | |||
1094 | default: | ||
1095 | lbs_pr_debug(1, "Invalid Scan mode Ioctl Option\n"); | ||
1096 | ret = -EINVAL; | ||
1097 | break; | ||
1098 | } | ||
1099 | |||
1100 | LEAVE(); | ||
1101 | return ret; | ||
1102 | } | ||
1103 | |||
1104 | /** | ||
1105 | * @brief Get/Set Adhoc G Rate | ||
1106 | * | ||
1107 | * @param priv A pointer to wlan_private structure | ||
1108 | * @param wrq A pointer to user data | ||
1109 | * @return 0--success, otherwise fail | ||
1110 | */ | ||
1111 | static int wlan_do_set_grate_ioctl(wlan_private * priv, struct iwreq *wrq) | ||
1112 | { | ||
1113 | wlan_adapter *adapter = priv->adapter; | ||
1114 | int data, data1; | ||
1115 | int *val; | ||
1116 | |||
1117 | ENTER(); | ||
1118 | |||
1119 | data1 = SUBCMD_DATA(wrq); | ||
1120 | switch (data1) { | ||
1121 | case 0: | ||
1122 | adapter->adhoc_grate_enabled = 0; | ||
1123 | break; | ||
1124 | case 1: | ||
1125 | adapter->adhoc_grate_enabled = 1; | ||
1126 | break; | ||
1127 | case 2: | ||
1128 | break; | ||
1129 | default: | ||
1130 | return -EINVAL; | ||
1131 | } | ||
1132 | data = adapter->adhoc_grate_enabled; | ||
1133 | val = (int *)wrq->u.name; | ||
1134 | *val = data; | ||
1135 | LEAVE(); | ||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | static inline int hex2int(char c) | ||
1140 | { | ||
1141 | if (c >= '0' && c <= '9') | ||
1142 | return (c - '0'); | ||
1143 | if (c >= 'a' && c <= 'f') | ||
1144 | return (c - 'a' + 10); | ||
1145 | if (c >= 'A' && c <= 'F') | ||
1146 | return (c - 'A' + 10); | ||
1147 | return -1; | ||
1148 | } | ||
1149 | |||
1150 | /* Convert a string representation of a MAC address ("xx:xx:xx:xx:xx:xx") | ||
1151 | into binary format (6 bytes). | ||
1152 | |||
1153 | This function expects that each byte is represented with 2 characters | ||
1154 | (e.g., 11:2:11:11:11:11 is invalid) | ||
1155 | |||
1156 | */ | ||
1157 | static char *eth_str2addr(char *ethstr, u8 * addr) | ||
1158 | { | ||
1159 | int i, val, val2; | ||
1160 | char *pos = ethstr; | ||
1161 | |||
1162 | /* get rid of initial blanks */ | ||
1163 | while (*pos == ' ' || *pos == '\t') | ||
1164 | ++pos; | ||
1165 | |||
1166 | for (i = 0; i < 6; i++) { | ||
1167 | val = hex2int(*pos++); | ||
1168 | if (val < 0) | ||
1169 | return NULL; | ||
1170 | val2 = hex2int(*pos++); | ||
1171 | if (val2 < 0) | ||
1172 | return NULL; | ||
1173 | addr[i] = (val * 16 + val2) & 0xff; | ||
1174 | |||
1175 | if (i < 5 && *pos++ != ':') | ||
1176 | return NULL; | ||
1177 | } | ||
1178 | return pos; | ||
1179 | } | ||
1180 | |||
1181 | /* this writes xx:xx:xx:xx:xx:xx into ethstr | ||
1182 | (ethstr must have space for 18 chars) */ | ||
1183 | static int eth_addr2str(u8 * addr, char *ethstr) | ||
1184 | { | ||
1185 | int i; | ||
1186 | char *pos = ethstr; | ||
1187 | |||
1188 | for (i = 0; i < 6; i++) { | ||
1189 | sprintf(pos, "%02x", addr[i] & 0xff); | ||
1190 | pos += 2; | ||
1191 | if (i < 5) | ||
1192 | *pos++ = ':'; | ||
1193 | } | ||
1194 | return 17; | ||
1195 | } | ||
1196 | |||
1197 | /** | ||
1198 | * @brief Add an entry to the BT table | ||
1199 | * @param priv A pointer to wlan_private structure | ||
1200 | * @param req A pointer to ifreq structure | ||
1201 | * @return 0 --success, otherwise fail | ||
1202 | */ | ||
1203 | static int wlan_bt_add_ioctl(wlan_private * priv, struct ifreq *req) | ||
1204 | { | ||
1205 | struct iwreq *wrq = (struct iwreq *)req; | ||
1206 | char ethaddrs_str[18]; | ||
1207 | char *pos; | ||
1208 | u8 ethaddr[ETH_ALEN]; | ||
1209 | |||
1210 | ENTER(); | ||
1211 | if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, | ||
1212 | sizeof(ethaddrs_str))) | ||
1213 | return -EFAULT; | ||
1214 | |||
1215 | if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { | ||
1216 | lbs_pr_info("BT_ADD: Invalid MAC address\n"); | ||
1217 | return -EINVAL; | ||
1218 | } | ||
1219 | |||
1220 | lbs_pr_debug(1, "BT: adding %s\n", ethaddrs_str); | ||
1221 | LEAVE(); | ||
1222 | return (libertas_prepare_and_send_command(priv, cmd_bt_access, | ||
1223 | cmd_act_bt_access_add, | ||
1224 | cmd_option_waitforrsp, 0, ethaddr)); | ||
1225 | } | ||
1226 | |||
1227 | /** | ||
1228 | * @brief Delete an entry from the BT table | ||
1229 | * @param priv A pointer to wlan_private structure | ||
1230 | * @param req A pointer to ifreq structure | ||
1231 | * @return 0 --success, otherwise fail | ||
1232 | */ | ||
1233 | static int wlan_bt_del_ioctl(wlan_private * priv, struct ifreq *req) | ||
1234 | { | ||
1235 | struct iwreq *wrq = (struct iwreq *)req; | ||
1236 | char ethaddrs_str[18]; | ||
1237 | u8 ethaddr[ETH_ALEN]; | ||
1238 | char *pos; | ||
1239 | |||
1240 | ENTER(); | ||
1241 | if (copy_from_user(ethaddrs_str, wrq->u.data.pointer, | ||
1242 | sizeof(ethaddrs_str))) | ||
1243 | return -EFAULT; | ||
1244 | |||
1245 | if ((pos = eth_str2addr(ethaddrs_str, ethaddr)) == NULL) { | ||
1246 | lbs_pr_info("Invalid MAC address\n"); | ||
1247 | return -EINVAL; | ||
1248 | } | ||
1249 | |||
1250 | lbs_pr_debug(1, "BT: deleting %s\n", ethaddrs_str); | ||
1251 | |||
1252 | return (libertas_prepare_and_send_command(priv, | ||
1253 | cmd_bt_access, | ||
1254 | cmd_act_bt_access_del, | ||
1255 | cmd_option_waitforrsp, 0, ethaddr)); | ||
1256 | LEAVE(); | ||
1257 | return 0; | ||
1258 | } | ||
1259 | |||
1260 | /** | ||
1261 | * @brief Reset all entries from the BT table | ||
1262 | * @param priv A pointer to wlan_private structure | ||
1263 | * @return 0 --success, otherwise fail | ||
1264 | */ | ||
1265 | static int wlan_bt_reset_ioctl(wlan_private * priv) | ||
1266 | { | ||
1267 | ENTER(); | ||
1268 | |||
1269 | lbs_pr_alert( "BT: resetting\n"); | ||
1270 | |||
1271 | return (libertas_prepare_and_send_command(priv, | ||
1272 | cmd_bt_access, | ||
1273 | cmd_act_bt_access_reset, | ||
1274 | cmd_option_waitforrsp, 0, NULL)); | ||
1275 | |||
1276 | LEAVE(); | ||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | /** | ||
1281 | * @brief List an entry from the BT table | ||
1282 | * @param priv A pointer to wlan_private structure | ||
1283 | * @param req A pointer to ifreq structure | ||
1284 | * @return 0 --success, otherwise fail | ||
1285 | */ | ||
1286 | static int wlan_bt_list_ioctl(wlan_private * priv, struct ifreq *req) | ||
1287 | { | ||
1288 | int pos; | ||
1289 | char *addr1; | ||
1290 | struct iwreq *wrq = (struct iwreq *)req; | ||
1291 | /* used to pass id and store the bt entry returned by the FW */ | ||
1292 | union { | ||
1293 | int id; | ||
1294 | char addr1addr2[2 * ETH_ALEN]; | ||
1295 | } param; | ||
1296 | static char outstr[64]; | ||
1297 | char *pbuf = outstr; | ||
1298 | int ret; | ||
1299 | |||
1300 | ENTER(); | ||
1301 | |||
1302 | if (copy_from_user(outstr, wrq->u.data.pointer, sizeof(outstr))) { | ||
1303 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
1304 | return -1; | ||
1305 | } | ||
1306 | param.id = simple_strtoul(outstr, NULL, 10); | ||
1307 | pos = sprintf(pbuf, "%d: ", param.id); | ||
1308 | pbuf += pos; | ||
1309 | |||
1310 | ret = libertas_prepare_and_send_command(priv, cmd_bt_access, | ||
1311 | cmd_act_bt_access_list, | ||
1312 | cmd_option_waitforrsp, 0, | ||
1313 | (char *)¶m); | ||
1314 | |||
1315 | if (ret == 0) { | ||
1316 | addr1 = param.addr1addr2; | ||
1317 | |||
1318 | pos = sprintf(pbuf, "ignoring traffic from "); | ||
1319 | pbuf += pos; | ||
1320 | pos = eth_addr2str(addr1, pbuf); | ||
1321 | pbuf += pos; | ||
1322 | } else { | ||
1323 | sprintf(pbuf, "(null)"); | ||
1324 | pbuf += pos; | ||
1325 | } | ||
1326 | |||
1327 | wrq->u.data.length = strlen(outstr); | ||
1328 | if (copy_to_user(wrq->u.data.pointer, (char *)outstr, | ||
1329 | wrq->u.data.length)) { | ||
1330 | lbs_pr_debug(1, "BT_LIST: Copy to user failed!\n"); | ||
1331 | return -EFAULT; | ||
1332 | } | ||
1333 | |||
1334 | LEAVE(); | ||
1335 | return 0; | ||
1336 | } | ||
1337 | |||
1338 | /** | ||
1339 | * @brief Find the next parameter in an input string | ||
1340 | * @param ptr A pointer to the input parameter string | ||
1341 | * @return A pointer to the next parameter, or 0 if no parameters left. | ||
1342 | */ | ||
1343 | static char * next_param(char * ptr) | ||
1344 | { | ||
1345 | if (!ptr) return NULL; | ||
1346 | while (*ptr == ' ' || *ptr == '\t') ++ptr; | ||
1347 | return (*ptr == '\0') ? NULL : ptr; | ||
1348 | } | ||
1349 | |||
1350 | /** | ||
1351 | * @brief Add an entry to the FWT table | ||
1352 | * @param priv A pointer to wlan_private structure | ||
1353 | * @param req A pointer to ifreq structure | ||
1354 | * @return 0 --success, otherwise fail | ||
1355 | */ | ||
1356 | static int wlan_fwt_add_ioctl(wlan_private * priv, struct ifreq *req) | ||
1357 | { | ||
1358 | struct iwreq *wrq = (struct iwreq *)req; | ||
1359 | char in_str[128]; | ||
1360 | static struct cmd_ds_fwt_access fwt_access; | ||
1361 | char *ptr; | ||
1362 | |||
1363 | ENTER(); | ||
1364 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1365 | return -EFAULT; | ||
1366 | |||
1367 | if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { | ||
1368 | lbs_pr_alert( "FWT_ADD: Invalid MAC address 1\n"); | ||
1369 | return -EINVAL; | ||
1370 | } | ||
1371 | |||
1372 | if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { | ||
1373 | lbs_pr_alert( "FWT_ADD: Invalid MAC address 2\n"); | ||
1374 | return -EINVAL; | ||
1375 | } | ||
1376 | |||
1377 | if ((ptr = next_param(ptr))) | ||
1378 | fwt_access.metric = | ||
1379 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1380 | else | ||
1381 | fwt_access.metric = FWT_DEFAULT_METRIC; | ||
1382 | |||
1383 | if ((ptr = next_param(ptr))) | ||
1384 | fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); | ||
1385 | else | ||
1386 | fwt_access.dir = FWT_DEFAULT_DIR; | ||
1387 | |||
1388 | if ((ptr = next_param(ptr))) | ||
1389 | fwt_access.ssn = | ||
1390 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1391 | else | ||
1392 | fwt_access.ssn = FWT_DEFAULT_SSN; | ||
1393 | |||
1394 | if ((ptr = next_param(ptr))) | ||
1395 | fwt_access.dsn = | ||
1396 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1397 | else | ||
1398 | fwt_access.dsn = FWT_DEFAULT_DSN; | ||
1399 | |||
1400 | if ((ptr = next_param(ptr))) | ||
1401 | fwt_access.hopcount = simple_strtoul(ptr, &ptr, 10); | ||
1402 | else | ||
1403 | fwt_access.hopcount = FWT_DEFAULT_HOPCOUNT; | ||
1404 | |||
1405 | if ((ptr = next_param(ptr))) | ||
1406 | fwt_access.ttl = simple_strtoul(ptr, &ptr, 10); | ||
1407 | else | ||
1408 | fwt_access.ttl = FWT_DEFAULT_TTL; | ||
1409 | |||
1410 | if ((ptr = next_param(ptr))) | ||
1411 | fwt_access.expiration = | ||
1412 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1413 | else | ||
1414 | fwt_access.expiration = FWT_DEFAULT_EXPIRATION; | ||
1415 | |||
1416 | if ((ptr = next_param(ptr))) | ||
1417 | fwt_access.sleepmode = (u8)simple_strtoul(ptr, &ptr, 10); | ||
1418 | else | ||
1419 | fwt_access.sleepmode = FWT_DEFAULT_SLEEPMODE; | ||
1420 | |||
1421 | if ((ptr = next_param(ptr))) | ||
1422 | fwt_access.snr = | ||
1423 | cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1424 | else | ||
1425 | fwt_access.snr = FWT_DEFAULT_SNR; | ||
1426 | |||
1427 | #ifdef DEBUG | ||
1428 | { | ||
1429 | char ethaddr1_str[18], ethaddr2_str[18]; | ||
1430 | eth_addr2str(fwt_access.da, ethaddr1_str); | ||
1431 | eth_addr2str(fwt_access.ra, ethaddr2_str); | ||
1432 | lbs_pr_debug(1, "FWT_ADD: adding (da:%s,%i,ra:%s)\n", ethaddr1_str, | ||
1433 | fwt_access.dir, ethaddr2_str); | ||
1434 | lbs_pr_debug(1, "FWT_ADD: ssn:%u dsn:%u met:%u hop:%u ttl:%u exp:%u slp:%u snr:%u\n", | ||
1435 | fwt_access.ssn, fwt_access.dsn, fwt_access.metric, | ||
1436 | fwt_access.hopcount, fwt_access.ttl, fwt_access.expiration, | ||
1437 | fwt_access.sleepmode, fwt_access.snr); | ||
1438 | } | ||
1439 | #endif | ||
1440 | |||
1441 | LEAVE(); | ||
1442 | return (libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1443 | cmd_act_fwt_access_add, | ||
1444 | cmd_option_waitforrsp, 0, | ||
1445 | (void *)&fwt_access)); | ||
1446 | } | ||
1447 | |||
1448 | /** | ||
1449 | * @brief Delete an entry from the FWT table | ||
1450 | * @param priv A pointer to wlan_private structure | ||
1451 | * @param req A pointer to ifreq structure | ||
1452 | * @return 0 --success, otherwise fail | ||
1453 | */ | ||
1454 | static int wlan_fwt_del_ioctl(wlan_private * priv, struct ifreq *req) | ||
1455 | { | ||
1456 | struct iwreq *wrq = (struct iwreq *)req; | ||
1457 | char in_str[64]; | ||
1458 | static struct cmd_ds_fwt_access fwt_access; | ||
1459 | char *ptr; | ||
1460 | |||
1461 | ENTER(); | ||
1462 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1463 | return -EFAULT; | ||
1464 | |||
1465 | if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { | ||
1466 | lbs_pr_alert( "FWT_DEL: Invalid MAC address 1\n"); | ||
1467 | return -EINVAL; | ||
1468 | } | ||
1469 | |||
1470 | if ((ptr = eth_str2addr(ptr, fwt_access.ra)) == NULL) { | ||
1471 | lbs_pr_alert( "FWT_DEL: Invalid MAC address 2\n"); | ||
1472 | return -EINVAL; | ||
1473 | } | ||
1474 | |||
1475 | if ((ptr = next_param(ptr))) | ||
1476 | fwt_access.dir = (u8)simple_strtoul(ptr, &ptr, 10); | ||
1477 | else | ||
1478 | fwt_access.dir = FWT_DEFAULT_DIR; | ||
1479 | |||
1480 | #ifdef DEBUG | ||
1481 | { | ||
1482 | char ethaddr1_str[18], ethaddr2_str[18]; | ||
1483 | lbs_pr_debug(1, "FWT_DEL: line is %s\n", in_str); | ||
1484 | eth_addr2str(fwt_access.da, ethaddr1_str); | ||
1485 | eth_addr2str(fwt_access.ra, ethaddr2_str); | ||
1486 | lbs_pr_debug(1, "FWT_DEL: removing (da:%s,ra:%s,dir:%d)\n", ethaddr1_str, | ||
1487 | ethaddr2_str, fwt_access.dir); | ||
1488 | } | ||
1489 | #endif | ||
1490 | |||
1491 | LEAVE(); | ||
1492 | return (libertas_prepare_and_send_command(priv, | ||
1493 | cmd_fwt_access, | ||
1494 | cmd_act_fwt_access_del, | ||
1495 | cmd_option_waitforrsp, 0, | ||
1496 | (void *)&fwt_access)); | ||
1497 | } | ||
1498 | |||
1499 | |||
1500 | /** | ||
1501 | * @brief Print route parameters | ||
1502 | * @param fwt_access struct cmd_ds_fwt_access with route info | ||
1503 | * @param buf destination buffer for route info | ||
1504 | */ | ||
1505 | static void print_route(struct cmd_ds_fwt_access fwt_access, char *buf) | ||
1506 | { | ||
1507 | buf += sprintf(buf, " "); | ||
1508 | buf += eth_addr2str(fwt_access.da, buf); | ||
1509 | buf += sprintf(buf, " "); | ||
1510 | buf += eth_addr2str(fwt_access.ra, buf); | ||
1511 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.metric)); | ||
1512 | buf += sprintf(buf, " %u", fwt_access.dir); | ||
1513 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.ssn)); | ||
1514 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.dsn)); | ||
1515 | buf += sprintf(buf, " %u", fwt_access.hopcount); | ||
1516 | buf += sprintf(buf, " %u", fwt_access.ttl); | ||
1517 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.expiration)); | ||
1518 | buf += sprintf(buf, " %u", fwt_access.sleepmode); | ||
1519 | buf += sprintf(buf, " %u", le32_to_cpu(fwt_access.snr)); | ||
1520 | } | ||
1521 | |||
1522 | /** | ||
1523 | * @brief Lookup an entry in the FWT table | ||
1524 | * @param priv A pointer to wlan_private structure | ||
1525 | * @param req A pointer to ifreq structure | ||
1526 | * @return 0 --success, otherwise fail | ||
1527 | */ | ||
1528 | static int wlan_fwt_lookup_ioctl(wlan_private * priv, struct ifreq *req) | ||
1529 | { | ||
1530 | struct iwreq *wrq = (struct iwreq *)req; | ||
1531 | char in_str[64]; | ||
1532 | char *ptr; | ||
1533 | static struct cmd_ds_fwt_access fwt_access; | ||
1534 | static char out_str[128]; | ||
1535 | int ret; | ||
1536 | |||
1537 | ENTER(); | ||
1538 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1539 | return -EFAULT; | ||
1540 | |||
1541 | if ((ptr = eth_str2addr(in_str, fwt_access.da)) == NULL) { | ||
1542 | lbs_pr_alert( "FWT_LOOKUP: Invalid MAC address\n"); | ||
1543 | return -EINVAL; | ||
1544 | } | ||
1545 | |||
1546 | #ifdef DEBUG | ||
1547 | { | ||
1548 | char ethaddr1_str[18]; | ||
1549 | lbs_pr_debug(1, "FWT_LOOKUP: line is %s\n", in_str); | ||
1550 | eth_addr2str(fwt_access.da, ethaddr1_str); | ||
1551 | lbs_pr_debug(1, "FWT_LOOKUP: looking for (da:%s)\n", ethaddr1_str); | ||
1552 | } | ||
1553 | #endif | ||
1554 | |||
1555 | ret = libertas_prepare_and_send_command(priv, | ||
1556 | cmd_fwt_access, | ||
1557 | cmd_act_fwt_access_lookup, | ||
1558 | cmd_option_waitforrsp, 0, | ||
1559 | (void *)&fwt_access); | ||
1560 | |||
1561 | if (ret == 0) | ||
1562 | print_route(fwt_access, out_str); | ||
1563 | else | ||
1564 | sprintf(out_str, "(null)"); | ||
1565 | |||
1566 | wrq->u.data.length = strlen(out_str); | ||
1567 | if (copy_to_user(wrq->u.data.pointer, (char *)out_str, | ||
1568 | wrq->u.data.length)) { | ||
1569 | lbs_pr_debug(1, "FWT_LOOKUP: Copy to user failed!\n"); | ||
1570 | return -EFAULT; | ||
1571 | } | ||
1572 | |||
1573 | LEAVE(); | ||
1574 | return 0; | ||
1575 | } | ||
1576 | |||
1577 | /** | ||
1578 | * @brief Reset all entries from the FWT table | ||
1579 | * @param priv A pointer to wlan_private structure | ||
1580 | * @return 0 --success, otherwise fail | ||
1581 | */ | ||
1582 | static int wlan_fwt_reset_ioctl(wlan_private * priv) | ||
1583 | { | ||
1584 | lbs_pr_debug(1, "FWT: resetting\n"); | ||
1585 | |||
1586 | return (libertas_prepare_and_send_command(priv, | ||
1587 | cmd_fwt_access, | ||
1588 | cmd_act_fwt_access_reset, | ||
1589 | cmd_option_waitforrsp, 0, NULL)); | ||
1590 | } | ||
1591 | |||
1592 | /** | ||
1593 | * @brief List an entry from the FWT table | ||
1594 | * @param priv A pointer to wlan_private structure | ||
1595 | * @param req A pointer to ifreq structure | ||
1596 | * @return 0 --success, otherwise fail | ||
1597 | */ | ||
1598 | static int wlan_fwt_list_ioctl(wlan_private * priv, struct ifreq *req) | ||
1599 | { | ||
1600 | struct iwreq *wrq = (struct iwreq *)req; | ||
1601 | char in_str[8]; | ||
1602 | static struct cmd_ds_fwt_access fwt_access; | ||
1603 | char *ptr = in_str; | ||
1604 | static char out_str[128]; | ||
1605 | char *pbuf = out_str; | ||
1606 | int ret; | ||
1607 | |||
1608 | ENTER(); | ||
1609 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1610 | return -EFAULT; | ||
1611 | |||
1612 | fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1613 | |||
1614 | #ifdef DEBUG | ||
1615 | { | ||
1616 | lbs_pr_debug(1, "FWT_LIST: line is %s\n", in_str); | ||
1617 | lbs_pr_debug(1, "FWT_LIST: listing id:%i\n", le32_to_cpu(fwt_access.id)); | ||
1618 | } | ||
1619 | #endif | ||
1620 | |||
1621 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1622 | cmd_act_fwt_access_list, | ||
1623 | cmd_option_waitforrsp, 0, (void *)&fwt_access); | ||
1624 | |||
1625 | if (ret == 0) | ||
1626 | print_route(fwt_access, pbuf); | ||
1627 | else | ||
1628 | pbuf += sprintf(pbuf, " (null)"); | ||
1629 | |||
1630 | wrq->u.data.length = strlen(out_str); | ||
1631 | if (copy_to_user(wrq->u.data.pointer, (char *)out_str, | ||
1632 | wrq->u.data.length)) { | ||
1633 | lbs_pr_debug(1, "FWT_LIST: Copy to user failed!\n"); | ||
1634 | return -EFAULT; | ||
1635 | } | ||
1636 | |||
1637 | LEAVE(); | ||
1638 | return 0; | ||
1639 | } | ||
1640 | |||
1641 | /** | ||
1642 | * @brief List an entry from the FRT table | ||
1643 | * @param priv A pointer to wlan_private structure | ||
1644 | * @param req A pointer to ifreq structure | ||
1645 | * @return 0 --success, otherwise fail | ||
1646 | */ | ||
1647 | static int wlan_fwt_list_route_ioctl(wlan_private * priv, struct ifreq *req) | ||
1648 | { | ||
1649 | struct iwreq *wrq = (struct iwreq *)req; | ||
1650 | char in_str[64]; | ||
1651 | static struct cmd_ds_fwt_access fwt_access; | ||
1652 | char *ptr = in_str; | ||
1653 | static char out_str[128]; | ||
1654 | char *pbuf = out_str; | ||
1655 | int ret; | ||
1656 | |||
1657 | ENTER(); | ||
1658 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1659 | return -EFAULT; | ||
1660 | |||
1661 | fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1662 | |||
1663 | #ifdef DEBUG | ||
1664 | { | ||
1665 | lbs_pr_debug(1, "FWT_LIST_ROUTE: line is %s\n", in_str); | ||
1666 | lbs_pr_debug(1, "FWT_LIST_ROUTE: listing id:%i\n", le32_to_cpu(fwt_access.id)); | ||
1667 | } | ||
1668 | #endif | ||
1669 | |||
1670 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1671 | cmd_act_fwt_access_list_route, | ||
1672 | cmd_option_waitforrsp, 0, (void *)&fwt_access); | ||
1673 | |||
1674 | if (ret == 0) { | ||
1675 | pbuf += sprintf(pbuf, " "); | ||
1676 | pbuf += eth_addr2str(fwt_access.da, pbuf); | ||
1677 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.metric)); | ||
1678 | pbuf += sprintf(pbuf, " %u", fwt_access.dir); | ||
1679 | /* note that the firmware returns the nid in the id field */ | ||
1680 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.id)); | ||
1681 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.ssn)); | ||
1682 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.dsn)); | ||
1683 | pbuf += sprintf(pbuf, " hop %u", fwt_access.hopcount); | ||
1684 | pbuf += sprintf(pbuf, " ttl %u", fwt_access.ttl); | ||
1685 | pbuf += sprintf(pbuf, " %u", le32_to_cpu(fwt_access.expiration)); | ||
1686 | } else | ||
1687 | pbuf += sprintf(pbuf, " (null)"); | ||
1688 | |||
1689 | wrq->u.data.length = strlen(out_str); | ||
1690 | if (copy_to_user(wrq->u.data.pointer, (char *)out_str, | ||
1691 | wrq->u.data.length)) { | ||
1692 | lbs_pr_debug(1, "FWT_LIST_ROUTE: Copy to user failed!\n"); | ||
1693 | return -EFAULT; | ||
1694 | } | ||
1695 | |||
1696 | LEAVE(); | ||
1697 | return 0; | ||
1698 | } | ||
1699 | |||
1700 | /** | ||
1701 | * @brief List an entry from the FNT table | ||
1702 | * @param priv A pointer to wlan_private structure | ||
1703 | * @param req A pointer to ifreq structure | ||
1704 | * @return 0 --success, otherwise fail | ||
1705 | */ | ||
1706 | static int wlan_fwt_list_neighbor_ioctl(wlan_private * priv, struct ifreq *req) | ||
1707 | { | ||
1708 | struct iwreq *wrq = (struct iwreq *)req; | ||
1709 | char in_str[8]; | ||
1710 | static struct cmd_ds_fwt_access fwt_access; | ||
1711 | char *ptr = in_str; | ||
1712 | static char out_str[128]; | ||
1713 | char *pbuf = out_str; | ||
1714 | int ret; | ||
1715 | |||
1716 | ENTER(); | ||
1717 | if (copy_from_user(in_str, wrq->u.data.pointer, sizeof(in_str))) | ||
1718 | return -EFAULT; | ||
1719 | |||
1720 | memset(&fwt_access, 0, sizeof(fwt_access)); | ||
1721 | fwt_access.id = cpu_to_le32(simple_strtoul(ptr, &ptr, 10)); | ||
1722 | |||
1723 | #ifdef DEBUG | ||
1724 | { | ||
1725 | lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: line is %s\n", in_str); | ||
1726 | lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: listing id:%i\n", le32_to_cpu(fwt_access.id)); | ||
1727 | } | ||
1728 | #endif | ||
1729 | |||
1730 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1731 | cmd_act_fwt_access_list_neighbor, | ||
1732 | cmd_option_waitforrsp, 0, | ||
1733 | (void *)&fwt_access); | ||
1734 | |||
1735 | if (ret == 0) { | ||
1736 | pbuf += sprintf(pbuf, " ra "); | ||
1737 | pbuf += eth_addr2str(fwt_access.ra, pbuf); | ||
1738 | pbuf += sprintf(pbuf, " slp %u", fwt_access.sleepmode); | ||
1739 | pbuf += sprintf(pbuf, " snr %u", le32_to_cpu(fwt_access.snr)); | ||
1740 | pbuf += sprintf(pbuf, " ref %u", le32_to_cpu(fwt_access.references)); | ||
1741 | } else | ||
1742 | pbuf += sprintf(pbuf, " (null)"); | ||
1743 | |||
1744 | wrq->u.data.length = strlen(out_str); | ||
1745 | if (copy_to_user(wrq->u.data.pointer, (char *)out_str, | ||
1746 | wrq->u.data.length)) { | ||
1747 | lbs_pr_debug(1, "FWT_LIST_NEIGHBOR: Copy to user failed!\n"); | ||
1748 | return -EFAULT; | ||
1749 | } | ||
1750 | |||
1751 | LEAVE(); | ||
1752 | return 0; | ||
1753 | } | ||
1754 | |||
1755 | /** | ||
1756 | * @brief Cleans up the route (FRT) and neighbor (FNT) tables | ||
1757 | * (Garbage Collection) | ||
1758 | * @param priv A pointer to wlan_private structure | ||
1759 | * @param req A pointer to ifreq structure | ||
1760 | * @return 0 --success, otherwise fail | ||
1761 | */ | ||
1762 | static int wlan_fwt_cleanup_ioctl(wlan_private * priv, struct ifreq *req) | ||
1763 | { | ||
1764 | static struct cmd_ds_fwt_access fwt_access; | ||
1765 | int ret; | ||
1766 | |||
1767 | ENTER(); | ||
1768 | |||
1769 | lbs_pr_debug(1, "FWT: cleaning up\n"); | ||
1770 | |||
1771 | memset(&fwt_access, 0, sizeof(fwt_access)); | ||
1772 | |||
1773 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1774 | cmd_act_fwt_access_cleanup, | ||
1775 | cmd_option_waitforrsp, 0, | ||
1776 | (void *)&fwt_access); | ||
1777 | |||
1778 | if (ret == 0) | ||
1779 | req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); | ||
1780 | else | ||
1781 | return -EFAULT; | ||
1782 | |||
1783 | LEAVE(); | ||
1784 | return 0; | ||
1785 | } | ||
1786 | |||
1787 | /** | ||
1788 | * @brief Gets firmware internal time (debug purposes) | ||
1789 | * @param priv A pointer to wlan_private structure | ||
1790 | * @param req A pointer to ifreq structure | ||
1791 | * @return 0 --success, otherwise fail | ||
1792 | */ | ||
1793 | static int wlan_fwt_time_ioctl(wlan_private * priv, struct ifreq *req) | ||
1794 | { | ||
1795 | static struct cmd_ds_fwt_access fwt_access; | ||
1796 | int ret; | ||
1797 | |||
1798 | ENTER(); | ||
1799 | |||
1800 | lbs_pr_debug(1, "FWT: getting time\n"); | ||
1801 | |||
1802 | memset(&fwt_access, 0, sizeof(fwt_access)); | ||
1803 | |||
1804 | ret = libertas_prepare_and_send_command(priv, cmd_fwt_access, | ||
1805 | cmd_act_fwt_access_time, | ||
1806 | cmd_option_waitforrsp, 0, | ||
1807 | (void *)&fwt_access); | ||
1808 | |||
1809 | if (ret == 0) | ||
1810 | req->ifr_data = (char *)(le32_to_cpu(fwt_access.references)); | ||
1811 | else | ||
1812 | return -EFAULT; | ||
1813 | |||
1814 | LEAVE(); | ||
1815 | return 0; | ||
1816 | } | ||
1817 | |||
1818 | /** | ||
1819 | * @brief Gets mesh ttl from firmware | ||
1820 | * @param priv A pointer to wlan_private structure | ||
1821 | * @param req A pointer to ifreq structure | ||
1822 | * @return 0 --success, otherwise fail | ||
1823 | */ | ||
1824 | static int wlan_mesh_get_ttl_ioctl(wlan_private * priv, struct ifreq *req) | ||
1825 | { | ||
1826 | struct cmd_ds_mesh_access mesh_access; | ||
1827 | int ret; | ||
1828 | |||
1829 | ENTER(); | ||
1830 | |||
1831 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
1832 | |||
1833 | ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, | ||
1834 | cmd_act_mesh_get_ttl, | ||
1835 | cmd_option_waitforrsp, 0, | ||
1836 | (void *)&mesh_access); | ||
1837 | |||
1838 | if (ret == 0) { | ||
1839 | req->ifr_data = (char *)(le32_to_cpu(mesh_access.data[0])); | ||
1840 | } | ||
1841 | else | ||
1842 | return -EFAULT; | ||
1843 | |||
1844 | LEAVE(); | ||
1845 | return 0; | ||
1846 | } | ||
1847 | |||
1848 | /** | ||
1849 | * @brief Gets mesh ttl from firmware | ||
1850 | * @param priv A pointer to wlan_private structure | ||
1851 | * @param ttl New ttl value | ||
1852 | * @return 0 --success, otherwise fail | ||
1853 | */ | ||
1854 | static int wlan_mesh_set_ttl_ioctl(wlan_private * priv, int ttl) | ||
1855 | { | ||
1856 | struct cmd_ds_mesh_access mesh_access; | ||
1857 | int ret; | ||
1858 | |||
1859 | ENTER(); | ||
1860 | |||
1861 | if( (ttl > 0xff) || (ttl < 0) ) | ||
1862 | return -EINVAL; | ||
1863 | |||
1864 | memset(&mesh_access, 0, sizeof(mesh_access)); | ||
1865 | mesh_access.data[0] = ttl; | ||
1866 | |||
1867 | ret = libertas_prepare_and_send_command(priv, cmd_mesh_access, | ||
1868 | cmd_act_mesh_set_ttl, | ||
1869 | cmd_option_waitforrsp, 0, | ||
1870 | (void *)&mesh_access); | ||
1871 | |||
1872 | if (ret != 0) | ||
1873 | ret = -EFAULT; | ||
1874 | |||
1875 | LEAVE(); | ||
1876 | return ret; | ||
1877 | } | ||
1878 | |||
1879 | /** | ||
1880 | * @brief ioctl function - entry point | ||
1881 | * | ||
1882 | * @param dev A pointer to net_device structure | ||
1883 | * @param req A pointer to ifreq structure | ||
1884 | * @param cmd command | ||
1885 | * @return 0--success, otherwise fail | ||
1886 | */ | ||
1887 | int libertas_do_ioctl(struct net_device *dev, struct ifreq *req, int cmd) | ||
1888 | { | ||
1889 | int subcmd = 0; | ||
1890 | int idata = 0; | ||
1891 | int *pdata; | ||
1892 | int ret = 0; | ||
1893 | wlan_private *priv = dev->priv; | ||
1894 | wlan_adapter *adapter = priv->adapter; | ||
1895 | struct iwreq *wrq = (struct iwreq *)req; | ||
1896 | |||
1897 | ENTER(); | ||
1898 | |||
1899 | lbs_pr_debug(1, "libertas_do_ioctl: ioctl cmd = 0x%x\n", cmd); | ||
1900 | switch (cmd) { | ||
1901 | case WLANSCAN_TYPE: | ||
1902 | lbs_pr_debug(1, "Scan type Ioctl\n"); | ||
1903 | ret = wlan_scan_type_ioctl(priv, wrq); | ||
1904 | break; | ||
1905 | |||
1906 | case WLAN_SETNONE_GETNONE: /* set WPA mode on/off ioctl #20 */ | ||
1907 | switch (wrq->u.data.flags) { | ||
1908 | case WLANDEAUTH: | ||
1909 | lbs_pr_debug(1, "Deauth\n"); | ||
1910 | libertas_send_deauth(priv); | ||
1911 | break; | ||
1912 | |||
1913 | case WLANADHOCSTOP: | ||
1914 | lbs_pr_debug(1, "Adhoc stop\n"); | ||
1915 | ret = libertas_do_adhocstop_ioctl(priv); | ||
1916 | break; | ||
1917 | |||
1918 | case WLANRADIOON: | ||
1919 | wlan_radio_ioctl(priv, 1); | ||
1920 | break; | ||
1921 | |||
1922 | case WLANRADIOOFF: | ||
1923 | wlan_radio_ioctl(priv, 0); | ||
1924 | break; | ||
1925 | case WLANWLANIDLEON: | ||
1926 | libertas_idle_on(priv); | ||
1927 | break; | ||
1928 | case WLANWLANIDLEOFF: | ||
1929 | libertas_idle_off(priv); | ||
1930 | break; | ||
1931 | case WLAN_SUBCMD_BT_RESET: /* bt_reset */ | ||
1932 | wlan_bt_reset_ioctl(priv); | ||
1933 | break; | ||
1934 | case WLAN_SUBCMD_FWT_RESET: /* fwt_reset */ | ||
1935 | wlan_fwt_reset_ioctl(priv); | ||
1936 | break; | ||
1937 | } /* End of switch */ | ||
1938 | break; | ||
1939 | |||
1940 | case WLANSETWPAIE: | ||
1941 | ret = wlan_setwpaie_ioctl(priv, req); | ||
1942 | break; | ||
1943 | case WLAN_SETINT_GETINT: | ||
1944 | /* The first 4 bytes of req->ifr_data is sub-ioctl number | ||
1945 | * after 4 bytes sits the payload. | ||
1946 | */ | ||
1947 | subcmd = (int)req->ifr_data; //from iwpriv subcmd | ||
1948 | switch (subcmd) { | ||
1949 | case WLANNF: | ||
1950 | ret = wlan_get_nf(priv, wrq); | ||
1951 | break; | ||
1952 | case WLANRSSI: | ||
1953 | ret = wlan_get_rssi(priv, wrq); | ||
1954 | break; | ||
1955 | case WLANENABLE11D: | ||
1956 | ret = libertas_cmd_enable_11d(priv, wrq); | ||
1957 | break; | ||
1958 | case WLANADHOCGRATE: | ||
1959 | ret = wlan_do_set_grate_ioctl(priv, wrq); | ||
1960 | break; | ||
1961 | case WLAN_SUBCMD_SET_PRESCAN: | ||
1962 | ret = wlan_subcmd_setprescan_ioctl(priv, wrq); | ||
1963 | break; | ||
1964 | } | ||
1965 | break; | ||
1966 | |||
1967 | case WLAN_SETONEINT_GETONEINT: | ||
1968 | switch (wrq->u.data.flags) { | ||
1969 | case WLAN_BEACON_INTERVAL: | ||
1970 | ret = wlan_beacon_interval(priv, wrq); | ||
1971 | break; | ||
1972 | |||
1973 | case WLAN_LISTENINTRVL: | ||
1974 | if (!wrq->u.data.length) { | ||
1975 | int data; | ||
1976 | lbs_pr_debug(1, "Get locallisteninterval value\n"); | ||
1977 | #define GET_ONE_INT 1 | ||
1978 | data = adapter->locallisteninterval; | ||
1979 | if (copy_to_user(wrq->u.data.pointer, | ||
1980 | &data, sizeof(int))) { | ||
1981 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
1982 | return -EFAULT; | ||
1983 | } | ||
1984 | |||
1985 | wrq->u.data.length = GET_ONE_INT; | ||
1986 | } else { | ||
1987 | int data; | ||
1988 | if (copy_from_user | ||
1989 | (&data, wrq->u.data.pointer, sizeof(int))) { | ||
1990 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
1991 | return -EFAULT; | ||
1992 | } | ||
1993 | |||
1994 | lbs_pr_debug(1, "Set locallisteninterval = %d\n", | ||
1995 | data); | ||
1996 | #define MAX_U16_VAL 65535 | ||
1997 | if (data > MAX_U16_VAL) { | ||
1998 | lbs_pr_debug(1, "Exceeds U16 value\n"); | ||
1999 | return -EINVAL; | ||
2000 | } | ||
2001 | adapter->locallisteninterval = data; | ||
2002 | } | ||
2003 | break; | ||
2004 | case WLAN_TXCONTROL: | ||
2005 | ret = wlan_txcontrol(priv, wrq); //adds for txcontrol ioctl | ||
2006 | break; | ||
2007 | |||
2008 | case WLAN_NULLPKTINTERVAL: | ||
2009 | ret = wlan_null_pkt_interval(priv, wrq); | ||
2010 | break; | ||
2011 | |||
2012 | default: | ||
2013 | ret = -EOPNOTSUPP; | ||
2014 | break; | ||
2015 | } | ||
2016 | break; | ||
2017 | |||
2018 | case WLAN_SETONEINT_GETNONE: | ||
2019 | /* The first 4 bytes of req->ifr_data is sub-ioctl number | ||
2020 | * after 4 bytes sits the payload. | ||
2021 | */ | ||
2022 | subcmd = wrq->u.data.flags; //from wpa_supplicant subcmd | ||
2023 | |||
2024 | if (!subcmd) | ||
2025 | subcmd = (int)req->ifr_data; //from iwpriv subcmd | ||
2026 | |||
2027 | switch (subcmd) { | ||
2028 | case WLAN_SUBCMD_SETRXANTENNA: /* SETRXANTENNA */ | ||
2029 | idata = SUBCMD_DATA(wrq); | ||
2030 | ret = setrxantenna(priv, idata); | ||
2031 | break; | ||
2032 | case WLAN_SUBCMD_SETTXANTENNA: /* SETTXANTENNA */ | ||
2033 | idata = SUBCMD_DATA(wrq); | ||
2034 | ret = settxantenna(priv, idata); | ||
2035 | break; | ||
2036 | case WLAN_SET_ATIM_WINDOW: | ||
2037 | adapter->atimwindow = SUBCMD_DATA(wrq); | ||
2038 | adapter->atimwindow = min_t(__u16, adapter->atimwindow, 50); | ||
2039 | break; | ||
2040 | case WLANSETBCNAVG: | ||
2041 | adapter->bcn_avg_factor = SUBCMD_DATA(wrq); | ||
2042 | if (adapter->bcn_avg_factor == 0) | ||
2043 | adapter->bcn_avg_factor = | ||
2044 | DEFAULT_BCN_AVG_FACTOR; | ||
2045 | if (adapter->bcn_avg_factor > DEFAULT_BCN_AVG_FACTOR) | ||
2046 | adapter->bcn_avg_factor = | ||
2047 | DEFAULT_BCN_AVG_FACTOR; | ||
2048 | break; | ||
2049 | case WLANSETDATAAVG: | ||
2050 | adapter->data_avg_factor = SUBCMD_DATA(wrq); | ||
2051 | if (adapter->data_avg_factor == 0) | ||
2052 | adapter->data_avg_factor = | ||
2053 | DEFAULT_DATA_AVG_FACTOR; | ||
2054 | if (adapter->data_avg_factor > DEFAULT_DATA_AVG_FACTOR) | ||
2055 | adapter->data_avg_factor = | ||
2056 | DEFAULT_DATA_AVG_FACTOR; | ||
2057 | break; | ||
2058 | case WLANSETREGION: | ||
2059 | idata = SUBCMD_DATA(wrq); | ||
2060 | ret = wlan_set_region(priv, (u16) idata); | ||
2061 | break; | ||
2062 | |||
2063 | case WLAN_SET_LISTEN_INTERVAL: | ||
2064 | idata = SUBCMD_DATA(wrq); | ||
2065 | adapter->listeninterval = (u16) idata; | ||
2066 | break; | ||
2067 | |||
2068 | case WLAN_SET_MULTIPLE_DTIM: | ||
2069 | ret = wlan_set_multiple_dtim_ioctl(priv, req); | ||
2070 | break; | ||
2071 | |||
2072 | case WLANSETAUTHALG: | ||
2073 | ret = wlan_setauthalg_ioctl(priv, req); | ||
2074 | break; | ||
2075 | |||
2076 | case WLANSET8021XAUTHALG: | ||
2077 | ret = wlan_set8021xauthalg_ioctl(priv, req); | ||
2078 | break; | ||
2079 | |||
2080 | case WLANSETENCRYPTIONMODE: | ||
2081 | ret = wlan_setencryptionmode_ioctl(priv, req); | ||
2082 | break; | ||
2083 | |||
2084 | case WLAN_SET_LINKMODE: | ||
2085 | ret = wlan_set_linkmode_ioctl(priv, req); | ||
2086 | break; | ||
2087 | |||
2088 | case WLAN_SET_RADIOMODE: | ||
2089 | ret = wlan_set_radiomode_ioctl(priv, req); | ||
2090 | break; | ||
2091 | |||
2092 | case WLAN_SET_DEBUGMODE: | ||
2093 | ret = wlan_set_debugmode_ioctl(priv, req); | ||
2094 | break; | ||
2095 | |||
2096 | case WLAN_SUBCMD_MESH_SET_TTL: | ||
2097 | idata = SUBCMD_DATA(wrq); | ||
2098 | ret = wlan_mesh_set_ttl_ioctl(priv, idata); | ||
2099 | break; | ||
2100 | |||
2101 | default: | ||
2102 | ret = -EOPNOTSUPP; | ||
2103 | break; | ||
2104 | } | ||
2105 | |||
2106 | break; | ||
2107 | |||
2108 | case WLAN_SETNONE_GETTWELVE_CHAR: /* Get Antenna settings */ | ||
2109 | /* | ||
2110 | * We've not used IW_PRIV_TYPE_FIXED so sub-ioctl number is | ||
2111 | * in flags of iwreq structure, otherwise it will be in | ||
2112 | * mode member of iwreq structure. | ||
2113 | */ | ||
2114 | switch ((int)wrq->u.data.flags) { | ||
2115 | case WLAN_SUBCMD_GETRXANTENNA: /* Get Rx Antenna */ | ||
2116 | ret = wlan_subcmd_getrxantenna_ioctl(priv, req); | ||
2117 | break; | ||
2118 | |||
2119 | case WLAN_SUBCMD_GETTXANTENNA: /* Get Tx Antenna */ | ||
2120 | ret = wlan_subcmd_gettxantenna_ioctl(priv, req); | ||
2121 | break; | ||
2122 | |||
2123 | case WLAN_GET_TSF: | ||
2124 | ret = wlan_get_tsf_ioctl(priv, wrq); | ||
2125 | break; | ||
2126 | } | ||
2127 | break; | ||
2128 | |||
2129 | case WLAN_SET128CHAR_GET128CHAR: | ||
2130 | switch ((int)wrq->u.data.flags) { | ||
2131 | |||
2132 | case WLANSCAN_MODE: | ||
2133 | lbs_pr_debug(1, "Scan mode Ioctl\n"); | ||
2134 | ret = wlan_scan_mode_ioctl(priv, wrq); | ||
2135 | break; | ||
2136 | |||
2137 | case WLAN_GET_ADHOC_STATUS: | ||
2138 | ret = wlan_get_adhoc_status_ioctl(priv, wrq); | ||
2139 | break; | ||
2140 | case WLAN_SUBCMD_BT_ADD: | ||
2141 | ret = wlan_bt_add_ioctl(priv, req); | ||
2142 | break; | ||
2143 | case WLAN_SUBCMD_BT_DEL: | ||
2144 | ret = wlan_bt_del_ioctl(priv, req); | ||
2145 | break; | ||
2146 | case WLAN_SUBCMD_BT_LIST: | ||
2147 | ret = wlan_bt_list_ioctl(priv, req); | ||
2148 | break; | ||
2149 | case WLAN_SUBCMD_FWT_ADD: | ||
2150 | ret = wlan_fwt_add_ioctl(priv, req); | ||
2151 | break; | ||
2152 | case WLAN_SUBCMD_FWT_DEL: | ||
2153 | ret = wlan_fwt_del_ioctl(priv, req); | ||
2154 | break; | ||
2155 | case WLAN_SUBCMD_FWT_LOOKUP: | ||
2156 | ret = wlan_fwt_lookup_ioctl(priv, req); | ||
2157 | break; | ||
2158 | case WLAN_SUBCMD_FWT_LIST_NEIGHBOR: | ||
2159 | ret = wlan_fwt_list_neighbor_ioctl(priv, req); | ||
2160 | break; | ||
2161 | case WLAN_SUBCMD_FWT_LIST: | ||
2162 | ret = wlan_fwt_list_ioctl(priv, req); | ||
2163 | break; | ||
2164 | case WLAN_SUBCMD_FWT_LIST_ROUTE: | ||
2165 | ret = wlan_fwt_list_route_ioctl(priv, req); | ||
2166 | break; | ||
2167 | } | ||
2168 | break; | ||
2169 | |||
2170 | case WLAN_SETNONE_GETONEINT: | ||
2171 | switch ((int)req->ifr_data) { | ||
2172 | case WLANGETBCNAVG: | ||
2173 | pdata = (int *)wrq->u.name; | ||
2174 | *pdata = (int)adapter->bcn_avg_factor; | ||
2175 | break; | ||
2176 | |||
2177 | case WLANGETREGION: | ||
2178 | pdata = (int *)wrq->u.name; | ||
2179 | *pdata = (int)adapter->regioncode; | ||
2180 | break; | ||
2181 | |||
2182 | case WLAN_GET_LISTEN_INTERVAL: | ||
2183 | pdata = (int *)wrq->u.name; | ||
2184 | *pdata = (int)adapter->listeninterval; | ||
2185 | break; | ||
2186 | |||
2187 | case WLAN_GET_LINKMODE: | ||
2188 | req->ifr_data = (char *)((u32) adapter->linkmode); | ||
2189 | break; | ||
2190 | |||
2191 | case WLAN_GET_RADIOMODE: | ||
2192 | req->ifr_data = (char *)((u32) adapter->radiomode); | ||
2193 | break; | ||
2194 | |||
2195 | case WLAN_GET_DEBUGMODE: | ||
2196 | req->ifr_data = (char *)((u32) adapter->debugmode); | ||
2197 | break; | ||
2198 | |||
2199 | case WLAN_GET_MULTIPLE_DTIM: | ||
2200 | pdata = (int *)wrq->u.name; | ||
2201 | *pdata = (int)adapter->multipledtim; | ||
2202 | break; | ||
2203 | case WLAN_GET_TX_RATE: | ||
2204 | ret = wlan_get_txrate_ioctl(priv, req); | ||
2205 | break; | ||
2206 | case WLAN_SUBCMD_FWT_CLEANUP: /* fwt_cleanup */ | ||
2207 | ret = wlan_fwt_cleanup_ioctl(priv, req); | ||
2208 | break; | ||
2209 | |||
2210 | case WLAN_SUBCMD_FWT_TIME: /* fwt_time */ | ||
2211 | ret = wlan_fwt_time_ioctl(priv, req); | ||
2212 | break; | ||
2213 | |||
2214 | case WLAN_SUBCMD_MESH_GET_TTL: | ||
2215 | ret = wlan_mesh_get_ttl_ioctl(priv, req); | ||
2216 | break; | ||
2217 | |||
2218 | default: | ||
2219 | ret = -EOPNOTSUPP; | ||
2220 | |||
2221 | } | ||
2222 | |||
2223 | break; | ||
2224 | |||
2225 | case WLANGETLOG: | ||
2226 | ret = wlan_do_getlog_ioctl(priv, wrq); | ||
2227 | break; | ||
2228 | |||
2229 | case WLAN_SET_GET_SIXTEEN_INT: | ||
2230 | switch ((int)wrq->u.data.flags) { | ||
2231 | case WLAN_TPCCFG: | ||
2232 | { | ||
2233 | int data[5]; | ||
2234 | struct cmd_ds_802_11_tpc_cfg cfg; | ||
2235 | memset(&cfg, 0, sizeof(cfg)); | ||
2236 | if ((wrq->u.data.length > 1) | ||
2237 | && (wrq->u.data.length != 5)) | ||
2238 | return -1; | ||
2239 | |||
2240 | if (wrq->u.data.length == 0) { | ||
2241 | cfg.action = | ||
2242 | cpu_to_le16 | ||
2243 | (cmd_act_get); | ||
2244 | } else { | ||
2245 | if (copy_from_user | ||
2246 | (data, wrq->u.data.pointer, | ||
2247 | sizeof(int) * 5)) { | ||
2248 | lbs_pr_debug(1, | ||
2249 | "Copy from user failed\n"); | ||
2250 | return -EFAULT; | ||
2251 | } | ||
2252 | |||
2253 | cfg.action = | ||
2254 | cpu_to_le16 | ||
2255 | (cmd_act_set); | ||
2256 | cfg.enable = data[0]; | ||
2257 | cfg.usesnr = data[1]; | ||
2258 | cfg.P0 = data[2]; | ||
2259 | cfg.P1 = data[3]; | ||
2260 | cfg.P2 = data[4]; | ||
2261 | } | ||
2262 | |||
2263 | ret = | ||
2264 | libertas_prepare_and_send_command(priv, | ||
2265 | cmd_802_11_tpc_cfg, | ||
2266 | 0, | ||
2267 | cmd_option_waitforrsp, | ||
2268 | 0, (void *)&cfg); | ||
2269 | |||
2270 | data[0] = cfg.enable; | ||
2271 | data[1] = cfg.usesnr; | ||
2272 | data[2] = cfg.P0; | ||
2273 | data[3] = cfg.P1; | ||
2274 | data[4] = cfg.P2; | ||
2275 | if (copy_to_user | ||
2276 | (wrq->u.data.pointer, data, | ||
2277 | sizeof(int) * 5)) { | ||
2278 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
2279 | return -EFAULT; | ||
2280 | } | ||
2281 | |||
2282 | wrq->u.data.length = 5; | ||
2283 | } | ||
2284 | break; | ||
2285 | |||
2286 | case WLAN_POWERCFG: | ||
2287 | { | ||
2288 | int data[4]; | ||
2289 | struct cmd_ds_802_11_pwr_cfg cfg; | ||
2290 | memset(&cfg, 0, sizeof(cfg)); | ||
2291 | if ((wrq->u.data.length > 1) | ||
2292 | && (wrq->u.data.length != 4)) | ||
2293 | return -1; | ||
2294 | if (wrq->u.data.length == 0) { | ||
2295 | cfg.action = | ||
2296 | cpu_to_le16 | ||
2297 | (cmd_act_get); | ||
2298 | } else { | ||
2299 | if (copy_from_user | ||
2300 | (data, wrq->u.data.pointer, | ||
2301 | sizeof(int) * 4)) { | ||
2302 | lbs_pr_debug(1, | ||
2303 | "Copy from user failed\n"); | ||
2304 | return -EFAULT; | ||
2305 | } | ||
2306 | |||
2307 | cfg.action = | ||
2308 | cpu_to_le16 | ||
2309 | (cmd_act_set); | ||
2310 | cfg.enable = data[0]; | ||
2311 | cfg.PA_P0 = data[1]; | ||
2312 | cfg.PA_P1 = data[2]; | ||
2313 | cfg.PA_P2 = data[3]; | ||
2314 | } | ||
2315 | ret = | ||
2316 | libertas_prepare_and_send_command(priv, | ||
2317 | cmd_802_11_pwr_cfg, | ||
2318 | 0, | ||
2319 | cmd_option_waitforrsp, | ||
2320 | 0, (void *)&cfg); | ||
2321 | data[0] = cfg.enable; | ||
2322 | data[1] = cfg.PA_P0; | ||
2323 | data[2] = cfg.PA_P1; | ||
2324 | data[3] = cfg.PA_P2; | ||
2325 | if (copy_to_user | ||
2326 | (wrq->u.data.pointer, data, | ||
2327 | sizeof(int) * 4)) { | ||
2328 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
2329 | return -EFAULT; | ||
2330 | } | ||
2331 | |||
2332 | wrq->u.data.length = 4; | ||
2333 | } | ||
2334 | break; | ||
2335 | case WLAN_AUTO_FREQ_SET: | ||
2336 | { | ||
2337 | int data[3]; | ||
2338 | struct cmd_ds_802_11_afc afc; | ||
2339 | memset(&afc, 0, sizeof(afc)); | ||
2340 | if (wrq->u.data.length != 3) | ||
2341 | return -1; | ||
2342 | if (copy_from_user | ||
2343 | (data, wrq->u.data.pointer, | ||
2344 | sizeof(int) * 3)) { | ||
2345 | lbs_pr_debug(1, "Copy from user failed\n"); | ||
2346 | return -EFAULT; | ||
2347 | } | ||
2348 | afc.afc_auto = data[0]; | ||
2349 | |||
2350 | if (afc.afc_auto != 0) { | ||
2351 | afc.threshold = data[1]; | ||
2352 | afc.period = data[2]; | ||
2353 | } else { | ||
2354 | afc.timing_offset = data[1]; | ||
2355 | afc.carrier_offset = data[2]; | ||
2356 | } | ||
2357 | ret = | ||
2358 | libertas_prepare_and_send_command(priv, | ||
2359 | cmd_802_11_set_afc, | ||
2360 | 0, | ||
2361 | cmd_option_waitforrsp, | ||
2362 | 0, (void *)&afc); | ||
2363 | } | ||
2364 | break; | ||
2365 | case WLAN_AUTO_FREQ_GET: | ||
2366 | { | ||
2367 | int data[3]; | ||
2368 | struct cmd_ds_802_11_afc afc; | ||
2369 | memset(&afc, 0, sizeof(afc)); | ||
2370 | ret = | ||
2371 | libertas_prepare_and_send_command(priv, | ||
2372 | cmd_802_11_get_afc, | ||
2373 | 0, | ||
2374 | cmd_option_waitforrsp, | ||
2375 | 0, (void *)&afc); | ||
2376 | data[0] = afc.afc_auto; | ||
2377 | data[1] = afc.timing_offset; | ||
2378 | data[2] = afc.carrier_offset; | ||
2379 | if (copy_to_user | ||
2380 | (wrq->u.data.pointer, data, | ||
2381 | sizeof(int) * 3)) { | ||
2382 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
2383 | return -EFAULT; | ||
2384 | } | ||
2385 | |||
2386 | wrq->u.data.length = 3; | ||
2387 | } | ||
2388 | break; | ||
2389 | case WLAN_SCANPROBES: | ||
2390 | { | ||
2391 | int data; | ||
2392 | if (wrq->u.data.length > 0) { | ||
2393 | if (copy_from_user | ||
2394 | (&data, wrq->u.data.pointer, | ||
2395 | sizeof(int))) { | ||
2396 | lbs_pr_debug(1, | ||
2397 | "Copy from user failed\n"); | ||
2398 | return -EFAULT; | ||
2399 | } | ||
2400 | |||
2401 | adapter->scanprobes = data; | ||
2402 | } else { | ||
2403 | data = adapter->scanprobes; | ||
2404 | if (copy_to_user | ||
2405 | (wrq->u.data.pointer, &data, | ||
2406 | sizeof(int))) { | ||
2407 | lbs_pr_debug(1, | ||
2408 | "Copy to user failed\n"); | ||
2409 | return -EFAULT; | ||
2410 | } | ||
2411 | } | ||
2412 | wrq->u.data.length = 1; | ||
2413 | } | ||
2414 | break; | ||
2415 | case WLAN_LED_GPIO_CTRL: | ||
2416 | { | ||
2417 | int i; | ||
2418 | int data[16]; | ||
2419 | |||
2420 | struct cmd_ds_802_11_led_ctrl ctrl; | ||
2421 | struct mrvlietypes_ledgpio *gpio = | ||
2422 | (struct mrvlietypes_ledgpio *) ctrl.data; | ||
2423 | |||
2424 | memset(&ctrl, 0, sizeof(ctrl)); | ||
2425 | if (wrq->u.data.length > MAX_LEDS * 2) | ||
2426 | return -ENOTSUPP; | ||
2427 | if ((wrq->u.data.length % 2) != 0) | ||
2428 | return -ENOTSUPP; | ||
2429 | if (wrq->u.data.length == 0) { | ||
2430 | ctrl.action = | ||
2431 | cpu_to_le16 | ||
2432 | (cmd_act_get); | ||
2433 | } else { | ||
2434 | if (copy_from_user | ||
2435 | (data, wrq->u.data.pointer, | ||
2436 | sizeof(int) * | ||
2437 | wrq->u.data.length)) { | ||
2438 | lbs_pr_debug(1, | ||
2439 | "Copy from user failed\n"); | ||
2440 | return -EFAULT; | ||
2441 | } | ||
2442 | |||
2443 | ctrl.action = | ||
2444 | cpu_to_le16 | ||
2445 | (cmd_act_set); | ||
2446 | ctrl.numled = cpu_to_le16(0); | ||
2447 | gpio->header.type = | ||
2448 | cpu_to_le16(TLV_TYPE_LED_GPIO); | ||
2449 | gpio->header.len = wrq->u.data.length; | ||
2450 | for (i = 0; i < wrq->u.data.length; | ||
2451 | i += 2) { | ||
2452 | gpio->ledpin[i / 2].led = | ||
2453 | data[i]; | ||
2454 | gpio->ledpin[i / 2].pin = | ||
2455 | data[i + 1]; | ||
2456 | } | ||
2457 | } | ||
2458 | ret = | ||
2459 | libertas_prepare_and_send_command(priv, | ||
2460 | cmd_802_11_led_gpio_ctrl, | ||
2461 | 0, | ||
2462 | cmd_option_waitforrsp, | ||
2463 | 0, (void *)&ctrl); | ||
2464 | for (i = 0; i < gpio->header.len; i += 2) { | ||
2465 | data[i] = gpio->ledpin[i / 2].led; | ||
2466 | data[i + 1] = gpio->ledpin[i / 2].pin; | ||
2467 | } | ||
2468 | if (copy_to_user(wrq->u.data.pointer, data, | ||
2469 | sizeof(int) * | ||
2470 | gpio->header.len)) { | ||
2471 | lbs_pr_debug(1, "Copy to user failed\n"); | ||
2472 | return -EFAULT; | ||
2473 | } | ||
2474 | |||
2475 | wrq->u.data.length = gpio->header.len; | ||
2476 | } | ||
2477 | break; | ||
2478 | case WLAN_ADAPT_RATESET: | ||
2479 | ret = wlan_adapt_rateset(priv, wrq); | ||
2480 | break; | ||
2481 | case WLAN_INACTIVITY_TIMEOUT: | ||
2482 | ret = wlan_inactivity_timeout(priv, wrq); | ||
2483 | break; | ||
2484 | case WLANSNR: | ||
2485 | ret = wlan_get_snr(priv, wrq); | ||
2486 | break; | ||
2487 | case WLAN_GET_RXINFO: | ||
2488 | ret = wlan_get_rxinfo(priv, wrq); | ||
2489 | } | ||
2490 | break; | ||
2491 | |||
2492 | default: | ||
2493 | ret = -EINVAL; | ||
2494 | break; | ||
2495 | } | ||
2496 | LEAVE(); | ||
2497 | return ret; | ||
2498 | } | ||
2499 | |||
2500 | |||