Staging: rtl8192su: remove kernel version compatibility wrappers
[deliverable/linux.git] / drivers / staging / rtl8192su / ieee80211 / ieee80211_wx.c
CommitLineData
5f53d8ca
JC
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>
33#include <linux/version.h>
34#include <linux/kmod.h>
35#include <linux/module.h>
36
37#include "ieee80211.h"
38#if 0
39static const char *ieee80211_modes[] = {
40 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
41};
42#endif
43struct modes_unit {
44 char *mode_string;
45 int mode_size;
46};
47struct modes_unit ieee80211_modes[] = {
48 {"a",1},
49 {"b",1},
50 {"g",1},
51 {"?",1},
52 {"N-24G",5},
53 {"N-5G",4},
54};
55
5f53d8ca 56#define iwe_stream_add_event_rsl iwe_stream_add_event
5f53d8ca
JC
57
58#define MAX_CUSTOM_LEN 64
59static inline char *rtl819x_translate_scan(struct ieee80211_device *ieee,
60 char *start, char *stop,
61 struct ieee80211_network *network,
62 struct iw_request_info *info)
63{
64 char custom[MAX_CUSTOM_LEN];
65 char proto_name[IFNAMSIZ];
66 char *pname = proto_name;
67 char *p;
68 struct iw_event iwe;
69 int i, j;
70 u16 max_rate, rate;
71 static u8 EWC11NHTCap[] = {0x00, 0x90, 0x4c, 0x33};
72
73 /* First entry *MUST* be the AP MAC address */
74 iwe.cmd = SIOCGIWAP;
75 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
76 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
5f53d8ca 77 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
1ec9e48d 78
5f53d8ca
JC
79 /* Remaining entries will be displayed in the order we provide them */
80
81 /* Add the ESSID */
82 iwe.cmd = SIOCGIWESSID;
83 iwe.u.data.flags = 1;
84// if (network->flags & NETWORK_EMPTY_ESSID) {
85 if (network->ssid_len == 0) {
86 iwe.u.data.length = sizeof("<hidden>");
5f53d8ca 87 start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
5f53d8ca
JC
88 } else {
89 iwe.u.data.length = min(network->ssid_len, (u8)32);
5f53d8ca 90 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
5f53d8ca
JC
91 }
92 /* Add the protocol name */
93 iwe.cmd = SIOCGIWNAME;
94 for(i=0; i<(sizeof(ieee80211_modes)/sizeof(ieee80211_modes[0])); i++) {
95 if(network->mode&(1<<i)) {
96 sprintf(pname,ieee80211_modes[i].mode_string,ieee80211_modes[i].mode_size);
97 pname +=ieee80211_modes[i].mode_size;
98 }
99 }
100 *pname = '\0';
101 snprintf(iwe.u.name, IFNAMSIZ, "IEEE802.11%s", proto_name);
5f53d8ca 102 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
5f53d8ca
JC
103 /* Add mode */
104 iwe.cmd = SIOCGIWMODE;
105 if (network->capability &
106 (WLAN_CAPABILITY_BSS | WLAN_CAPABILITY_IBSS)) {
107 if (network->capability & WLAN_CAPABILITY_BSS)
108 iwe.u.mode = IW_MODE_MASTER;
109 else
110 iwe.u.mode = IW_MODE_ADHOC;
5f53d8ca 111 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
5f53d8ca
JC
112 }
113
114 /* Add frequency/channel */
115 iwe.cmd = SIOCGIWFREQ;
116/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
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;
5f53d8ca 121 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
5f53d8ca
JC
122 /* Add encryption capability */
123 iwe.cmd = SIOCGIWENCODE;
124 if (network->capability & WLAN_CAPABILITY_PRIVACY)
125 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
126 else
127 iwe.u.data.flags = IW_ENCODE_DISABLED;
128 iwe.u.data.length = 0;
5f53d8ca 129 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
5f53d8ca
JC
130 /* Add basic and extended rates */
131 max_rate = 0;
132 p = custom;
133 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
134 for (i = 0, j = 0; i < network->rates_len; ) {
135 if (j < network->rates_ex_len &&
136 ((network->rates_ex[j] & 0x7F) <
137 (network->rates[i] & 0x7F)))
138 rate = network->rates_ex[j++] & 0x7F;
139 else
140 rate = network->rates[i++] & 0x7F;
141 if (rate > max_rate)
142 max_rate = rate;
143 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
144 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
145 }
146 for (; j < network->rates_ex_len; j++) {
147 rate = network->rates_ex[j] & 0x7F;
148 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
149 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
150 if (rate > max_rate)
151 max_rate = rate;
152 }
153
154 if (network->mode >= IEEE_N_24G)//add N rate here;
155 {
156 PHT_CAPABILITY_ELE ht_cap = NULL;
157 bool is40M = false, isShortGI = false;
158 u8 max_mcs = 0;
159 if (!memcmp(network->bssht.bdHTCapBuf, EWC11NHTCap, 4))
160 ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[4];
161 else
162 ht_cap = (PHT_CAPABILITY_ELE)&network->bssht.bdHTCapBuf[0];
163 is40M = (ht_cap->ChlWidth)?1:0;
164 isShortGI = (ht_cap->ChlWidth)?
165 ((ht_cap->ShortGI40Mhz)?1:0):
166 ((ht_cap->ShortGI20Mhz)?1:0);
167
168 max_mcs = HTGetHighestMCSRate(ieee, ht_cap->MCS, MCS_FILTER_ALL);
169 rate = MCS_DATA_RATE[is40M][isShortGI][max_mcs&0x7f];
170 if (rate > max_rate)
171 max_rate = rate;
172 }
173#if 0
174 printk("max rate:%d ===basic rate:\n", max_rate);
175 for (i=0;i<network->rates_len;i++)
176 printk(" %x", network->rates[i]);
177 printk("\n=======extend rate\n");
178 for (i=0; i<network->rates_ex_len; i++)
179 printk(" %x", network->rates_ex[i]);
180 printk("\n");
181#endif
182 iwe.cmd = SIOCGIWRATE;
183 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
184 iwe.u.bitrate.value = max_rate * 500000;
5f53d8ca
JC
185 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
186 IW_EV_PARAM_LEN);
1ec9e48d 187
5f53d8ca
JC
188 iwe.cmd = IWEVCUSTOM;
189 iwe.u.data.length = p - custom;
190 if (iwe.u.data.length)
5f53d8ca 191 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
1ec9e48d 192
5f53d8ca
JC
193 /* Add quality statistics */
194 /* TODO: Fix these values... */
195 iwe.cmd = IWEVQUAL;
196 iwe.u.qual.qual = network->stats.signal;
197 iwe.u.qual.level = network->stats.rssi;
198 iwe.u.qual.noise = network->stats.noise;
199 iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
200 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
201 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
202 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
203 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
204 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
205 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
206 iwe.u.qual.updated = 7;
5f53d8ca 207 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
5f53d8ca
JC
208 iwe.cmd = IWEVCUSTOM;
209 p = custom;
210
211 iwe.u.data.length = p - custom;
212 if (iwe.u.data.length)
5f53d8ca 213 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
5f53d8ca
JC
214#if (WIRELESS_EXT < 18)
215 if (ieee->wpa_enabled && network->wpa_ie_len){
216 char buf[MAX_WPA_IE_LEN * 2 + 30];
217 // printk("WPA IE\n");
218 u8 *p = buf;
219 p += sprintf(p, "wpa_ie=");
220 for (i = 0; i < network->wpa_ie_len; i++) {
221 p += sprintf(p, "%02x", network->wpa_ie[i]);
222 }
223
224 memset(&iwe, 0, sizeof(iwe));
225 iwe.cmd = IWEVCUSTOM;
226 iwe.u.data.length = strlen(buf);
5f53d8ca 227 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
5f53d8ca
JC
228 }
229
230 if (ieee->wpa_enabled && network->rsn_ie_len){
231 char buf[MAX_WPA_IE_LEN * 2 + 30];
232
233 u8 *p = buf;
234 p += sprintf(p, "rsn_ie=");
235 for (i = 0; i < network->rsn_ie_len; i++) {
236 p += sprintf(p, "%02x", network->rsn_ie[i]);
237 }
238
239 memset(&iwe, 0, sizeof(iwe));
240 iwe.cmd = IWEVCUSTOM;
241 iwe.u.data.length = strlen(buf);
5f53d8ca 242 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
5f53d8ca
JC
243 }
244#else
245 memset(&iwe, 0, sizeof(iwe));
246 if (network->wpa_ie_len)
247 {
248 char buf[MAX_WPA_IE_LEN];
249 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
250 iwe.cmd = IWEVGENIE;
251 iwe.u.data.length = network->wpa_ie_len;
5f53d8ca 252 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
5f53d8ca
JC
253 }
254 memset(&iwe, 0, sizeof(iwe));
255 if (network->rsn_ie_len)
256 {
257 char buf[MAX_WPA_IE_LEN];
258 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
259 iwe.cmd = IWEVGENIE;
260 iwe.u.data.length = network->rsn_ie_len;
5f53d8ca 261 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
5f53d8ca
JC
262 }
263#endif
264
265
266 /* Add EXTRA: Age to display seconds since last beacon/probe response
267 * for given network. */
268 iwe.cmd = IWEVCUSTOM;
269 p = custom;
270 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
271 " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
272 iwe.u.data.length = p - custom;
273 if (iwe.u.data.length)
5f53d8ca 274 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
5f53d8ca
JC
275
276 return start;
277}
278
279int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
280 struct iw_request_info *info,
281 union iwreq_data *wrqu, char *extra)
282{
283 struct ieee80211_network *network;
284 unsigned long flags;
285
286 char *ev = extra;
287// char *stop = ev + IW_SCAN_MAX_DATA;
288 char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
289 //char *stop = ev + IW_SCAN_MAX_DATA;
290 int i = 0;
291 int err = 0;
292 IEEE80211_DEBUG_WX("Getting scan\n");
293 down(&ieee->wx_sem);
294 spin_lock_irqsave(&ieee->lock, flags);
295
296 list_for_each_entry(network, &ieee->network_list, list) {
297 i++;
298 if((stop-ev)<200)
299 {
300 err = -E2BIG;
301 break;
302 }
303 if (ieee->scan_age == 0 ||
304 time_after(network->last_scanned + ieee->scan_age, jiffies))
305 ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
306 else
307 IEEE80211_DEBUG_SCAN(
308 "Not showing network '%s ("
309 MAC_FMT ")' due to age (%lums).\n",
310 escape_essid(network->ssid,
311 network->ssid_len),
312 MAC_ARG(network->bssid),
313 (jiffies - network->last_scanned) / (HZ / 100));
314 }
315
316 spin_unlock_irqrestore(&ieee->lock, flags);
317 up(&ieee->wx_sem);
318 wrqu->data.length = ev - extra;
319 wrqu->data.flags = 0;
320
321 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
322
323 return err;
324}
325
326int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
327 struct iw_request_info *info,
328 union iwreq_data *wrqu, char *keybuf)
329{
330 struct iw_point *erq = &(wrqu->encoding);
331 struct net_device *dev = ieee->dev;
332 struct ieee80211_security sec = {
333 .flags = 0
334 };
335 int i, key, key_provided, len;
336 struct ieee80211_crypt_data **crypt;
337
338 IEEE80211_DEBUG_WX("SET_ENCODE\n");
339
340 key = erq->flags & IW_ENCODE_INDEX;
341 if (key) {
342 if (key > WEP_KEYS)
343 return -EINVAL;
344 key--;
345 key_provided = 1;
346 } else {
347 key_provided = 0;
348 key = ieee->tx_keyidx;
349 }
350
351 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
352 "provided" : "default");
353 crypt = &ieee->crypt[key];
354
355 if (erq->flags & IW_ENCODE_DISABLED) {
356 if (key_provided && *crypt) {
357 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
358 key);
359 ieee80211_crypt_delayed_deinit(ieee, crypt);
360 } else
361 IEEE80211_DEBUG_WX("Disabling encryption.\n");
362
363 /* Check all the keys to see if any are still configured,
364 * and if no key index was provided, de-init them all */
365 for (i = 0; i < WEP_KEYS; i++) {
366 if (ieee->crypt[i] != NULL) {
367 if (key_provided)
368 break;
369 ieee80211_crypt_delayed_deinit(
370 ieee, &ieee->crypt[i]);
371 }
372 }
373
374 if (i == WEP_KEYS) {
375 sec.enabled = 0;
376 sec.level = SEC_LEVEL_0;
377 sec.flags |= SEC_ENABLED | SEC_LEVEL;
378 }
379
380 goto done;
381 }
382
383
384
385 sec.enabled = 1;
386 sec.flags |= SEC_ENABLED;
387
388 if (*crypt != NULL && (*crypt)->ops != NULL &&
389 strcmp((*crypt)->ops->name, "WEP") != 0) {
390 /* changing to use WEP; deinit previously used algorithm
391 * on this key */
392 ieee80211_crypt_delayed_deinit(ieee, crypt);
393 }
394
395 if (*crypt == NULL) {
396 struct ieee80211_crypt_data *new_crypt;
397
398 /* take WEP into use */
399 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
400 GFP_KERNEL);
401 if (new_crypt == NULL)
402 return -ENOMEM;
403 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
404 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
405 if (!new_crypt->ops) {
406 request_module("ieee80211_crypt_wep");
407 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
408 }
5f53d8ca 409 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
5f53d8ca
JC
410 new_crypt->priv = new_crypt->ops->init(key);
411
412 if (!new_crypt->ops || !new_crypt->priv) {
413 kfree(new_crypt);
414 new_crypt = NULL;
415
416 printk(KERN_WARNING "%s: could not initialize WEP: "
417 "load module ieee80211_crypt_wep\n",
418 dev->name);
419 return -EOPNOTSUPP;
420 }
421 *crypt = new_crypt;
422 }
423
424 /* If a new key was provided, set it up */
425 if (erq->length > 0) {
426 len = erq->length <= 5 ? 5 : 13;
427 memcpy(sec.keys[key], keybuf, erq->length);
428 if (len > erq->length)
429 memset(sec.keys[key] + erq->length, 0,
430 len - erq->length);
431 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
432 key, escape_essid(sec.keys[key], len),
433 erq->length, len);
434 sec.key_sizes[key] = len;
435 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
436 (*crypt)->priv);
437 sec.flags |= (1 << key);
438 /* This ensures a key will be activated if no key is
439 * explicitely set */
440 if (key == sec.active_key)
441 sec.flags |= SEC_ACTIVE_KEY;
442 ieee->tx_keyidx = key;
443
444 } else {
445 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
446 NULL, (*crypt)->priv);
447 if (len == 0) {
448 /* Set a default key of all 0 */
449 printk("Setting key %d to all zero.\n",
450 key);
451
452 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
453 key);
454 memset(sec.keys[key], 0, 13);
455 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
456 (*crypt)->priv);
457 sec.key_sizes[key] = 13;
458 sec.flags |= (1 << key);
459 }
460
461 /* No key data - just set the default TX key index */
462 if (key_provided) {
463 IEEE80211_DEBUG_WX(
464 "Setting key %d to default Tx key.\n", key);
465 ieee->tx_keyidx = key;
466 sec.active_key = key;
467 sec.flags |= SEC_ACTIVE_KEY;
468 }
469 }
470
471 done:
472 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
473 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
474 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
475 sec.flags |= SEC_AUTH_MODE;
476 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
477 "OPEN" : "SHARED KEY");
478
479 /* For now we just support WEP, so only set that security level...
480 * TODO: When WPA is added this is one place that needs to change */
481 sec.flags |= SEC_LEVEL;
482 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
483
484 if (ieee->set_security)
485 ieee->set_security(dev, &sec);
486
487 /* Do not reset port if card is in Managed mode since resetting will
488 * generate new IEEE 802.11 authentication which may end up in looping
489 * with IEEE 802.1X. If your hardware requires a reset after WEP
490 * configuration (for example... Prism2), implement the reset_port in
491 * the callbacks structures used to initialize the 802.11 stack. */
492 if (ieee->reset_on_keychange &&
493 ieee->iw_mode != IW_MODE_INFRA &&
494 ieee->reset_port && ieee->reset_port(dev)) {
495 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
496 return -EINVAL;
497 }
498 return 0;
499}
500
501int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
502 struct iw_request_info *info,
503 union iwreq_data *wrqu, char *keybuf)
504{
505 struct iw_point *erq = &(wrqu->encoding);
506 int len, key;
507 struct ieee80211_crypt_data *crypt;
508
509 IEEE80211_DEBUG_WX("GET_ENCODE\n");
510
511 if(ieee->iw_mode == IW_MODE_MONITOR)
512 return -1;
513
514 key = erq->flags & IW_ENCODE_INDEX;
515 if (key) {
516 if (key > WEP_KEYS)
517 return -EINVAL;
518 key--;
519 } else
520 key = ieee->tx_keyidx;
521
522 crypt = ieee->crypt[key];
523 erq->flags = key + 1;
524
525 if (crypt == NULL || crypt->ops == NULL) {
526 erq->length = 0;
527 erq->flags |= IW_ENCODE_DISABLED;
528 return 0;
529 }
530#if 0
531 if (strcmp(crypt->ops->name, "WEP") != 0) {
532 /* only WEP is supported with wireless extensions, so just
533 * report that encryption is used */
534 erq->length = 0;
535 erq->flags |= IW_ENCODE_ENABLED;
536 return 0;
537 }
538#endif
539 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
540 erq->length = (len >= 0 ? len : 0);
541
542 erq->flags |= IW_ENCODE_ENABLED;
543
544 if (ieee->open_wep)
545 erq->flags |= IW_ENCODE_OPEN;
546 else
547 erq->flags |= IW_ENCODE_RESTRICTED;
548
549 return 0;
550}
551#if (WIRELESS_EXT >= 18)
552int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
553 struct iw_request_info *info,
554 union iwreq_data *wrqu, char *extra)
555{
556 int ret = 0;
5f53d8ca
JC
557 struct net_device *dev = ieee->dev;
558 struct iw_point *encoding = &wrqu->encoding;
559 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
560 int i, idx;
561 int group_key = 0;
562 const char *alg, *module;
563 struct ieee80211_crypto_ops *ops;
564 struct ieee80211_crypt_data **crypt;
565
566 struct ieee80211_security sec = {
567 .flags = 0,
568 };
569 //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
570 idx = encoding->flags & IW_ENCODE_INDEX;
571 if (idx) {
572 if (idx < 1 || idx > WEP_KEYS)
573 return -EINVAL;
574 idx--;
575 } else
576 idx = ieee->tx_keyidx;
577
578 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
579
580 crypt = &ieee->crypt[idx];
581
582 group_key = 1;
583 } else {
584 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
585 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
586 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
587 return -EINVAL;
588 if (ieee->iw_mode == IW_MODE_INFRA)
589
590 crypt = &ieee->crypt[idx];
591
592 else
593 return -EINVAL;
594 }
595
596 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
597 if ((encoding->flags & IW_ENCODE_DISABLED) ||
598 ext->alg == IW_ENCODE_ALG_NONE) {
599 if (*crypt)
600 ieee80211_crypt_delayed_deinit(ieee, crypt);
601
602 for (i = 0; i < WEP_KEYS; i++)
603
604 if (ieee->crypt[i] != NULL)
605
606 break;
607
608 if (i == WEP_KEYS) {
609 sec.enabled = 0;
610 // sec.encrypt = 0;
611 sec.level = SEC_LEVEL_0;
612 sec.flags |= SEC_LEVEL;
613 }
614 //printk("disabled: flag:%x\n", encoding->flags);
615 goto done;
616 }
617
618 sec.enabled = 1;
619 // sec.encrypt = 1;
620#if 0
621 if (group_key ? !ieee->host_mc_decrypt :
622 !(ieee->host_encrypt || ieee->host_decrypt ||
623 ieee->host_encrypt_msdu))
624 goto skip_host_crypt;
625#endif
626 switch (ext->alg) {
627 case IW_ENCODE_ALG_WEP:
628 alg = "WEP";
629 module = "ieee80211_crypt_wep";
630 break;
631 case IW_ENCODE_ALG_TKIP:
632 alg = "TKIP";
633 module = "ieee80211_crypt_tkip";
634 break;
635 case IW_ENCODE_ALG_CCMP:
636 alg = "CCMP";
637 module = "ieee80211_crypt_ccmp";
638 break;
639 default:
640 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
641 dev->name, ext->alg);
642 ret = -EINVAL;
643 goto done;
644 }
645 printk("alg name:%s\n",alg);
646
647 ops = ieee80211_get_crypto_ops(alg);
648 if (ops == NULL) {
36dbd401 649 request_module("%s", module);
5f53d8ca
JC
650 ops = ieee80211_get_crypto_ops(alg);
651 }
652 if (ops == NULL) {
653 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
654 dev->name, ext->alg);
655 printk("========>unknown crypto alg %d\n", ext->alg);
656 ret = -EINVAL;
657 goto done;
658 }
659
660 if (*crypt == NULL || (*crypt)->ops != ops) {
661 struct ieee80211_crypt_data *new_crypt;
662
663 ieee80211_crypt_delayed_deinit(ieee, crypt);
664
5f53d8ca 665 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
5f53d8ca
JC
666 if (new_crypt == NULL) {
667 ret = -ENOMEM;
668 goto done;
669 }
670 new_crypt->ops = ops;
671 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
672 new_crypt->priv = new_crypt->ops->init(idx);
673 if (new_crypt->priv == NULL) {
674 kfree(new_crypt);
675 ret = -EINVAL;
676 goto done;
677 }
678 *crypt = new_crypt;
679
680 }
681
682 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
683 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
684 (*crypt)->priv) < 0) {
685 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
686 printk("key setting failed\n");
687 ret = -EINVAL;
688 goto done;
689 }
690#if 1
691 //skip_host_crypt:
692 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
693 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
694 ieee->tx_keyidx = idx;
695 sec.active_key = idx;
696 sec.flags |= SEC_ACTIVE_KEY;
697 }
698
699 if (ext->alg != IW_ENCODE_ALG_NONE) {
700 //memcpy(sec.keys[idx], ext->key, ext->key_len);
701 sec.key_sizes[idx] = ext->key_len;
702 sec.flags |= (1 << idx);
703 if (ext->alg == IW_ENCODE_ALG_WEP) {
704 // sec.encode_alg[idx] = SEC_ALG_WEP;
705 sec.flags |= SEC_LEVEL;
706 sec.level = SEC_LEVEL_1;
707 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
708 // sec.encode_alg[idx] = SEC_ALG_TKIP;
709 sec.flags |= SEC_LEVEL;
710 sec.level = SEC_LEVEL_2;
711 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
712 // sec.encode_alg[idx] = SEC_ALG_CCMP;
713 sec.flags |= SEC_LEVEL;
714 sec.level = SEC_LEVEL_3;
715 }
716 /* Don't set sec level for group keys. */
717 if (group_key)
718 sec.flags &= ~SEC_LEVEL;
719 }
720#endif
721done:
722 if (ieee->set_security)
723 ieee->set_security(ieee->dev, &sec);
724
725 if (ieee->reset_on_keychange &&
726 ieee->iw_mode != IW_MODE_INFRA &&
727 ieee->reset_port && ieee->reset_port(dev)) {
728 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
729 return -EINVAL;
730 }
1ec9e48d 731
5f53d8ca
JC
732 return ret;
733}
734
735int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
736 struct iw_request_info *info,
737 union iwreq_data *wrqu, char *extra)
738{
739 struct iw_point *encoding = &wrqu->encoding;
740 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
741 struct ieee80211_crypt_data *crypt;
742 int idx, max_key_len;
743
744 max_key_len = encoding->length - sizeof(*ext);
745 if (max_key_len < 0)
746 return -EINVAL;
747
748 idx = encoding->flags & IW_ENCODE_INDEX;
749 if (idx) {
750 if (idx < 1 || idx > WEP_KEYS)
751 return -EINVAL;
752 idx--;
753 } else
754 idx = ieee->tx_keyidx;
755
38526988 756 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
5f53d8ca
JC
757 ext->alg != IW_ENCODE_ALG_WEP)
758 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
759 return -EINVAL;
760
761 crypt = ieee->crypt[idx];
762 encoding->flags = idx + 1;
763 memset(ext, 0, sizeof(*ext));
764
765 if (crypt == NULL || crypt->ops == NULL ) {
766 ext->alg = IW_ENCODE_ALG_NONE;
767 ext->key_len = 0;
768 encoding->flags |= IW_ENCODE_DISABLED;
769 } else {
770 if (strcmp(crypt->ops->name, "WEP") == 0 )
771 ext->alg = IW_ENCODE_ALG_WEP;
772 else if (strcmp(crypt->ops->name, "TKIP"))
773 ext->alg = IW_ENCODE_ALG_TKIP;
774 else if (strcmp(crypt->ops->name, "CCMP"))
775 ext->alg = IW_ENCODE_ALG_CCMP;
776 else
777 return -EINVAL;
778 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
779 encoding->flags |= IW_ENCODE_ENABLED;
780 if (ext->key_len &&
781 (ext->alg == IW_ENCODE_ALG_TKIP ||
782 ext->alg == IW_ENCODE_ALG_CCMP))
783 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
784
785 }
786
787 return 0;
788}
789
790int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
791 struct iw_request_info *info,
792 union iwreq_data *wrqu, char *extra)
793{
5f53d8ca 794 struct iw_mlme *mlme = (struct iw_mlme *) extra;
1ec9e48d 795
5f53d8ca
JC
796 switch (mlme->cmd) {
797 case IW_MLME_DEAUTH:
798 case IW_MLME_DISASSOC:
799 ieee80211_disassociate(ieee);
800 break;
801 default:
802 return -EOPNOTSUPP;
803 }
1ec9e48d 804
5f53d8ca
JC
805 return 0;
806}
807
808int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
809 struct iw_request_info *info,
810 struct iw_param *data, char *extra)
811{
5f53d8ca
JC
812 switch (data->flags & IW_AUTH_INDEX) {
813 case IW_AUTH_WPA_VERSION:
814 /*need to support wpa2 here*/
815 //printk("wpa version:%x\n", data->value);
816 break;
817 case IW_AUTH_CIPHER_PAIRWISE:
818 case IW_AUTH_CIPHER_GROUP:
819 case IW_AUTH_KEY_MGMT:
820 /*
821 * * Host AP driver does not use these parameters and allows
822 * * wpa_supplicant to control them internally.
823 * */
824 break;
825 case IW_AUTH_TKIP_COUNTERMEASURES:
826 ieee->tkip_countermeasures = data->value;
827 break;
828 case IW_AUTH_DROP_UNENCRYPTED:
829 ieee->drop_unencrypted = data->value;
830 break;
831
832 case IW_AUTH_80211_AUTH_ALG:
833 //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
834 // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
835 if(data->value & IW_AUTH_ALG_SHARED_KEY){
836 ieee->open_wep = 0;
837 ieee->auth_mode = 1;
838 }
839 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
840 ieee->open_wep = 1;
841 ieee->auth_mode = 0;
842 }
843 else if(data->value & IW_AUTH_ALG_LEAP){
844 ieee->open_wep = 1;
845 ieee->auth_mode = 2;
846 //printk("hahahaa:LEAP\n");
847 }
848 else
849 return -EINVAL;
850 //printk("open_wep:%d\n", ieee->open_wep);
851 break;
852
853#if 1
854 case IW_AUTH_WPA_ENABLED:
855 ieee->wpa_enabled = (data->value)?1:0;
856 //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
857 break;
858
859#endif
860 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
861 ieee->ieee802_1x = data->value;
862 break;
863 case IW_AUTH_PRIVACY_INVOKED:
864 ieee->privacy_invoked = data->value;
865 break;
866 default:
867 return -EOPNOTSUPP;
868 }
1ec9e48d 869
5f53d8ca
JC
870 return 0;
871}
872#endif
873#if 1
874int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
875{
5f53d8ca
JC
876#if 0
877 printk("====>%s()\n", __FUNCTION__);
878 {
879 int i;
880 for (i=0; i<len; i++)
881 printk("%2x ", ie[i]&0xff);
882 printk("\n");
883 }
884#endif
885 u8 *buf;
886
887 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
888 {
889 // printk("return error out, len:%d\n", len);
890 return -EINVAL;
891 }
892
893
894 if (len)
895 {
896 if (len != ie[1]+2)
897 {
898 printk("len:%d, ie:%d\n", len, ie[1]);
899 return -EINVAL;
900 }
901 buf = kmalloc(len, GFP_KERNEL);
902 if (buf == NULL)
903 return -ENOMEM;
904 memcpy(buf, ie, len);
905 kfree(ieee->wpa_ie);
906 ieee->wpa_ie = buf;
907 ieee->wpa_ie_len = len;
908 }
909 else{
910 if (ieee->wpa_ie)
911 kfree(ieee->wpa_ie);
912 ieee->wpa_ie = NULL;
913 ieee->wpa_ie_len = 0;
914 }
1ec9e48d 915
5f53d8ca
JC
916 return 0;
917
918}
919#endif
920
5f53d8ca
JC
921EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
922#if (WIRELESS_EXT >= 18)
923EXPORT_SYMBOL(ieee80211_wx_set_mlme);
924EXPORT_SYMBOL(ieee80211_wx_set_auth);
925EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
926EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
927#endif
928EXPORT_SYMBOL(ieee80211_wx_get_scan);
929EXPORT_SYMBOL(ieee80211_wx_set_encode);
930EXPORT_SYMBOL(ieee80211_wx_get_encode);
This page took 0.078872 seconds and 5 git commands to generate.