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 Intel Linux Wireless <ilw@linux.intel.com>
29 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
31 ******************************************************************************/
33 #include <linux/hardirq.h>
34 #include <linux/kmod.h>
35 #include <linux/slab.h>
36 #include <linux/module.h>
37 #include <linux/jiffies.h>
39 #include <net/lib80211.h>
40 #include <linux/wireless.h>
44 static const char *libipw_modes
[] = {
45 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
48 static inline unsigned int elapsed_jiffies_msecs(unsigned long start
)
50 unsigned long end
= jiffies
;
53 return jiffies_to_msecs(end
- start
);
55 return jiffies_to_msecs(end
+ (MAX_JIFFY_OFFSET
- start
) + 1);
58 #define MAX_CUSTOM_LEN 64
59 static char *libipw_translate_scan(struct libipw_device
*ieee
,
60 char *start
, char *stop
,
61 struct libipw_network
*network
,
62 struct iw_request_info
*info
)
64 char custom
[MAX_CUSTOM_LEN
];
68 char *current_val
; /* For rates */
71 /* First entry *MUST* be the AP MAC address */
73 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
74 memcpy(iwe
.u
.ap_addr
.sa_data
, network
->bssid
, ETH_ALEN
);
75 start
= iwe_stream_add_event(info
, start
, stop
, &iwe
, IW_EV_ADDR_LEN
);
77 /* Remaining entries will be displayed in the order we provide them */
80 iwe
.cmd
= SIOCGIWESSID
;
82 iwe
.u
.data
.length
= min(network
->ssid_len
, (u8
) 32);
83 start
= iwe_stream_add_point(info
, start
, stop
,
86 /* Add the protocol name */
87 iwe
.cmd
= SIOCGIWNAME
;
88 snprintf(iwe
.u
.name
, IFNAMSIZ
, "IEEE 802.11%s",
89 libipw_modes
[network
->mode
]);
90 start
= iwe_stream_add_event(info
, start
, stop
, &iwe
, IW_EV_CHAR_LEN
);
93 iwe
.cmd
= SIOCGIWMODE
;
94 if (network
->capability
& (WLAN_CAPABILITY_ESS
| WLAN_CAPABILITY_IBSS
)) {
95 if (network
->capability
& WLAN_CAPABILITY_ESS
)
96 iwe
.u
.mode
= IW_MODE_MASTER
;
98 iwe
.u
.mode
= IW_MODE_ADHOC
;
100 start
= iwe_stream_add_event(info
, start
, stop
,
101 &iwe
, IW_EV_UINT_LEN
);
104 /* Add channel and frequency */
105 /* Note : userspace automatically computes channel using iwrange */
106 iwe
.cmd
= SIOCGIWFREQ
;
107 iwe
.u
.freq
.m
= libipw_channel_to_freq(ieee
, network
->channel
);
110 start
= iwe_stream_add_event(info
, start
, stop
, &iwe
, IW_EV_FREQ_LEN
);
112 /* Add encryption capability */
113 iwe
.cmd
= SIOCGIWENCODE
;
114 if (network
->capability
& WLAN_CAPABILITY_PRIVACY
)
115 iwe
.u
.data
.flags
= IW_ENCODE_ENABLED
| IW_ENCODE_NOKEY
;
117 iwe
.u
.data
.flags
= IW_ENCODE_DISABLED
;
118 iwe
.u
.data
.length
= 0;
119 start
= iwe_stream_add_point(info
, start
, stop
,
120 &iwe
, network
->ssid
);
122 /* Add basic and extended rates */
123 /* Rate : stuffing multiple values in a single event require a bit
124 * more of magic - Jean II */
125 current_val
= start
+ iwe_stream_lcp_len(info
);
126 iwe
.cmd
= SIOCGIWRATE
;
127 /* Those two flags are ignored... */
128 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
= 0;
130 for (i
= 0, j
= 0; i
< network
->rates_len
;) {
131 if (j
< network
->rates_ex_len
&&
132 ((network
->rates_ex
[j
] & 0x7F) <
133 (network
->rates
[i
] & 0x7F)))
134 rate
= network
->rates_ex
[j
++] & 0x7F;
136 rate
= network
->rates
[i
++] & 0x7F;
137 /* Bit rate given in 500 kb/s units (+ 0x80) */
138 iwe
.u
.bitrate
.value
= ((rate
& 0x7f) * 500000);
139 /* Add new value to event */
140 current_val
= iwe_stream_add_value(info
, start
, current_val
,
141 stop
, &iwe
, IW_EV_PARAM_LEN
);
143 for (; j
< network
->rates_ex_len
; j
++) {
144 rate
= network
->rates_ex
[j
] & 0x7F;
145 /* Bit rate given in 500 kb/s units (+ 0x80) */
146 iwe
.u
.bitrate
.value
= ((rate
& 0x7f) * 500000);
147 /* Add new value to event */
148 current_val
= iwe_stream_add_value(info
, start
, current_val
,
149 stop
, &iwe
, IW_EV_PARAM_LEN
);
151 /* Check if we added any rate */
152 if ((current_val
- start
) > iwe_stream_lcp_len(info
))
155 /* Add quality statistics */
157 iwe
.u
.qual
.updated
= IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
|
158 IW_QUAL_NOISE_UPDATED
;
160 if (!(network
->stats
.mask
& LIBIPW_STATMASK_RSSI
)) {
161 iwe
.u
.qual
.updated
|= IW_QUAL_QUAL_INVALID
|
162 IW_QUAL_LEVEL_INVALID
;
165 if (ieee
->perfect_rssi
== ieee
->worst_rssi
)
166 iwe
.u
.qual
.qual
= 100;
170 (ieee
->perfect_rssi
- ieee
->worst_rssi
) *
171 (ieee
->perfect_rssi
- ieee
->worst_rssi
) -
172 (ieee
->perfect_rssi
- network
->stats
.rssi
) *
173 (15 * (ieee
->perfect_rssi
- ieee
->worst_rssi
) +
174 62 * (ieee
->perfect_rssi
-
175 network
->stats
.rssi
))) /
176 ((ieee
->perfect_rssi
-
177 ieee
->worst_rssi
) * (ieee
->perfect_rssi
-
179 if (iwe
.u
.qual
.qual
> 100)
180 iwe
.u
.qual
.qual
= 100;
181 else if (iwe
.u
.qual
.qual
< 1)
185 if (!(network
->stats
.mask
& LIBIPW_STATMASK_NOISE
)) {
186 iwe
.u
.qual
.updated
|= IW_QUAL_NOISE_INVALID
;
187 iwe
.u
.qual
.noise
= 0;
189 iwe
.u
.qual
.noise
= network
->stats
.noise
;
192 if (!(network
->stats
.mask
& LIBIPW_STATMASK_SIGNAL
)) {
193 iwe
.u
.qual
.updated
|= IW_QUAL_LEVEL_INVALID
;
194 iwe
.u
.qual
.level
= 0;
196 iwe
.u
.qual
.level
= network
->stats
.signal
;
199 start
= iwe_stream_add_event(info
, start
, stop
, &iwe
, IW_EV_QUAL_LEN
);
201 iwe
.cmd
= IWEVCUSTOM
;
204 iwe
.u
.data
.length
= p
- custom
;
205 if (iwe
.u
.data
.length
)
206 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, custom
);
208 memset(&iwe
, 0, sizeof(iwe
));
209 if (network
->wpa_ie_len
) {
210 char buf
[MAX_WPA_IE_LEN
];
211 memcpy(buf
, network
->wpa_ie
, network
->wpa_ie_len
);
213 iwe
.u
.data
.length
= network
->wpa_ie_len
;
214 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, buf
);
217 memset(&iwe
, 0, sizeof(iwe
));
218 if (network
->rsn_ie_len
) {
219 char buf
[MAX_WPA_IE_LEN
];
220 memcpy(buf
, network
->rsn_ie
, network
->rsn_ie_len
);
222 iwe
.u
.data
.length
= network
->rsn_ie_len
;
223 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, buf
);
226 /* Add EXTRA: Age to display seconds since last beacon/probe response
227 * for given network. */
228 iwe
.cmd
= IWEVCUSTOM
;
230 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
),
231 " Last beacon: %ums ago",
232 elapsed_jiffies_msecs(network
->last_scanned
));
233 iwe
.u
.data
.length
= p
- custom
;
234 if (iwe
.u
.data
.length
)
235 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, custom
);
237 /* Add spectrum management information */
240 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), " Channel flags: ");
242 if (libipw_get_channel_flags(ieee
, network
->channel
) &
244 iwe
.cmd
= IWEVCUSTOM
;
245 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), "INVALID ");
248 if (libipw_get_channel_flags(ieee
, network
->channel
) &
249 LIBIPW_CH_RADAR_DETECT
) {
250 iwe
.cmd
= IWEVCUSTOM
;
251 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), "DFS ");
254 if (iwe
.cmd
== IWEVCUSTOM
) {
255 iwe
.u
.data
.length
= p
- custom
;
256 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, custom
);
262 #define SCAN_ITEM_SIZE 128
264 int libipw_wx_get_scan(struct libipw_device
*ieee
,
265 struct iw_request_info
*info
,
266 union iwreq_data
*wrqu
, char *extra
)
268 struct libipw_network
*network
;
273 char *stop
= ev
+ wrqu
->data
.length
;
276 LIBIPW_DEBUG_WX("Getting scan\n");
278 spin_lock_irqsave(&ieee
->lock
, flags
);
280 list_for_each_entry(network
, &ieee
->network_list
, list
) {
282 if (stop
- ev
< SCAN_ITEM_SIZE
) {
287 if (ieee
->scan_age
== 0 ||
288 time_after(network
->last_scanned
+ ieee
->scan_age
, jiffies
))
289 ev
= libipw_translate_scan(ieee
, ev
, stop
, network
,
292 LIBIPW_DEBUG_SCAN("Not showing network '%*pE (%pM)' due to age (%ums).\n",
293 network
->ssid_len
, network
->ssid
,
295 elapsed_jiffies_msecs(
296 network
->last_scanned
));
300 spin_unlock_irqrestore(&ieee
->lock
, flags
);
302 wrqu
->data
.length
= ev
- extra
;
303 wrqu
->data
.flags
= 0;
305 LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i
);
310 int libipw_wx_set_encode(struct libipw_device
*ieee
,
311 struct iw_request_info
*info
,
312 union iwreq_data
*wrqu
, char *keybuf
)
314 struct iw_point
*erq
= &(wrqu
->encoding
);
315 struct net_device
*dev
= ieee
->dev
;
316 struct libipw_security sec
= {
319 int i
, key
, key_provided
, len
;
320 struct lib80211_crypt_data
**crypt
;
321 int host_crypto
= ieee
->host_encrypt
|| ieee
->host_decrypt
;
323 LIBIPW_DEBUG_WX("SET_ENCODE\n");
325 key
= erq
->flags
& IW_ENCODE_INDEX
;
333 key
= ieee
->crypt_info
.tx_keyidx
;
336 LIBIPW_DEBUG_WX("Key: %d [%s]\n", key
, key_provided
?
337 "provided" : "default");
339 crypt
= &ieee
->crypt_info
.crypt
[key
];
341 if (erq
->flags
& IW_ENCODE_DISABLED
) {
342 if (key_provided
&& *crypt
) {
343 LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
345 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
, crypt
);
347 LIBIPW_DEBUG_WX("Disabling encryption.\n");
349 /* Check all the keys to see if any are still configured,
350 * and if no key index was provided, de-init them all */
351 for (i
= 0; i
< WEP_KEYS
; i
++) {
352 if (ieee
->crypt_info
.crypt
[i
] != NULL
) {
355 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
,
356 &ieee
->crypt_info
.crypt
[i
]);
363 sec
.level
= SEC_LEVEL_0
;
364 sec
.flags
|= SEC_ENABLED
| SEC_LEVEL
| SEC_ENCRYPT
;
372 sec
.flags
|= SEC_ENABLED
| SEC_ENCRYPT
;
374 if (*crypt
!= NULL
&& (*crypt
)->ops
!= NULL
&&
375 strcmp((*crypt
)->ops
->name
, "WEP") != 0) {
376 /* changing to use WEP; deinit previously used algorithm
378 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
, crypt
);
381 if (*crypt
== NULL
&& host_crypto
) {
382 struct lib80211_crypt_data
*new_crypt
;
384 /* take WEP into use */
385 new_crypt
= kzalloc(sizeof(struct lib80211_crypt_data
),
387 if (new_crypt
== NULL
)
389 new_crypt
->ops
= lib80211_get_crypto_ops("WEP");
390 if (!new_crypt
->ops
) {
391 request_module("lib80211_crypt_wep");
392 new_crypt
->ops
= lib80211_get_crypto_ops("WEP");
395 if (new_crypt
->ops
&& try_module_get(new_crypt
->ops
->owner
))
396 new_crypt
->priv
= new_crypt
->ops
->init(key
);
398 if (!new_crypt
->ops
|| !new_crypt
->priv
) {
402 printk(KERN_WARNING
"%s: could not initialize WEP: "
403 "load module lib80211_crypt_wep\n", dev
->name
);
409 /* If a new key was provided, set it up */
410 if (erq
->length
> 0) {
411 len
= erq
->length
<= 5 ? 5 : 13;
412 memcpy(sec
.keys
[key
], keybuf
, erq
->length
);
413 if (len
> erq
->length
)
414 memset(sec
.keys
[key
] + erq
->length
, 0,
416 LIBIPW_DEBUG_WX("Setting key %d to '%*pE' (%d:%d bytes)\n",
417 key
, len
, sec
.keys
[key
],
419 sec
.key_sizes
[key
] = len
;
421 (*crypt
)->ops
->set_key(sec
.keys
[key
], len
, NULL
,
423 sec
.flags
|= (1 << key
);
424 /* This ensures a key will be activated if no key is
426 if (key
== sec
.active_key
)
427 sec
.flags
|= SEC_ACTIVE_KEY
;
431 len
= (*crypt
)->ops
->get_key(sec
.keys
[key
], WEP_KEY_LEN
,
432 NULL
, (*crypt
)->priv
);
434 /* Set a default key of all 0 */
435 LIBIPW_DEBUG_WX("Setting key %d to all "
437 memset(sec
.keys
[key
], 0, 13);
438 (*crypt
)->ops
->set_key(sec
.keys
[key
], 13, NULL
,
440 sec
.key_sizes
[key
] = 13;
441 sec
.flags
|= (1 << key
);
444 /* No key data - just set the default TX key index */
446 LIBIPW_DEBUG_WX("Setting key %d to default Tx "
448 ieee
->crypt_info
.tx_keyidx
= key
;
449 sec
.active_key
= key
;
450 sec
.flags
|= SEC_ACTIVE_KEY
;
453 if (erq
->flags
& (IW_ENCODE_OPEN
| IW_ENCODE_RESTRICTED
)) {
454 ieee
->open_wep
= !(erq
->flags
& IW_ENCODE_RESTRICTED
);
455 sec
.auth_mode
= ieee
->open_wep
? WLAN_AUTH_OPEN
:
456 WLAN_AUTH_SHARED_KEY
;
457 sec
.flags
|= SEC_AUTH_MODE
;
458 LIBIPW_DEBUG_WX("Auth: %s\n",
459 sec
.auth_mode
== WLAN_AUTH_OPEN
?
460 "OPEN" : "SHARED KEY");
463 /* For now we just support WEP, so only set that security level...
464 * TODO: When WPA is added this is one place that needs to change */
465 sec
.flags
|= SEC_LEVEL
;
466 sec
.level
= SEC_LEVEL_1
; /* 40 and 104 bit WEP */
467 sec
.encode_alg
[key
] = SEC_ALG_WEP
;
470 if (ieee
->set_security
)
471 ieee
->set_security(dev
, &sec
);
476 int libipw_wx_get_encode(struct libipw_device
*ieee
,
477 struct iw_request_info
*info
,
478 union iwreq_data
*wrqu
, char *keybuf
)
480 struct iw_point
*erq
= &(wrqu
->encoding
);
482 struct lib80211_crypt_data
*crypt
;
483 struct libipw_security
*sec
= &ieee
->sec
;
485 LIBIPW_DEBUG_WX("GET_ENCODE\n");
487 key
= erq
->flags
& IW_ENCODE_INDEX
;
493 key
= ieee
->crypt_info
.tx_keyidx
;
495 crypt
= ieee
->crypt_info
.crypt
[key
];
496 erq
->flags
= key
+ 1;
500 erq
->flags
|= IW_ENCODE_DISABLED
;
504 len
= sec
->key_sizes
[key
];
505 memcpy(keybuf
, sec
->keys
[key
], len
);
508 erq
->flags
|= IW_ENCODE_ENABLED
;
511 erq
->flags
|= IW_ENCODE_OPEN
;
513 erq
->flags
|= IW_ENCODE_RESTRICTED
;
518 int libipw_wx_set_encodeext(struct libipw_device
*ieee
,
519 struct iw_request_info
*info
,
520 union iwreq_data
*wrqu
, char *extra
)
522 struct net_device
*dev
= ieee
->dev
;
523 struct iw_point
*encoding
= &wrqu
->encoding
;
524 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
527 const char *alg
, *module
;
528 struct lib80211_crypto_ops
*ops
;
529 struct lib80211_crypt_data
**crypt
;
531 struct libipw_security sec
= {
535 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
537 if (idx
< 1 || idx
> WEP_KEYS
)
541 idx
= ieee
->crypt_info
.tx_keyidx
;
543 if (ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
) {
544 crypt
= &ieee
->crypt_info
.crypt
[idx
];
547 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
548 if (idx
!= 0 && ext
->alg
!= IW_ENCODE_ALG_WEP
)
550 if (ieee
->iw_mode
== IW_MODE_INFRA
)
551 crypt
= &ieee
->crypt_info
.crypt
[idx
];
556 sec
.flags
|= SEC_ENABLED
| SEC_ENCRYPT
;
557 if ((encoding
->flags
& IW_ENCODE_DISABLED
) ||
558 ext
->alg
== IW_ENCODE_ALG_NONE
) {
560 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
, crypt
);
562 for (i
= 0; i
< WEP_KEYS
; i
++)
563 if (ieee
->crypt_info
.crypt
[i
] != NULL
)
569 sec
.level
= SEC_LEVEL_0
;
570 sec
.flags
|= SEC_LEVEL
;
578 if (group_key
? !ieee
->host_mc_decrypt
:
579 !(ieee
->host_encrypt
|| ieee
->host_decrypt
||
580 ieee
->host_encrypt_msdu
))
581 goto skip_host_crypt
;
584 case IW_ENCODE_ALG_WEP
:
586 module
= "lib80211_crypt_wep";
588 case IW_ENCODE_ALG_TKIP
:
590 module
= "lib80211_crypt_tkip";
592 case IW_ENCODE_ALG_CCMP
:
594 module
= "lib80211_crypt_ccmp";
597 LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
598 dev
->name
, ext
->alg
);
603 ops
= lib80211_get_crypto_ops(alg
);
605 request_module(module
);
606 ops
= lib80211_get_crypto_ops(alg
);
609 LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
610 dev
->name
, ext
->alg
);
615 if (*crypt
== NULL
|| (*crypt
)->ops
!= ops
) {
616 struct lib80211_crypt_data
*new_crypt
;
618 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
, crypt
);
620 new_crypt
= kzalloc(sizeof(*new_crypt
), GFP_KERNEL
);
621 if (new_crypt
== NULL
) {
625 new_crypt
->ops
= ops
;
626 if (new_crypt
->ops
&& try_module_get(new_crypt
->ops
->owner
))
627 new_crypt
->priv
= new_crypt
->ops
->init(idx
);
628 if (new_crypt
->priv
== NULL
) {
636 if (ext
->key_len
> 0 && (*crypt
)->ops
->set_key
&&
637 (*crypt
)->ops
->set_key(ext
->key
, ext
->key_len
, ext
->rx_seq
,
638 (*crypt
)->priv
) < 0) {
639 LIBIPW_DEBUG_WX("%s: key setting failed\n", dev
->name
);
645 if (ext
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
646 ieee
->crypt_info
.tx_keyidx
= idx
;
647 sec
.active_key
= idx
;
648 sec
.flags
|= SEC_ACTIVE_KEY
;
651 if (ext
->alg
!= IW_ENCODE_ALG_NONE
) {
652 memcpy(sec
.keys
[idx
], ext
->key
, ext
->key_len
);
653 sec
.key_sizes
[idx
] = ext
->key_len
;
654 sec
.flags
|= (1 << idx
);
655 if (ext
->alg
== IW_ENCODE_ALG_WEP
) {
656 sec
.encode_alg
[idx
] = SEC_ALG_WEP
;
657 sec
.flags
|= SEC_LEVEL
;
658 sec
.level
= SEC_LEVEL_1
;
659 } else if (ext
->alg
== IW_ENCODE_ALG_TKIP
) {
660 sec
.encode_alg
[idx
] = SEC_ALG_TKIP
;
661 sec
.flags
|= SEC_LEVEL
;
662 sec
.level
= SEC_LEVEL_2
;
663 } else if (ext
->alg
== IW_ENCODE_ALG_CCMP
) {
664 sec
.encode_alg
[idx
] = SEC_ALG_CCMP
;
665 sec
.flags
|= SEC_LEVEL
;
666 sec
.level
= SEC_LEVEL_3
;
668 /* Don't set sec level for group keys. */
670 sec
.flags
&= ~SEC_LEVEL
;
673 if (ieee
->set_security
)
674 ieee
->set_security(dev
, &sec
);
679 int libipw_wx_get_encodeext(struct libipw_device
*ieee
,
680 struct iw_request_info
*info
,
681 union iwreq_data
*wrqu
, char *extra
)
683 struct iw_point
*encoding
= &wrqu
->encoding
;
684 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
685 struct libipw_security
*sec
= &ieee
->sec
;
686 int idx
, max_key_len
;
688 max_key_len
= encoding
->length
- sizeof(*ext
);
692 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
694 if (idx
< 1 || idx
> WEP_KEYS
)
698 idx
= ieee
->crypt_info
.tx_keyidx
;
700 if (!(ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
) &&
701 ext
->alg
!= IW_ENCODE_ALG_WEP
)
702 if (idx
!= 0 || ieee
->iw_mode
!= IW_MODE_INFRA
)
705 encoding
->flags
= idx
+ 1;
706 memset(ext
, 0, sizeof(*ext
));
709 ext
->alg
= IW_ENCODE_ALG_NONE
;
711 encoding
->flags
|= IW_ENCODE_DISABLED
;
713 if (sec
->encode_alg
[idx
] == SEC_ALG_WEP
)
714 ext
->alg
= IW_ENCODE_ALG_WEP
;
715 else if (sec
->encode_alg
[idx
] == SEC_ALG_TKIP
)
716 ext
->alg
= IW_ENCODE_ALG_TKIP
;
717 else if (sec
->encode_alg
[idx
] == SEC_ALG_CCMP
)
718 ext
->alg
= IW_ENCODE_ALG_CCMP
;
722 ext
->key_len
= sec
->key_sizes
[idx
];
723 memcpy(ext
->key
, sec
->keys
[idx
], ext
->key_len
);
724 encoding
->flags
|= IW_ENCODE_ENABLED
;
726 (ext
->alg
== IW_ENCODE_ALG_TKIP
||
727 ext
->alg
== IW_ENCODE_ALG_CCMP
))
728 ext
->ext_flags
|= IW_ENCODE_EXT_TX_SEQ_VALID
;
735 EXPORT_SYMBOL(libipw_wx_set_encodeext
);
736 EXPORT_SYMBOL(libipw_wx_get_encodeext
);
738 EXPORT_SYMBOL(libipw_wx_get_scan
);
739 EXPORT_SYMBOL(libipw_wx_set_encode
);
740 EXPORT_SYMBOL(libipw_wx_get_encode
);