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/kmod.h>
34 #include <linux/slab.h>
35 #include <linux/module.h>
36 #include <linux/jiffies.h>
38 #include <net/lib80211.h>
39 #include <linux/wireless.h>
43 static const char *libipw_modes
[] = {
44 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
47 static inline unsigned int elapsed_jiffies_msecs(unsigned long start
)
49 unsigned long end
= jiffies
;
52 return jiffies_to_msecs(end
- start
);
54 return jiffies_to_msecs(end
+ (MAX_JIFFY_OFFSET
- start
) + 1);
57 #define MAX_CUSTOM_LEN 64
58 static char *libipw_translate_scan(struct libipw_device
*ieee
,
59 char *start
, char *stop
,
60 struct libipw_network
*network
,
61 struct iw_request_info
*info
)
63 char custom
[MAX_CUSTOM_LEN
];
67 char *current_val
; /* For rates */
70 /* First entry *MUST* be the AP MAC address */
72 iwe
.u
.ap_addr
.sa_family
= ARPHRD_ETHER
;
73 memcpy(iwe
.u
.ap_addr
.sa_data
, network
->bssid
, ETH_ALEN
);
74 start
= iwe_stream_add_event(info
, start
, stop
, &iwe
, IW_EV_ADDR_LEN
);
76 /* Remaining entries will be displayed in the order we provide them */
79 iwe
.cmd
= SIOCGIWESSID
;
81 iwe
.u
.data
.length
= min(network
->ssid_len
, (u8
) 32);
82 start
= iwe_stream_add_point(info
, start
, stop
,
85 /* Add the protocol name */
86 iwe
.cmd
= SIOCGIWNAME
;
87 snprintf(iwe
.u
.name
, IFNAMSIZ
, "IEEE 802.11%s",
88 libipw_modes
[network
->mode
]);
89 start
= iwe_stream_add_event(info
, start
, stop
, &iwe
, IW_EV_CHAR_LEN
);
92 iwe
.cmd
= SIOCGIWMODE
;
93 if (network
->capability
& (WLAN_CAPABILITY_ESS
| WLAN_CAPABILITY_IBSS
)) {
94 if (network
->capability
& WLAN_CAPABILITY_ESS
)
95 iwe
.u
.mode
= IW_MODE_MASTER
;
97 iwe
.u
.mode
= IW_MODE_ADHOC
;
99 start
= iwe_stream_add_event(info
, start
, stop
,
100 &iwe
, IW_EV_UINT_LEN
);
103 /* Add channel and frequency */
104 /* Note : userspace automatically computes channel using iwrange */
105 iwe
.cmd
= SIOCGIWFREQ
;
106 iwe
.u
.freq
.m
= libipw_channel_to_freq(ieee
, network
->channel
);
109 start
= iwe_stream_add_event(info
, start
, stop
, &iwe
, IW_EV_FREQ_LEN
);
111 /* Add encryption capability */
112 iwe
.cmd
= SIOCGIWENCODE
;
113 if (network
->capability
& WLAN_CAPABILITY_PRIVACY
)
114 iwe
.u
.data
.flags
= IW_ENCODE_ENABLED
| IW_ENCODE_NOKEY
;
116 iwe
.u
.data
.flags
= IW_ENCODE_DISABLED
;
117 iwe
.u
.data
.length
= 0;
118 start
= iwe_stream_add_point(info
, start
, stop
,
119 &iwe
, network
->ssid
);
121 /* Add basic and extended rates */
122 /* Rate : stuffing multiple values in a single event require a bit
123 * more of magic - Jean II */
124 current_val
= start
+ iwe_stream_lcp_len(info
);
125 iwe
.cmd
= SIOCGIWRATE
;
126 /* Those two flags are ignored... */
127 iwe
.u
.bitrate
.fixed
= iwe
.u
.bitrate
.disabled
= 0;
129 for (i
= 0, j
= 0; i
< network
->rates_len
;) {
130 if (j
< network
->rates_ex_len
&&
131 ((network
->rates_ex
[j
] & 0x7F) <
132 (network
->rates
[i
] & 0x7F)))
133 rate
= network
->rates_ex
[j
++] & 0x7F;
135 rate
= network
->rates
[i
++] & 0x7F;
136 /* Bit rate given in 500 kb/s units (+ 0x80) */
137 iwe
.u
.bitrate
.value
= ((rate
& 0x7f) * 500000);
138 /* Add new value to event */
139 current_val
= iwe_stream_add_value(info
, start
, current_val
,
140 stop
, &iwe
, IW_EV_PARAM_LEN
);
142 for (; j
< network
->rates_ex_len
; j
++) {
143 rate
= network
->rates_ex
[j
] & 0x7F;
144 /* Bit rate given in 500 kb/s units (+ 0x80) */
145 iwe
.u
.bitrate
.value
= ((rate
& 0x7f) * 500000);
146 /* Add new value to event */
147 current_val
= iwe_stream_add_value(info
, start
, current_val
,
148 stop
, &iwe
, IW_EV_PARAM_LEN
);
150 /* Check if we added any rate */
151 if ((current_val
- start
) > iwe_stream_lcp_len(info
))
154 /* Add quality statistics */
156 iwe
.u
.qual
.updated
= IW_QUAL_QUAL_UPDATED
| IW_QUAL_LEVEL_UPDATED
|
157 IW_QUAL_NOISE_UPDATED
;
159 if (!(network
->stats
.mask
& LIBIPW_STATMASK_RSSI
)) {
160 iwe
.u
.qual
.updated
|= IW_QUAL_QUAL_INVALID
|
161 IW_QUAL_LEVEL_INVALID
;
164 if (ieee
->perfect_rssi
== ieee
->worst_rssi
)
165 iwe
.u
.qual
.qual
= 100;
169 (ieee
->perfect_rssi
- ieee
->worst_rssi
) *
170 (ieee
->perfect_rssi
- ieee
->worst_rssi
) -
171 (ieee
->perfect_rssi
- network
->stats
.rssi
) *
172 (15 * (ieee
->perfect_rssi
- ieee
->worst_rssi
) +
173 62 * (ieee
->perfect_rssi
-
174 network
->stats
.rssi
))) /
175 ((ieee
->perfect_rssi
-
176 ieee
->worst_rssi
) * (ieee
->perfect_rssi
-
178 if (iwe
.u
.qual
.qual
> 100)
179 iwe
.u
.qual
.qual
= 100;
180 else if (iwe
.u
.qual
.qual
< 1)
184 if (!(network
->stats
.mask
& LIBIPW_STATMASK_NOISE
)) {
185 iwe
.u
.qual
.updated
|= IW_QUAL_NOISE_INVALID
;
186 iwe
.u
.qual
.noise
= 0;
188 iwe
.u
.qual
.noise
= network
->stats
.noise
;
191 if (!(network
->stats
.mask
& LIBIPW_STATMASK_SIGNAL
)) {
192 iwe
.u
.qual
.updated
|= IW_QUAL_LEVEL_INVALID
;
193 iwe
.u
.qual
.level
= 0;
195 iwe
.u
.qual
.level
= network
->stats
.signal
;
198 start
= iwe_stream_add_event(info
, start
, stop
, &iwe
, IW_EV_QUAL_LEN
);
200 iwe
.cmd
= IWEVCUSTOM
;
203 iwe
.u
.data
.length
= p
- custom
;
204 if (iwe
.u
.data
.length
)
205 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, custom
);
207 memset(&iwe
, 0, sizeof(iwe
));
208 if (network
->wpa_ie_len
) {
209 char buf
[MAX_WPA_IE_LEN
];
210 memcpy(buf
, network
->wpa_ie
, network
->wpa_ie_len
);
212 iwe
.u
.data
.length
= network
->wpa_ie_len
;
213 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, buf
);
216 memset(&iwe
, 0, sizeof(iwe
));
217 if (network
->rsn_ie_len
) {
218 char buf
[MAX_WPA_IE_LEN
];
219 memcpy(buf
, network
->rsn_ie
, network
->rsn_ie_len
);
221 iwe
.u
.data
.length
= network
->rsn_ie_len
;
222 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, buf
);
225 /* Add EXTRA: Age to display seconds since last beacon/probe response
226 * for given network. */
227 iwe
.cmd
= IWEVCUSTOM
;
229 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
),
230 " Last beacon: %ums ago",
231 elapsed_jiffies_msecs(network
->last_scanned
));
232 iwe
.u
.data
.length
= p
- custom
;
233 if (iwe
.u
.data
.length
)
234 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, custom
);
236 /* Add spectrum management information */
239 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), " Channel flags: ");
241 if (libipw_get_channel_flags(ieee
, network
->channel
) &
243 iwe
.cmd
= IWEVCUSTOM
;
244 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), "INVALID ");
247 if (libipw_get_channel_flags(ieee
, network
->channel
) &
248 LIBIPW_CH_RADAR_DETECT
) {
249 iwe
.cmd
= IWEVCUSTOM
;
250 p
+= snprintf(p
, MAX_CUSTOM_LEN
- (p
- custom
), "DFS ");
253 if (iwe
.cmd
== IWEVCUSTOM
) {
254 iwe
.u
.data
.length
= p
- custom
;
255 start
= iwe_stream_add_point(info
, start
, stop
, &iwe
, custom
);
261 #define SCAN_ITEM_SIZE 128
263 int libipw_wx_get_scan(struct libipw_device
*ieee
,
264 struct iw_request_info
*info
,
265 union iwreq_data
*wrqu
, char *extra
)
267 struct libipw_network
*network
;
272 char *stop
= ev
+ wrqu
->data
.length
;
274 DECLARE_SSID_BUF(ssid
);
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 '%s ("
293 "%pM)' due to age (%ums).\n",
294 print_ssid(ssid
, network
->ssid
,
297 elapsed_jiffies_msecs(
298 network
->last_scanned
));
302 spin_unlock_irqrestore(&ieee
->lock
, flags
);
304 wrqu
->data
.length
= ev
- extra
;
305 wrqu
->data
.flags
= 0;
307 LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i
);
312 int libipw_wx_set_encode(struct libipw_device
*ieee
,
313 struct iw_request_info
*info
,
314 union iwreq_data
*wrqu
, char *keybuf
)
316 struct iw_point
*erq
= &(wrqu
->encoding
);
317 struct net_device
*dev
= ieee
->dev
;
318 struct libipw_security sec
= {
321 int i
, key
, key_provided
, len
;
322 struct lib80211_crypt_data
**crypt
;
323 int host_crypto
= ieee
->host_encrypt
|| ieee
->host_decrypt
;
324 DECLARE_SSID_BUF(ssid
);
326 LIBIPW_DEBUG_WX("SET_ENCODE\n");
328 key
= erq
->flags
& IW_ENCODE_INDEX
;
336 key
= ieee
->crypt_info
.tx_keyidx
;
339 LIBIPW_DEBUG_WX("Key: %d [%s]\n", key
, key_provided
?
340 "provided" : "default");
342 crypt
= &ieee
->crypt_info
.crypt
[key
];
344 if (erq
->flags
& IW_ENCODE_DISABLED
) {
345 if (key_provided
&& *crypt
) {
346 LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
348 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
, crypt
);
350 LIBIPW_DEBUG_WX("Disabling encryption.\n");
352 /* Check all the keys to see if any are still configured,
353 * and if no key index was provided, de-init them all */
354 for (i
= 0; i
< WEP_KEYS
; i
++) {
355 if (ieee
->crypt_info
.crypt
[i
] != NULL
) {
358 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
,
359 &ieee
->crypt_info
.crypt
[i
]);
366 sec
.level
= SEC_LEVEL_0
;
367 sec
.flags
|= SEC_ENABLED
| SEC_LEVEL
| SEC_ENCRYPT
;
375 sec
.flags
|= SEC_ENABLED
| SEC_ENCRYPT
;
377 if (*crypt
!= NULL
&& (*crypt
)->ops
!= NULL
&&
378 strcmp((*crypt
)->ops
->name
, "WEP") != 0) {
379 /* changing to use WEP; deinit previously used algorithm
381 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
, crypt
);
384 if (*crypt
== NULL
&& host_crypto
) {
385 struct lib80211_crypt_data
*new_crypt
;
387 /* take WEP into use */
388 new_crypt
= kzalloc(sizeof(struct lib80211_crypt_data
),
390 if (new_crypt
== NULL
)
392 new_crypt
->ops
= lib80211_get_crypto_ops("WEP");
393 if (!new_crypt
->ops
) {
394 request_module("lib80211_crypt_wep");
395 new_crypt
->ops
= lib80211_get_crypto_ops("WEP");
398 if (new_crypt
->ops
&& try_module_get(new_crypt
->ops
->owner
))
399 new_crypt
->priv
= new_crypt
->ops
->init(key
);
401 if (!new_crypt
->ops
|| !new_crypt
->priv
) {
405 printk(KERN_WARNING
"%s: could not initialize WEP: "
406 "load module lib80211_crypt_wep\n", dev
->name
);
412 /* If a new key was provided, set it up */
413 if (erq
->length
> 0) {
414 len
= erq
->length
<= 5 ? 5 : 13;
415 memcpy(sec
.keys
[key
], keybuf
, erq
->length
);
416 if (len
> erq
->length
)
417 memset(sec
.keys
[key
] + erq
->length
, 0,
419 LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
420 key
, print_ssid(ssid
, sec
.keys
[key
], len
),
422 sec
.key_sizes
[key
] = len
;
424 (*crypt
)->ops
->set_key(sec
.keys
[key
], len
, NULL
,
426 sec
.flags
|= (1 << key
);
427 /* This ensures a key will be activated if no key is
429 if (key
== sec
.active_key
)
430 sec
.flags
|= SEC_ACTIVE_KEY
;
434 len
= (*crypt
)->ops
->get_key(sec
.keys
[key
], WEP_KEY_LEN
,
435 NULL
, (*crypt
)->priv
);
437 /* Set a default key of all 0 */
438 LIBIPW_DEBUG_WX("Setting key %d to all "
440 memset(sec
.keys
[key
], 0, 13);
441 (*crypt
)->ops
->set_key(sec
.keys
[key
], 13, NULL
,
443 sec
.key_sizes
[key
] = 13;
444 sec
.flags
|= (1 << key
);
447 /* No key data - just set the default TX key index */
449 LIBIPW_DEBUG_WX("Setting key %d to default Tx "
451 ieee
->crypt_info
.tx_keyidx
= key
;
452 sec
.active_key
= key
;
453 sec
.flags
|= SEC_ACTIVE_KEY
;
456 if (erq
->flags
& (IW_ENCODE_OPEN
| IW_ENCODE_RESTRICTED
)) {
457 ieee
->open_wep
= !(erq
->flags
& IW_ENCODE_RESTRICTED
);
458 sec
.auth_mode
= ieee
->open_wep
? WLAN_AUTH_OPEN
:
459 WLAN_AUTH_SHARED_KEY
;
460 sec
.flags
|= SEC_AUTH_MODE
;
461 LIBIPW_DEBUG_WX("Auth: %s\n",
462 sec
.auth_mode
== WLAN_AUTH_OPEN
?
463 "OPEN" : "SHARED KEY");
466 /* For now we just support WEP, so only set that security level...
467 * TODO: When WPA is added this is one place that needs to change */
468 sec
.flags
|= SEC_LEVEL
;
469 sec
.level
= SEC_LEVEL_1
; /* 40 and 104 bit WEP */
470 sec
.encode_alg
[key
] = SEC_ALG_WEP
;
473 if (ieee
->set_security
)
474 ieee
->set_security(dev
, &sec
);
476 /* Do not reset port if card is in Managed mode since resetting will
477 * generate new IEEE 802.11 authentication which may end up in looping
478 * with IEEE 802.1X. If your hardware requires a reset after WEP
479 * configuration (for example... Prism2), implement the reset_port in
480 * the callbacks structures used to initialize the 802.11 stack. */
481 if (ieee
->reset_on_keychange
&&
482 ieee
->iw_mode
!= IW_MODE_INFRA
&&
483 ieee
->reset_port
&& ieee
->reset_port(dev
)) {
484 printk(KERN_DEBUG
"%s: reset_port failed\n", dev
->name
);
490 int libipw_wx_get_encode(struct libipw_device
*ieee
,
491 struct iw_request_info
*info
,
492 union iwreq_data
*wrqu
, char *keybuf
)
494 struct iw_point
*erq
= &(wrqu
->encoding
);
496 struct lib80211_crypt_data
*crypt
;
497 struct libipw_security
*sec
= &ieee
->sec
;
499 LIBIPW_DEBUG_WX("GET_ENCODE\n");
501 key
= erq
->flags
& IW_ENCODE_INDEX
;
507 key
= ieee
->crypt_info
.tx_keyidx
;
509 crypt
= ieee
->crypt_info
.crypt
[key
];
510 erq
->flags
= key
+ 1;
514 erq
->flags
|= IW_ENCODE_DISABLED
;
518 len
= sec
->key_sizes
[key
];
519 memcpy(keybuf
, sec
->keys
[key
], len
);
522 erq
->flags
|= IW_ENCODE_ENABLED
;
525 erq
->flags
|= IW_ENCODE_OPEN
;
527 erq
->flags
|= IW_ENCODE_RESTRICTED
;
532 int libipw_wx_set_encodeext(struct libipw_device
*ieee
,
533 struct iw_request_info
*info
,
534 union iwreq_data
*wrqu
, char *extra
)
536 struct net_device
*dev
= ieee
->dev
;
537 struct iw_point
*encoding
= &wrqu
->encoding
;
538 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
541 const char *alg
, *module
;
542 struct lib80211_crypto_ops
*ops
;
543 struct lib80211_crypt_data
**crypt
;
545 struct libipw_security sec
= {
549 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
551 if (idx
< 1 || idx
> WEP_KEYS
)
555 idx
= ieee
->crypt_info
.tx_keyidx
;
557 if (ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
) {
558 crypt
= &ieee
->crypt_info
.crypt
[idx
];
561 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
562 if (idx
!= 0 && ext
->alg
!= IW_ENCODE_ALG_WEP
)
564 if (ieee
->iw_mode
== IW_MODE_INFRA
)
565 crypt
= &ieee
->crypt_info
.crypt
[idx
];
570 sec
.flags
|= SEC_ENABLED
| SEC_ENCRYPT
;
571 if ((encoding
->flags
& IW_ENCODE_DISABLED
) ||
572 ext
->alg
== IW_ENCODE_ALG_NONE
) {
574 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
, crypt
);
576 for (i
= 0; i
< WEP_KEYS
; i
++)
577 if (ieee
->crypt_info
.crypt
[i
] != NULL
)
583 sec
.level
= SEC_LEVEL_0
;
584 sec
.flags
|= SEC_LEVEL
;
592 if (group_key
? !ieee
->host_mc_decrypt
:
593 !(ieee
->host_encrypt
|| ieee
->host_decrypt
||
594 ieee
->host_encrypt_msdu
))
595 goto skip_host_crypt
;
598 case IW_ENCODE_ALG_WEP
:
600 module
= "lib80211_crypt_wep";
602 case IW_ENCODE_ALG_TKIP
:
604 module
= "lib80211_crypt_tkip";
606 case IW_ENCODE_ALG_CCMP
:
608 module
= "lib80211_crypt_ccmp";
611 LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
612 dev
->name
, ext
->alg
);
617 ops
= lib80211_get_crypto_ops(alg
);
619 request_module(module
);
620 ops
= lib80211_get_crypto_ops(alg
);
623 LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
624 dev
->name
, ext
->alg
);
629 if (*crypt
== NULL
|| (*crypt
)->ops
!= ops
) {
630 struct lib80211_crypt_data
*new_crypt
;
632 lib80211_crypt_delayed_deinit(&ieee
->crypt_info
, crypt
);
634 new_crypt
= kzalloc(sizeof(*new_crypt
), GFP_KERNEL
);
635 if (new_crypt
== NULL
) {
639 new_crypt
->ops
= ops
;
640 if (new_crypt
->ops
&& try_module_get(new_crypt
->ops
->owner
))
641 new_crypt
->priv
= new_crypt
->ops
->init(idx
);
642 if (new_crypt
->priv
== NULL
) {
650 if (ext
->key_len
> 0 && (*crypt
)->ops
->set_key
&&
651 (*crypt
)->ops
->set_key(ext
->key
, ext
->key_len
, ext
->rx_seq
,
652 (*crypt
)->priv
) < 0) {
653 LIBIPW_DEBUG_WX("%s: key setting failed\n", dev
->name
);
659 if (ext
->ext_flags
& IW_ENCODE_EXT_SET_TX_KEY
) {
660 ieee
->crypt_info
.tx_keyidx
= idx
;
661 sec
.active_key
= idx
;
662 sec
.flags
|= SEC_ACTIVE_KEY
;
665 if (ext
->alg
!= IW_ENCODE_ALG_NONE
) {
666 memcpy(sec
.keys
[idx
], ext
->key
, ext
->key_len
);
667 sec
.key_sizes
[idx
] = ext
->key_len
;
668 sec
.flags
|= (1 << idx
);
669 if (ext
->alg
== IW_ENCODE_ALG_WEP
) {
670 sec
.encode_alg
[idx
] = SEC_ALG_WEP
;
671 sec
.flags
|= SEC_LEVEL
;
672 sec
.level
= SEC_LEVEL_1
;
673 } else if (ext
->alg
== IW_ENCODE_ALG_TKIP
) {
674 sec
.encode_alg
[idx
] = SEC_ALG_TKIP
;
675 sec
.flags
|= SEC_LEVEL
;
676 sec
.level
= SEC_LEVEL_2
;
677 } else if (ext
->alg
== IW_ENCODE_ALG_CCMP
) {
678 sec
.encode_alg
[idx
] = SEC_ALG_CCMP
;
679 sec
.flags
|= SEC_LEVEL
;
680 sec
.level
= SEC_LEVEL_3
;
682 /* Don't set sec level for group keys. */
684 sec
.flags
&= ~SEC_LEVEL
;
687 if (ieee
->set_security
)
688 ieee
->set_security(ieee
->dev
, &sec
);
691 * Do not reset port if card is in Managed mode since resetting will
692 * generate new IEEE 802.11 authentication which may end up in looping
693 * with IEEE 802.1X. If your hardware requires a reset after WEP
694 * configuration (for example... Prism2), implement the reset_port in
695 * the callbacks structures used to initialize the 802.11 stack.
697 if (ieee
->reset_on_keychange
&&
698 ieee
->iw_mode
!= IW_MODE_INFRA
&&
699 ieee
->reset_port
&& ieee
->reset_port(dev
)) {
700 LIBIPW_DEBUG_WX("%s: reset_port failed\n", dev
->name
);
707 int libipw_wx_get_encodeext(struct libipw_device
*ieee
,
708 struct iw_request_info
*info
,
709 union iwreq_data
*wrqu
, char *extra
)
711 struct iw_point
*encoding
= &wrqu
->encoding
;
712 struct iw_encode_ext
*ext
= (struct iw_encode_ext
*)extra
;
713 struct libipw_security
*sec
= &ieee
->sec
;
714 int idx
, max_key_len
;
716 max_key_len
= encoding
->length
- sizeof(*ext
);
720 idx
= encoding
->flags
& IW_ENCODE_INDEX
;
722 if (idx
< 1 || idx
> WEP_KEYS
)
726 idx
= ieee
->crypt_info
.tx_keyidx
;
728 if (!(ext
->ext_flags
& IW_ENCODE_EXT_GROUP_KEY
) &&
729 ext
->alg
!= IW_ENCODE_ALG_WEP
)
730 if (idx
!= 0 || ieee
->iw_mode
!= IW_MODE_INFRA
)
733 encoding
->flags
= idx
+ 1;
734 memset(ext
, 0, sizeof(*ext
));
737 ext
->alg
= IW_ENCODE_ALG_NONE
;
739 encoding
->flags
|= IW_ENCODE_DISABLED
;
741 if (sec
->encode_alg
[idx
] == SEC_ALG_WEP
)
742 ext
->alg
= IW_ENCODE_ALG_WEP
;
743 else if (sec
->encode_alg
[idx
] == SEC_ALG_TKIP
)
744 ext
->alg
= IW_ENCODE_ALG_TKIP
;
745 else if (sec
->encode_alg
[idx
] == SEC_ALG_CCMP
)
746 ext
->alg
= IW_ENCODE_ALG_CCMP
;
750 ext
->key_len
= sec
->key_sizes
[idx
];
751 memcpy(ext
->key
, sec
->keys
[idx
], ext
->key_len
);
752 encoding
->flags
|= IW_ENCODE_ENABLED
;
754 (ext
->alg
== IW_ENCODE_ALG_TKIP
||
755 ext
->alg
== IW_ENCODE_ALG_CCMP
))
756 ext
->ext_flags
|= IW_ENCODE_EXT_TX_SEQ_VALID
;
763 EXPORT_SYMBOL(libipw_wx_set_encodeext
);
764 EXPORT_SYMBOL(libipw_wx_get_encodeext
);
766 EXPORT_SYMBOL(libipw_wx_get_scan
);
767 EXPORT_SYMBOL(libipw_wx_set_encode
);
768 EXPORT_SYMBOL(libipw_wx_get_encode
);