1 /******************************************************************************
3 Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
5 Portions of this file are based on the WEP enablement code provided by the
6 Host AP project hostap-drivers v0.1.3
7 Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
9 Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
11 This program is free software; you can redistribute it and/or modify it
12 under the terms of version 2 of the GNU General Public License as
13 published by the Free Software Foundation.
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59
22 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 The full GNU General Public License is included in this distribution in the
28 James P. Ketrenos <ipw2100-admin@linux.intel.com>
29 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
31 ******************************************************************************/
33 #include <linux/kmod.h>
34 #include <linux/module.h>
35 #include <linux/jiffies.h>
37 #include <net/ieee80211.h>
38 #include <linux/wireless.h>
40 static const char *ieee80211_modes
[] = {
41 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
44 #define MAX_CUSTOM_LEN 64
45 static char *ieee80211_translate_scan(struct ieee80211_device
*ieee
,
46 char *start
, char *stop
,
47 struct ieee80211_network
*network
)
49 char custom
[MAX_CUSTOM_LEN
];
53 char *current_val
; /* For rates */
56 /* First entry *MUST* be the AP MAC address */
58 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
59 memcpy(iwe
.u
.ap_addr
.sa_data
, network
->bssid
, ETH_ALEN
);
60 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_ADDR_LEN
);
62 /* Remaining entries will be displayed in the order we provide them */
65 iwe
.cmd
= SIOCGIWESSID
;
67 if (network
->flags
& NETWORK_EMPTY_ESSID
) {
68 iwe
.u
.data
.length
= sizeof("<hidden>");
69 start
= iwe_stream_add_point(start
, stop
, &iwe
, "<hidden>");
71 iwe
.u
.data
.length
= min(network
->ssid_len
, (u8
) 32);
72 start
= iwe_stream_add_point(start
, stop
, &iwe
, network
->ssid
);
75 /* Add the protocol name */
76 iwe
.cmd
= SIOCGIWNAME
;
77 snprintf(iwe
.u
.name
, IFNAMSIZ
, "IEEE 802.11%s",
78 ieee80211_modes
[network
->mode
]);
79 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_CHAR_LEN
);
82 iwe
.cmd
= SIOCGIWMODE
;
83 if (network
->capability
& (WLAN_CAPABILITY_ESS
| WLAN_CAPABILITY_IBSS
)) {
84 if (network
->capability
& WLAN_CAPABILITY_ESS
)
85 iwe
.u
.mode
= IW_MODE_MASTER
;
87 iwe
.u
.mode
= IW_MODE_ADHOC
;
89 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_UINT_LEN
);
92 /* Add channel and frequency */
93 /* Note : userspace automatically computes channel using iwrange */
94 iwe
.cmd
= SIOCGIWFREQ
;
95 iwe
.u
.freq
.m
= ieee80211_channel_to_freq(ieee
, network
->channel
);
98 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_FREQ_LEN
);
100 /* Add encryption capability */
101 iwe
.cmd
= SIOCGIWENCODE
;
102 if (network
->capability
& WLAN_CAPABILITY_PRIVACY
)
103 iwe
.u
.data
.flags
= IW_ENCODE_ENABLED
| IW_ENCODE_NOKEY
;
105 iwe
.u
.data
.flags
= IW_ENCODE_DISABLED
;
106 iwe
.u
.data
.length
= 0;
107 start
= iwe_stream_add_point(start
, stop
, &iwe
, network
->ssid
);
109 /* Add basic and extended rates */
110 /* Rate : stuffing multiple values in a single event require a bit
111 * more of magic - Jean II */
112 current_val
= start
+ IW_EV_LCP_LEN
;
113 iwe
.cmd
= SIOCGIWRATE
;
114 /* Those two flags are ignored... */
115 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
= 0;
117 for (i
= 0, j
= 0; i
< network
->rates_len
;) {
118 if (j
< network
->rates_ex_len
&&
119 ((network
->rates_ex
[j
] & 0x7F) <
120 (network
->rates
[i
] & 0x7F)))
121 rate
= network
->rates_ex
[j
++] & 0x7F;
123 rate
= network
->rates
[i
++] & 0x7F;
124 /* Bit rate given in 500 kb/s units (+ 0x80) */
125 iwe
.u
.bitrate
.value
= ((rate
& 0x7f) * 500000);
126 /* Add new value to event */
127 current_val
= iwe_stream_add_value(start
, current_val
, stop
, &iwe
, IW_EV_PARAM_LEN
);
129 for (; j
< network
->rates_ex_len
; j
++) {
130 rate
= network
->rates_ex
[j
] & 0x7F;
131 /* Bit rate given in 500 kb/s units (+ 0x80) */
132 iwe
.u
.bitrate
.value
= ((rate
& 0x7f) * 500000);
133 /* Add new value to event */
134 current_val
= iwe_stream_add_value(start
, current_val
, stop
, &iwe
, IW_EV_PARAM_LEN
);
136 /* Check if we added any rate */
137 if((current_val
- start
) > IW_EV_LCP_LEN
)
140 /* Add quality statistics */
142 iwe
.u
.qual
.updated
= IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
|
143 IW_QUAL_NOISE_UPDATED
;
145 if (!(network
->stats
.mask
& IEEE80211_STATMASK_RSSI
)) {
146 iwe
.u
.qual
.updated
|= IW_QUAL_QUAL_INVALID
|
147 IW_QUAL_LEVEL_INVALID
;
150 if (ieee
->perfect_rssi
== ieee
->worst_rssi
)
151 iwe
.u
.qual
.qual
= 100;
155 (ieee
->perfect_rssi
- ieee
->worst_rssi
) *
156 (ieee
->perfect_rssi
- ieee
->worst_rssi
) -
157 (ieee
->perfect_rssi
- network
->stats
.rssi
) *
158 (15 * (ieee
->perfect_rssi
- ieee
->worst_rssi
) +
159 62 * (ieee
->perfect_rssi
-
160 network
->stats
.rssi
))) /
161 ((ieee
->perfect_rssi
-
162 ieee
->worst_rssi
) * (ieee
->perfect_rssi
-
164 if (iwe
.u
.qual
.qual
> 100)
165 iwe
.u
.qual
.qual
= 100;
166 else if (iwe
.u
.qual
.qual
< 1)
170 if (!(network
->stats
.mask
& IEEE80211_STATMASK_NOISE
)) {
171 iwe
.u
.qual
.updated
|= IW_QUAL_NOISE_INVALID
;
172 iwe
.u
.qual
.noise
= 0;
174 iwe
.u
.qual
.noise
= network
->stats
.noise
;
177 if (!(network
->stats
.mask
& IEEE80211_STATMASK_SIGNAL
)) {
178 iwe
.u
.qual
.updated
|= IW_QUAL_LEVEL_INVALID
;
179 iwe
.u
.qual
.level
= 0;
181 iwe
.u
.qual
.level
= network
->stats
.signal
;
184 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_QUAL_LEN
);
186 iwe
.cmd
= IWEVCUSTOM
;
189 iwe
.u
.data
.length
= p
- custom
;
190 if (iwe
.u
.data
.length
)
191 start
= iwe_stream_add_point(start
, stop
, &iwe
, custom
);
193 memset(&iwe
, 0, sizeof(iwe
));
194 if (network
->wpa_ie_len
) {
195 char buf
[MAX_WPA_IE_LEN
];
196 memcpy(buf
, network
->wpa_ie
, network
->wpa_ie_len
);
198 iwe
.u
.data
.length
= network
->wpa_ie_len
;
199 start
= iwe_stream_add_point(start
, stop
, &iwe
, buf
);
202 memset(&iwe
, 0, sizeof(iwe
));
203 if (network
->rsn_ie_len
) {
204 char buf
[MAX_WPA_IE_LEN
];
205 memcpy(buf
, network
->rsn_ie
, network
->rsn_ie_len
);
207 iwe
.u
.data
.length
= network
->rsn_ie_len
;
208 start
= iwe_stream_add_point(start
, stop
, &iwe
, buf
);
211 /* Add EXTRA: Age to display seconds since last beacon/probe response
212 * for given network. */
213 iwe
.cmd
= IWEVCUSTOM
;
215 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
),
216 " Last beacon: %dms ago",
217 jiffies_to_msecs(jiffies
- network
->last_scanned
));
218 iwe
.u
.data
.length
= p
- custom
;
219 if (iwe
.u
.data
.length
)
220 start
= iwe_stream_add_point(start
, stop
, &iwe
, custom
);
222 /* Add spectrum management information */
225 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), " Channel flags: ");
227 if (ieee80211_get_channel_flags(ieee
, network
->channel
) &
228 IEEE80211_CH_INVALID
) {
229 iwe
.cmd
= IWEVCUSTOM
;
230 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), "INVALID ");
233 if (ieee80211_get_channel_flags(ieee
, network
->channel
) &
234 IEEE80211_CH_RADAR_DETECT
) {
235 iwe
.cmd
= IWEVCUSTOM
;
236 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), "DFS ");
239 if (iwe
.cmd
== IWEVCUSTOM
) {
240 iwe
.u
.data
.length
= p
- custom
;
241 start
= iwe_stream_add_point(start
, stop
, &iwe
, custom
);
247 #define SCAN_ITEM_SIZE 128
249 int ieee80211_wx_get_scan(struct ieee80211_device
*ieee
,
250 struct iw_request_info
*info
,
251 union iwreq_data
*wrqu
, char *extra
)
253 struct ieee80211_network
*network
;
258 char *stop
= ev
+ wrqu
->data
.length
;
260 DECLARE_MAC_BUF(mac
);
262 IEEE80211_DEBUG_WX("Getting scan\n");
264 spin_lock_irqsave(&ieee
->lock
, flags
);
266 list_for_each_entry(network
, &ieee
->network_list
, list
) {
268 if (stop
- ev
< SCAN_ITEM_SIZE
) {
273 if (ieee
->scan_age
== 0 ||
274 time_after(network
->last_scanned
+ ieee
->scan_age
, jiffies
))
275 ev
= ieee80211_translate_scan(ieee
, ev
, stop
, network
);
277 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
278 "%s)' due to age (%dms).\n",
279 escape_essid(network
->ssid
,
281 print_mac(mac
, network
->bssid
),
282 jiffies_to_msecs(jiffies
-
287 spin_unlock_irqrestore(&ieee
->lock
, flags
);
289 wrqu
->data
.length
= ev
- extra
;
290 wrqu
->data
.flags
= 0;
292 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i
);
297 int ieee80211_wx_set_encode(struct ieee80211_device
*ieee
,
298 struct iw_request_info
*info
,
299 union iwreq_data
*wrqu
, char *keybuf
)
301 struct iw_point
*erq
= &(wrqu
->encoding
);
302 struct net_device
*dev
= ieee
->dev
;
303 struct ieee80211_security sec
= {
306 int i
, key
, key_provided
, len
;
307 struct ieee80211_crypt_data
**crypt
;
308 int host_crypto
= ieee
->host_encrypt
|| ieee
->host_decrypt
|| ieee
->host_build_iv
;
310 IEEE80211_DEBUG_WX("SET_ENCODE\n");
312 key
= erq
->flags
& IW_ENCODE_INDEX
;
320 key
= ieee
->tx_keyidx
;
323 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key
, key_provided
?
324 "provided" : "default");
326 crypt
= &ieee
->crypt
[key
];
328 if (erq
->flags
& IW_ENCODE_DISABLED
) {
329 if (key_provided
&& *crypt
) {
330 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
332 ieee80211_crypt_delayed_deinit(ieee
, crypt
);
334 IEEE80211_DEBUG_WX("Disabling encryption.\n");
336 /* Check all the keys to see if any are still configured,
337 * and if no key index was provided, de-init them all */
338 for (i
= 0; i
< WEP_KEYS
; i
++) {
339 if (ieee
->crypt
[i
] != NULL
) {
342 ieee80211_crypt_delayed_deinit(ieee
,
350 sec
.level
= SEC_LEVEL_0
;
351 sec
.flags
|= SEC_ENABLED
| SEC_LEVEL
| SEC_ENCRYPT
;
359 sec
.flags
|= SEC_ENABLED
| SEC_ENCRYPT
;
361 if (*crypt
!= NULL
&& (*crypt
)->ops
!= NULL
&&
362 strcmp((*crypt
)->ops
->name
, "WEP") != 0) {
363 /* changing to use WEP; deinit previously used algorithm
365 ieee80211_crypt_delayed_deinit(ieee
, crypt
);
368 if (*crypt
== NULL
&& host_crypto
) {
369 struct ieee80211_crypt_data
*new_crypt
;
371 /* take WEP into use */
372 new_crypt
= kzalloc(sizeof(struct ieee80211_crypt_data
),
374 if (new_crypt
== NULL
)
376 new_crypt
->ops
= ieee80211_get_crypto_ops("WEP");
377 if (!new_crypt
->ops
) {
378 request_module("ieee80211_crypt_wep");
379 new_crypt
->ops
= ieee80211_get_crypto_ops("WEP");
382 if (new_crypt
->ops
&& try_module_get(new_crypt
->ops
->owner
))
383 new_crypt
->priv
= new_crypt
->ops
->init(key
);
385 if (!new_crypt
->ops
|| !new_crypt
->priv
) {
389 printk(KERN_WARNING
"%s: could not initialize WEP: "
390 "load module ieee80211_crypt_wep\n", dev
->name
);
396 /* If a new key was provided, set it up */
397 if (erq
->length
> 0) {
398 len
= erq
->length
<= 5 ? 5 : 13;
399 memcpy(sec
.keys
[key
], keybuf
, erq
->length
);
400 if (len
> erq
->length
)
401 memset(sec
.keys
[key
] + erq
->length
, 0,
403 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
404 key
, escape_essid(sec
.keys
[key
], len
),
406 sec
.key_sizes
[key
] = len
;
408 (*crypt
)->ops
->set_key(sec
.keys
[key
], len
, NULL
,
410 sec
.flags
|= (1 << key
);
411 /* This ensures a key will be activated if no key is
413 if (key
== sec
.active_key
)
414 sec
.flags
|= SEC_ACTIVE_KEY
;
418 len
= (*crypt
)->ops
->get_key(sec
.keys
[key
], WEP_KEY_LEN
,
419 NULL
, (*crypt
)->priv
);
421 /* Set a default key of all 0 */
422 IEEE80211_DEBUG_WX("Setting key %d to all "
424 memset(sec
.keys
[key
], 0, 13);
425 (*crypt
)->ops
->set_key(sec
.keys
[key
], 13, NULL
,
427 sec
.key_sizes
[key
] = 13;
428 sec
.flags
|= (1 << key
);
431 /* No key data - just set the default TX key index */
433 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
435 ieee
->tx_keyidx
= key
;
436 sec
.active_key
= key
;
437 sec
.flags
|= SEC_ACTIVE_KEY
;
440 if (erq
->flags
& (IW_ENCODE_OPEN
| IW_ENCODE_RESTRICTED
)) {
441 ieee
->open_wep
= !(erq
->flags
& IW_ENCODE_RESTRICTED
);
442 sec
.auth_mode
= ieee
->open_wep
? WLAN_AUTH_OPEN
:
443 WLAN_AUTH_SHARED_KEY
;
444 sec
.flags
|= SEC_AUTH_MODE
;
445 IEEE80211_DEBUG_WX("Auth: %s\n",
446 sec
.auth_mode
== WLAN_AUTH_OPEN
?
447 "OPEN" : "SHARED KEY");
450 /* For now we just support WEP, so only set that security level...
451 * TODO: When WPA is added this is one place that needs to change */
452 sec
.flags
|= SEC_LEVEL
;
453 sec
.level
= SEC_LEVEL_1
; /* 40 and 104 bit WEP */
454 sec
.encode_alg
[key
] = SEC_ALG_WEP
;
457 if (ieee
->set_security
)
458 ieee
->set_security(dev
, &sec
);
460 /* Do not reset port if card is in Managed mode since resetting will
461 * generate new IEEE 802.11 authentication which may end up in looping
462 * with IEEE 802.1X. If your hardware requires a reset after WEP
463 * configuration (for example... Prism2), implement the reset_port in
464 * the callbacks structures used to initialize the 802.11 stack. */
465 if (ieee
->reset_on_keychange
&&
466 ieee
->iw_mode
!= IW_MODE_INFRA
&&
467 ieee
->reset_port
&& ieee
->reset_port(dev
)) {
468 printk(KERN_DEBUG
"%s: reset_port failed\n", dev
->name
);
474 int ieee80211_wx_get_encode(struct ieee80211_device
*ieee
,
475 struct iw_request_info
*info
,
476 union iwreq_data
*wrqu
, char *keybuf
)
478 struct iw_point
*erq
= &(wrqu
->encoding
);
480 struct ieee80211_crypt_data
*crypt
;
481 struct ieee80211_security
*sec
= &ieee
->sec
;
483 IEEE80211_DEBUG_WX("GET_ENCODE\n");
485 key
= erq
->flags
& IW_ENCODE_INDEX
;
491 key
= ieee
->tx_keyidx
;
493 crypt
= ieee
->crypt
[key
];
494 erq
->flags
= key
+ 1;
498 erq
->flags
|= IW_ENCODE_DISABLED
;
502 len
= sec
->key_sizes
[key
];
503 memcpy(keybuf
, sec
->keys
[key
], len
);
506 erq
->flags
|= IW_ENCODE_ENABLED
;
509 erq
->flags
|= IW_ENCODE_OPEN
;
511 erq
->flags
|= IW_ENCODE_RESTRICTED
;
516 int ieee80211_wx_set_encodeext(struct ieee80211_device
*ieee
,
517 struct iw_request_info
*info
,
518 union iwreq_data
*wrqu
, char *extra
)
520 struct net_device
*dev
= ieee
->dev
;
521 struct iw_point
*encoding
= &wrqu
->encoding
;
522 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
525 const char *alg
, *module
;
526 struct ieee80211_crypto_ops
*ops
;
527 struct ieee80211_crypt_data
**crypt
;
529 struct ieee80211_security sec
= {
533 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
535 if (idx
< 1 || idx
> WEP_KEYS
)
539 idx
= ieee
->tx_keyidx
;
541 if (ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
) {
542 crypt
= &ieee
->crypt
[idx
];
545 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
546 if (idx
!= 0 && ext
->alg
!= IW_ENCODE_ALG_WEP
)
548 if (ieee
->iw_mode
== IW_MODE_INFRA
)
549 crypt
= &ieee
->crypt
[idx
];
554 sec
.flags
|= SEC_ENABLED
| SEC_ENCRYPT
;
555 if ((encoding
->flags
& IW_ENCODE_DISABLED
) ||
556 ext
->alg
== IW_ENCODE_ALG_NONE
) {
558 ieee80211_crypt_delayed_deinit(ieee
, crypt
);
560 for (i
= 0; i
< WEP_KEYS
; i
++)
561 if (ieee
->crypt
[i
] != NULL
)
567 sec
.level
= SEC_LEVEL_0
;
568 sec
.flags
|= SEC_LEVEL
;
576 if (group_key
? !ieee
->host_mc_decrypt
:
577 !(ieee
->host_encrypt
|| ieee
->host_decrypt
||
578 ieee
->host_encrypt_msdu
))
579 goto skip_host_crypt
;
582 case IW_ENCODE_ALG_WEP
:
584 module
= "ieee80211_crypt_wep";
586 case IW_ENCODE_ALG_TKIP
:
588 module
= "ieee80211_crypt_tkip";
590 case IW_ENCODE_ALG_CCMP
:
592 module
= "ieee80211_crypt_ccmp";
595 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
596 dev
->name
, ext
->alg
);
601 ops
= ieee80211_get_crypto_ops(alg
);
603 request_module(module
);
604 ops
= ieee80211_get_crypto_ops(alg
);
607 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
608 dev
->name
, ext
->alg
);
613 if (*crypt
== NULL
|| (*crypt
)->ops
!= ops
) {
614 struct ieee80211_crypt_data
*new_crypt
;
616 ieee80211_crypt_delayed_deinit(ieee
, crypt
);
618 new_crypt
= kzalloc(sizeof(*new_crypt
), GFP_KERNEL
);
619 if (new_crypt
== NULL
) {
623 new_crypt
->ops
= ops
;
624 if (new_crypt
->ops
&& try_module_get(new_crypt
->ops
->owner
))
625 new_crypt
->priv
= new_crypt
->ops
->init(idx
);
626 if (new_crypt
->priv
== NULL
) {
634 if (ext
->key_len
> 0 && (*crypt
)->ops
->set_key
&&
635 (*crypt
)->ops
->set_key(ext
->key
, ext
->key_len
, ext
->rx_seq
,
636 (*crypt
)->priv
) < 0) {
637 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev
->name
);
643 if (ext
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
644 ieee
->tx_keyidx
= idx
;
645 sec
.active_key
= idx
;
646 sec
.flags
|= SEC_ACTIVE_KEY
;
649 if (ext
->alg
!= IW_ENCODE_ALG_NONE
) {
650 memcpy(sec
.keys
[idx
], ext
->key
, ext
->key_len
);
651 sec
.key_sizes
[idx
] = ext
->key_len
;
652 sec
.flags
|= (1 << idx
);
653 if (ext
->alg
== IW_ENCODE_ALG_WEP
) {
654 sec
.encode_alg
[idx
] = SEC_ALG_WEP
;
655 sec
.flags
|= SEC_LEVEL
;
656 sec
.level
= SEC_LEVEL_1
;
657 } else if (ext
->alg
== IW_ENCODE_ALG_TKIP
) {
658 sec
.encode_alg
[idx
] = SEC_ALG_TKIP
;
659 sec
.flags
|= SEC_LEVEL
;
660 sec
.level
= SEC_LEVEL_2
;
661 } else if (ext
->alg
== IW_ENCODE_ALG_CCMP
) {
662 sec
.encode_alg
[idx
] = SEC_ALG_CCMP
;
663 sec
.flags
|= SEC_LEVEL
;
664 sec
.level
= SEC_LEVEL_3
;
666 /* Don't set sec level for group keys. */
668 sec
.flags
&= ~SEC_LEVEL
;
671 if (ieee
->set_security
)
672 ieee
->set_security(ieee
->dev
, &sec
);
675 * Do not reset port if card is in Managed mode since resetting will
676 * generate new IEEE 802.11 authentication which may end up in looping
677 * with IEEE 802.1X. If your hardware requires a reset after WEP
678 * configuration (for example... Prism2), implement the reset_port in
679 * the callbacks structures used to initialize the 802.11 stack.
681 if (ieee
->reset_on_keychange
&&
682 ieee
->iw_mode
!= IW_MODE_INFRA
&&
683 ieee
->reset_port
&& ieee
->reset_port(dev
)) {
684 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev
->name
);
691 int ieee80211_wx_get_encodeext(struct ieee80211_device
*ieee
,
692 struct iw_request_info
*info
,
693 union iwreq_data
*wrqu
, char *extra
)
695 struct iw_point
*encoding
= &wrqu
->encoding
;
696 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
697 struct ieee80211_security
*sec
= &ieee
->sec
;
698 int idx
, max_key_len
;
700 max_key_len
= encoding
->length
- sizeof(*ext
);
704 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
706 if (idx
< 1 || idx
> WEP_KEYS
)
710 idx
= ieee
->tx_keyidx
;
712 if (!(ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
) &&
713 ext
->alg
!= IW_ENCODE_ALG_WEP
)
714 if (idx
!= 0 || ieee
->iw_mode
!= IW_MODE_INFRA
)
717 encoding
->flags
= idx
+ 1;
718 memset(ext
, 0, sizeof(*ext
));
721 ext
->alg
= IW_ENCODE_ALG_NONE
;
723 encoding
->flags
|= IW_ENCODE_DISABLED
;
725 if (sec
->encode_alg
[idx
] == SEC_ALG_WEP
)
726 ext
->alg
= IW_ENCODE_ALG_WEP
;
727 else if (sec
->encode_alg
[idx
] == SEC_ALG_TKIP
)
728 ext
->alg
= IW_ENCODE_ALG_TKIP
;
729 else if (sec
->encode_alg
[idx
] == SEC_ALG_CCMP
)
730 ext
->alg
= IW_ENCODE_ALG_CCMP
;
734 ext
->key_len
= sec
->key_sizes
[idx
];
735 memcpy(ext
->key
, sec
->keys
[idx
], ext
->key_len
);
736 encoding
->flags
|= IW_ENCODE_ENABLED
;
738 (ext
->alg
== IW_ENCODE_ALG_TKIP
||
739 ext
->alg
== IW_ENCODE_ALG_CCMP
))
740 ext
->ext_flags
|= IW_ENCODE_EXT_TX_SEQ_VALID
;
747 EXPORT_SYMBOL(ieee80211_wx_set_encodeext
);
748 EXPORT_SYMBOL(ieee80211_wx_get_encodeext
);
750 EXPORT_SYMBOL(ieee80211_wx_get_scan
);
751 EXPORT_SYMBOL(ieee80211_wx_set_encode
);
752 EXPORT_SYMBOL(ieee80211_wx_get_encode
);