diff options
author | Kalle Valo <kvalo@codeaurora.org> | 2015-11-18 02:57:18 -0500 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2015-11-18 07:28:31 -0500 |
commit | 2be45b66dee080326d0f240aa4f18ef932cc3deb (patch) | |
tree | 2892a95ff9ae89065f3d554c8b72e704bdeec679 /drivers/net/wireless/orinoco/wext.c | |
parent | d3466830c165a298419788b88086ea99974e63ff (diff) |
orinoco: move under intersil vendor directory
Part of reorganising wireless drivers directory and Kconfig.
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/orinoco/wext.c')
-rw-r--r-- | drivers/net/wireless/orinoco/wext.c | 1413 |
1 files changed, 0 insertions, 1413 deletions
diff --git a/drivers/net/wireless/orinoco/wext.c b/drivers/net/wireless/orinoco/wext.c deleted file mode 100644 index 1d4dae422106..000000000000 --- a/drivers/net/wireless/orinoco/wext.c +++ /dev/null | |||
@@ -1,1413 +0,0 @@ | |||
1 | /* Wireless extensions support. | ||
2 | * | ||
3 | * See copyright notice in main.c | ||
4 | */ | ||
5 | #include <linux/slab.h> | ||
6 | #include <linux/kernel.h> | ||
7 | #include <linux/if_arp.h> | ||
8 | #include <linux/wireless.h> | ||
9 | #include <linux/ieee80211.h> | ||
10 | #include <linux/etherdevice.h> | ||
11 | #include <net/iw_handler.h> | ||
12 | #include <net/cfg80211.h> | ||
13 | #include <net/cfg80211-wext.h> | ||
14 | |||
15 | #include "hermes.h" | ||
16 | #include "hermes_rid.h" | ||
17 | #include "orinoco.h" | ||
18 | |||
19 | #include "hw.h" | ||
20 | #include "mic.h" | ||
21 | #include "scan.h" | ||
22 | #include "main.h" | ||
23 | |||
24 | #include "wext.h" | ||
25 | |||
26 | #define MAX_RID_LEN 1024 | ||
27 | |||
28 | /* Helper routine to record keys | ||
29 | * It is called under orinoco_lock so it may not sleep */ | ||
30 | static int orinoco_set_key(struct orinoco_private *priv, int index, | ||
31 | enum orinoco_alg alg, const u8 *key, int key_len, | ||
32 | const u8 *seq, int seq_len) | ||
33 | { | ||
34 | kzfree(priv->keys[index].key); | ||
35 | kzfree(priv->keys[index].seq); | ||
36 | |||
37 | if (key_len) { | ||
38 | priv->keys[index].key = kzalloc(key_len, GFP_ATOMIC); | ||
39 | if (!priv->keys[index].key) | ||
40 | goto nomem; | ||
41 | } else | ||
42 | priv->keys[index].key = NULL; | ||
43 | |||
44 | if (seq_len) { | ||
45 | priv->keys[index].seq = kzalloc(seq_len, GFP_ATOMIC); | ||
46 | if (!priv->keys[index].seq) | ||
47 | goto free_key; | ||
48 | } else | ||
49 | priv->keys[index].seq = NULL; | ||
50 | |||
51 | priv->keys[index].key_len = key_len; | ||
52 | priv->keys[index].seq_len = seq_len; | ||
53 | |||
54 | if (key_len) | ||
55 | memcpy((void *)priv->keys[index].key, key, key_len); | ||
56 | if (seq_len) | ||
57 | memcpy((void *)priv->keys[index].seq, seq, seq_len); | ||
58 | |||
59 | switch (alg) { | ||
60 | case ORINOCO_ALG_TKIP: | ||
61 | priv->keys[index].cipher = WLAN_CIPHER_SUITE_TKIP; | ||
62 | break; | ||
63 | |||
64 | case ORINOCO_ALG_WEP: | ||
65 | priv->keys[index].cipher = (key_len > SMALL_KEY_SIZE) ? | ||
66 | WLAN_CIPHER_SUITE_WEP104 : WLAN_CIPHER_SUITE_WEP40; | ||
67 | break; | ||
68 | |||
69 | case ORINOCO_ALG_NONE: | ||
70 | default: | ||
71 | priv->keys[index].cipher = 0; | ||
72 | break; | ||
73 | } | ||
74 | |||
75 | return 0; | ||
76 | |||
77 | free_key: | ||
78 | kfree(priv->keys[index].key); | ||
79 | priv->keys[index].key = NULL; | ||
80 | |||
81 | nomem: | ||
82 | priv->keys[index].key_len = 0; | ||
83 | priv->keys[index].seq_len = 0; | ||
84 | priv->keys[index].cipher = 0; | ||
85 | |||
86 | return -ENOMEM; | ||
87 | } | ||
88 | |||
89 | static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) | ||
90 | { | ||
91 | struct orinoco_private *priv = ndev_priv(dev); | ||
92 | struct hermes *hw = &priv->hw; | ||
93 | struct iw_statistics *wstats = &priv->wstats; | ||
94 | int err; | ||
95 | unsigned long flags; | ||
96 | |||
97 | if (!netif_device_present(dev)) { | ||
98 | printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", | ||
99 | dev->name); | ||
100 | return NULL; /* FIXME: Can we do better than this? */ | ||
101 | } | ||
102 | |||
103 | /* If busy, return the old stats. Returning NULL may cause | ||
104 | * the interface to disappear from /proc/net/wireless */ | ||
105 | if (orinoco_lock(priv, &flags) != 0) | ||
106 | return wstats; | ||
107 | |||
108 | /* We can't really wait for the tallies inquiry command to | ||
109 | * complete, so we just use the previous results and trigger | ||
110 | * a new tallies inquiry command for next time - Jean II */ | ||
111 | /* FIXME: Really we should wait for the inquiry to come back - | ||
112 | * as it is the stats we give don't make a whole lot of sense. | ||
113 | * Unfortunately, it's not clear how to do that within the | ||
114 | * wireless extensions framework: I think we're in user | ||
115 | * context, but a lock seems to be held by the time we get in | ||
116 | * here so we're not safe to sleep here. */ | ||
117 | hermes_inquire(hw, HERMES_INQ_TALLIES); | ||
118 | |||
119 | if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { | ||
120 | memset(&wstats->qual, 0, sizeof(wstats->qual)); | ||
121 | /* If a spy address is defined, we report stats of the | ||
122 | * first spy address - Jean II */ | ||
123 | if (SPY_NUMBER(priv)) { | ||
124 | wstats->qual.qual = priv->spy_data.spy_stat[0].qual; | ||
125 | wstats->qual.level = priv->spy_data.spy_stat[0].level; | ||
126 | wstats->qual.noise = priv->spy_data.spy_stat[0].noise; | ||
127 | wstats->qual.updated = | ||
128 | priv->spy_data.spy_stat[0].updated; | ||
129 | } | ||
130 | } else { | ||
131 | struct { | ||
132 | __le16 qual, signal, noise, unused; | ||
133 | } __packed cq; | ||
134 | |||
135 | err = HERMES_READ_RECORD(hw, USER_BAP, | ||
136 | HERMES_RID_COMMSQUALITY, &cq); | ||
137 | |||
138 | if (!err) { | ||
139 | wstats->qual.qual = (int)le16_to_cpu(cq.qual); | ||
140 | wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; | ||
141 | wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; | ||
142 | wstats->qual.updated = | ||
143 | IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | orinoco_unlock(priv, &flags); | ||
148 | return wstats; | ||
149 | } | ||
150 | |||
151 | /********************************************************************/ | ||
152 | /* Wireless extensions */ | ||
153 | /********************************************************************/ | ||
154 | |||
155 | static int orinoco_ioctl_setwap(struct net_device *dev, | ||
156 | struct iw_request_info *info, | ||
157 | struct sockaddr *ap_addr, | ||
158 | char *extra) | ||
159 | { | ||
160 | struct orinoco_private *priv = ndev_priv(dev); | ||
161 | int err = -EINPROGRESS; /* Call commit handler */ | ||
162 | unsigned long flags; | ||
163 | |||
164 | if (orinoco_lock(priv, &flags) != 0) | ||
165 | return -EBUSY; | ||
166 | |||
167 | /* Enable automatic roaming - no sanity checks are needed */ | ||
168 | if (is_zero_ether_addr(ap_addr->sa_data) || | ||
169 | is_broadcast_ether_addr(ap_addr->sa_data)) { | ||
170 | priv->bssid_fixed = 0; | ||
171 | eth_zero_addr(priv->desired_bssid); | ||
172 | |||
173 | /* "off" means keep existing connection */ | ||
174 | if (ap_addr->sa_data[0] == 0) { | ||
175 | __orinoco_hw_set_wap(priv); | ||
176 | err = 0; | ||
177 | } | ||
178 | goto out; | ||
179 | } | ||
180 | |||
181 | if (priv->firmware_type == FIRMWARE_TYPE_AGERE) { | ||
182 | printk(KERN_WARNING "%s: Lucent/Agere firmware doesn't " | ||
183 | "support manual roaming\n", | ||
184 | dev->name); | ||
185 | err = -EOPNOTSUPP; | ||
186 | goto out; | ||
187 | } | ||
188 | |||
189 | if (priv->iw_mode != NL80211_IFTYPE_STATION) { | ||
190 | printk(KERN_WARNING "%s: Manual roaming supported only in " | ||
191 | "managed mode\n", dev->name); | ||
192 | err = -EOPNOTSUPP; | ||
193 | goto out; | ||
194 | } | ||
195 | |||
196 | /* Intersil firmware hangs without Desired ESSID */ | ||
197 | if (priv->firmware_type == FIRMWARE_TYPE_INTERSIL && | ||
198 | strlen(priv->desired_essid) == 0) { | ||
199 | printk(KERN_WARNING "%s: Desired ESSID must be set for " | ||
200 | "manual roaming\n", dev->name); | ||
201 | err = -EOPNOTSUPP; | ||
202 | goto out; | ||
203 | } | ||
204 | |||
205 | /* Finally, enable manual roaming */ | ||
206 | priv->bssid_fixed = 1; | ||
207 | memcpy(priv->desired_bssid, &ap_addr->sa_data, ETH_ALEN); | ||
208 | |||
209 | out: | ||
210 | orinoco_unlock(priv, &flags); | ||
211 | return err; | ||
212 | } | ||
213 | |||
214 | static int orinoco_ioctl_getwap(struct net_device *dev, | ||
215 | struct iw_request_info *info, | ||
216 | struct sockaddr *ap_addr, | ||
217 | char *extra) | ||
218 | { | ||
219 | struct orinoco_private *priv = ndev_priv(dev); | ||
220 | |||
221 | int err = 0; | ||
222 | unsigned long flags; | ||
223 | |||
224 | if (orinoco_lock(priv, &flags) != 0) | ||
225 | return -EBUSY; | ||
226 | |||
227 | ap_addr->sa_family = ARPHRD_ETHER; | ||
228 | err = orinoco_hw_get_current_bssid(priv, ap_addr->sa_data); | ||
229 | |||
230 | orinoco_unlock(priv, &flags); | ||
231 | |||
232 | return err; | ||
233 | } | ||
234 | |||
235 | static int orinoco_ioctl_setiwencode(struct net_device *dev, | ||
236 | struct iw_request_info *info, | ||
237 | struct iw_point *erq, | ||
238 | char *keybuf) | ||
239 | { | ||
240 | struct orinoco_private *priv = ndev_priv(dev); | ||
241 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | ||
242 | int setindex = priv->tx_key; | ||
243 | enum orinoco_alg encode_alg = priv->encode_alg; | ||
244 | int restricted = priv->wep_restrict; | ||
245 | int err = -EINPROGRESS; /* Call commit handler */ | ||
246 | unsigned long flags; | ||
247 | |||
248 | if (!priv->has_wep) | ||
249 | return -EOPNOTSUPP; | ||
250 | |||
251 | if (erq->pointer) { | ||
252 | /* We actually have a key to set - check its length */ | ||
253 | if (erq->length > LARGE_KEY_SIZE) | ||
254 | return -E2BIG; | ||
255 | |||
256 | if ((erq->length > SMALL_KEY_SIZE) && !priv->has_big_wep) | ||
257 | return -E2BIG; | ||
258 | } | ||
259 | |||
260 | if (orinoco_lock(priv, &flags) != 0) | ||
261 | return -EBUSY; | ||
262 | |||
263 | /* Clear any TKIP key we have */ | ||
264 | if ((priv->has_wpa) && (priv->encode_alg == ORINOCO_ALG_TKIP)) | ||
265 | (void) orinoco_clear_tkip_key(priv, setindex); | ||
266 | |||
267 | if (erq->length > 0) { | ||
268 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) | ||
269 | index = priv->tx_key; | ||
270 | |||
271 | /* Switch on WEP if off */ | ||
272 | if (encode_alg != ORINOCO_ALG_WEP) { | ||
273 | setindex = index; | ||
274 | encode_alg = ORINOCO_ALG_WEP; | ||
275 | } | ||
276 | } else { | ||
277 | /* Important note : if the user do "iwconfig eth0 enc off", | ||
278 | * we will arrive there with an index of -1. This is valid | ||
279 | * but need to be taken care off... Jean II */ | ||
280 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) { | ||
281 | if ((index != -1) || (erq->flags == 0)) { | ||
282 | err = -EINVAL; | ||
283 | goto out; | ||
284 | } | ||
285 | } else { | ||
286 | /* Set the index : Check that the key is valid */ | ||
287 | if (priv->keys[index].key_len == 0) { | ||
288 | err = -EINVAL; | ||
289 | goto out; | ||
290 | } | ||
291 | setindex = index; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | if (erq->flags & IW_ENCODE_DISABLED) | ||
296 | encode_alg = ORINOCO_ALG_NONE; | ||
297 | if (erq->flags & IW_ENCODE_OPEN) | ||
298 | restricted = 0; | ||
299 | if (erq->flags & IW_ENCODE_RESTRICTED) | ||
300 | restricted = 1; | ||
301 | |||
302 | if (erq->pointer && erq->length > 0) { | ||
303 | err = orinoco_set_key(priv, index, ORINOCO_ALG_WEP, keybuf, | ||
304 | erq->length, NULL, 0); | ||
305 | } | ||
306 | priv->tx_key = setindex; | ||
307 | |||
308 | /* Try fast key change if connected and only keys are changed */ | ||
309 | if ((priv->encode_alg == encode_alg) && | ||
310 | (priv->wep_restrict == restricted) && | ||
311 | netif_carrier_ok(dev)) { | ||
312 | err = __orinoco_hw_setup_wepkeys(priv); | ||
313 | /* No need to commit if successful */ | ||
314 | goto out; | ||
315 | } | ||
316 | |||
317 | priv->encode_alg = encode_alg; | ||
318 | priv->wep_restrict = restricted; | ||
319 | |||
320 | out: | ||
321 | orinoco_unlock(priv, &flags); | ||
322 | |||
323 | return err; | ||
324 | } | ||
325 | |||
326 | static int orinoco_ioctl_getiwencode(struct net_device *dev, | ||
327 | struct iw_request_info *info, | ||
328 | struct iw_point *erq, | ||
329 | char *keybuf) | ||
330 | { | ||
331 | struct orinoco_private *priv = ndev_priv(dev); | ||
332 | int index = (erq->flags & IW_ENCODE_INDEX) - 1; | ||
333 | unsigned long flags; | ||
334 | |||
335 | if (!priv->has_wep) | ||
336 | return -EOPNOTSUPP; | ||
337 | |||
338 | if (orinoco_lock(priv, &flags) != 0) | ||
339 | return -EBUSY; | ||
340 | |||
341 | if ((index < 0) || (index >= ORINOCO_MAX_KEYS)) | ||
342 | index = priv->tx_key; | ||
343 | |||
344 | erq->flags = 0; | ||
345 | if (!priv->encode_alg) | ||
346 | erq->flags |= IW_ENCODE_DISABLED; | ||
347 | erq->flags |= index + 1; | ||
348 | |||
349 | if (priv->wep_restrict) | ||
350 | erq->flags |= IW_ENCODE_RESTRICTED; | ||
351 | else | ||
352 | erq->flags |= IW_ENCODE_OPEN; | ||
353 | |||
354 | erq->length = priv->keys[index].key_len; | ||
355 | |||
356 | memcpy(keybuf, priv->keys[index].key, erq->length); | ||
357 | |||
358 | orinoco_unlock(priv, &flags); | ||
359 | return 0; | ||
360 | } | ||
361 | |||
362 | static int orinoco_ioctl_setessid(struct net_device *dev, | ||
363 | struct iw_request_info *info, | ||
364 | struct iw_point *erq, | ||
365 | char *essidbuf) | ||
366 | { | ||
367 | struct orinoco_private *priv = ndev_priv(dev); | ||
368 | unsigned long flags; | ||
369 | |||
370 | /* Note : ESSID is ignored in Ad-Hoc demo mode, but we can set it | ||
371 | * anyway... - Jean II */ | ||
372 | |||
373 | /* Hum... Should not use Wireless Extension constant (may change), | ||
374 | * should use our own... - Jean II */ | ||
375 | if (erq->length > IW_ESSID_MAX_SIZE) | ||
376 | return -E2BIG; | ||
377 | |||
378 | if (orinoco_lock(priv, &flags) != 0) | ||
379 | return -EBUSY; | ||
380 | |||
381 | /* NULL the string (for NULL termination & ESSID = ANY) - Jean II */ | ||
382 | memset(priv->desired_essid, 0, sizeof(priv->desired_essid)); | ||
383 | |||
384 | /* If not ANY, get the new ESSID */ | ||
385 | if (erq->flags) | ||
386 | memcpy(priv->desired_essid, essidbuf, erq->length); | ||
387 | |||
388 | orinoco_unlock(priv, &flags); | ||
389 | |||
390 | return -EINPROGRESS; /* Call commit handler */ | ||
391 | } | ||
392 | |||
393 | static int orinoco_ioctl_getessid(struct net_device *dev, | ||
394 | struct iw_request_info *info, | ||
395 | struct iw_point *erq, | ||
396 | char *essidbuf) | ||
397 | { | ||
398 | struct orinoco_private *priv = ndev_priv(dev); | ||
399 | int active; | ||
400 | int err = 0; | ||
401 | unsigned long flags; | ||
402 | |||
403 | if (netif_running(dev)) { | ||
404 | err = orinoco_hw_get_essid(priv, &active, essidbuf); | ||
405 | if (err < 0) | ||
406 | return err; | ||
407 | erq->length = err; | ||
408 | } else { | ||
409 | if (orinoco_lock(priv, &flags) != 0) | ||
410 | return -EBUSY; | ||
411 | memcpy(essidbuf, priv->desired_essid, IW_ESSID_MAX_SIZE); | ||
412 | erq->length = strlen(priv->desired_essid); | ||
413 | orinoco_unlock(priv, &flags); | ||
414 | } | ||
415 | |||
416 | erq->flags = 1; | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | static int orinoco_ioctl_setfreq(struct net_device *dev, | ||
422 | struct iw_request_info *info, | ||
423 | struct iw_freq *frq, | ||
424 | char *extra) | ||
425 | { | ||
426 | struct orinoco_private *priv = ndev_priv(dev); | ||
427 | int chan = -1; | ||
428 | unsigned long flags; | ||
429 | int err = -EINPROGRESS; /* Call commit handler */ | ||
430 | |||
431 | /* In infrastructure mode the AP sets the channel */ | ||
432 | if (priv->iw_mode == NL80211_IFTYPE_STATION) | ||
433 | return -EBUSY; | ||
434 | |||
435 | if ((frq->e == 0) && (frq->m <= 1000)) { | ||
436 | /* Setting by channel number */ | ||
437 | chan = frq->m; | ||
438 | } else { | ||
439 | /* Setting by frequency */ | ||
440 | int denom = 1; | ||
441 | int i; | ||
442 | |||
443 | /* Calculate denominator to rescale to MHz */ | ||
444 | for (i = 0; i < (6 - frq->e); i++) | ||
445 | denom *= 10; | ||
446 | |||
447 | chan = ieee80211_frequency_to_channel(frq->m / denom); | ||
448 | } | ||
449 | |||
450 | if ((chan < 1) || (chan > NUM_CHANNELS) || | ||
451 | !(priv->channel_mask & (1 << (chan - 1)))) | ||
452 | return -EINVAL; | ||
453 | |||
454 | if (orinoco_lock(priv, &flags) != 0) | ||
455 | return -EBUSY; | ||
456 | |||
457 | priv->channel = chan; | ||
458 | if (priv->iw_mode == NL80211_IFTYPE_MONITOR) { | ||
459 | /* Fast channel change - no commit if successful */ | ||
460 | struct hermes *hw = &priv->hw; | ||
461 | err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST | | ||
462 | HERMES_TEST_SET_CHANNEL, | ||
463 | chan, NULL); | ||
464 | } | ||
465 | orinoco_unlock(priv, &flags); | ||
466 | |||
467 | return err; | ||
468 | } | ||
469 | |||
470 | static int orinoco_ioctl_getfreq(struct net_device *dev, | ||
471 | struct iw_request_info *info, | ||
472 | struct iw_freq *frq, | ||
473 | char *extra) | ||
474 | { | ||
475 | struct orinoco_private *priv = ndev_priv(dev); | ||
476 | int tmp; | ||
477 | |||
478 | /* Locking done in there */ | ||
479 | tmp = orinoco_hw_get_freq(priv); | ||
480 | if (tmp < 0) | ||
481 | return tmp; | ||
482 | |||
483 | frq->m = tmp * 100000; | ||
484 | frq->e = 1; | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int orinoco_ioctl_getsens(struct net_device *dev, | ||
490 | struct iw_request_info *info, | ||
491 | struct iw_param *srq, | ||
492 | char *extra) | ||
493 | { | ||
494 | struct orinoco_private *priv = ndev_priv(dev); | ||
495 | struct hermes *hw = &priv->hw; | ||
496 | u16 val; | ||
497 | int err; | ||
498 | unsigned long flags; | ||
499 | |||
500 | if (!priv->has_sensitivity) | ||
501 | return -EOPNOTSUPP; | ||
502 | |||
503 | if (orinoco_lock(priv, &flags) != 0) | ||
504 | return -EBUSY; | ||
505 | err = hermes_read_wordrec(hw, USER_BAP, | ||
506 | HERMES_RID_CNFSYSTEMSCALE, &val); | ||
507 | orinoco_unlock(priv, &flags); | ||
508 | |||
509 | if (err) | ||
510 | return err; | ||
511 | |||
512 | srq->value = val; | ||
513 | srq->fixed = 0; /* auto */ | ||
514 | |||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static int orinoco_ioctl_setsens(struct net_device *dev, | ||
519 | struct iw_request_info *info, | ||
520 | struct iw_param *srq, | ||
521 | char *extra) | ||
522 | { | ||
523 | struct orinoco_private *priv = ndev_priv(dev); | ||
524 | int val = srq->value; | ||
525 | unsigned long flags; | ||
526 | |||
527 | if (!priv->has_sensitivity) | ||
528 | return -EOPNOTSUPP; | ||
529 | |||
530 | if ((val < 1) || (val > 3)) | ||
531 | return -EINVAL; | ||
532 | |||
533 | if (orinoco_lock(priv, &flags) != 0) | ||
534 | return -EBUSY; | ||
535 | priv->ap_density = val; | ||
536 | orinoco_unlock(priv, &flags); | ||
537 | |||
538 | return -EINPROGRESS; /* Call commit handler */ | ||
539 | } | ||
540 | |||
541 | static int orinoco_ioctl_setrate(struct net_device *dev, | ||
542 | struct iw_request_info *info, | ||
543 | struct iw_param *rrq, | ||
544 | char *extra) | ||
545 | { | ||
546 | struct orinoco_private *priv = ndev_priv(dev); | ||
547 | int ratemode; | ||
548 | int bitrate; /* 100s of kilobits */ | ||
549 | unsigned long flags; | ||
550 | |||
551 | /* As the user space doesn't know our highest rate, it uses -1 | ||
552 | * to ask us to set the highest rate. Test it using "iwconfig | ||
553 | * ethX rate auto" - Jean II */ | ||
554 | if (rrq->value == -1) | ||
555 | bitrate = 110; | ||
556 | else { | ||
557 | if (rrq->value % 100000) | ||
558 | return -EINVAL; | ||
559 | bitrate = rrq->value / 100000; | ||
560 | } | ||
561 | |||
562 | ratemode = orinoco_get_bitratemode(bitrate, !rrq->fixed); | ||
563 | |||
564 | if (ratemode == -1) | ||
565 | return -EINVAL; | ||
566 | |||
567 | if (orinoco_lock(priv, &flags) != 0) | ||
568 | return -EBUSY; | ||
569 | priv->bitratemode = ratemode; | ||
570 | orinoco_unlock(priv, &flags); | ||
571 | |||
572 | return -EINPROGRESS; | ||
573 | } | ||
574 | |||
575 | static int orinoco_ioctl_getrate(struct net_device *dev, | ||
576 | struct iw_request_info *info, | ||
577 | struct iw_param *rrq, | ||
578 | char *extra) | ||
579 | { | ||
580 | struct orinoco_private *priv = ndev_priv(dev); | ||
581 | int err = 0; | ||
582 | int bitrate, automatic; | ||
583 | unsigned long flags; | ||
584 | |||
585 | if (orinoco_lock(priv, &flags) != 0) | ||
586 | return -EBUSY; | ||
587 | |||
588 | orinoco_get_ratemode_cfg(priv->bitratemode, &bitrate, &automatic); | ||
589 | |||
590 | /* If the interface is running we try to find more about the | ||
591 | current mode */ | ||
592 | if (netif_running(dev)) { | ||
593 | int act_bitrate; | ||
594 | int lerr; | ||
595 | |||
596 | /* Ignore errors if we can't get the actual bitrate */ | ||
597 | lerr = orinoco_hw_get_act_bitrate(priv, &act_bitrate); | ||
598 | if (!lerr) | ||
599 | bitrate = act_bitrate; | ||
600 | } | ||
601 | |||
602 | orinoco_unlock(priv, &flags); | ||
603 | |||
604 | rrq->value = bitrate; | ||
605 | rrq->fixed = !automatic; | ||
606 | rrq->disabled = 0; | ||
607 | |||
608 | return err; | ||
609 | } | ||
610 | |||
611 | static int orinoco_ioctl_setpower(struct net_device *dev, | ||
612 | struct iw_request_info *info, | ||
613 | struct iw_param *prq, | ||
614 | char *extra) | ||
615 | { | ||
616 | struct orinoco_private *priv = ndev_priv(dev); | ||
617 | int err = -EINPROGRESS; /* Call commit handler */ | ||
618 | unsigned long flags; | ||
619 | |||
620 | if (orinoco_lock(priv, &flags) != 0) | ||
621 | return -EBUSY; | ||
622 | |||
623 | if (prq->disabled) { | ||
624 | priv->pm_on = 0; | ||
625 | } else { | ||
626 | switch (prq->flags & IW_POWER_MODE) { | ||
627 | case IW_POWER_UNICAST_R: | ||
628 | priv->pm_mcast = 0; | ||
629 | priv->pm_on = 1; | ||
630 | break; | ||
631 | case IW_POWER_ALL_R: | ||
632 | priv->pm_mcast = 1; | ||
633 | priv->pm_on = 1; | ||
634 | break; | ||
635 | case IW_POWER_ON: | ||
636 | /* No flags : but we may have a value - Jean II */ | ||
637 | break; | ||
638 | default: | ||
639 | err = -EINVAL; | ||
640 | goto out; | ||
641 | } | ||
642 | |||
643 | if (prq->flags & IW_POWER_TIMEOUT) { | ||
644 | priv->pm_on = 1; | ||
645 | priv->pm_timeout = prq->value / 1000; | ||
646 | } | ||
647 | if (prq->flags & IW_POWER_PERIOD) { | ||
648 | priv->pm_on = 1; | ||
649 | priv->pm_period = prq->value / 1000; | ||
650 | } | ||
651 | /* It's valid to not have a value if we are just toggling | ||
652 | * the flags... Jean II */ | ||
653 | if (!priv->pm_on) { | ||
654 | err = -EINVAL; | ||
655 | goto out; | ||
656 | } | ||
657 | } | ||
658 | |||
659 | out: | ||
660 | orinoco_unlock(priv, &flags); | ||
661 | |||
662 | return err; | ||
663 | } | ||
664 | |||
665 | static int orinoco_ioctl_getpower(struct net_device *dev, | ||
666 | struct iw_request_info *info, | ||
667 | struct iw_param *prq, | ||
668 | char *extra) | ||
669 | { | ||
670 | struct orinoco_private *priv = ndev_priv(dev); | ||
671 | struct hermes *hw = &priv->hw; | ||
672 | int err = 0; | ||
673 | u16 enable, period, timeout, mcast; | ||
674 | unsigned long flags; | ||
675 | |||
676 | if (orinoco_lock(priv, &flags) != 0) | ||
677 | return -EBUSY; | ||
678 | |||
679 | err = hermes_read_wordrec(hw, USER_BAP, | ||
680 | HERMES_RID_CNFPMENABLED, &enable); | ||
681 | if (err) | ||
682 | goto out; | ||
683 | |||
684 | err = hermes_read_wordrec(hw, USER_BAP, | ||
685 | HERMES_RID_CNFMAXSLEEPDURATION, &period); | ||
686 | if (err) | ||
687 | goto out; | ||
688 | |||
689 | err = hermes_read_wordrec(hw, USER_BAP, | ||
690 | HERMES_RID_CNFPMHOLDOVERDURATION, &timeout); | ||
691 | if (err) | ||
692 | goto out; | ||
693 | |||
694 | err = hermes_read_wordrec(hw, USER_BAP, | ||
695 | HERMES_RID_CNFMULTICASTRECEIVE, &mcast); | ||
696 | if (err) | ||
697 | goto out; | ||
698 | |||
699 | prq->disabled = !enable; | ||
700 | /* Note : by default, display the period */ | ||
701 | if ((prq->flags & IW_POWER_TYPE) == IW_POWER_TIMEOUT) { | ||
702 | prq->flags = IW_POWER_TIMEOUT; | ||
703 | prq->value = timeout * 1000; | ||
704 | } else { | ||
705 | prq->flags = IW_POWER_PERIOD; | ||
706 | prq->value = period * 1000; | ||
707 | } | ||
708 | if (mcast) | ||
709 | prq->flags |= IW_POWER_ALL_R; | ||
710 | else | ||
711 | prq->flags |= IW_POWER_UNICAST_R; | ||
712 | |||
713 | out: | ||
714 | orinoco_unlock(priv, &flags); | ||
715 | |||
716 | return err; | ||
717 | } | ||
718 | |||
719 | static int orinoco_ioctl_set_encodeext(struct net_device *dev, | ||
720 | struct iw_request_info *info, | ||
721 | union iwreq_data *wrqu, | ||
722 | char *extra) | ||
723 | { | ||
724 | struct orinoco_private *priv = ndev_priv(dev); | ||
725 | struct iw_point *encoding = &wrqu->encoding; | ||
726 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
727 | int idx, alg = ext->alg, set_key = 1; | ||
728 | unsigned long flags; | ||
729 | int err = -EINVAL; | ||
730 | |||
731 | if (orinoco_lock(priv, &flags) != 0) | ||
732 | return -EBUSY; | ||
733 | |||
734 | /* Determine and validate the key index */ | ||
735 | idx = encoding->flags & IW_ENCODE_INDEX; | ||
736 | if (idx) { | ||
737 | if ((idx < 1) || (idx > 4)) | ||
738 | goto out; | ||
739 | idx--; | ||
740 | } else | ||
741 | idx = priv->tx_key; | ||
742 | |||
743 | if (encoding->flags & IW_ENCODE_DISABLED) | ||
744 | alg = IW_ENCODE_ALG_NONE; | ||
745 | |||
746 | if (priv->has_wpa && (alg != IW_ENCODE_ALG_TKIP)) { | ||
747 | /* Clear any TKIP TX key we had */ | ||
748 | (void) orinoco_clear_tkip_key(priv, priv->tx_key); | ||
749 | } | ||
750 | |||
751 | if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { | ||
752 | priv->tx_key = idx; | ||
753 | set_key = ((alg == IW_ENCODE_ALG_TKIP) || | ||
754 | (ext->key_len > 0)) ? 1 : 0; | ||
755 | } | ||
756 | |||
757 | if (set_key) { | ||
758 | /* Set the requested key first */ | ||
759 | switch (alg) { | ||
760 | case IW_ENCODE_ALG_NONE: | ||
761 | priv->encode_alg = ORINOCO_ALG_NONE; | ||
762 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_NONE, | ||
763 | NULL, 0, NULL, 0); | ||
764 | break; | ||
765 | |||
766 | case IW_ENCODE_ALG_WEP: | ||
767 | if (ext->key_len <= 0) | ||
768 | goto out; | ||
769 | |||
770 | priv->encode_alg = ORINOCO_ALG_WEP; | ||
771 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_WEP, | ||
772 | ext->key, ext->key_len, NULL, 0); | ||
773 | break; | ||
774 | |||
775 | case IW_ENCODE_ALG_TKIP: | ||
776 | { | ||
777 | u8 *tkip_iv = NULL; | ||
778 | |||
779 | if (!priv->has_wpa || | ||
780 | (ext->key_len > sizeof(struct orinoco_tkip_key))) | ||
781 | goto out; | ||
782 | |||
783 | priv->encode_alg = ORINOCO_ALG_TKIP; | ||
784 | |||
785 | if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) | ||
786 | tkip_iv = &ext->rx_seq[0]; | ||
787 | |||
788 | err = orinoco_set_key(priv, idx, ORINOCO_ALG_TKIP, | ||
789 | ext->key, ext->key_len, tkip_iv, | ||
790 | ORINOCO_SEQ_LEN); | ||
791 | |||
792 | err = __orinoco_hw_set_tkip_key(priv, idx, | ||
793 | ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY, | ||
794 | priv->keys[idx].key, | ||
795 | tkip_iv, ORINOCO_SEQ_LEN, NULL, 0); | ||
796 | if (err) | ||
797 | printk(KERN_ERR "%s: Error %d setting TKIP key" | ||
798 | "\n", dev->name, err); | ||
799 | |||
800 | goto out; | ||
801 | } | ||
802 | default: | ||
803 | goto out; | ||
804 | } | ||
805 | } | ||
806 | err = -EINPROGRESS; | ||
807 | out: | ||
808 | orinoco_unlock(priv, &flags); | ||
809 | |||
810 | return err; | ||
811 | } | ||
812 | |||
813 | static int orinoco_ioctl_get_encodeext(struct net_device *dev, | ||
814 | struct iw_request_info *info, | ||
815 | union iwreq_data *wrqu, | ||
816 | char *extra) | ||
817 | { | ||
818 | struct orinoco_private *priv = ndev_priv(dev); | ||
819 | struct iw_point *encoding = &wrqu->encoding; | ||
820 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | ||
821 | int idx, max_key_len; | ||
822 | unsigned long flags; | ||
823 | int err; | ||
824 | |||
825 | if (orinoco_lock(priv, &flags) != 0) | ||
826 | return -EBUSY; | ||
827 | |||
828 | err = -EINVAL; | ||
829 | max_key_len = encoding->length - sizeof(*ext); | ||
830 | if (max_key_len < 0) | ||
831 | goto out; | ||
832 | |||
833 | idx = encoding->flags & IW_ENCODE_INDEX; | ||
834 | if (idx) { | ||
835 | if ((idx < 1) || (idx > 4)) | ||
836 | goto out; | ||
837 | idx--; | ||
838 | } else | ||
839 | idx = priv->tx_key; | ||
840 | |||
841 | encoding->flags = idx + 1; | ||
842 | memset(ext, 0, sizeof(*ext)); | ||
843 | |||
844 | switch (priv->encode_alg) { | ||
845 | case ORINOCO_ALG_NONE: | ||
846 | ext->alg = IW_ENCODE_ALG_NONE; | ||
847 | ext->key_len = 0; | ||
848 | encoding->flags |= IW_ENCODE_DISABLED; | ||
849 | break; | ||
850 | case ORINOCO_ALG_WEP: | ||
851 | ext->alg = IW_ENCODE_ALG_WEP; | ||
852 | ext->key_len = min(priv->keys[idx].key_len, max_key_len); | ||
853 | memcpy(ext->key, priv->keys[idx].key, ext->key_len); | ||
854 | encoding->flags |= IW_ENCODE_ENABLED; | ||
855 | break; | ||
856 | case ORINOCO_ALG_TKIP: | ||
857 | ext->alg = IW_ENCODE_ALG_TKIP; | ||
858 | ext->key_len = min(priv->keys[idx].key_len, max_key_len); | ||
859 | memcpy(ext->key, priv->keys[idx].key, ext->key_len); | ||
860 | encoding->flags |= IW_ENCODE_ENABLED; | ||
861 | break; | ||
862 | } | ||
863 | |||
864 | err = 0; | ||
865 | out: | ||
866 | orinoco_unlock(priv, &flags); | ||
867 | |||
868 | return err; | ||
869 | } | ||
870 | |||
871 | static int orinoco_ioctl_set_auth(struct net_device *dev, | ||
872 | struct iw_request_info *info, | ||
873 | union iwreq_data *wrqu, char *extra) | ||
874 | { | ||
875 | struct orinoco_private *priv = ndev_priv(dev); | ||
876 | struct hermes *hw = &priv->hw; | ||
877 | struct iw_param *param = &wrqu->param; | ||
878 | unsigned long flags; | ||
879 | int ret = -EINPROGRESS; | ||
880 | |||
881 | if (orinoco_lock(priv, &flags) != 0) | ||
882 | return -EBUSY; | ||
883 | |||
884 | switch (param->flags & IW_AUTH_INDEX) { | ||
885 | case IW_AUTH_WPA_VERSION: | ||
886 | case IW_AUTH_CIPHER_PAIRWISE: | ||
887 | case IW_AUTH_CIPHER_GROUP: | ||
888 | case IW_AUTH_RX_UNENCRYPTED_EAPOL: | ||
889 | case IW_AUTH_PRIVACY_INVOKED: | ||
890 | case IW_AUTH_DROP_UNENCRYPTED: | ||
891 | /* | ||
892 | * orinoco does not use these parameters | ||
893 | */ | ||
894 | break; | ||
895 | |||
896 | case IW_AUTH_MFP: | ||
897 | /* Management Frame Protection not supported. | ||
898 | * Only fail if set to required. | ||
899 | */ | ||
900 | if (param->value == IW_AUTH_MFP_REQUIRED) | ||
901 | ret = -EINVAL; | ||
902 | break; | ||
903 | |||
904 | case IW_AUTH_KEY_MGMT: | ||
905 | /* wl_lkm implies value 2 == PSK for Hermes I | ||
906 | * which ties in with WEXT | ||
907 | * no other hints tho :( | ||
908 | */ | ||
909 | priv->key_mgmt = param->value; | ||
910 | break; | ||
911 | |||
912 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
913 | /* When countermeasures are enabled, shut down the | ||
914 | * card; when disabled, re-enable the card. This must | ||
915 | * take effect immediately. | ||
916 | * | ||
917 | * TODO: Make sure that the EAPOL message is getting | ||
918 | * out before card disabled | ||
919 | */ | ||
920 | if (param->value) { | ||
921 | priv->tkip_cm_active = 1; | ||
922 | ret = hermes_disable_port(hw, 0); | ||
923 | } else { | ||
924 | priv->tkip_cm_active = 0; | ||
925 | ret = hermes_enable_port(hw, 0); | ||
926 | } | ||
927 | break; | ||
928 | |||
929 | case IW_AUTH_80211_AUTH_ALG: | ||
930 | if (param->value & IW_AUTH_ALG_SHARED_KEY) | ||
931 | priv->wep_restrict = 1; | ||
932 | else if (param->value & IW_AUTH_ALG_OPEN_SYSTEM) | ||
933 | priv->wep_restrict = 0; | ||
934 | else | ||
935 | ret = -EINVAL; | ||
936 | break; | ||
937 | |||
938 | case IW_AUTH_WPA_ENABLED: | ||
939 | if (priv->has_wpa) { | ||
940 | priv->wpa_enabled = param->value ? 1 : 0; | ||
941 | } else { | ||
942 | if (param->value) | ||
943 | ret = -EOPNOTSUPP; | ||
944 | /* else silently accept disable of WPA */ | ||
945 | priv->wpa_enabled = 0; | ||
946 | } | ||
947 | break; | ||
948 | |||
949 | default: | ||
950 | ret = -EOPNOTSUPP; | ||
951 | } | ||
952 | |||
953 | orinoco_unlock(priv, &flags); | ||
954 | return ret; | ||
955 | } | ||
956 | |||
957 | static int orinoco_ioctl_get_auth(struct net_device *dev, | ||
958 | struct iw_request_info *info, | ||
959 | union iwreq_data *wrqu, char *extra) | ||
960 | { | ||
961 | struct orinoco_private *priv = ndev_priv(dev); | ||
962 | struct iw_param *param = &wrqu->param; | ||
963 | unsigned long flags; | ||
964 | int ret = 0; | ||
965 | |||
966 | if (orinoco_lock(priv, &flags) != 0) | ||
967 | return -EBUSY; | ||
968 | |||
969 | switch (param->flags & IW_AUTH_INDEX) { | ||
970 | case IW_AUTH_KEY_MGMT: | ||
971 | param->value = priv->key_mgmt; | ||
972 | break; | ||
973 | |||
974 | case IW_AUTH_TKIP_COUNTERMEASURES: | ||
975 | param->value = priv->tkip_cm_active; | ||
976 | break; | ||
977 | |||
978 | case IW_AUTH_80211_AUTH_ALG: | ||
979 | if (priv->wep_restrict) | ||
980 | param->value = IW_AUTH_ALG_SHARED_KEY; | ||
981 | else | ||
982 | param->value = IW_AUTH_ALG_OPEN_SYSTEM; | ||
983 | break; | ||
984 | |||
985 | case IW_AUTH_WPA_ENABLED: | ||
986 | param->value = priv->wpa_enabled; | ||
987 | break; | ||
988 | |||
989 | default: | ||
990 | ret = -EOPNOTSUPP; | ||
991 | } | ||
992 | |||
993 | orinoco_unlock(priv, &flags); | ||
994 | return ret; | ||
995 | } | ||
996 | |||
997 | static int orinoco_ioctl_set_genie(struct net_device *dev, | ||
998 | struct iw_request_info *info, | ||
999 | union iwreq_data *wrqu, char *extra) | ||
1000 | { | ||
1001 | struct orinoco_private *priv = ndev_priv(dev); | ||
1002 | u8 *buf; | ||
1003 | unsigned long flags; | ||
1004 | |||
1005 | /* cut off at IEEE80211_MAX_DATA_LEN */ | ||
1006 | if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || | ||
1007 | (wrqu->data.length && (extra == NULL))) | ||
1008 | return -EINVAL; | ||
1009 | |||
1010 | if (wrqu->data.length) { | ||
1011 | buf = kmemdup(extra, wrqu->data.length, GFP_KERNEL); | ||
1012 | if (buf == NULL) | ||
1013 | return -ENOMEM; | ||
1014 | } else | ||
1015 | buf = NULL; | ||
1016 | |||
1017 | if (orinoco_lock(priv, &flags) != 0) { | ||
1018 | kfree(buf); | ||
1019 | return -EBUSY; | ||
1020 | } | ||
1021 | |||
1022 | kfree(priv->wpa_ie); | ||
1023 | priv->wpa_ie = buf; | ||
1024 | priv->wpa_ie_len = wrqu->data.length; | ||
1025 | |||
1026 | if (priv->wpa_ie) { | ||
1027 | /* Looks like wl_lkm wants to check the auth alg, and | ||
1028 | * somehow pass it to the firmware. | ||
1029 | * Instead it just calls the key mgmt rid | ||
1030 | * - we do this in set auth. | ||
1031 | */ | ||
1032 | } | ||
1033 | |||
1034 | orinoco_unlock(priv, &flags); | ||
1035 | return 0; | ||
1036 | } | ||
1037 | |||
1038 | static int orinoco_ioctl_get_genie(struct net_device *dev, | ||
1039 | struct iw_request_info *info, | ||
1040 | union iwreq_data *wrqu, char *extra) | ||
1041 | { | ||
1042 | struct orinoco_private *priv = ndev_priv(dev); | ||
1043 | unsigned long flags; | ||
1044 | int err = 0; | ||
1045 | |||
1046 | if (orinoco_lock(priv, &flags) != 0) | ||
1047 | return -EBUSY; | ||
1048 | |||
1049 | if ((priv->wpa_ie_len == 0) || (priv->wpa_ie == NULL)) { | ||
1050 | wrqu->data.length = 0; | ||
1051 | goto out; | ||
1052 | } | ||
1053 | |||
1054 | if (wrqu->data.length < priv->wpa_ie_len) { | ||
1055 | err = -E2BIG; | ||
1056 | goto out; | ||
1057 | } | ||
1058 | |||
1059 | wrqu->data.length = priv->wpa_ie_len; | ||
1060 | memcpy(extra, priv->wpa_ie, priv->wpa_ie_len); | ||
1061 | |||
1062 | out: | ||
1063 | orinoco_unlock(priv, &flags); | ||
1064 | return err; | ||
1065 | } | ||
1066 | |||
1067 | static int orinoco_ioctl_set_mlme(struct net_device *dev, | ||
1068 | struct iw_request_info *info, | ||
1069 | union iwreq_data *wrqu, char *extra) | ||
1070 | { | ||
1071 | struct orinoco_private *priv = ndev_priv(dev); | ||
1072 | struct iw_mlme *mlme = (struct iw_mlme *)extra; | ||
1073 | unsigned long flags; | ||
1074 | int ret = 0; | ||
1075 | |||
1076 | if (orinoco_lock(priv, &flags) != 0) | ||
1077 | return -EBUSY; | ||
1078 | |||
1079 | switch (mlme->cmd) { | ||
1080 | case IW_MLME_DEAUTH: | ||
1081 | /* silently ignore */ | ||
1082 | break; | ||
1083 | |||
1084 | case IW_MLME_DISASSOC: | ||
1085 | |||
1086 | ret = orinoco_hw_disassociate(priv, mlme->addr.sa_data, | ||
1087 | mlme->reason_code); | ||
1088 | break; | ||
1089 | |||
1090 | default: | ||
1091 | ret = -EOPNOTSUPP; | ||
1092 | } | ||
1093 | |||
1094 | orinoco_unlock(priv, &flags); | ||
1095 | return ret; | ||
1096 | } | ||
1097 | |||
1098 | static int orinoco_ioctl_reset(struct net_device *dev, | ||
1099 | struct iw_request_info *info, | ||
1100 | void *wrqu, | ||
1101 | char *extra) | ||
1102 | { | ||
1103 | struct orinoco_private *priv = ndev_priv(dev); | ||
1104 | |||
1105 | if (!capable(CAP_NET_ADMIN)) | ||
1106 | return -EPERM; | ||
1107 | |||
1108 | if (info->cmd == (SIOCIWFIRSTPRIV + 0x1)) { | ||
1109 | printk(KERN_DEBUG "%s: Forcing reset!\n", dev->name); | ||
1110 | |||
1111 | /* Firmware reset */ | ||
1112 | orinoco_reset(&priv->reset_work); | ||
1113 | } else { | ||
1114 | printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); | ||
1115 | |||
1116 | schedule_work(&priv->reset_work); | ||
1117 | } | ||
1118 | |||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
1122 | static int orinoco_ioctl_setibssport(struct net_device *dev, | ||
1123 | struct iw_request_info *info, | ||
1124 | void *wrqu, | ||
1125 | char *extra) | ||
1126 | |||
1127 | { | ||
1128 | struct orinoco_private *priv = ndev_priv(dev); | ||
1129 | int val = *((int *) extra); | ||
1130 | unsigned long flags; | ||
1131 | |||
1132 | if (orinoco_lock(priv, &flags) != 0) | ||
1133 | return -EBUSY; | ||
1134 | |||
1135 | priv->ibss_port = val; | ||
1136 | |||
1137 | /* Actually update the mode we are using */ | ||
1138 | set_port_type(priv); | ||
1139 | |||
1140 | orinoco_unlock(priv, &flags); | ||
1141 | return -EINPROGRESS; /* Call commit handler */ | ||
1142 | } | ||
1143 | |||
1144 | static int orinoco_ioctl_getibssport(struct net_device *dev, | ||
1145 | struct iw_request_info *info, | ||
1146 | void *wrqu, | ||
1147 | char *extra) | ||
1148 | { | ||
1149 | struct orinoco_private *priv = ndev_priv(dev); | ||
1150 | int *val = (int *) extra; | ||
1151 | |||
1152 | *val = priv->ibss_port; | ||
1153 | return 0; | ||
1154 | } | ||
1155 | |||
1156 | static int orinoco_ioctl_setport3(struct net_device *dev, | ||
1157 | struct iw_request_info *info, | ||
1158 | void *wrqu, | ||
1159 | char *extra) | ||
1160 | { | ||
1161 | struct orinoco_private *priv = ndev_priv(dev); | ||
1162 | int val = *((int *) extra); | ||
1163 | int err = 0; | ||
1164 | unsigned long flags; | ||
1165 | |||
1166 | if (orinoco_lock(priv, &flags) != 0) | ||
1167 | return -EBUSY; | ||
1168 | |||
1169 | switch (val) { | ||
1170 | case 0: /* Try to do IEEE ad-hoc mode */ | ||
1171 | if (!priv->has_ibss) { | ||
1172 | err = -EINVAL; | ||
1173 | break; | ||
1174 | } | ||
1175 | priv->prefer_port3 = 0; | ||
1176 | |||
1177 | break; | ||
1178 | |||
1179 | case 1: /* Try to do Lucent proprietary ad-hoc mode */ | ||
1180 | if (!priv->has_port3) { | ||
1181 | err = -EINVAL; | ||
1182 | break; | ||
1183 | } | ||
1184 | priv->prefer_port3 = 1; | ||
1185 | break; | ||
1186 | |||
1187 | default: | ||
1188 | err = -EINVAL; | ||
1189 | } | ||
1190 | |||
1191 | if (!err) { | ||
1192 | /* Actually update the mode we are using */ | ||
1193 | set_port_type(priv); | ||
1194 | err = -EINPROGRESS; | ||
1195 | } | ||
1196 | |||
1197 | orinoco_unlock(priv, &flags); | ||
1198 | |||
1199 | return err; | ||
1200 | } | ||
1201 | |||
1202 | static int orinoco_ioctl_getport3(struct net_device *dev, | ||
1203 | struct iw_request_info *info, | ||
1204 | void *wrqu, | ||
1205 | char *extra) | ||
1206 | { | ||
1207 | struct orinoco_private *priv = ndev_priv(dev); | ||
1208 | int *val = (int *) extra; | ||
1209 | |||
1210 | *val = priv->prefer_port3; | ||
1211 | return 0; | ||
1212 | } | ||
1213 | |||
1214 | static int orinoco_ioctl_setpreamble(struct net_device *dev, | ||
1215 | struct iw_request_info *info, | ||
1216 | void *wrqu, | ||
1217 | char *extra) | ||
1218 | { | ||
1219 | struct orinoco_private *priv = ndev_priv(dev); | ||
1220 | unsigned long flags; | ||
1221 | int val; | ||
1222 | |||
1223 | if (!priv->has_preamble) | ||
1224 | return -EOPNOTSUPP; | ||
1225 | |||
1226 | /* 802.11b has recently defined some short preamble. | ||
1227 | * Basically, the Phy header has been reduced in size. | ||
1228 | * This increase performance, especially at high rates | ||
1229 | * (the preamble is transmitted at 1Mb/s), unfortunately | ||
1230 | * this give compatibility troubles... - Jean II */ | ||
1231 | val = *((int *) extra); | ||
1232 | |||
1233 | if (orinoco_lock(priv, &flags) != 0) | ||
1234 | return -EBUSY; | ||
1235 | |||
1236 | if (val) | ||
1237 | priv->preamble = 1; | ||
1238 | else | ||
1239 | priv->preamble = 0; | ||
1240 | |||
1241 | orinoco_unlock(priv, &flags); | ||
1242 | |||
1243 | return -EINPROGRESS; /* Call commit handler */ | ||
1244 | } | ||
1245 | |||
1246 | static int orinoco_ioctl_getpreamble(struct net_device *dev, | ||
1247 | struct iw_request_info *info, | ||
1248 | void *wrqu, | ||
1249 | char *extra) | ||
1250 | { | ||
1251 | struct orinoco_private *priv = ndev_priv(dev); | ||
1252 | int *val = (int *) extra; | ||
1253 | |||
1254 | if (!priv->has_preamble) | ||
1255 | return -EOPNOTSUPP; | ||
1256 | |||
1257 | *val = priv->preamble; | ||
1258 | return 0; | ||
1259 | } | ||
1260 | |||
1261 | /* ioctl interface to hermes_read_ltv() | ||
1262 | * To use with iwpriv, pass the RID as the token argument, e.g. | ||
1263 | * iwpriv get_rid [0xfc00] | ||
1264 | * At least Wireless Tools 25 is required to use iwpriv. | ||
1265 | * For Wireless Tools 25 and 26 append "dummy" are the end. */ | ||
1266 | static int orinoco_ioctl_getrid(struct net_device *dev, | ||
1267 | struct iw_request_info *info, | ||
1268 | struct iw_point *data, | ||
1269 | char *extra) | ||
1270 | { | ||
1271 | struct orinoco_private *priv = ndev_priv(dev); | ||
1272 | struct hermes *hw = &priv->hw; | ||
1273 | int rid = data->flags; | ||
1274 | u16 length; | ||
1275 | int err; | ||
1276 | unsigned long flags; | ||
1277 | |||
1278 | /* It's a "get" function, but we don't want users to access the | ||
1279 | * WEP key and other raw firmware data */ | ||
1280 | if (!capable(CAP_NET_ADMIN)) | ||
1281 | return -EPERM; | ||
1282 | |||
1283 | if (rid < 0xfc00 || rid > 0xffff) | ||
1284 | return -EINVAL; | ||
1285 | |||
1286 | if (orinoco_lock(priv, &flags) != 0) | ||
1287 | return -EBUSY; | ||
1288 | |||
1289 | err = hw->ops->read_ltv(hw, USER_BAP, rid, MAX_RID_LEN, &length, | ||
1290 | extra); | ||
1291 | if (err) | ||
1292 | goto out; | ||
1293 | |||
1294 | data->length = min_t(u16, HERMES_RECLEN_TO_BYTES(length), | ||
1295 | MAX_RID_LEN); | ||
1296 | |||
1297 | out: | ||
1298 | orinoco_unlock(priv, &flags); | ||
1299 | return err; | ||
1300 | } | ||
1301 | |||
1302 | |||
1303 | /* Commit handler, called after set operations */ | ||
1304 | static int orinoco_ioctl_commit(struct net_device *dev, | ||
1305 | struct iw_request_info *info, | ||
1306 | void *wrqu, | ||
1307 | char *extra) | ||
1308 | { | ||
1309 | struct orinoco_private *priv = ndev_priv(dev); | ||
1310 | unsigned long flags; | ||
1311 | int err = 0; | ||
1312 | |||
1313 | if (!priv->open) | ||
1314 | return 0; | ||
1315 | |||
1316 | if (orinoco_lock(priv, &flags) != 0) | ||
1317 | return err; | ||
1318 | |||
1319 | err = orinoco_commit(priv); | ||
1320 | |||
1321 | orinoco_unlock(priv, &flags); | ||
1322 | return err; | ||
1323 | } | ||
1324 | |||
1325 | static const struct iw_priv_args orinoco_privtab[] = { | ||
1326 | { SIOCIWFIRSTPRIV + 0x0, 0, 0, "force_reset" }, | ||
1327 | { SIOCIWFIRSTPRIV + 0x1, 0, 0, "card_reset" }, | ||
1328 | { SIOCIWFIRSTPRIV + 0x2, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1329 | 0, "set_port3" }, | ||
1330 | { SIOCIWFIRSTPRIV + 0x3, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1331 | "get_port3" }, | ||
1332 | { SIOCIWFIRSTPRIV + 0x4, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1333 | 0, "set_preamble" }, | ||
1334 | { SIOCIWFIRSTPRIV + 0x5, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1335 | "get_preamble" }, | ||
1336 | { SIOCIWFIRSTPRIV + 0x6, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1337 | 0, "set_ibssport" }, | ||
1338 | { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, | ||
1339 | "get_ibssport" }, | ||
1340 | { SIOCIWFIRSTPRIV + 0x9, 0, IW_PRIV_TYPE_BYTE | MAX_RID_LEN, | ||
1341 | "get_rid" }, | ||
1342 | }; | ||
1343 | |||
1344 | |||
1345 | /* | ||
1346 | * Structures to export the Wireless Handlers | ||
1347 | */ | ||
1348 | |||
1349 | static const iw_handler orinoco_handler[] = { | ||
1350 | IW_HANDLER(SIOCSIWCOMMIT, (iw_handler)orinoco_ioctl_commit), | ||
1351 | IW_HANDLER(SIOCGIWNAME, (iw_handler)cfg80211_wext_giwname), | ||
1352 | IW_HANDLER(SIOCSIWFREQ, (iw_handler)orinoco_ioctl_setfreq), | ||
1353 | IW_HANDLER(SIOCGIWFREQ, (iw_handler)orinoco_ioctl_getfreq), | ||
1354 | IW_HANDLER(SIOCSIWMODE, (iw_handler)cfg80211_wext_siwmode), | ||
1355 | IW_HANDLER(SIOCGIWMODE, (iw_handler)cfg80211_wext_giwmode), | ||
1356 | IW_HANDLER(SIOCSIWSENS, (iw_handler)orinoco_ioctl_setsens), | ||
1357 | IW_HANDLER(SIOCGIWSENS, (iw_handler)orinoco_ioctl_getsens), | ||
1358 | IW_HANDLER(SIOCGIWRANGE, (iw_handler)cfg80211_wext_giwrange), | ||
1359 | IW_HANDLER(SIOCSIWSPY, iw_handler_set_spy), | ||
1360 | IW_HANDLER(SIOCGIWSPY, iw_handler_get_spy), | ||
1361 | IW_HANDLER(SIOCSIWTHRSPY, iw_handler_set_thrspy), | ||
1362 | IW_HANDLER(SIOCGIWTHRSPY, iw_handler_get_thrspy), | ||
1363 | IW_HANDLER(SIOCSIWAP, (iw_handler)orinoco_ioctl_setwap), | ||
1364 | IW_HANDLER(SIOCGIWAP, (iw_handler)orinoco_ioctl_getwap), | ||
1365 | IW_HANDLER(SIOCSIWSCAN, (iw_handler)cfg80211_wext_siwscan), | ||
1366 | IW_HANDLER(SIOCGIWSCAN, (iw_handler)cfg80211_wext_giwscan), | ||
1367 | IW_HANDLER(SIOCSIWESSID, (iw_handler)orinoco_ioctl_setessid), | ||
1368 | IW_HANDLER(SIOCGIWESSID, (iw_handler)orinoco_ioctl_getessid), | ||
1369 | IW_HANDLER(SIOCSIWRATE, (iw_handler)orinoco_ioctl_setrate), | ||
1370 | IW_HANDLER(SIOCGIWRATE, (iw_handler)orinoco_ioctl_getrate), | ||
1371 | IW_HANDLER(SIOCSIWRTS, (iw_handler)cfg80211_wext_siwrts), | ||
1372 | IW_HANDLER(SIOCGIWRTS, (iw_handler)cfg80211_wext_giwrts), | ||
1373 | IW_HANDLER(SIOCSIWFRAG, (iw_handler)cfg80211_wext_siwfrag), | ||
1374 | IW_HANDLER(SIOCGIWFRAG, (iw_handler)cfg80211_wext_giwfrag), | ||
1375 | IW_HANDLER(SIOCGIWRETRY, (iw_handler)cfg80211_wext_giwretry), | ||
1376 | IW_HANDLER(SIOCSIWENCODE, (iw_handler)orinoco_ioctl_setiwencode), | ||
1377 | IW_HANDLER(SIOCGIWENCODE, (iw_handler)orinoco_ioctl_getiwencode), | ||
1378 | IW_HANDLER(SIOCSIWPOWER, (iw_handler)orinoco_ioctl_setpower), | ||
1379 | IW_HANDLER(SIOCGIWPOWER, (iw_handler)orinoco_ioctl_getpower), | ||
1380 | IW_HANDLER(SIOCSIWGENIE, orinoco_ioctl_set_genie), | ||
1381 | IW_HANDLER(SIOCGIWGENIE, orinoco_ioctl_get_genie), | ||
1382 | IW_HANDLER(SIOCSIWMLME, orinoco_ioctl_set_mlme), | ||
1383 | IW_HANDLER(SIOCSIWAUTH, orinoco_ioctl_set_auth), | ||
1384 | IW_HANDLER(SIOCGIWAUTH, orinoco_ioctl_get_auth), | ||
1385 | IW_HANDLER(SIOCSIWENCODEEXT, orinoco_ioctl_set_encodeext), | ||
1386 | IW_HANDLER(SIOCGIWENCODEEXT, orinoco_ioctl_get_encodeext), | ||
1387 | }; | ||
1388 | |||
1389 | |||
1390 | /* | ||
1391 | Added typecasting since we no longer use iwreq_data -- Moustafa | ||
1392 | */ | ||
1393 | static const iw_handler orinoco_private_handler[] = { | ||
1394 | [0] = (iw_handler)orinoco_ioctl_reset, | ||
1395 | [1] = (iw_handler)orinoco_ioctl_reset, | ||
1396 | [2] = (iw_handler)orinoco_ioctl_setport3, | ||
1397 | [3] = (iw_handler)orinoco_ioctl_getport3, | ||
1398 | [4] = (iw_handler)orinoco_ioctl_setpreamble, | ||
1399 | [5] = (iw_handler)orinoco_ioctl_getpreamble, | ||
1400 | [6] = (iw_handler)orinoco_ioctl_setibssport, | ||
1401 | [7] = (iw_handler)orinoco_ioctl_getibssport, | ||
1402 | [9] = (iw_handler)orinoco_ioctl_getrid, | ||
1403 | }; | ||
1404 | |||
1405 | const struct iw_handler_def orinoco_handler_def = { | ||
1406 | .num_standard = ARRAY_SIZE(orinoco_handler), | ||
1407 | .num_private = ARRAY_SIZE(orinoco_private_handler), | ||
1408 | .num_private_args = ARRAY_SIZE(orinoco_privtab), | ||
1409 | .standard = orinoco_handler, | ||
1410 | .private = orinoco_private_handler, | ||
1411 | .private_args = orinoco_privtab, | ||
1412 | .get_wireless_stats = orinoco_get_wireless_stats, | ||
1413 | }; | ||