blob: 3633c6682e4967575ef040ad620fbb8550531c35 [file] [log] [blame]
Jeff Garzikb4538722005-05-12 22:48:20 -04001/******************************************************************************
2
James Ketrenosebeaddc2005-09-21 11:58:43 -05003 Copyright(c) 2004-2005 Intel Corporation. All rights reserved.
Jeff Garzikb4538722005-05-12 22:48:20 -04004
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
Jouni Malinen85d32e72007-03-24 17:15:30 -07008 <j@w1.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
Jeff Garzikb4538722005-05-12 22:48:20 -040010
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.
14
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
18 more details.
19
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.
23
24 The full GNU General Public License is included in this distribution in the
25 file called LICENSE.
26
27 Contact Information:
Reinette Chatrec1eb2c82009-08-21 13:34:26 -070028 Intel Linux Wireless <ilw@linux.intel.com>
Jeff Garzikb4538722005-05-12 22:48:20 -040029 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31******************************************************************************/
Jeff Garzikbbeec902005-09-07 00:27:54 -040032
Jeff Garzikb4538722005-05-12 22:48:20 -040033#include <linux/kmod.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040035#include <linux/module.h>
James Ketrenos42e349f2005-09-21 11:54:07 -050036#include <linux/jiffies.h>
Jeff Garzikb4538722005-05-12 22:48:20 -040037
John W. Linville9387b7c2008-09-30 20:59:05 -040038#include <net/lib80211.h>
Jeff Garzikbbeec902005-09-07 00:27:54 -040039#include <linux/wireless.h>
40
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040041#include "libipw.h"
Dan Williamsf3734ee2009-02-12 12:32:55 -050042
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040043static const char *libipw_modes[] = {
Jeff Garzikb4538722005-05-12 22:48:20 -040044 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
45};
46
Dan Williamsc3d72b92009-02-11 13:26:06 -050047static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
48{
49 unsigned long end = jiffies;
50
51 if (end >= start)
52 return jiffies_to_msecs(end - start);
53
54 return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
55}
56
Jeff Garzikb4538722005-05-12 22:48:20 -040057#define MAX_CUSTOM_LEN 64
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040058static char *libipw_translate_scan(struct libipw_device *ieee,
David S. Millerccc58052008-06-16 18:50:49 -070059 char *start, char *stop,
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040060 struct libipw_network *network,
David S. Millerccc58052008-06-16 18:50:49 -070061 struct iw_request_info *info)
Jeff Garzikb4538722005-05-12 22:48:20 -040062{
63 char custom[MAX_CUSTOM_LEN];
64 char *p;
65 struct iw_event iwe;
66 int i, j;
Zhu Yi09593042006-04-13 17:17:26 +080067 char *current_val; /* For rates */
68 u8 rate;
Jeff Garzikb4538722005-05-12 22:48:20 -040069
70 /* First entry *MUST* be the AP MAC address */
71 iwe.cmd = SIOCGIWAP;
72 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
73 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
David S. Millerccc58052008-06-16 18:50:49 -070074 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_ADDR_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -040075
76 /* Remaining entries will be displayed in the order we provide them */
77
78 /* Add the ESSID */
79 iwe.cmd = SIOCGIWESSID;
80 iwe.u.data.flags = 1;
John W. Linvillec5d3dce2008-09-30 17:17:26 -040081 iwe.u.data.length = min(network->ssid_len, (u8) 32);
82 start = iwe_stream_add_point(info, start, stop,
83 &iwe, network->ssid);
Jeff Garzikb4538722005-05-12 22:48:20 -040084
85 /* Add the protocol name */
86 iwe.cmd = SIOCGIWNAME;
Jeff Garzik0edd5b42005-09-07 00:48:31 -040087 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s",
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -040088 libipw_modes[network->mode]);
David S. Millerccc58052008-06-16 18:50:49 -070089 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_CHAR_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -040090
Jeff Garzik0edd5b42005-09-07 00:48:31 -040091 /* Add mode */
92 iwe.cmd = SIOCGIWMODE;
93 if (network->capability & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
Jeff Garzik1b5cca32005-08-15 00:32:15 -040094 if (network->capability & WLAN_CAPABILITY_ESS)
Jeff Garzikb4538722005-05-12 22:48:20 -040095 iwe.u.mode = IW_MODE_MASTER;
96 else
97 iwe.u.mode = IW_MODE_ADHOC;
98
David S. Millerccc58052008-06-16 18:50:49 -070099 start = iwe_stream_add_event(info, start, stop,
100 &iwe, IW_EV_UINT_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400101 }
102
Larry Finger93afe3d2007-04-21 17:56:43 -0500103 /* Add channel and frequency */
Jean Tourrilhes90869b22007-07-10 15:51:14 -0500104 /* Note : userspace automatically computes channel using iwrange */
Jeff Garzikb4538722005-05-12 22:48:20 -0400105 iwe.cmd = SIOCGIWFREQ;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400106 iwe.u.freq.m = libipw_channel_to_freq(ieee, network->channel);
Larry Finger93afe3d2007-04-21 17:56:43 -0500107 iwe.u.freq.e = 6;
Jean Tourrilhes90869b22007-07-10 15:51:14 -0500108 iwe.u.freq.i = 0;
David S. Millerccc58052008-06-16 18:50:49 -0700109 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_FREQ_LEN);
Larry Finger93afe3d2007-04-21 17:56:43 -0500110
Jeff Garzikb4538722005-05-12 22:48:20 -0400111 /* 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;
115 else
116 iwe.u.data.flags = IW_ENCODE_DISABLED;
117 iwe.u.data.length = 0;
David S. Millerccc58052008-06-16 18:50:49 -0700118 start = iwe_stream_add_point(info, start, stop,
119 &iwe, network->ssid);
Jeff Garzikb4538722005-05-12 22:48:20 -0400120
121 /* Add basic and extended rates */
Zhu Yi09593042006-04-13 17:17:26 +0800122 /* Rate : stuffing multiple values in a single event require a bit
123 * more of magic - Jean II */
David S. Millerccc58052008-06-16 18:50:49 -0700124 current_val = start + iwe_stream_lcp_len(info);
Zhu Yi09593042006-04-13 17:17:26 +0800125 iwe.cmd = SIOCGIWRATE;
126 /* Those two flags are ignored... */
127 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
128
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400129 for (i = 0, j = 0; i < network->rates_len;) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400130 if (j < network->rates_ex_len &&
131 ((network->rates_ex[j] & 0x7F) <
132 (network->rates[i] & 0x7F)))
133 rate = network->rates_ex[j++] & 0x7F;
134 else
135 rate = network->rates[i++] & 0x7F;
Zhu Yi09593042006-04-13 17:17:26 +0800136 /* Bit rate given in 500 kb/s units (+ 0x80) */
137 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
138 /* Add new value to event */
David S. Millerccc58052008-06-16 18:50:49 -0700139 current_val = iwe_stream_add_value(info, start, current_val,
140 stop, &iwe, IW_EV_PARAM_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400141 }
142 for (; j < network->rates_ex_len; j++) {
143 rate = network->rates_ex[j] & 0x7F;
Zhu Yi09593042006-04-13 17:17:26 +0800144 /* Bit rate given in 500 kb/s units (+ 0x80) */
145 iwe.u.bitrate.value = ((rate & 0x7f) * 500000);
146 /* Add new value to event */
David S. Millerccc58052008-06-16 18:50:49 -0700147 current_val = iwe_stream_add_value(info, start, current_val,
148 stop, &iwe, IW_EV_PARAM_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400149 }
Zhu Yi09593042006-04-13 17:17:26 +0800150 /* Check if we added any rate */
David S. Millerccc58052008-06-16 18:50:49 -0700151 if ((current_val - start) > iwe_stream_lcp_len(info))
Zhu Yi09593042006-04-13 17:17:26 +0800152 start = current_val;
Jeff Garzikb4538722005-05-12 22:48:20 -0400153
154 /* Add quality statistics */
Jeff Garzikb4538722005-05-12 22:48:20 -0400155 iwe.cmd = IWEVQUAL;
James Ketrenosb1b508e2005-09-13 17:27:19 -0500156 iwe.u.qual.updated = IW_QUAL_QUAL_UPDATED | IW_QUAL_LEVEL_UPDATED |
157 IW_QUAL_NOISE_UPDATED;
158
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400159 if (!(network->stats.mask & LIBIPW_STATMASK_RSSI)) {
James Ketrenosb1b508e2005-09-13 17:27:19 -0500160 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID |
161 IW_QUAL_LEVEL_INVALID;
162 iwe.u.qual.qual = 0;
James Ketrenosb1b508e2005-09-13 17:27:19 -0500163 } else {
Jiri Benc757d18f2005-10-10 19:16:53 +0200164 if (ieee->perfect_rssi == ieee->worst_rssi)
165 iwe.u.qual.qual = 100;
166 else
167 iwe.u.qual.qual =
168 (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) +
James Ketrenos81f87522005-10-24 10:20:53 -0500173 62 * (ieee->perfect_rssi -
174 network->stats.rssi))) /
175 ((ieee->perfect_rssi -
176 ieee->worst_rssi) * (ieee->perfect_rssi -
177 ieee->worst_rssi));
James Ketrenosb1b508e2005-09-13 17:27:19 -0500178 if (iwe.u.qual.qual > 100)
179 iwe.u.qual.qual = 100;
180 else if (iwe.u.qual.qual < 1)
181 iwe.u.qual.qual = 0;
182 }
183
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400184 if (!(network->stats.mask & LIBIPW_STATMASK_NOISE)) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400185 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
James Ketrenosb1b508e2005-09-13 17:27:19 -0500186 iwe.u.qual.noise = 0;
187 } else {
188 iwe.u.qual.noise = network->stats.noise;
189 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400190
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400191 if (!(network->stats.mask & LIBIPW_STATMASK_SIGNAL)) {
Zhu Yi7bd64362006-01-19 16:21:54 +0800192 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
193 iwe.u.qual.level = 0;
194 } else {
195 iwe.u.qual.level = network->stats.signal;
196 }
197
David S. Millerccc58052008-06-16 18:50:49 -0700198 start = iwe_stream_add_event(info, start, stop, &iwe, IW_EV_QUAL_LEN);
Jeff Garzikb4538722005-05-12 22:48:20 -0400199
200 iwe.cmd = IWEVCUSTOM;
201 p = custom;
202
203 iwe.u.data.length = p - custom;
204 if (iwe.u.data.length)
David S. Millerccc58052008-06-16 18:50:49 -0700205 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
Jeff Garzikb4538722005-05-12 22:48:20 -0400206
Zhu Yi47168082006-02-13 13:37:03 +0800207 memset(&iwe, 0, sizeof(iwe));
James Ketrenos20d64712005-09-21 11:53:43 -0500208 if (network->wpa_ie_len) {
Zhu Yi47168082006-02-13 13:37:03 +0800209 char buf[MAX_WPA_IE_LEN];
210 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
211 iwe.cmd = IWEVGENIE;
212 iwe.u.data.length = network->wpa_ie_len;
David S. Millerccc58052008-06-16 18:50:49 -0700213 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
Jeff Garzikb4538722005-05-12 22:48:20 -0400214 }
215
Zhu Yi47168082006-02-13 13:37:03 +0800216 memset(&iwe, 0, sizeof(iwe));
James Ketrenos20d64712005-09-21 11:53:43 -0500217 if (network->rsn_ie_len) {
Zhu Yi47168082006-02-13 13:37:03 +0800218 char buf[MAX_WPA_IE_LEN];
219 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
220 iwe.cmd = IWEVGENIE;
221 iwe.u.data.length = network->rsn_ie_len;
David S. Millerccc58052008-06-16 18:50:49 -0700222 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
Jeff Garzikb4538722005-05-12 22:48:20 -0400223 }
224
225 /* Add EXTRA: Age to display seconds since last beacon/probe response
226 * for given network. */
227 iwe.cmd = IWEVCUSTOM;
228 p = custom;
229 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
Dan Williamsc3d72b92009-02-11 13:26:06 -0500230 " Last beacon: %ums ago",
231 elapsed_jiffies_msecs(network->last_scanned));
Jeff Garzikb4538722005-05-12 22:48:20 -0400232 iwe.u.data.length = p - custom;
233 if (iwe.u.data.length)
David S. Millerccc58052008-06-16 18:50:49 -0700234 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
Jeff Garzikb4538722005-05-12 22:48:20 -0400235
Zhu Yi7bd64362006-01-19 16:21:54 +0800236 /* Add spectrum management information */
237 iwe.cmd = -1;
238 p = custom;
239 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Channel flags: ");
240
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400241 if (libipw_get_channel_flags(ieee, network->channel) &
242 LIBIPW_CH_INVALID) {
Zhu Yi7bd64362006-01-19 16:21:54 +0800243 iwe.cmd = IWEVCUSTOM;
244 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "INVALID ");
245 }
246
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400247 if (libipw_get_channel_flags(ieee, network->channel) &
248 LIBIPW_CH_RADAR_DETECT) {
Zhu Yi7bd64362006-01-19 16:21:54 +0800249 iwe.cmd = IWEVCUSTOM;
250 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), "DFS ");
251 }
252
253 if (iwe.cmd == IWEVCUSTOM) {
254 iwe.u.data.length = p - custom;
David S. Millerccc58052008-06-16 18:50:49 -0700255 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
Zhu Yi7bd64362006-01-19 16:21:54 +0800256 }
257
Jeff Garzikb4538722005-05-12 22:48:20 -0400258 return start;
259}
260
Zhu Yi55cd94a2006-01-19 16:20:59 +0800261#define SCAN_ITEM_SIZE 128
262
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400263int libipw_wx_get_scan(struct libipw_device *ieee,
Jeff Garzikb4538722005-05-12 22:48:20 -0400264 struct iw_request_info *info,
265 union iwreq_data *wrqu, char *extra)
266{
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400267 struct libipw_network *network;
Jeff Garzikb4538722005-05-12 22:48:20 -0400268 unsigned long flags;
Zhu Yi55cd94a2006-01-19 16:20:59 +0800269 int err = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400270
271 char *ev = extra;
Zhu Yi55cd94a2006-01-19 16:20:59 +0800272 char *stop = ev + wrqu->data.length;
Jeff Garzikb4538722005-05-12 22:48:20 -0400273 int i = 0;
John W. Linville9387b7c2008-09-30 20:59:05 -0400274 DECLARE_SSID_BUF(ssid);
Jeff Garzikb4538722005-05-12 22:48:20 -0400275
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400276 LIBIPW_DEBUG_WX("Getting scan\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400277
278 spin_lock_irqsave(&ieee->lock, flags);
279
280 list_for_each_entry(network, &ieee->network_list, list) {
281 i++;
Zhu Yi55cd94a2006-01-19 16:20:59 +0800282 if (stop - ev < SCAN_ITEM_SIZE) {
283 err = -E2BIG;
284 break;
285 }
286
Jeff Garzikb4538722005-05-12 22:48:20 -0400287 if (ieee->scan_age == 0 ||
288 time_after(network->last_scanned + ieee->scan_age, jiffies))
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400289 ev = libipw_translate_scan(ieee, ev, stop, network,
David S. Millerccc58052008-06-16 18:50:49 -0700290 info);
Dan Williamsc3d72b92009-02-11 13:26:06 -0500291 else {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400292 LIBIPW_DEBUG_SCAN("Not showing network '%s ("
Dan Williamsc3d72b92009-02-11 13:26:06 -0500293 "%pM)' due to age (%ums).\n",
John W. Linville9387b7c2008-09-30 20:59:05 -0400294 print_ssid(ssid, network->ssid,
John W. Linville7e272fc2008-09-24 18:13:14 -0400295 network->ssid_len),
Johannes Berge1749612008-10-27 15:59:26 -0700296 network->bssid,
Dan Williamsc3d72b92009-02-11 13:26:06 -0500297 elapsed_jiffies_msecs(
298 network->last_scanned));
299 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400300 }
301
302 spin_unlock_irqrestore(&ieee->lock, flags);
303
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400304 wrqu->data.length = ev - extra;
Jeff Garzikb4538722005-05-12 22:48:20 -0400305 wrqu->data.flags = 0;
306
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400307 LIBIPW_DEBUG_WX("exit: %d networks returned.\n", i);
Jeff Garzikb4538722005-05-12 22:48:20 -0400308
Zhu Yi55cd94a2006-01-19 16:20:59 +0800309 return err;
Jeff Garzikb4538722005-05-12 22:48:20 -0400310}
311
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400312int libipw_wx_set_encode(struct libipw_device *ieee,
Jeff Garzikb4538722005-05-12 22:48:20 -0400313 struct iw_request_info *info,
314 union iwreq_data *wrqu, char *keybuf)
315{
316 struct iw_point *erq = &(wrqu->encoding);
317 struct net_device *dev = ieee->dev;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400318 struct libipw_security sec = {
Jeff Garzikb4538722005-05-12 22:48:20 -0400319 .flags = 0
320 };
321 int i, key, key_provided, len;
John W. Linville274bfb82008-10-29 11:35:05 -0400322 struct lib80211_crypt_data **crypt;
Johannes Berga4bf26f2005-12-31 11:35:20 +0100323 int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv;
John W. Linville9387b7c2008-09-30 20:59:05 -0400324 DECLARE_SSID_BUF(ssid);
Jeff Garzikb4538722005-05-12 22:48:20 -0400325
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400326 LIBIPW_DEBUG_WX("SET_ENCODE\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400327
328 key = erq->flags & IW_ENCODE_INDEX;
329 if (key) {
330 if (key > WEP_KEYS)
331 return -EINVAL;
332 key--;
333 key_provided = 1;
334 } else {
335 key_provided = 0;
John W. Linville274bfb82008-10-29 11:35:05 -0400336 key = ieee->crypt_info.tx_keyidx;
Jeff Garzikb4538722005-05-12 22:48:20 -0400337 }
338
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400339 LIBIPW_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
Jeff Garzikb4538722005-05-12 22:48:20 -0400340 "provided" : "default");
341
John W. Linville274bfb82008-10-29 11:35:05 -0400342 crypt = &ieee->crypt_info.crypt[key];
Jeff Garzikb4538722005-05-12 22:48:20 -0400343
344 if (erq->flags & IW_ENCODE_DISABLED) {
345 if (key_provided && *crypt) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400346 LIBIPW_DEBUG_WX("Disabling encryption on key %d.\n",
Jeff Garzikb4538722005-05-12 22:48:20 -0400347 key);
John W. Linville274bfb82008-10-29 11:35:05 -0400348 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
Jeff Garzikb4538722005-05-12 22:48:20 -0400349 } else
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400350 LIBIPW_DEBUG_WX("Disabling encryption.\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400351
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++) {
John W. Linville274bfb82008-10-29 11:35:05 -0400355 if (ieee->crypt_info.crypt[i] != NULL) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400356 if (key_provided)
357 break;
John W. Linville274bfb82008-10-29 11:35:05 -0400358 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
359 &ieee->crypt_info.crypt[i]);
Jeff Garzikb4538722005-05-12 22:48:20 -0400360 }
361 }
362
363 if (i == WEP_KEYS) {
364 sec.enabled = 0;
James Ketrenosf1bf6632005-09-21 11:53:54 -0500365 sec.encrypt = 0;
Jeff Garzikb4538722005-05-12 22:48:20 -0400366 sec.level = SEC_LEVEL_0;
James Ketrenos259bf1f2005-09-21 11:54:22 -0500367 sec.flags |= SEC_ENABLED | SEC_LEVEL | SEC_ENCRYPT;
Jeff Garzikb4538722005-05-12 22:48:20 -0400368 }
369
370 goto done;
371 }
372
Jeff Garzikb4538722005-05-12 22:48:20 -0400373 sec.enabled = 1;
James Ketrenosf1bf6632005-09-21 11:53:54 -0500374 sec.encrypt = 1;
James Ketrenos259bf1f2005-09-21 11:54:22 -0500375 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
Jeff Garzikb4538722005-05-12 22:48:20 -0400376
377 if (*crypt != NULL && (*crypt)->ops != NULL &&
378 strcmp((*crypt)->ops->name, "WEP") != 0) {
379 /* changing to use WEP; deinit previously used algorithm
380 * on this key */
John W. Linville274bfb82008-10-29 11:35:05 -0400381 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
Jeff Garzikb4538722005-05-12 22:48:20 -0400382 }
383
James Ketrenosf1bf6632005-09-21 11:53:54 -0500384 if (*crypt == NULL && host_crypto) {
John W. Linville274bfb82008-10-29 11:35:05 -0400385 struct lib80211_crypt_data *new_crypt;
Jeff Garzikb4538722005-05-12 22:48:20 -0400386
387 /* take WEP into use */
John W. Linville274bfb82008-10-29 11:35:05 -0400388 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
Jeff Garzikb4538722005-05-12 22:48:20 -0400389 GFP_KERNEL);
390 if (new_crypt == NULL)
391 return -ENOMEM;
John W. Linville274bfb82008-10-29 11:35:05 -0400392 new_crypt->ops = lib80211_get_crypto_ops("WEP");
Jeff Garzikb4538722005-05-12 22:48:20 -0400393 if (!new_crypt->ops) {
John W. Linville274bfb82008-10-29 11:35:05 -0400394 request_module("lib80211_crypt_wep");
395 new_crypt->ops = lib80211_get_crypto_ops("WEP");
Jeff Garzikb4538722005-05-12 22:48:20 -0400396 }
397
398 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000399 new_crypt->priv = new_crypt->ops->init(key);
Jeff Garzikb4538722005-05-12 22:48:20 -0400400
401 if (!new_crypt->ops || !new_crypt->priv) {
402 kfree(new_crypt);
403 new_crypt = NULL;
404
405 printk(KERN_WARNING "%s: could not initialize WEP: "
John W. Linville274bfb82008-10-29 11:35:05 -0400406 "load module lib80211_crypt_wep\n", dev->name);
Jeff Garzikb4538722005-05-12 22:48:20 -0400407 return -EOPNOTSUPP;
408 }
409 *crypt = new_crypt;
410 }
411
412 /* If a new key was provided, set it up */
413 if (erq->length > 0) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400414#ifdef CONFIG_LIBIPW_DEBUG
Holger Schurig2a941ec2008-10-29 09:43:50 +0100415 DECLARE_SSID_BUF(ssid);
416#endif
417
Jeff Garzikb4538722005-05-12 22:48:20 -0400418 len = erq->length <= 5 ? 5 : 13;
419 memcpy(sec.keys[key], keybuf, erq->length);
420 if (len > erq->length)
421 memset(sec.keys[key] + erq->length, 0,
422 len - erq->length);
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400423 LIBIPW_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
John W. Linville9387b7c2008-09-30 20:59:05 -0400424 key, print_ssid(ssid, sec.keys[key], len),
Jeff Garzikb4538722005-05-12 22:48:20 -0400425 erq->length, len);
426 sec.key_sizes[key] = len;
James Ketrenosf1bf6632005-09-21 11:53:54 -0500427 if (*crypt)
428 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
429 (*crypt)->priv);
Jeff Garzikb4538722005-05-12 22:48:20 -0400430 sec.flags |= (1 << key);
431 /* This ensures a key will be activated if no key is
Jean Delvarec03983a2007-10-19 23:22:55 +0200432 * explicitly set */
Jeff Garzikb4538722005-05-12 22:48:20 -0400433 if (key == sec.active_key)
434 sec.flags |= SEC_ACTIVE_KEY;
Jeff Garzikb4538722005-05-12 22:48:20 -0400435
James Ketrenosf1bf6632005-09-21 11:53:54 -0500436 } else {
437 if (host_crypto) {
438 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
439 NULL, (*crypt)->priv);
440 if (len == 0) {
441 /* Set a default key of all 0 */
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400442 LIBIPW_DEBUG_WX("Setting key %d to all "
James Ketrenosf1bf6632005-09-21 11:53:54 -0500443 "zero.\n", key);
444 memset(sec.keys[key], 0, 13);
445 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
446 (*crypt)->priv);
447 sec.key_sizes[key] = 13;
448 sec.flags |= (1 << key);
449 }
450 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400451 /* No key data - just set the default TX key index */
452 if (key_provided) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400453 LIBIPW_DEBUG_WX("Setting key %d to default Tx "
James Ketrenosf1bf6632005-09-21 11:53:54 -0500454 "key.\n", key);
John W. Linville274bfb82008-10-29 11:35:05 -0400455 ieee->crypt_info.tx_keyidx = key;
Jeff Garzikb4538722005-05-12 22:48:20 -0400456 sec.active_key = key;
457 sec.flags |= SEC_ACTIVE_KEY;
458 }
459 }
James Ketrenos7dc888f2005-09-21 11:58:38 -0500460 if (erq->flags & (IW_ENCODE_OPEN | IW_ENCODE_RESTRICTED)) {
461 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
462 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
463 WLAN_AUTH_SHARED_KEY;
464 sec.flags |= SEC_AUTH_MODE;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400465 LIBIPW_DEBUG_WX("Auth: %s\n",
James Ketrenos7dc888f2005-09-21 11:58:38 -0500466 sec.auth_mode == WLAN_AUTH_OPEN ?
467 "OPEN" : "SHARED KEY");
468 }
Jeff Garzikb4538722005-05-12 22:48:20 -0400469
470 /* For now we just support WEP, so only set that security level...
471 * TODO: When WPA is added this is one place that needs to change */
472 sec.flags |= SEC_LEVEL;
Jeff Garzik0edd5b42005-09-07 00:48:31 -0400473 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
James Ketrenose0d369d2005-09-21 11:54:30 -0500474 sec.encode_alg[key] = SEC_ALG_WEP;
Jeff Garzikb4538722005-05-12 22:48:20 -0400475
James Ketrenos259bf1f2005-09-21 11:54:22 -0500476 done:
Jeff Garzikb4538722005-05-12 22:48:20 -0400477 if (ieee->set_security)
478 ieee->set_security(dev, &sec);
479
480 /* Do not reset port if card is in Managed mode since resetting will
481 * generate new IEEE 802.11 authentication which may end up in looping
482 * with IEEE 802.1X. If your hardware requires a reset after WEP
483 * configuration (for example... Prism2), implement the reset_port in
484 * the callbacks structures used to initialize the 802.11 stack. */
485 if (ieee->reset_on_keychange &&
486 ieee->iw_mode != IW_MODE_INFRA &&
487 ieee->reset_port && ieee->reset_port(dev)) {
488 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
489 return -EINVAL;
490 }
491 return 0;
492}
493
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400494int libipw_wx_get_encode(struct libipw_device *ieee,
Jeff Garzikb4538722005-05-12 22:48:20 -0400495 struct iw_request_info *info,
496 union iwreq_data *wrqu, char *keybuf)
497{
498 struct iw_point *erq = &(wrqu->encoding);
499 int len, key;
John W. Linville274bfb82008-10-29 11:35:05 -0400500 struct lib80211_crypt_data *crypt;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400501 struct libipw_security *sec = &ieee->sec;
Jeff Garzikb4538722005-05-12 22:48:20 -0400502
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400503 LIBIPW_DEBUG_WX("GET_ENCODE\n");
Jeff Garzikb4538722005-05-12 22:48:20 -0400504
505 key = erq->flags & IW_ENCODE_INDEX;
506 if (key) {
507 if (key > WEP_KEYS)
508 return -EINVAL;
509 key--;
510 } else
John W. Linville274bfb82008-10-29 11:35:05 -0400511 key = ieee->crypt_info.tx_keyidx;
Jeff Garzikb4538722005-05-12 22:48:20 -0400512
John W. Linville274bfb82008-10-29 11:35:05 -0400513 crypt = ieee->crypt_info.crypt[key];
Jeff Garzikb4538722005-05-12 22:48:20 -0400514 erq->flags = key + 1;
515
James Ketrenosf1bf6632005-09-21 11:53:54 -0500516 if (!sec->enabled) {
Jeff Garzikb4538722005-05-12 22:48:20 -0400517 erq->length = 0;
518 erq->flags |= IW_ENCODE_DISABLED;
519 return 0;
520 }
521
James Ketrenosf1bf6632005-09-21 11:53:54 -0500522 len = sec->key_sizes[key];
523 memcpy(keybuf, sec->keys[key], len);
Jeff Garzikb4538722005-05-12 22:48:20 -0400524
Adrian Bunk62741152006-04-27 02:33:42 -0700525 erq->length = len;
Jeff Garzikb4538722005-05-12 22:48:20 -0400526 erq->flags |= IW_ENCODE_ENABLED;
527
528 if (ieee->open_wep)
529 erq->flags |= IW_ENCODE_OPEN;
530 else
531 erq->flags |= IW_ENCODE_RESTRICTED;
532
533 return 0;
534}
535
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400536int libipw_wx_set_encodeext(struct libipw_device *ieee,
James Ketrenose0d369d2005-09-21 11:54:30 -0500537 struct iw_request_info *info,
538 union iwreq_data *wrqu, char *extra)
539{
540 struct net_device *dev = ieee->dev;
541 struct iw_point *encoding = &wrqu->encoding;
542 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
543 int i, idx, ret = 0;
James Ketrenosccd0fda2005-09-21 11:58:32 -0500544 int group_key = 0;
James Ketrenose0d369d2005-09-21 11:54:30 -0500545 const char *alg, *module;
John W. Linville274bfb82008-10-29 11:35:05 -0400546 struct lib80211_crypto_ops *ops;
547 struct lib80211_crypt_data **crypt;
James Ketrenose0d369d2005-09-21 11:54:30 -0500548
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400549 struct libipw_security sec = {
James Ketrenose0d369d2005-09-21 11:54:30 -0500550 .flags = 0,
551 };
552
553 idx = encoding->flags & IW_ENCODE_INDEX;
554 if (idx) {
555 if (idx < 1 || idx > WEP_KEYS)
556 return -EINVAL;
557 idx--;
558 } else
John W. Linville274bfb82008-10-29 11:35:05 -0400559 idx = ieee->crypt_info.tx_keyidx;
James Ketrenose0d369d2005-09-21 11:54:30 -0500560
James Ketrenosccd0fda2005-09-21 11:58:32 -0500561 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
John W. Linville274bfb82008-10-29 11:35:05 -0400562 crypt = &ieee->crypt_info.crypt[idx];
James Ketrenosccd0fda2005-09-21 11:58:32 -0500563 group_key = 1;
564 } else {
Volker Braune1892772005-10-24 10:15:36 -0500565 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
566 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
James Ketrenose0d369d2005-09-21 11:54:30 -0500567 return -EINVAL;
568 if (ieee->iw_mode == IW_MODE_INFRA)
John W. Linville274bfb82008-10-29 11:35:05 -0400569 crypt = &ieee->crypt_info.crypt[idx];
James Ketrenose0d369d2005-09-21 11:54:30 -0500570 else
571 return -EINVAL;
572 }
573
574 sec.flags |= SEC_ENABLED | SEC_ENCRYPT;
575 if ((encoding->flags & IW_ENCODE_DISABLED) ||
576 ext->alg == IW_ENCODE_ALG_NONE) {
577 if (*crypt)
John W. Linville274bfb82008-10-29 11:35:05 -0400578 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
James Ketrenose0d369d2005-09-21 11:54:30 -0500579
580 for (i = 0; i < WEP_KEYS; i++)
John W. Linville274bfb82008-10-29 11:35:05 -0400581 if (ieee->crypt_info.crypt[i] != NULL)
James Ketrenose0d369d2005-09-21 11:54:30 -0500582 break;
583
584 if (i == WEP_KEYS) {
585 sec.enabled = 0;
586 sec.encrypt = 0;
587 sec.level = SEC_LEVEL_0;
588 sec.flags |= SEC_LEVEL;
589 }
590 goto done;
591 }
592
593 sec.enabled = 1;
594 sec.encrypt = 1;
595
James Ketrenosccd0fda2005-09-21 11:58:32 -0500596 if (group_key ? !ieee->host_mc_decrypt :
597 !(ieee->host_encrypt || ieee->host_decrypt ||
598 ieee->host_encrypt_msdu))
James Ketrenose0d369d2005-09-21 11:54:30 -0500599 goto skip_host_crypt;
600
601 switch (ext->alg) {
602 case IW_ENCODE_ALG_WEP:
603 alg = "WEP";
John W. Linville274bfb82008-10-29 11:35:05 -0400604 module = "lib80211_crypt_wep";
James Ketrenose0d369d2005-09-21 11:54:30 -0500605 break;
606 case IW_ENCODE_ALG_TKIP:
607 alg = "TKIP";
John W. Linville274bfb82008-10-29 11:35:05 -0400608 module = "lib80211_crypt_tkip";
James Ketrenose0d369d2005-09-21 11:54:30 -0500609 break;
610 case IW_ENCODE_ALG_CCMP:
611 alg = "CCMP";
John W. Linville274bfb82008-10-29 11:35:05 -0400612 module = "lib80211_crypt_ccmp";
James Ketrenose0d369d2005-09-21 11:54:30 -0500613 break;
614 default:
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400615 LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
James Ketrenose0d369d2005-09-21 11:54:30 -0500616 dev->name, ext->alg);
617 ret = -EINVAL;
618 goto done;
619 }
620
John W. Linville274bfb82008-10-29 11:35:05 -0400621 ops = lib80211_get_crypto_ops(alg);
James Ketrenose0d369d2005-09-21 11:54:30 -0500622 if (ops == NULL) {
623 request_module(module);
John W. Linville274bfb82008-10-29 11:35:05 -0400624 ops = lib80211_get_crypto_ops(alg);
James Ketrenose0d369d2005-09-21 11:54:30 -0500625 }
626 if (ops == NULL) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400627 LIBIPW_DEBUG_WX("%s: unknown crypto alg %d\n",
James Ketrenose0d369d2005-09-21 11:54:30 -0500628 dev->name, ext->alg);
629 ret = -EINVAL;
630 goto done;
631 }
632
633 if (*crypt == NULL || (*crypt)->ops != ops) {
John W. Linville274bfb82008-10-29 11:35:05 -0400634 struct lib80211_crypt_data *new_crypt;
James Ketrenose0d369d2005-09-21 11:54:30 -0500635
John W. Linville274bfb82008-10-29 11:35:05 -0400636 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
James Ketrenose0d369d2005-09-21 11:54:30 -0500637
Panagiotis Issaris0da974f2006-07-21 14:51:30 -0700638 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
James Ketrenose0d369d2005-09-21 11:54:30 -0500639 if (new_crypt == NULL) {
640 ret = -ENOMEM;
641 goto done;
642 }
James Ketrenose0d369d2005-09-21 11:54:30 -0500643 new_crypt->ops = ops;
644 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
James Ketrenos6eb6edf2005-09-22 10:34:15 +0000645 new_crypt->priv = new_crypt->ops->init(idx);
James Ketrenose0d369d2005-09-21 11:54:30 -0500646 if (new_crypt->priv == NULL) {
647 kfree(new_crypt);
648 ret = -EINVAL;
649 goto done;
650 }
651 *crypt = new_crypt;
652 }
653
654 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
655 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
656 (*crypt)->priv) < 0) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400657 LIBIPW_DEBUG_WX("%s: key setting failed\n", dev->name);
James Ketrenose0d369d2005-09-21 11:54:30 -0500658 ret = -EINVAL;
659 goto done;
660 }
661
662 skip_host_crypt:
663 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
John W. Linville274bfb82008-10-29 11:35:05 -0400664 ieee->crypt_info.tx_keyidx = idx;
James Ketrenose0d369d2005-09-21 11:54:30 -0500665 sec.active_key = idx;
666 sec.flags |= SEC_ACTIVE_KEY;
667 }
668
669 if (ext->alg != IW_ENCODE_ALG_NONE) {
670 memcpy(sec.keys[idx], ext->key, ext->key_len);
671 sec.key_sizes[idx] = ext->key_len;
672 sec.flags |= (1 << idx);
673 if (ext->alg == IW_ENCODE_ALG_WEP) {
674 sec.encode_alg[idx] = SEC_ALG_WEP;
675 sec.flags |= SEC_LEVEL;
676 sec.level = SEC_LEVEL_1;
677 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
678 sec.encode_alg[idx] = SEC_ALG_TKIP;
679 sec.flags |= SEC_LEVEL;
680 sec.level = SEC_LEVEL_2;
681 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
682 sec.encode_alg[idx] = SEC_ALG_CCMP;
683 sec.flags |= SEC_LEVEL;
684 sec.level = SEC_LEVEL_3;
685 }
James Ketrenosccd0fda2005-09-21 11:58:32 -0500686 /* Don't set sec level for group keys. */
687 if (group_key)
688 sec.flags &= ~SEC_LEVEL;
James Ketrenose0d369d2005-09-21 11:54:30 -0500689 }
690 done:
691 if (ieee->set_security)
692 ieee->set_security(ieee->dev, &sec);
693
694 /*
695 * Do not reset port if card is in Managed mode since resetting will
696 * generate new IEEE 802.11 authentication which may end up in looping
697 * with IEEE 802.1X. If your hardware requires a reset after WEP
698 * configuration (for example... Prism2), implement the reset_port in
699 * the callbacks structures used to initialize the 802.11 stack.
700 */
701 if (ieee->reset_on_keychange &&
702 ieee->iw_mode != IW_MODE_INFRA &&
703 ieee->reset_port && ieee->reset_port(dev)) {
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400704 LIBIPW_DEBUG_WX("%s: reset_port failed\n", dev->name);
James Ketrenose0d369d2005-09-21 11:54:30 -0500705 return -EINVAL;
706 }
707
708 return ret;
709}
710
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400711int libipw_wx_get_encodeext(struct libipw_device *ieee,
James Ketrenose0d369d2005-09-21 11:54:30 -0500712 struct iw_request_info *info,
713 union iwreq_data *wrqu, char *extra)
714{
715 struct iw_point *encoding = &wrqu->encoding;
716 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400717 struct libipw_security *sec = &ieee->sec;
James Ketrenose0d369d2005-09-21 11:54:30 -0500718 int idx, max_key_len;
719
720 max_key_len = encoding->length - sizeof(*ext);
721 if (max_key_len < 0)
722 return -EINVAL;
723
724 idx = encoding->flags & IW_ENCODE_INDEX;
725 if (idx) {
726 if (idx < 1 || idx > WEP_KEYS)
727 return -EINVAL;
728 idx--;
729 } else
John W. Linville274bfb82008-10-29 11:35:05 -0400730 idx = ieee->crypt_info.tx_keyidx;
James Ketrenose0d369d2005-09-21 11:54:30 -0500731
Roel Kluinf59d9782007-10-26 21:51:26 +0200732 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
Volker Braune1892772005-10-24 10:15:36 -0500733 ext->alg != IW_ENCODE_ALG_WEP)
James Ketrenose0d369d2005-09-21 11:54:30 -0500734 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
735 return -EINVAL;
736
737 encoding->flags = idx + 1;
738 memset(ext, 0, sizeof(*ext));
739
740 if (!sec->enabled) {
741 ext->alg = IW_ENCODE_ALG_NONE;
742 ext->key_len = 0;
743 encoding->flags |= IW_ENCODE_DISABLED;
744 } else {
745 if (sec->encode_alg[idx] == SEC_ALG_WEP)
746 ext->alg = IW_ENCODE_ALG_WEP;
747 else if (sec->encode_alg[idx] == SEC_ALG_TKIP)
748 ext->alg = IW_ENCODE_ALG_TKIP;
749 else if (sec->encode_alg[idx] == SEC_ALG_CCMP)
750 ext->alg = IW_ENCODE_ALG_CCMP;
751 else
752 return -EINVAL;
753
754 ext->key_len = sec->key_sizes[idx];
755 memcpy(ext->key, sec->keys[idx], ext->key_len);
756 encoding->flags |= IW_ENCODE_ENABLED;
757 if (ext->key_len &&
758 (ext->alg == IW_ENCODE_ALG_TKIP ||
759 ext->alg == IW_ENCODE_ALG_CCMP))
760 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
761
762 }
763
764 return 0;
765}
766
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400767EXPORT_SYMBOL(libipw_wx_set_encodeext);
768EXPORT_SYMBOL(libipw_wx_get_encodeext);
James Ketrenose0d369d2005-09-21 11:54:30 -0500769
John W. Linvilleb0a4e7d2009-08-20 14:48:03 -0400770EXPORT_SYMBOL(libipw_wx_get_scan);
771EXPORT_SYMBOL(libipw_wx_set_encode);
772EXPORT_SYMBOL(libipw_wx_get_encode);