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 <jkmaline@cc.hut.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 *ipw2100_translate_scan(struct ieee80211_device
*ieee
,
46 char *start
, char *stop
,
47 struct ieee80211_network
*network
)
49 char custom
[MAX_CUSTOM_LEN
];
55 /* First entry *MUST* be the AP MAC address */
57 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
58 memcpy(iwe
.u
.ap_addr
.sa_data
, network
->bssid
, ETH_ALEN
);
59 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_ADDR_LEN
);
61 /* Remaining entries will be displayed in the order we provide them */
64 iwe
.cmd
= SIOCGIWESSID
;
66 if (network
->flags
& NETWORK_EMPTY_ESSID
) {
67 iwe
.u
.data
.length
= sizeof("<hidden>");
68 start
= iwe_stream_add_point(start
, stop
, &iwe
, "<hidden>");
70 iwe
.u
.data
.length
= min(network
->ssid_len
, (u8
) 32);
71 start
= iwe_stream_add_point(start
, stop
, &iwe
, network
->ssid
);
74 /* Add the protocol name */
75 iwe
.cmd
= SIOCGIWNAME
;
76 snprintf(iwe
.u
.name
, IFNAMSIZ
, "IEEE 802.11%s",
77 ieee80211_modes
[network
->mode
]);
78 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_CHAR_LEN
);
81 iwe
.cmd
= SIOCGIWMODE
;
82 if (network
->capability
& (WLAN_CAPABILITY_ESS
| WLAN_CAPABILITY_IBSS
)) {
83 if (network
->capability
& WLAN_CAPABILITY_ESS
)
84 iwe
.u
.mode
= IW_MODE_MASTER
;
86 iwe
.u
.mode
= IW_MODE_ADHOC
;
88 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_UINT_LEN
);
91 /* Add frequency/channel */
92 iwe
.cmd
= SIOCGIWFREQ
;
93 /* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
95 iwe
.u
.freq
.m
= 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 */
112 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), " Rates (Mb/s): ");
113 for (i
= 0, j
= 0; i
< network
->rates_len
;) {
114 if (j
< network
->rates_ex_len
&&
115 ((network
->rates_ex
[j
] & 0x7F) <
116 (network
->rates
[i
] & 0x7F)))
117 rate
= network
->rates_ex
[j
++] & 0x7F;
119 rate
= network
->rates
[i
++] & 0x7F;
122 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
),
123 "%d%s ", rate
>> 1, (rate
& 1) ? ".5" : "");
125 for (; j
< network
->rates_ex_len
; j
++) {
126 rate
= network
->rates_ex
[j
] & 0x7F;
127 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
),
128 "%d%s ", rate
>> 1, (rate
& 1) ? ".5" : "");
133 iwe
.cmd
= SIOCGIWRATE
;
134 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
= 0;
135 iwe
.u
.bitrate
.value
= max_rate
* 500000;
136 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_PARAM_LEN
);
138 iwe
.cmd
= IWEVCUSTOM
;
139 iwe
.u
.data
.length
= p
- custom
;
140 if (iwe
.u
.data
.length
)
141 start
= iwe_stream_add_point(start
, stop
, &iwe
, custom
);
143 /* Add quality statistics */
145 iwe
.u
.qual
.updated
= IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
|
146 IW_QUAL_NOISE_UPDATED
;
148 if (!(network
->stats
.mask
& IEEE80211_STATMASK_RSSI
)) {
149 iwe
.u
.qual
.updated
|= IW_QUAL_QUAL_INVALID
|
150 IW_QUAL_LEVEL_INVALID
;
152 iwe
.u
.qual
.level
= 0;
154 iwe
.u
.qual
.level
= network
->stats
.rssi
;
155 if (ieee
->perfect_rssi
== ieee
->worst_rssi
)
156 iwe
.u
.qual
.qual
= 100;
160 (ieee
->perfect_rssi
- ieee
->worst_rssi
) *
161 (ieee
->perfect_rssi
- ieee
->worst_rssi
) -
162 (ieee
->perfect_rssi
- network
->stats
.rssi
) *
163 (15 * (ieee
->perfect_rssi
- ieee
->worst_rssi
) +
164 62 * (ieee
->perfect_rssi
-
165 network
->stats
.rssi
))) /
166 ((ieee
->perfect_rssi
-
167 ieee
->worst_rssi
) * (ieee
->perfect_rssi
-
169 if (iwe
.u
.qual
.qual
> 100)
170 iwe
.u
.qual
.qual
= 100;
171 else if (iwe
.u
.qual
.qual
< 1)
175 if (!(network
->stats
.mask
& IEEE80211_STATMASK_NOISE
)) {
176 iwe
.u
.qual
.updated
|= IW_QUAL_NOISE_INVALID
;
177 iwe
.u
.qual
.noise
= 0;
179 iwe
.u
.qual
.noise
= network
->stats
.noise
;
182 start
= iwe_stream_add_event(start
, stop
, &iwe
, IW_EV_QUAL_LEN
);
184 iwe
.cmd
= IWEVCUSTOM
;
187 iwe
.u
.data
.length
= p
- custom
;
188 if (iwe
.u
.data
.length
)
189 start
= iwe_stream_add_point(start
, stop
, &iwe
, custom
);
191 if (network
->wpa_ie_len
) {
192 char buf
[MAX_WPA_IE_LEN
* 2 + 30];
195 p
+= sprintf(p
, "wpa_ie=");
196 for (i
= 0; i
< network
->wpa_ie_len
; i
++) {
197 p
+= sprintf(p
, "%02x", network
->wpa_ie
[i
]);
200 memset(&iwe
, 0, sizeof(iwe
));
201 iwe
.cmd
= IWEVCUSTOM
;
202 iwe
.u
.data
.length
= strlen(buf
);
203 start
= iwe_stream_add_point(start
, stop
, &iwe
, buf
);
206 if (network
->rsn_ie_len
) {
207 char buf
[MAX_WPA_IE_LEN
* 2 + 30];
210 p
+= sprintf(p
, "rsn_ie=");
211 for (i
= 0; i
< network
->rsn_ie_len
; i
++) {
212 p
+= sprintf(p
, "%02x", network
->rsn_ie
[i
]);
215 memset(&iwe
, 0, sizeof(iwe
));
216 iwe
.cmd
= IWEVCUSTOM
;
217 iwe
.u
.data
.length
= strlen(buf
);
218 start
= iwe_stream_add_point(start
, stop
, &iwe
, buf
);
221 /* Add EXTRA: Age to display seconds since last beacon/probe response
222 * for given network. */
223 iwe
.cmd
= IWEVCUSTOM
;
225 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
),
226 " Last beacon: %dms ago",
227 jiffies_to_msecs(jiffies
- network
->last_scanned
));
228 iwe
.u
.data
.length
= p
- custom
;
229 if (iwe
.u
.data
.length
)
230 start
= iwe_stream_add_point(start
, stop
, &iwe
, custom
);
235 int ieee80211_wx_get_scan(struct ieee80211_device
*ieee
,
236 struct iw_request_info
*info
,
237 union iwreq_data
*wrqu
, char *extra
)
239 struct ieee80211_network
*network
;
243 char *stop
= ev
+ IW_SCAN_MAX_DATA
;
246 IEEE80211_DEBUG_WX("Getting scan\n");
248 spin_lock_irqsave(&ieee
->lock
, flags
);
250 list_for_each_entry(network
, &ieee
->network_list
, list
) {
252 if (ieee
->scan_age
== 0 ||
253 time_after(network
->last_scanned
+ ieee
->scan_age
, jiffies
))
254 ev
= ipw2100_translate_scan(ieee
, ev
, stop
, network
);
256 IEEE80211_DEBUG_SCAN("Not showing network '%s ("
257 MAC_FMT
")' due to age (%dms).\n",
258 escape_essid(network
->ssid
,
260 MAC_ARG(network
->bssid
),
261 jiffies_to_msecs(jiffies
-
266 spin_unlock_irqrestore(&ieee
->lock
, flags
);
268 wrqu
->data
.length
= ev
- extra
;
269 wrqu
->data
.flags
= 0;
271 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i
);
276 int ieee80211_wx_set_encode(struct ieee80211_device
*ieee
,
277 struct iw_request_info
*info
,
278 union iwreq_data
*wrqu
, char *keybuf
)
280 struct iw_point
*erq
= &(wrqu
->encoding
);
281 struct net_device
*dev
= ieee
->dev
;
282 struct ieee80211_security sec
= {
285 int i
, key
, key_provided
, len
;
286 struct ieee80211_crypt_data
**crypt
;
287 int host_crypto
= ieee
->host_encrypt
|| ieee
->host_decrypt
|| ieee
->host_build_iv
;
289 IEEE80211_DEBUG_WX("SET_ENCODE\n");
291 key
= erq
->flags
& IW_ENCODE_INDEX
;
299 key
= ieee
->tx_keyidx
;
302 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key
, key_provided
?
303 "provided" : "default");
305 crypt
= &ieee
->crypt
[key
];
307 if (erq
->flags
& IW_ENCODE_DISABLED
) {
308 if (key_provided
&& *crypt
) {
309 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
311 ieee80211_crypt_delayed_deinit(ieee
, crypt
);
313 IEEE80211_DEBUG_WX("Disabling encryption.\n");
315 /* Check all the keys to see if any are still configured,
316 * and if no key index was provided, de-init them all */
317 for (i
= 0; i
< WEP_KEYS
; i
++) {
318 if (ieee
->crypt
[i
] != NULL
) {
321 ieee80211_crypt_delayed_deinit(ieee
,
329 sec
.level
= SEC_LEVEL_0
;
330 sec
.flags
|= SEC_ENABLED
| SEC_LEVEL
| SEC_ENCRYPT
;
338 sec
.flags
|= SEC_ENABLED
| SEC_ENCRYPT
;
340 if (*crypt
!= NULL
&& (*crypt
)->ops
!= NULL
&&
341 strcmp((*crypt
)->ops
->name
, "WEP") != 0) {
342 /* changing to use WEP; deinit previously used algorithm
344 ieee80211_crypt_delayed_deinit(ieee
, crypt
);
347 if (*crypt
== NULL
&& host_crypto
) {
348 struct ieee80211_crypt_data
*new_crypt
;
350 /* take WEP into use */
351 new_crypt
= kmalloc(sizeof(struct ieee80211_crypt_data
),
353 if (new_crypt
== NULL
)
355 memset(new_crypt
, 0, sizeof(struct ieee80211_crypt_data
));
356 new_crypt
->ops
= ieee80211_get_crypto_ops("WEP");
357 if (!new_crypt
->ops
) {
358 request_module("ieee80211_crypt_wep");
359 new_crypt
->ops
= ieee80211_get_crypto_ops("WEP");
362 if (new_crypt
->ops
&& try_module_get(new_crypt
->ops
->owner
))
363 new_crypt
->priv
= new_crypt
->ops
->init(key
);
365 if (!new_crypt
->ops
|| !new_crypt
->priv
) {
369 printk(KERN_WARNING
"%s: could not initialize WEP: "
370 "load module ieee80211_crypt_wep\n", dev
->name
);
376 /* If a new key was provided, set it up */
377 if (erq
->length
> 0) {
378 len
= erq
->length
<= 5 ? 5 : 13;
379 memcpy(sec
.keys
[key
], keybuf
, erq
->length
);
380 if (len
> erq
->length
)
381 memset(sec
.keys
[key
] + erq
->length
, 0,
383 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
384 key
, escape_essid(sec
.keys
[key
], len
),
386 sec
.key_sizes
[key
] = len
;
388 (*crypt
)->ops
->set_key(sec
.keys
[key
], len
, NULL
,
390 sec
.flags
|= (1 << key
);
391 /* This ensures a key will be activated if no key is
393 if (key
== sec
.active_key
)
394 sec
.flags
|= SEC_ACTIVE_KEY
;
398 len
= (*crypt
)->ops
->get_key(sec
.keys
[key
], WEP_KEY_LEN
,
399 NULL
, (*crypt
)->priv
);
401 /* Set a default key of all 0 */
402 IEEE80211_DEBUG_WX("Setting key %d to all "
404 memset(sec
.keys
[key
], 0, 13);
405 (*crypt
)->ops
->set_key(sec
.keys
[key
], 13, NULL
,
407 sec
.key_sizes
[key
] = 13;
408 sec
.flags
|= (1 << key
);
411 /* No key data - just set the default TX key index */
413 IEEE80211_DEBUG_WX("Setting key %d to default Tx "
415 ieee
->tx_keyidx
= key
;
416 sec
.active_key
= key
;
417 sec
.flags
|= SEC_ACTIVE_KEY
;
420 if (erq
->flags
& (IW_ENCODE_OPEN
| IW_ENCODE_RESTRICTED
)) {
421 ieee
->open_wep
= !(erq
->flags
& IW_ENCODE_RESTRICTED
);
422 sec
.auth_mode
= ieee
->open_wep
? WLAN_AUTH_OPEN
:
423 WLAN_AUTH_SHARED_KEY
;
424 sec
.flags
|= SEC_AUTH_MODE
;
425 IEEE80211_DEBUG_WX("Auth: %s\n",
426 sec
.auth_mode
== WLAN_AUTH_OPEN
?
427 "OPEN" : "SHARED KEY");
430 /* For now we just support WEP, so only set that security level...
431 * TODO: When WPA is added this is one place that needs to change */
432 sec
.flags
|= SEC_LEVEL
;
433 sec
.level
= SEC_LEVEL_1
; /* 40 and 104 bit WEP */
434 sec
.encode_alg
[key
] = SEC_ALG_WEP
;
437 if (ieee
->set_security
)
438 ieee
->set_security(dev
, &sec
);
440 /* Do not reset port if card is in Managed mode since resetting will
441 * generate new IEEE 802.11 authentication which may end up in looping
442 * with IEEE 802.1X. If your hardware requires a reset after WEP
443 * configuration (for example... Prism2), implement the reset_port in
444 * the callbacks structures used to initialize the 802.11 stack. */
445 if (ieee
->reset_on_keychange
&&
446 ieee
->iw_mode
!= IW_MODE_INFRA
&&
447 ieee
->reset_port
&& ieee
->reset_port(dev
)) {
448 printk(KERN_DEBUG
"%s: reset_port failed\n", dev
->name
);
454 int ieee80211_wx_get_encode(struct ieee80211_device
*ieee
,
455 struct iw_request_info
*info
,
456 union iwreq_data
*wrqu
, char *keybuf
)
458 struct iw_point
*erq
= &(wrqu
->encoding
);
460 struct ieee80211_crypt_data
*crypt
;
461 struct ieee80211_security
*sec
= &ieee
->sec
;
463 IEEE80211_DEBUG_WX("GET_ENCODE\n");
465 key
= erq
->flags
& IW_ENCODE_INDEX
;
471 key
= ieee
->tx_keyidx
;
473 crypt
= ieee
->crypt
[key
];
474 erq
->flags
= key
+ 1;
478 erq
->flags
|= IW_ENCODE_DISABLED
;
482 len
= sec
->key_sizes
[key
];
483 memcpy(keybuf
, sec
->keys
[key
], len
);
485 erq
->length
= (len
>= 0 ? len
: 0);
486 erq
->flags
|= IW_ENCODE_ENABLED
;
489 erq
->flags
|= IW_ENCODE_OPEN
;
491 erq
->flags
|= IW_ENCODE_RESTRICTED
;
496 int ieee80211_wx_set_encodeext(struct ieee80211_device
*ieee
,
497 struct iw_request_info
*info
,
498 union iwreq_data
*wrqu
, char *extra
)
500 struct net_device
*dev
= ieee
->dev
;
501 struct iw_point
*encoding
= &wrqu
->encoding
;
502 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
505 const char *alg
, *module
;
506 struct ieee80211_crypto_ops
*ops
;
507 struct ieee80211_crypt_data
**crypt
;
509 struct ieee80211_security sec
= {
513 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
515 if (idx
< 1 || idx
> WEP_KEYS
)
519 idx
= ieee
->tx_keyidx
;
521 if (ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
) {
522 crypt
= &ieee
->crypt
[idx
];
525 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
526 if (idx
!= 0 && ext
->alg
!= IW_ENCODE_ALG_WEP
)
528 if (ieee
->iw_mode
== IW_MODE_INFRA
)
529 crypt
= &ieee
->crypt
[idx
];
534 sec
.flags
|= SEC_ENABLED
| SEC_ENCRYPT
;
535 if ((encoding
->flags
& IW_ENCODE_DISABLED
) ||
536 ext
->alg
== IW_ENCODE_ALG_NONE
) {
538 ieee80211_crypt_delayed_deinit(ieee
, crypt
);
540 for (i
= 0; i
< WEP_KEYS
; i
++)
541 if (ieee
->crypt
[i
] != NULL
)
547 sec
.level
= SEC_LEVEL_0
;
548 sec
.flags
|= SEC_LEVEL
;
556 if (group_key
? !ieee
->host_mc_decrypt
:
557 !(ieee
->host_encrypt
|| ieee
->host_decrypt
||
558 ieee
->host_encrypt_msdu
))
559 goto skip_host_crypt
;
562 case IW_ENCODE_ALG_WEP
:
564 module
= "ieee80211_crypt_wep";
566 case IW_ENCODE_ALG_TKIP
:
568 module
= "ieee80211_crypt_tkip";
570 case IW_ENCODE_ALG_CCMP
:
572 module
= "ieee80211_crypt_ccmp";
575 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
576 dev
->name
, ext
->alg
);
581 ops
= ieee80211_get_crypto_ops(alg
);
583 request_module(module
);
584 ops
= ieee80211_get_crypto_ops(alg
);
587 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
588 dev
->name
, ext
->alg
);
593 if (*crypt
== NULL
|| (*crypt
)->ops
!= ops
) {
594 struct ieee80211_crypt_data
*new_crypt
;
596 ieee80211_crypt_delayed_deinit(ieee
, crypt
);
598 new_crypt
= (struct ieee80211_crypt_data
*)
599 kmalloc(sizeof(*new_crypt
), GFP_KERNEL
);
600 if (new_crypt
== NULL
) {
604 memset(new_crypt
, 0, sizeof(struct ieee80211_crypt_data
));
605 new_crypt
->ops
= ops
;
606 if (new_crypt
->ops
&& try_module_get(new_crypt
->ops
->owner
))
607 new_crypt
->priv
= new_crypt
->ops
->init(idx
);
608 if (new_crypt
->priv
== NULL
) {
616 if (ext
->key_len
> 0 && (*crypt
)->ops
->set_key
&&
617 (*crypt
)->ops
->set_key(ext
->key
, ext
->key_len
, ext
->rx_seq
,
618 (*crypt
)->priv
) < 0) {
619 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev
->name
);
625 if (ext
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
626 ieee
->tx_keyidx
= idx
;
627 sec
.active_key
= idx
;
628 sec
.flags
|= SEC_ACTIVE_KEY
;
631 if (ext
->alg
!= IW_ENCODE_ALG_NONE
) {
632 memcpy(sec
.keys
[idx
], ext
->key
, ext
->key_len
);
633 sec
.key_sizes
[idx
] = ext
->key_len
;
634 sec
.flags
|= (1 << idx
);
635 if (ext
->alg
== IW_ENCODE_ALG_WEP
) {
636 sec
.encode_alg
[idx
] = SEC_ALG_WEP
;
637 sec
.flags
|= SEC_LEVEL
;
638 sec
.level
= SEC_LEVEL_1
;
639 } else if (ext
->alg
== IW_ENCODE_ALG_TKIP
) {
640 sec
.encode_alg
[idx
] = SEC_ALG_TKIP
;
641 sec
.flags
|= SEC_LEVEL
;
642 sec
.level
= SEC_LEVEL_2
;
643 } else if (ext
->alg
== IW_ENCODE_ALG_CCMP
) {
644 sec
.encode_alg
[idx
] = SEC_ALG_CCMP
;
645 sec
.flags
|= SEC_LEVEL
;
646 sec
.level
= SEC_LEVEL_3
;
648 /* Don't set sec level for group keys. */
650 sec
.flags
&= ~SEC_LEVEL
;
653 if (ieee
->set_security
)
654 ieee
->set_security(ieee
->dev
, &sec
);
657 * Do not reset port if card is in Managed mode since resetting will
658 * generate new IEEE 802.11 authentication which may end up in looping
659 * with IEEE 802.1X. If your hardware requires a reset after WEP
660 * configuration (for example... Prism2), implement the reset_port in
661 * the callbacks structures used to initialize the 802.11 stack.
663 if (ieee
->reset_on_keychange
&&
664 ieee
->iw_mode
!= IW_MODE_INFRA
&&
665 ieee
->reset_port
&& ieee
->reset_port(dev
)) {
666 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev
->name
);
673 int ieee80211_wx_get_encodeext(struct ieee80211_device
*ieee
,
674 struct iw_request_info
*info
,
675 union iwreq_data
*wrqu
, char *extra
)
677 struct iw_point
*encoding
= &wrqu
->encoding
;
678 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
679 struct ieee80211_security
*sec
= &ieee
->sec
;
680 int idx
, max_key_len
;
682 max_key_len
= encoding
->length
- sizeof(*ext
);
686 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
688 if (idx
< 1 || idx
> WEP_KEYS
)
692 idx
= ieee
->tx_keyidx
;
694 if (!ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
&&
695 ext
->alg
!= IW_ENCODE_ALG_WEP
)
696 if (idx
!= 0 || ieee
->iw_mode
!= IW_MODE_INFRA
)
699 encoding
->flags
= idx
+ 1;
700 memset(ext
, 0, sizeof(*ext
));
703 ext
->alg
= IW_ENCODE_ALG_NONE
;
705 encoding
->flags
|= IW_ENCODE_DISABLED
;
707 if (sec
->encode_alg
[idx
] == SEC_ALG_WEP
)
708 ext
->alg
= IW_ENCODE_ALG_WEP
;
709 else if (sec
->encode_alg
[idx
] == SEC_ALG_TKIP
)
710 ext
->alg
= IW_ENCODE_ALG_TKIP
;
711 else if (sec
->encode_alg
[idx
] == SEC_ALG_CCMP
)
712 ext
->alg
= IW_ENCODE_ALG_CCMP
;
716 ext
->key_len
= sec
->key_sizes
[idx
];
717 memcpy(ext
->key
, sec
->keys
[idx
], ext
->key_len
);
718 encoding
->flags
|= IW_ENCODE_ENABLED
;
720 (ext
->alg
== IW_ENCODE_ALG_TKIP
||
721 ext
->alg
== IW_ENCODE_ALG_CCMP
))
722 ext
->ext_flags
|= IW_ENCODE_EXT_TX_SEQ_VALID
;
729 EXPORT_SYMBOL(ieee80211_wx_set_encodeext
);
730 EXPORT_SYMBOL(ieee80211_wx_get_encodeext
);
732 EXPORT_SYMBOL(ieee80211_wx_get_scan
);
733 EXPORT_SYMBOL(ieee80211_wx_set_encode
);
734 EXPORT_SYMBOL(ieee80211_wx_get_encode
);