Merge remote-tracking branch 'staging/staging-next'
[deliverable/linux.git] / drivers / staging / rtl8192e / rtllib_wx.c
CommitLineData
ecdfa446
GKH
1/******************************************************************************
2
3 Copyright(c) 2004 Intel Corporation. All rights reserved.
4
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
8 <jkmaline@cc.hut.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
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
ecdfa446
GKH
20 The full GNU General Public License is included in this distribution in the
21 file called LICENSE.
22
23 Contact Information:
24 James P. Ketrenos <ipw2100-admin@linux.intel.com>
25 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
26
27******************************************************************************/
28#include <linux/wireless.h>
ecdfa446
GKH
29#include <linux/kmod.h>
30#include <linux/module.h>
c63eee54 31#include <linux/etherdevice.h>
94a79942 32#include "rtllib.h"
ecdfa446
GKH
33struct modes_unit {
34 char *mode_string;
35 int mode_size;
36};
94a79942 37static struct modes_unit rtllib_modes[] = {
62f27cc4
LF
38 {"a", 1},
39 {"b", 1},
40 {"g", 1},
41 {"?", 1},
42 {"N-24G", 5},
43 {"N-5G", 4},
ecdfa446
GKH
44};
45
ecdfa446 46#define MAX_CUSTOM_LEN 64
94a79942
LF
47static inline char *rtl819x_translate_scan(struct rtllib_device *ieee,
48 char *start, char *stop,
49 struct rtllib_network *network,
62f27cc4 50 struct iw_request_info *info)
ecdfa446
GKH
51{
52 char custom[MAX_CUSTOM_LEN];
53 char proto_name[IFNAMSIZ];
54 char *pname = proto_name;
55 char *p;
56 struct iw_event iwe;
57 int i, j;
58 u16 max_rate, rate;
59 static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
60
61 /* First entry *MUST* be the AP MAC address */
62 iwe.cmd = SIOCGIWAP;
63 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
c63eee54 64 ether_addr_copy(iwe.u.ap_addr.sa_data, network->bssid);
62f27cc4
LF
65 start = iwe_stream_add_event_rsl(info, start, stop,
66 &iwe, IW_EV_ADDR_LEN);
ecdfa446
GKH
67 /* Remaining entries will be displayed in the order we provide them */
68
69 /* Add the ESSID */
70 iwe.cmd = SIOCGIWESSID;
71 iwe.u.data.flags = 1;
62f27cc4 72 if (network->ssid_len > 0) {
d009f0d7 73 iwe.u.data.length = min_t(u8, network->ssid_len, 32);
62f27cc4
LF
74 start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
75 network->ssid);
76 } else if (network->hidden_ssid_len == 0) {
94a79942 77 iwe.u.data.length = sizeof("<hidden>");
62f27cc4
LF
78 start = iwe_stream_add_point_rsl(info, start, stop,
79 &iwe, "<hidden>");
80 } else {
d009f0d7 81 iwe.u.data.length = min_t(u8, network->hidden_ssid_len, 32);
62f27cc4
LF
82 start = iwe_stream_add_point_rsl(info, start, stop, &iwe,
83 network->hidden_ssid);
94a79942 84 }
ecdfa446
GKH
85 /* Add the protocol name */
86 iwe.cmd = SIOCGIWNAME;
b330f606 87 for (i = 0; i < ARRAY_SIZE(rtllib_modes); i++) {
94a79942 88 if (network->mode&(1<<i)) {
62f27cc4
LF
89 sprintf(pname, rtllib_modes[i].mode_string,
90 rtllib_modes[i].mode_size);
91 pname += rtllib_modes[i].mode_size;
ecdfa446
GKH
92 }
93 }
94 *pname = '\0';
95 snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
62f27cc4
LF
96 start = iwe_stream_add_event_rsl(info, start, stop,
97 &iwe, IW_EV_CHAR_LEN);
98 /* Add mode */
99 iwe.cmd = SIOCGIWMODE;
100 if (network->capability &
94a79942
LF
101 (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
102 if (network->capability & WLAN_CAPABILITY_ESS)
ecdfa446
GKH
103 iwe.u.mode = IW_MODE_MASTER;
104 else
105 iwe.u.mode = IW_MODE_ADHOC;
62f27cc4
LF
106 start = iwe_stream_add_event_rsl(info, start, stop,
107 &iwe, IW_EV_UINT_LEN);
108 }
ecdfa446 109
62f27cc4 110 /* Add frequency/channel */
ecdfa446 111 iwe.cmd = SIOCGIWFREQ;
ecdfa446
GKH
112 iwe.u.freq.m = network->channel;
113 iwe.u.freq.e = 0;
114 iwe.u.freq.i = 0;
62f27cc4
LF
115 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
116 IW_EV_FREQ_LEN);
94a79942 117
ecdfa446
GKH
118 /* Add encryption capability */
119 iwe.cmd = SIOCGIWENCODE;
120 if (network->capability & WLAN_CAPABILITY_PRIVACY)
121 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
122 else
123 iwe.u.data.flags = IW_ENCODE_DISABLED;
124 iwe.u.data.length = 0;
62f27cc4
LF
125 start = iwe_stream_add_point_rsl(info, start, stop,
126 &iwe, network->ssid);
ecdfa446
GKH
127 /* Add basic and extended rates */
128 max_rate = 0;
129 p = custom;
130 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
62f27cc4 131 for (i = 0, j = 0; i < network->rates_len;) {
ecdfa446
GKH
132 if (j < network->rates_ex_len &&
133 ((network->rates_ex[j] & 0x7F) <
134 (network->rates[i] & 0x7F)))
135 rate = network->rates_ex[j++] & 0x7F;
136 else
137 rate = network->rates[i++] & 0x7F;
138 if (rate > max_rate)
139 max_rate = rate;
140 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
141 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
142 }
143 for (; j < network->rates_ex_len; j++) {
144 rate = network->rates_ex[j] & 0x7F;
145 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
146 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
147 if (rate > max_rate)
148 max_rate = rate;
149 }
150
62f27cc4 151 if (network->mode >= IEEE_N_24G) {
e92b71d5 152 struct ht_capab_ele *ht_cap = NULL;
ecdfa446
GKH
153 bool is40M = false, isShortGI = false;
154 u8 max_mcs = 0;
3a6b70c3 155
ecdfa446 156 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
62f27cc4
LF
157 ht_cap = (struct ht_capab_ele *)
158 &network->bssht.bdHTCapBuf[4];
ecdfa446 159 else
62f27cc4
LF
160 ht_cap = (struct ht_capab_ele *)
161 &network->bssht.bdHTCapBuf[0];
162 is40M = (ht_cap->ChlWidth) ? 1 : 0;
163 isShortGI = (ht_cap->ChlWidth) ?
164 ((ht_cap->ShortGI40Mhz) ? 1 : 0) :
165 ((ht_cap->ShortGI20Mhz) ? 1 : 0);
166
167 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS,
168 MCS_FILTER_ALL);
169 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs & 0x7f];
ecdfa446
GKH
170 if (rate > max_rate)
171 max_rate = rate;
172 }
ecdfa446
GKH
173 iwe.cmd = SIOCGIWRATE;
174 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
175 iwe.u.bitrate.value = max_rate * 500000;
94a79942 176 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
ecdfa446 177 IW_EV_PARAM_LEN);
ecdfa446
GKH
178 iwe.cmd = IWEVCUSTOM;
179 iwe.u.data.length = p - custom;
180 if (iwe.u.data.length)
62f27cc4
LF
181 start = iwe_stream_add_point_rsl(info, start, stop,
182 &iwe, custom);
ecdfa446
GKH
183 /* Add quality statistics */
184 /* TODO: Fix these values... */
185 iwe.cmd = IWEVQUAL;
186 iwe.u.qual.qual = network->stats.signal;
187 iwe.u.qual.level = network->stats.rssi;
188 iwe.u.qual.noise = network->stats.noise;
94a79942
LF
189 iwe.u.qual.updated = network->stats.mask & RTLLIB_STATMASK_WEMASK;
190 if (!(network->stats.mask & RTLLIB_STATMASK_RSSI))
ecdfa446 191 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
94a79942 192 if (!(network->stats.mask & RTLLIB_STATMASK_NOISE))
ecdfa446 193 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
94a79942 194 if (!(network->stats.mask & RTLLIB_STATMASK_SIGNAL))
ecdfa446
GKH
195 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
196 iwe.u.qual.updated = 7;
62f27cc4
LF
197 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
198 IW_EV_QUAL_LEN);
94a79942 199
ecdfa446
GKH
200 iwe.cmd = IWEVCUSTOM;
201 p = custom;
ecdfa446
GKH
202 iwe.u.data.length = p - custom;
203 if (iwe.u.data.length)
62f27cc4
LF
204 start = iwe_stream_add_point_rsl(info, start, stop,
205 &iwe, custom);
ecdfa446 206
ecdfa446 207 memset(&iwe, 0, sizeof(iwe));
62f27cc4 208 if (network->wpa_ie_len) {
ecdfa446 209 char buf[MAX_WPA_IE_LEN];
3a6b70c3 210
ecdfa446
GKH
211 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
212 iwe.cmd = IWEVGENIE;
213 iwe.u.data.length = network->wpa_ie_len;
94a79942 214 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
62f27cc4 215 }
ecdfa446 216 memset(&iwe, 0, sizeof(iwe));
62f27cc4 217 if (network->rsn_ie_len) {
ecdfa446 218 char buf[MAX_WPA_IE_LEN];
3a6b70c3 219
ecdfa446
GKH
220 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
221 iwe.cmd = IWEVGENIE;
222 iwe.u.data.length = network->rsn_ie_len;
94a79942 223 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
62f27cc4 224 }
ecdfa446 225
94a79942
LF
226 /* add info for WZC */
227 memset(&iwe, 0, sizeof(iwe));
62f27cc4 228 if (network->wzc_ie_len) {
94a79942 229 char buf[MAX_WZC_IE_LEN];
3a6b70c3 230
94a79942
LF
231 memcpy(buf, network->wzc_ie, network->wzc_ie_len);
232 iwe.cmd = IWEVGENIE;
233 iwe.u.data.length = network->wzc_ie_len;
234 start = iwe_stream_add_point_rsl(info, start, stop, &iwe, buf);
62f27cc4 235 }
ecdfa446
GKH
236
237 /* Add EXTRA: Age to display seconds since last beacon/probe response
14b40d92
MK
238 * for given network.
239 */
ecdfa446
GKH
240 iwe.cmd = IWEVCUSTOM;
241 p = custom;
242 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
62f27cc4
LF
243 " Last beacon: %lums ago",
244 (jiffies - network->last_scanned) / (HZ / 100));
ecdfa446
GKH
245 iwe.u.data.length = p - custom;
246 if (iwe.u.data.length)
62f27cc4
LF
247 start = iwe_stream_add_point_rsl(info, start, stop,
248 &iwe, custom);
ecdfa446
GKH
249
250 return start;
251}
252
94a79942 253int rtllib_wx_get_scan(struct rtllib_device *ieee,
ecdfa446
GKH
254 struct iw_request_info *info,
255 union iwreq_data *wrqu, char *extra)
256{
94a79942 257 struct rtllib_network *network;
ecdfa446
GKH
258 unsigned long flags;
259
260 char *ev = extra;
94a79942 261 char *stop = ev + wrqu->data.length;
ecdfa446
GKH
262 int i = 0;
263 int err = 0;
3a6b70c3 264
c6a91aba 265 netdev_dbg(ieee->dev, "Getting scan\n");
9afa9370 266 mutex_lock(&ieee->wx_mutex);
ecdfa446
GKH
267 spin_lock_irqsave(&ieee->lock, flags);
268
269 list_for_each_entry(network, &ieee->network_list, list) {
270 i++;
62f27cc4 271 if ((stop - ev) < 200) {
ecdfa446
GKH
272 err = -E2BIG;
273 break;
62f27cc4 274 }
ecdfa446
GKH
275 if (ieee->scan_age == 0 ||
276 time_after(network->last_scanned + ieee->scan_age, jiffies))
62f27cc4
LF
277 ev = rtl819x_translate_scan(ieee, ev, stop, network,
278 info);
ecdfa446 279 else
521a9cbd
MK
280 netdev_dbg(ieee->dev,
281 "Network '%s ( %pM)' hidden due to age (%lums).\n",
282 escape_essid(network->ssid,
283 network->ssid_len),
284 network->bssid,
285 (jiffies - network->last_scanned) /
286 (HZ / 100));
ecdfa446
GKH
287 }
288
289 spin_unlock_irqrestore(&ieee->lock, flags);
9afa9370 290 mutex_unlock(&ieee->wx_mutex);
ecdfa446
GKH
291 wrqu->data.length = ev - extra;
292 wrqu->data.flags = 0;
293
c6a91aba 294 netdev_dbg(ieee->dev, "%s(): %d networks returned.\n", __func__, i);
ecdfa446
GKH
295
296 return err;
297}
3b28499c 298EXPORT_SYMBOL(rtllib_wx_get_scan);
ecdfa446 299
94a79942 300int rtllib_wx_set_encode(struct rtllib_device *ieee,
ecdfa446
GKH
301 struct iw_request_info *info,
302 union iwreq_data *wrqu, char *keybuf)
303{
304 struct iw_point *erq = &(wrqu->encoding);
305 struct net_device *dev = ieee->dev;
94a79942 306 struct rtllib_security sec = {
ecdfa446
GKH
307 .flags = 0
308 };
309 int i, key, key_provided, len;
32c44cb5 310 struct lib80211_crypt_data **crypt;
ecdfa446 311
c6a91aba 312 netdev_dbg(ieee->dev, "%s()\n", __func__);
ecdfa446
GKH
313
314 key = erq->flags & IW_ENCODE_INDEX;
315 if (key) {
184f1938 316 if (key > NUM_WEP_KEYS)
ecdfa446
GKH
317 return -EINVAL;
318 key--;
319 key_provided = 1;
320 } else {
321 key_provided = 0;
0ddcf5fd 322 key = ieee->crypt_info.tx_keyidx;
ecdfa446
GKH
323 }
324
c6a91aba 325 netdev_dbg(ieee->dev, "Key: %d [%s]\n", key, key_provided ?
ecdfa446 326 "provided" : "default");
0ddcf5fd 327 crypt = &ieee->crypt_info.crypt[key];
ecdfa446
GKH
328 if (erq->flags & IW_ENCODE_DISABLED) {
329 if (key_provided && *crypt) {
c6a91aba
MK
330 netdev_dbg(ieee->dev,
331 "Disabling encryption on key %d.\n", key);
3b148be0 332 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
ecdfa446 333 } else
c6a91aba 334 netdev_dbg(ieee->dev, "Disabling encryption.\n");
ecdfa446
GKH
335
336 /* Check all the keys to see if any are still configured,
14b40d92
MK
337 * and if no key index was provided, de-init them all
338 */
184f1938 339 for (i = 0; i < NUM_WEP_KEYS; i++) {
0ddcf5fd 340 if (ieee->crypt_info.crypt[i] != NULL) {
ecdfa446
GKH
341 if (key_provided)
342 break;
3b148be0 343 lib80211_crypt_delayed_deinit(&ieee->crypt_info,
a3ed22ea 344 &ieee->crypt_info.crypt[i]);
ecdfa446
GKH
345 }
346 }
347
184f1938 348 if (i == NUM_WEP_KEYS) {
ecdfa446
GKH
349 sec.enabled = 0;
350 sec.level = SEC_LEVEL_0;
351 sec.flags |= SEC_ENABLED | SEC_LEVEL;
352 }
353
354 goto done;
355 }
356
357
358
359 sec.enabled = 1;
360 sec.flags |= SEC_ENABLED;
361
362 if (*crypt != NULL && (*crypt)->ops != NULL &&
3b148be0 363 strcmp((*crypt)->ops->name, "R-WEP") != 0) {
ecdfa446 364 /* changing to use WEP; deinit previously used algorithm
14b40d92
MK
365 * on this key
366 */
3b148be0 367 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
ecdfa446
GKH
368 }
369
370 if (*crypt == NULL) {
32c44cb5 371 struct lib80211_crypt_data *new_crypt;
ecdfa446
GKH
372
373 /* take WEP into use */
32c44cb5 374 new_crypt = kzalloc(sizeof(struct lib80211_crypt_data),
ecdfa446
GKH
375 GFP_KERNEL);
376 if (new_crypt == NULL)
377 return -ENOMEM;
3b148be0 378 new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
94a79942
LF
379 if (!new_crypt->ops) {
380 request_module("rtllib_crypt_wep");
3b148be0 381 new_crypt->ops = lib80211_get_crypto_ops("R-WEP");
94a79942
LF
382 }
383
a010a337 384 if (new_crypt->ops)
ecdfa446
GKH
385 new_crypt->priv = new_crypt->ops->init(key);
386
387 if (!new_crypt->ops || !new_crypt->priv) {
388 kfree(new_crypt);
389 new_crypt = NULL;
390
d69d2054
MK
391 netdev_warn(dev,
392 "%s: could not initialize WEP: load module rtllib_crypt_wep\n",
393 dev->name);
ecdfa446
GKH
394 return -EOPNOTSUPP;
395 }
396 *crypt = new_crypt;
397 }
398
399 /* If a new key was provided, set it up */
400 if (erq->length > 0) {
401 len = erq->length <= 5 ? 5 : 13;
402 memcpy(sec.keys[key], keybuf, erq->length);
403 if (len > erq->length)
404 memset(sec.keys[key] + erq->length, 0,
405 len - erq->length);
c6a91aba
MK
406 netdev_dbg(ieee->dev, "Setting key %d to '%s' (%d:%d bytes)\n",
407 key, escape_essid(sec.keys[key], len), erq->length,
408 len);
ecdfa446 409 sec.key_sizes[key] = len;
94a79942 410 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
ecdfa446
GKH
411 (*crypt)->priv);
412 sec.flags |= (1 << key);
413 /* This ensures a key will be activated if no key is
14b40d92
MK
414 * explicitly set
415 */
ecdfa446
GKH
416 if (key == sec.active_key)
417 sec.flags |= SEC_ACTIVE_KEY;
0ddcf5fd 418 ieee->crypt_info.tx_keyidx = key;
ecdfa446
GKH
419
420 } else {
421 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
422 NULL, (*crypt)->priv);
423 if (len == 0) {
424 /* Set a default key of all 0 */
c60cfc8e 425 netdev_info(ieee->dev, "Setting key %d to all zero.\n",
ecdfa446
GKH
426 key);
427
ecdfa446
GKH
428 memset(sec.keys[key], 0, 13);
429 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
430 (*crypt)->priv);
431 sec.key_sizes[key] = 13;
432 sec.flags |= (1 << key);
433 }
434
435 /* No key data - just set the default TX key index */
436 if (key_provided) {
c6a91aba
MK
437 netdev_dbg(ieee->dev,
438 "Setting key %d as default Tx key.\n", key);
0ddcf5fd 439 ieee->crypt_info.tx_keyidx = key;
ecdfa446
GKH
440 sec.active_key = key;
441 sec.flags |= SEC_ACTIVE_KEY;
442 }
443 }
ecdfa446
GKH
444 done:
445 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
62f27cc4
LF
446 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN :
447 WLAN_AUTH_SHARED_KEY;
ecdfa446
GKH
448 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
449 sec.flags |= SEC_AUTH_MODE;
c6a91aba 450 netdev_dbg(ieee->dev, "Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
ecdfa446
GKH
451 "OPEN" : "SHARED KEY");
452
453 /* For now we just support WEP, so only set that security level...
14b40d92
MK
454 * TODO: When WPA is added this is one place that needs to change
455 */
ecdfa446
GKH
456 sec.flags |= SEC_LEVEL;
457 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
458
459 if (ieee->set_security)
94a79942 460 ieee->set_security(dev, &sec);
ecdfa446
GKH
461
462 /* Do not reset port if card is in Managed mode since resetting will
463 * generate new IEEE 802.11 authentication which may end up in looping
464 * with IEEE 802.1X. If your hardware requires a reset after WEP
465 * configuration (for example... Prism2), implement the reset_port in
14b40d92
MK
466 * the callbacks structures used to initialize the 802.11 stack.
467 */
ecdfa446
GKH
468 if (ieee->reset_on_keychange &&
469 ieee->iw_mode != IW_MODE_INFRA &&
94a79942 470 ieee->reset_port && ieee->reset_port(dev)) {
c60cfc8e 471 netdev_dbg(dev, "%s: reset_port failed\n", dev->name);
ecdfa446
GKH
472 return -EINVAL;
473 }
474 return 0;
475}
3b28499c 476EXPORT_SYMBOL(rtllib_wx_set_encode);
ecdfa446 477
94a79942 478int rtllib_wx_get_encode(struct rtllib_device *ieee,
ecdfa446
GKH
479 struct iw_request_info *info,
480 union iwreq_data *wrqu, char *keybuf)
481{
482 struct iw_point *erq = &(wrqu->encoding);
483 int len, key;
32c44cb5 484 struct lib80211_crypt_data *crypt;
ecdfa446 485
c6a91aba 486 netdev_dbg(ieee->dev, "%s()\n", __func__);
ecdfa446 487
94a79942 488 if (ieee->iw_mode == IW_MODE_MONITOR)
ecdfa446
GKH
489 return -1;
490
491 key = erq->flags & IW_ENCODE_INDEX;
492 if (key) {
184f1938 493 if (key > NUM_WEP_KEYS)
ecdfa446
GKH
494 return -EINVAL;
495 key--;
94a79942 496 } else {
0ddcf5fd 497 key = ieee->crypt_info.tx_keyidx;
94a79942 498 }
0ddcf5fd 499 crypt = ieee->crypt_info.crypt[key];
94a79942 500
ecdfa446
GKH
501 erq->flags = key + 1;
502
503 if (crypt == NULL || crypt->ops == NULL) {
504 erq->length = 0;
505 erq->flags |= IW_ENCODE_DISABLED;
506 return 0;
507 }
ecdfa446 508 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
622fd494
MK
509
510 erq->length = max(len, 0);
ecdfa446
GKH
511
512 erq->flags |= IW_ENCODE_ENABLED;
513
514 if (ieee->open_wep)
515 erq->flags |= IW_ENCODE_OPEN;
516 else
517 erq->flags |= IW_ENCODE_RESTRICTED;
518
519 return 0;
520}
3b28499c 521EXPORT_SYMBOL(rtllib_wx_get_encode);
3591733d 522
94a79942 523int rtllib_wx_set_encode_ext(struct rtllib_device *ieee,
62f27cc4
LF
524 struct iw_request_info *info,
525 union iwreq_data *wrqu, char *extra)
ecdfa446
GKH
526{
527 int ret = 0;
ecdfa446 528 struct net_device *dev = ieee->dev;
62f27cc4
LF
529 struct iw_point *encoding = &wrqu->encoding;
530 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
531 int i, idx;
532 int group_key = 0;
533 const char *alg, *module;
32c44cb5
SM
534 struct lib80211_crypto_ops *ops;
535 struct lib80211_crypt_data **crypt;
62f27cc4
LF
536
537 struct rtllib_security sec = {
538 .flags = 0,
539 };
540 idx = encoding->flags & IW_ENCODE_INDEX;
541 if (idx) {
184f1938 542 if (idx < 1 || idx > NUM_WEP_KEYS)
62f27cc4
LF
543 return -EINVAL;
544 idx--;
94a79942 545 } else{
0ddcf5fd 546 idx = ieee->crypt_info.tx_keyidx;
94a79942
LF
547 }
548 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
0ddcf5fd 549 crypt = &ieee->crypt_info.crypt[idx];
94a79942
LF
550 group_key = 1;
551 } else {
552 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
553 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
62f27cc4 554 return -EINVAL;
94a79942 555 if (ieee->iw_mode == IW_MODE_INFRA)
0ddcf5fd 556 crypt = &ieee->crypt_info.crypt[idx];
94a79942
LF
557 else
558 return -EINVAL;
559 }
ecdfa446 560
94a79942
LF
561 sec.flags |= SEC_ENABLED;
562 if ((encoding->flags & IW_ENCODE_DISABLED) ||
62f27cc4 563 ext->alg == IW_ENCODE_ALG_NONE) {
94a79942 564 if (*crypt)
3b148be0 565 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
ecdfa446 566
184f1938 567 for (i = 0; i < NUM_WEP_KEYS; i++) {
0ddcf5fd 568 if (ieee->crypt_info.crypt[i] != NULL)
94a79942
LF
569 break;
570 }
184f1938 571 if (i == NUM_WEP_KEYS) {
94a79942
LF
572 sec.enabled = 0;
573 sec.level = SEC_LEVEL_0;
574 sec.flags |= SEC_LEVEL;
575 }
576 goto done;
577 }
ecdfa446
GKH
578
579 sec.enabled = 1;
62f27cc4
LF
580 switch (ext->alg) {
581 case IW_ENCODE_ALG_WEP:
3b148be0 582 alg = "R-WEP";
62f27cc4
LF
583 module = "rtllib_crypt_wep";
584 break;
585 case IW_ENCODE_ALG_TKIP:
3b148be0 586 alg = "R-TKIP";
62f27cc4
LF
587 module = "rtllib_crypt_tkip";
588 break;
589 case IW_ENCODE_ALG_CCMP:
3b148be0 590 alg = "R-CCMP";
62f27cc4
LF
591 module = "rtllib_crypt_ccmp";
592 break;
593 default:
c6a91aba 594 netdev_dbg(ieee->dev, "Unknown crypto alg %d\n", ext->alg);
62f27cc4
LF
595 ret = -EINVAL;
596 goto done;
597 }
c60cfc8e 598 netdev_info(dev, "alg name:%s\n", alg);
ecdfa446 599
3b148be0 600 ops = lib80211_get_crypto_ops(alg);
62f27cc4
LF
601 if (ops == NULL) {
602 char tempbuf[100];
603
604 memset(tempbuf, 0x00, 100);
605 sprintf(tempbuf, "%s", module);
606 request_module("%s", tempbuf);
3b148be0 607 ops = lib80211_get_crypto_ops(alg);
62f27cc4
LF
608 }
609 if (ops == NULL) {
c60cfc8e 610 netdev_info(dev, "========>unknown crypto alg %d\n", ext->alg);
62f27cc4
LF
611 ret = -EINVAL;
612 goto done;
613 }
614
615 if (*crypt == NULL || (*crypt)->ops != ops) {
32c44cb5 616 struct lib80211_crypt_data *new_crypt;
62f27cc4 617
3b148be0 618 lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt);
62f27cc4
LF
619
620 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
621 if (new_crypt == NULL) {
622 ret = -ENOMEM;
623 goto done;
624 }
625 new_crypt->ops = ops;
0bd35534 626 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
62f27cc4
LF
627 new_crypt->priv = new_crypt->ops->init(idx);
628
629 if (new_crypt->priv == NULL) {
630 kfree(new_crypt);
631 ret = -EINVAL;
632 goto done;
633 }
634 *crypt = new_crypt;
635
636 }
637
638 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
639 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
640 (*crypt)->priv) < 0) {
c60cfc8e 641 netdev_info(dev, "key setting failed\n");
62f27cc4
LF
642 ret = -EINVAL;
643 goto done;
644 }
645 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
0ddcf5fd 646 ieee->crypt_info.tx_keyidx = idx;
62f27cc4
LF
647 sec.active_key = idx;
648 sec.flags |= SEC_ACTIVE_KEY;
649 }
650 if (ext->alg != IW_ENCODE_ALG_NONE) {
651 sec.key_sizes[idx] = ext->key_len;
652 sec.flags |= (1 << idx);
653 if (ext->alg == IW_ENCODE_ALG_WEP) {
654 sec.flags |= SEC_LEVEL;
655 sec.level = SEC_LEVEL_1;
656 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
657 sec.flags |= SEC_LEVEL;
658 sec.level = SEC_LEVEL_2;
659 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
660 sec.flags |= SEC_LEVEL;
661 sec.level = SEC_LEVEL_3;
662 }
663 /* Don't set sec level for group keys. */
664 if (group_key)
665 sec.flags &= ~SEC_LEVEL;
666 }
ecdfa446 667done:
62f27cc4
LF
668 if (ieee->set_security)
669 ieee->set_security(ieee->dev, &sec);
ecdfa446
GKH
670
671 if (ieee->reset_on_keychange &&
62f27cc4
LF
672 ieee->iw_mode != IW_MODE_INFRA &&
673 ieee->reset_port && ieee->reset_port(dev)) {
c6a91aba 674 netdev_dbg(ieee->dev, "Port reset failed\n");
62f27cc4
LF
675 return -EINVAL;
676 }
677 return ret;
ecdfa446 678}
3b28499c 679EXPORT_SYMBOL(rtllib_wx_set_encode_ext);
ecdfa446 680
94a79942 681int rtllib_wx_set_mlme(struct rtllib_device *ieee,
62f27cc4
LF
682 struct iw_request_info *info,
683 union iwreq_data *wrqu, char *extra)
ecdfa446 684{
94a79942
LF
685 u8 i = 0;
686 bool deauth = false;
ecdfa446 687 struct iw_mlme *mlme = (struct iw_mlme *) extra;
94a79942
LF
688
689 if (ieee->state != RTLLIB_LINKED)
690 return -ENOLINK;
691
9afa9370 692 mutex_lock(&ieee->wx_mutex);
94a79942 693
ecdfa446 694 switch (mlme->cmd) {
62f27cc4
LF
695 case IW_MLME_DEAUTH:
696 deauth = true;
697 /* leave break out intentionly */
94a79942 698
62f27cc4 699 case IW_MLME_DISASSOC:
4bb01423 700 if (deauth)
c60cfc8e 701 netdev_info(ieee->dev, "disauth packet !\n");
62f27cc4 702 else
c60cfc8e 703 netdev_info(ieee->dev, "dis associate packet!\n");
94a79942 704
62f27cc4 705 ieee->cannot_notify = true;
94a79942 706
62f27cc4
LF
707 SendDisassociation(ieee, deauth, mlme->reason_code);
708 rtllib_disassociate(ieee);
94a79942 709
62f27cc4
LF
710 ieee->wap_set = 0;
711 for (i = 0; i < 6; i++)
712 ieee->current_network.bssid[i] = 0x55;
94a79942 713
62f27cc4
LF
714 ieee->ssid_set = 0;
715 ieee->current_network.ssid[0] = '\0';
716 ieee->current_network.ssid_len = 0;
ecdfa446 717 break;
94a79942 718 default:
9afa9370 719 mutex_unlock(&ieee->wx_mutex);
94a79942
LF
720 return -EOPNOTSUPP;
721 }
722
9afa9370 723 mutex_unlock(&ieee->wx_mutex);
94a79942 724
ecdfa446
GKH
725 return 0;
726}
3b28499c 727EXPORT_SYMBOL(rtllib_wx_set_mlme);
ecdfa446 728
94a79942 729int rtllib_wx_set_auth(struct rtllib_device *ieee,
62f27cc4
LF
730 struct iw_request_info *info,
731 struct iw_param *data, char *extra)
ecdfa446 732{
ecdfa446 733 switch (data->flags & IW_AUTH_INDEX) {
62f27cc4 734 case IW_AUTH_WPA_VERSION:
ecdfa446 735 break;
62f27cc4
LF
736 case IW_AUTH_CIPHER_PAIRWISE:
737 case IW_AUTH_CIPHER_GROUP:
738 case IW_AUTH_KEY_MGMT:
14b40d92 739 /* Host AP driver does not use these parameters and allows
94a79942
LF
740 * wpa_supplicant to control them internally.
741 */
62f27cc4
LF
742 break;
743 case IW_AUTH_TKIP_COUNTERMEASURES:
744 ieee->tkip_countermeasures = data->value;
745 break;
746 case IW_AUTH_DROP_UNENCRYPTED:
747 ieee->drop_unencrypted = data->value;
ecdfa446
GKH
748 break;
749
750 case IW_AUTH_80211_AUTH_ALG:
62f27cc4 751 if (data->value & IW_AUTH_ALG_SHARED_KEY) {
ecdfa446
GKH
752 ieee->open_wep = 0;
753 ieee->auth_mode = 1;
62f27cc4 754 } else if (data->value & IW_AUTH_ALG_OPEN_SYSTEM) {
ecdfa446
GKH
755 ieee->open_wep = 1;
756 ieee->auth_mode = 0;
62f27cc4 757 } else if (data->value & IW_AUTH_ALG_LEAP) {
ecdfa446
GKH
758 ieee->open_wep = 1;
759 ieee->auth_mode = 2;
62f27cc4 760 } else
ecdfa446 761 return -EINVAL;
ecdfa446
GKH
762 break;
763
ecdfa446 764 case IW_AUTH_WPA_ENABLED:
62f27cc4 765 ieee->wpa_enabled = (data->value) ? 1 : 0;
ecdfa446
GKH
766 break;
767
ecdfa446 768 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
62f27cc4 769 ieee->ieee802_1x = data->value;
ecdfa446
GKH
770 break;
771 case IW_AUTH_PRIVACY_INVOKED:
772 ieee->privacy_invoked = data->value;
773 break;
774 default:
62f27cc4 775 return -EOPNOTSUPP;
ecdfa446 776 }
ecdfa446
GKH
777 return 0;
778}
3b28499c 779EXPORT_SYMBOL(rtllib_wx_set_auth);
94a79942
LF
780
781int rtllib_wx_set_gen_ie(struct rtllib_device *ieee, u8 *ie, size_t len)
ecdfa446 782{
ecdfa446 783 u8 *buf;
62f27cc4 784 u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
ecdfa446 785
62f27cc4 786 if (len > MAX_WPA_IE_LEN || (len && ie == NULL))
94a79942 787 return -EINVAL;
ecdfa446 788
94a79942
LF
789 if (len) {
790 eid = ie[0];
62f27cc4
LF
791 if ((eid == MFIE_TYPE_GENERIC) && (!memcmp(&ie[2],
792 wps_oui, 4))) {
94a79942 793
a5c06ad8 794 ieee->wps_ie_len = min_t(size_t, len, MAX_WZC_IE_LEN);
23226977 795 buf = kmemdup(ie, ieee->wps_ie_len, GFP_KERNEL);
94a79942
LF
796 if (buf == NULL)
797 return -ENOMEM;
94a79942
LF
798 ieee->wps_ie = buf;
799 return 0;
800 }
801 }
802 ieee->wps_ie_len = 0;
62f27cc4 803 kfree(ieee->wps_ie);
94a79942
LF
804 ieee->wps_ie = NULL;
805 if (len) {
62f27cc4 806 if (len != ie[1]+2)
ecdfa446 807 return -EINVAL;
23226977 808 buf = kmemdup(ie, len, GFP_KERNEL);
ecdfa446
GKH
809 if (buf == NULL)
810 return -ENOMEM;
ecdfa446
GKH
811 kfree(ieee->wpa_ie);
812 ieee->wpa_ie = buf;
813 ieee->wpa_ie_len = len;
94a79942 814 } else {
ecdfa446
GKH
815 kfree(ieee->wpa_ie);
816 ieee->wpa_ie = NULL;
817 ieee->wpa_ie_len = 0;
818 }
ecdfa446 819 return 0;
ecdfa446 820}
3b28499c 821EXPORT_SYMBOL(rtllib_wx_set_gen_ie);
This page took 0.760882 seconds and 5 git commands to generate.