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