blob: ee04691d9330b4e1f4e8cdcee9e0133a7e713762 [file] [log] [blame]
Jerry Chuang5f53d8c2009-05-21 22:16:02 -07001/******************************************************************************
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
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070056#define iwe_stream_add_event_rsl iwe_stream_add_event
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070057
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);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070077 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_ADDR_LEN);
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +020078
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070079 /* 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>");
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070087 start = iwe_stream_add_point(info, start, stop, &iwe, "<hidden>");
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070088 } else {
89 iwe.u.data.length = min(network->ssid_len, (u8)32);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070090 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070091 }
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);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700102 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_CHAR_LEN);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700103 /* 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;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700111 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_UINT_LEN);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700112 }
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;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700121 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_FREQ_LEN);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700122 /* 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;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700129 start = iwe_stream_add_point(info, start, stop, &iwe, network->ssid);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700130 /* 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;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700185 start = iwe_stream_add_event_rsl(info, start, stop, &iwe,
186 IW_EV_PARAM_LEN);
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200187
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700188 iwe.cmd = IWEVCUSTOM;
189 iwe.u.data.length = p - custom;
190 if (iwe.u.data.length)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700191 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200192
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700193 /* 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;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700207 start = iwe_stream_add_event_rsl(info, start, stop, &iwe, IW_EV_QUAL_LEN);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700208 iwe.cmd = IWEVCUSTOM;
209 p = custom;
210
211 iwe.u.data.length = p - custom;
212 if (iwe.u.data.length)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700213 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700214
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700215 memset(&iwe, 0, sizeof(iwe));
216 if (network->wpa_ie_len)
217 {
218 char buf[MAX_WPA_IE_LEN];
219 memcpy(buf, network->wpa_ie, network->wpa_ie_len);
220 iwe.cmd = IWEVGENIE;
221 iwe.u.data.length = network->wpa_ie_len;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700222 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700223 }
224 memset(&iwe, 0, sizeof(iwe));
225 if (network->rsn_ie_len)
226 {
227 char buf[MAX_WPA_IE_LEN];
228 memcpy(buf, network->rsn_ie, network->rsn_ie_len);
229 iwe.cmd = IWEVGENIE;
230 iwe.u.data.length = network->rsn_ie_len;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700231 start = iwe_stream_add_point(info, start, stop, &iwe, buf);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700232 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700233
234 /* Add EXTRA: Age to display seconds since last beacon/probe response
235 * for given network. */
236 iwe.cmd = IWEVCUSTOM;
237 p = custom;
238 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
239 " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
240 iwe.u.data.length = p - custom;
241 if (iwe.u.data.length)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700242 start = iwe_stream_add_point(info, start, stop, &iwe, custom);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700243
244 return start;
245}
246
247int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
248 struct iw_request_info *info,
249 union iwreq_data *wrqu, char *extra)
250{
251 struct ieee80211_network *network;
252 unsigned long flags;
253
254 char *ev = extra;
255// char *stop = ev + IW_SCAN_MAX_DATA;
256 char *stop = ev + wrqu->data.length;//IW_SCAN_MAX_DATA;
257 //char *stop = ev + IW_SCAN_MAX_DATA;
258 int i = 0;
259 int err = 0;
260 IEEE80211_DEBUG_WX("Getting scan\n");
261 down(&ieee->wx_sem);
262 spin_lock_irqsave(&ieee->lock, flags);
263
264 list_for_each_entry(network, &ieee->network_list, list) {
265 i++;
266 if((stop-ev)<200)
267 {
268 err = -E2BIG;
269 break;
270 }
271 if (ieee->scan_age == 0 ||
272 time_after(network->last_scanned + ieee->scan_age, jiffies))
273 ev = rtl819x_translate_scan(ieee, ev, stop, network, info);
274 else
275 IEEE80211_DEBUG_SCAN(
276 "Not showing network '%s ("
277 MAC_FMT ")' due to age (%lums).\n",
278 escape_essid(network->ssid,
279 network->ssid_len),
280 MAC_ARG(network->bssid),
281 (jiffies - network->last_scanned) / (HZ / 100));
282 }
283
284 spin_unlock_irqrestore(&ieee->lock, flags);
285 up(&ieee->wx_sem);
286 wrqu->data.length = ev - extra;
287 wrqu->data.flags = 0;
288
289 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
290
291 return err;
292}
293
294int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
295 struct iw_request_info *info,
296 union iwreq_data *wrqu, char *keybuf)
297{
298 struct iw_point *erq = &(wrqu->encoding);
299 struct net_device *dev = ieee->dev;
300 struct ieee80211_security sec = {
301 .flags = 0
302 };
303 int i, key, key_provided, len;
304 struct ieee80211_crypt_data **crypt;
305
306 IEEE80211_DEBUG_WX("SET_ENCODE\n");
307
308 key = erq->flags & IW_ENCODE_INDEX;
309 if (key) {
310 if (key > WEP_KEYS)
311 return -EINVAL;
312 key--;
313 key_provided = 1;
314 } else {
315 key_provided = 0;
316 key = ieee->tx_keyidx;
317 }
318
319 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
320 "provided" : "default");
321 crypt = &ieee->crypt[key];
322
323 if (erq->flags & IW_ENCODE_DISABLED) {
324 if (key_provided && *crypt) {
325 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
326 key);
327 ieee80211_crypt_delayed_deinit(ieee, crypt);
328 } else
329 IEEE80211_DEBUG_WX("Disabling encryption.\n");
330
331 /* Check all the keys to see if any are still configured,
332 * and if no key index was provided, de-init them all */
333 for (i = 0; i < WEP_KEYS; i++) {
334 if (ieee->crypt[i] != NULL) {
335 if (key_provided)
336 break;
337 ieee80211_crypt_delayed_deinit(
338 ieee, &ieee->crypt[i]);
339 }
340 }
341
342 if (i == WEP_KEYS) {
343 sec.enabled = 0;
344 sec.level = SEC_LEVEL_0;
345 sec.flags |= SEC_ENABLED | SEC_LEVEL;
346 }
347
348 goto done;
349 }
350
351
352
353 sec.enabled = 1;
354 sec.flags |= SEC_ENABLED;
355
356 if (*crypt != NULL && (*crypt)->ops != NULL &&
357 strcmp((*crypt)->ops->name, "WEP") != 0) {
358 /* changing to use WEP; deinit previously used algorithm
359 * on this key */
360 ieee80211_crypt_delayed_deinit(ieee, crypt);
361 }
362
363 if (*crypt == NULL) {
364 struct ieee80211_crypt_data *new_crypt;
365
366 /* take WEP into use */
367 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
368 GFP_KERNEL);
369 if (new_crypt == NULL)
370 return -ENOMEM;
371 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
372 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
373 if (!new_crypt->ops) {
374 request_module("ieee80211_crypt_wep");
375 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
376 }
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700377 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700378 new_crypt->priv = new_crypt->ops->init(key);
379
380 if (!new_crypt->ops || !new_crypt->priv) {
381 kfree(new_crypt);
382 new_crypt = NULL;
383
384 printk(KERN_WARNING "%s: could not initialize WEP: "
385 "load module ieee80211_crypt_wep\n",
386 dev->name);
387 return -EOPNOTSUPP;
388 }
389 *crypt = new_crypt;
390 }
391
392 /* If a new key was provided, set it up */
393 if (erq->length > 0) {
394 len = erq->length <= 5 ? 5 : 13;
395 memcpy(sec.keys[key], keybuf, erq->length);
396 if (len > erq->length)
397 memset(sec.keys[key] + erq->length, 0,
398 len - erq->length);
399 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
400 key, escape_essid(sec.keys[key], len),
401 erq->length, len);
402 sec.key_sizes[key] = len;
403 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
404 (*crypt)->priv);
405 sec.flags |= (1 << key);
406 /* This ensures a key will be activated if no key is
407 * explicitely set */
408 if (key == sec.active_key)
409 sec.flags |= SEC_ACTIVE_KEY;
410 ieee->tx_keyidx = key;
411
412 } else {
413 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
414 NULL, (*crypt)->priv);
415 if (len == 0) {
416 /* Set a default key of all 0 */
417 printk("Setting key %d to all zero.\n",
418 key);
419
420 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
421 key);
422 memset(sec.keys[key], 0, 13);
423 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
424 (*crypt)->priv);
425 sec.key_sizes[key] = 13;
426 sec.flags |= (1 << key);
427 }
428
429 /* No key data - just set the default TX key index */
430 if (key_provided) {
431 IEEE80211_DEBUG_WX(
432 "Setting key %d to default Tx key.\n", key);
433 ieee->tx_keyidx = key;
434 sec.active_key = key;
435 sec.flags |= SEC_ACTIVE_KEY;
436 }
437 }
438
439 done:
440 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
441 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
442 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
443 sec.flags |= SEC_AUTH_MODE;
444 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
445 "OPEN" : "SHARED KEY");
446
447 /* For now we just support WEP, so only set that security level...
448 * TODO: When WPA is added this is one place that needs to change */
449 sec.flags |= SEC_LEVEL;
450 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
451
452 if (ieee->set_security)
453 ieee->set_security(dev, &sec);
454
455 /* Do not reset port if card is in Managed mode since resetting will
456 * generate new IEEE 802.11 authentication which may end up in looping
457 * with IEEE 802.1X. If your hardware requires a reset after WEP
458 * configuration (for example... Prism2), implement the reset_port in
459 * the callbacks structures used to initialize the 802.11 stack. */
460 if (ieee->reset_on_keychange &&
461 ieee->iw_mode != IW_MODE_INFRA &&
462 ieee->reset_port && ieee->reset_port(dev)) {
463 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
464 return -EINVAL;
465 }
466 return 0;
467}
468
469int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
470 struct iw_request_info *info,
471 union iwreq_data *wrqu, char *keybuf)
472{
473 struct iw_point *erq = &(wrqu->encoding);
474 int len, key;
475 struct ieee80211_crypt_data *crypt;
476
477 IEEE80211_DEBUG_WX("GET_ENCODE\n");
478
479 if(ieee->iw_mode == IW_MODE_MONITOR)
480 return -1;
481
482 key = erq->flags & IW_ENCODE_INDEX;
483 if (key) {
484 if (key > WEP_KEYS)
485 return -EINVAL;
486 key--;
487 } else
488 key = ieee->tx_keyidx;
489
490 crypt = ieee->crypt[key];
491 erq->flags = key + 1;
492
493 if (crypt == NULL || crypt->ops == NULL) {
494 erq->length = 0;
495 erq->flags |= IW_ENCODE_DISABLED;
496 return 0;
497 }
498#if 0
499 if (strcmp(crypt->ops->name, "WEP") != 0) {
500 /* only WEP is supported with wireless extensions, so just
501 * report that encryption is used */
502 erq->length = 0;
503 erq->flags |= IW_ENCODE_ENABLED;
504 return 0;
505 }
506#endif
507 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
508 erq->length = (len >= 0 ? len : 0);
509
510 erq->flags |= IW_ENCODE_ENABLED;
511
512 if (ieee->open_wep)
513 erq->flags |= IW_ENCODE_OPEN;
514 else
515 erq->flags |= IW_ENCODE_RESTRICTED;
516
517 return 0;
518}
Bartlomiej Zolnierkiewicz3bd709f2009-06-13 18:35:58 +0200519
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700520int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
521 struct iw_request_info *info,
522 union iwreq_data *wrqu, char *extra)
523{
524 int ret = 0;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700525 struct net_device *dev = ieee->dev;
526 struct iw_point *encoding = &wrqu->encoding;
527 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
528 int i, idx;
529 int group_key = 0;
530 const char *alg, *module;
531 struct ieee80211_crypto_ops *ops;
532 struct ieee80211_crypt_data **crypt;
533
534 struct ieee80211_security sec = {
535 .flags = 0,
536 };
537 //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
538 idx = encoding->flags & IW_ENCODE_INDEX;
539 if (idx) {
540 if (idx < 1 || idx > WEP_KEYS)
541 return -EINVAL;
542 idx--;
543 } else
544 idx = ieee->tx_keyidx;
545
546 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
547
548 crypt = &ieee->crypt[idx];
549
550 group_key = 1;
551 } else {
552 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
553 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
554 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
555 return -EINVAL;
556 if (ieee->iw_mode == IW_MODE_INFRA)
557
558 crypt = &ieee->crypt[idx];
559
560 else
561 return -EINVAL;
562 }
563
564 sec.flags |= SEC_ENABLED;// | SEC_ENCRYPT;
565 if ((encoding->flags & IW_ENCODE_DISABLED) ||
566 ext->alg == IW_ENCODE_ALG_NONE) {
567 if (*crypt)
568 ieee80211_crypt_delayed_deinit(ieee, crypt);
569
570 for (i = 0; i < WEP_KEYS; i++)
571
572 if (ieee->crypt[i] != NULL)
573
574 break;
575
576 if (i == WEP_KEYS) {
577 sec.enabled = 0;
578 // sec.encrypt = 0;
579 sec.level = SEC_LEVEL_0;
580 sec.flags |= SEC_LEVEL;
581 }
582 //printk("disabled: flag:%x\n", encoding->flags);
583 goto done;
584 }
585
586 sec.enabled = 1;
587 // sec.encrypt = 1;
588#if 0
589 if (group_key ? !ieee->host_mc_decrypt :
590 !(ieee->host_encrypt || ieee->host_decrypt ||
591 ieee->host_encrypt_msdu))
592 goto skip_host_crypt;
593#endif
594 switch (ext->alg) {
595 case IW_ENCODE_ALG_WEP:
596 alg = "WEP";
597 module = "ieee80211_crypt_wep";
598 break;
599 case IW_ENCODE_ALG_TKIP:
600 alg = "TKIP";
601 module = "ieee80211_crypt_tkip";
602 break;
603 case IW_ENCODE_ALG_CCMP:
604 alg = "CCMP";
605 module = "ieee80211_crypt_ccmp";
606 break;
607 default:
608 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
609 dev->name, ext->alg);
610 ret = -EINVAL;
611 goto done;
612 }
613 printk("alg name:%s\n",alg);
614
615 ops = ieee80211_get_crypto_ops(alg);
616 if (ops == NULL) {
Greg Kroah-Hartman36dbd402009-06-04 11:29:54 -0700617 request_module("%s", module);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700618 ops = ieee80211_get_crypto_ops(alg);
619 }
620 if (ops == NULL) {
621 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
622 dev->name, ext->alg);
623 printk("========>unknown crypto alg %d\n", ext->alg);
624 ret = -EINVAL;
625 goto done;
626 }
627
628 if (*crypt == NULL || (*crypt)->ops != ops) {
629 struct ieee80211_crypt_data *new_crypt;
630
631 ieee80211_crypt_delayed_deinit(ieee, crypt);
632
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700633 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700634 if (new_crypt == NULL) {
635 ret = -ENOMEM;
636 goto done;
637 }
638 new_crypt->ops = ops;
639 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
640 new_crypt->priv = new_crypt->ops->init(idx);
641 if (new_crypt->priv == NULL) {
642 kfree(new_crypt);
643 ret = -EINVAL;
644 goto done;
645 }
646 *crypt = new_crypt;
647
648 }
649
650 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
651 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
652 (*crypt)->priv) < 0) {
653 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
654 printk("key setting failed\n");
655 ret = -EINVAL;
656 goto done;
657 }
658#if 1
659 //skip_host_crypt:
660 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
661 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
662 ieee->tx_keyidx = idx;
663 sec.active_key = idx;
664 sec.flags |= SEC_ACTIVE_KEY;
665 }
666
667 if (ext->alg != IW_ENCODE_ALG_NONE) {
668 //memcpy(sec.keys[idx], ext->key, ext->key_len);
669 sec.key_sizes[idx] = ext->key_len;
670 sec.flags |= (1 << idx);
671 if (ext->alg == IW_ENCODE_ALG_WEP) {
672 // sec.encode_alg[idx] = SEC_ALG_WEP;
673 sec.flags |= SEC_LEVEL;
674 sec.level = SEC_LEVEL_1;
675 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
676 // sec.encode_alg[idx] = SEC_ALG_TKIP;
677 sec.flags |= SEC_LEVEL;
678 sec.level = SEC_LEVEL_2;
679 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
680 // sec.encode_alg[idx] = SEC_ALG_CCMP;
681 sec.flags |= SEC_LEVEL;
682 sec.level = SEC_LEVEL_3;
683 }
684 /* Don't set sec level for group keys. */
685 if (group_key)
686 sec.flags &= ~SEC_LEVEL;
687 }
688#endif
689done:
690 if (ieee->set_security)
691 ieee->set_security(ieee->dev, &sec);
692
693 if (ieee->reset_on_keychange &&
694 ieee->iw_mode != IW_MODE_INFRA &&
695 ieee->reset_port && ieee->reset_port(dev)) {
696 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
697 return -EINVAL;
698 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200699
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700700 return ret;
701}
702
703int ieee80211_wx_get_encode_ext(struct ieee80211_device *ieee,
704 struct iw_request_info *info,
705 union iwreq_data *wrqu, char *extra)
706{
707 struct iw_point *encoding = &wrqu->encoding;
708 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
709 struct ieee80211_crypt_data *crypt;
710 int idx, max_key_len;
711
712 max_key_len = encoding->length - sizeof(*ext);
713 if (max_key_len < 0)
714 return -EINVAL;
715
716 idx = encoding->flags & IW_ENCODE_INDEX;
717 if (idx) {
718 if (idx < 1 || idx > WEP_KEYS)
719 return -EINVAL;
720 idx--;
721 } else
722 idx = ieee->tx_keyidx;
723
Julia Lawall38526982009-06-05 17:07:38 +0200724 if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) &&
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700725 ext->alg != IW_ENCODE_ALG_WEP)
726 if (idx != 0 || ieee->iw_mode != IW_MODE_INFRA)
727 return -EINVAL;
728
729 crypt = ieee->crypt[idx];
730 encoding->flags = idx + 1;
731 memset(ext, 0, sizeof(*ext));
732
733 if (crypt == NULL || crypt->ops == NULL ) {
734 ext->alg = IW_ENCODE_ALG_NONE;
735 ext->key_len = 0;
736 encoding->flags |= IW_ENCODE_DISABLED;
737 } else {
738 if (strcmp(crypt->ops->name, "WEP") == 0 )
739 ext->alg = IW_ENCODE_ALG_WEP;
740 else if (strcmp(crypt->ops->name, "TKIP"))
741 ext->alg = IW_ENCODE_ALG_TKIP;
742 else if (strcmp(crypt->ops->name, "CCMP"))
743 ext->alg = IW_ENCODE_ALG_CCMP;
744 else
745 return -EINVAL;
746 ext->key_len = crypt->ops->get_key(ext->key, SCM_KEY_LEN, NULL, crypt->priv);
747 encoding->flags |= IW_ENCODE_ENABLED;
748 if (ext->key_len &&
749 (ext->alg == IW_ENCODE_ALG_TKIP ||
750 ext->alg == IW_ENCODE_ALG_CCMP))
751 ext->ext_flags |= IW_ENCODE_EXT_TX_SEQ_VALID;
752
753 }
754
755 return 0;
756}
757
758int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
759 struct iw_request_info *info,
760 union iwreq_data *wrqu, char *extra)
761{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700762 struct iw_mlme *mlme = (struct iw_mlme *) extra;
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200763
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700764 switch (mlme->cmd) {
765 case IW_MLME_DEAUTH:
766 case IW_MLME_DISASSOC:
767 ieee80211_disassociate(ieee);
768 break;
769 default:
770 return -EOPNOTSUPP;
771 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200772
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700773 return 0;
774}
775
776int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
777 struct iw_request_info *info,
778 struct iw_param *data, char *extra)
779{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700780 switch (data->flags & IW_AUTH_INDEX) {
781 case IW_AUTH_WPA_VERSION:
782 /*need to support wpa2 here*/
783 //printk("wpa version:%x\n", data->value);
784 break;
785 case IW_AUTH_CIPHER_PAIRWISE:
786 case IW_AUTH_CIPHER_GROUP:
787 case IW_AUTH_KEY_MGMT:
788 /*
789 * * Host AP driver does not use these parameters and allows
790 * * wpa_supplicant to control them internally.
791 * */
792 break;
793 case IW_AUTH_TKIP_COUNTERMEASURES:
794 ieee->tkip_countermeasures = data->value;
795 break;
796 case IW_AUTH_DROP_UNENCRYPTED:
797 ieee->drop_unencrypted = data->value;
798 break;
799
800 case IW_AUTH_80211_AUTH_ALG:
801 //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
802 // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
803 if(data->value & IW_AUTH_ALG_SHARED_KEY){
804 ieee->open_wep = 0;
805 ieee->auth_mode = 1;
806 }
807 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
808 ieee->open_wep = 1;
809 ieee->auth_mode = 0;
810 }
811 else if(data->value & IW_AUTH_ALG_LEAP){
812 ieee->open_wep = 1;
813 ieee->auth_mode = 2;
814 //printk("hahahaa:LEAP\n");
815 }
816 else
817 return -EINVAL;
818 //printk("open_wep:%d\n", ieee->open_wep);
819 break;
820
821#if 1
822 case IW_AUTH_WPA_ENABLED:
823 ieee->wpa_enabled = (data->value)?1:0;
824 //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
825 break;
826
827#endif
828 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
829 ieee->ieee802_1x = data->value;
830 break;
831 case IW_AUTH_PRIVACY_INVOKED:
832 ieee->privacy_invoked = data->value;
833 break;
834 default:
835 return -EOPNOTSUPP;
836 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200837
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700838 return 0;
839}
Bartlomiej Zolnierkiewicz3bd709f2009-06-13 18:35:58 +0200840
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700841#if 1
842int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
843{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700844#if 0
845 printk("====>%s()\n", __FUNCTION__);
846 {
847 int i;
848 for (i=0; i<len; i++)
849 printk("%2x ", ie[i]&0xff);
850 printk("\n");
851 }
852#endif
853 u8 *buf;
854
855 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
856 {
857 // printk("return error out, len:%d\n", len);
858 return -EINVAL;
859 }
860
861
862 if (len)
863 {
864 if (len != ie[1]+2)
865 {
866 printk("len:%d, ie:%d\n", len, ie[1]);
867 return -EINVAL;
868 }
869 buf = kmalloc(len, GFP_KERNEL);
870 if (buf == NULL)
871 return -ENOMEM;
872 memcpy(buf, ie, len);
873 kfree(ieee->wpa_ie);
874 ieee->wpa_ie = buf;
875 ieee->wpa_ie_len = len;
876 }
877 else{
878 if (ieee->wpa_ie)
879 kfree(ieee->wpa_ie);
880 ieee->wpa_ie = NULL;
881 ieee->wpa_ie_len = 0;
882 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200883
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700884 return 0;
885
886}
887#endif
888
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700889EXPORT_SYMBOL(ieee80211_wx_set_gen_ie);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700890EXPORT_SYMBOL(ieee80211_wx_set_mlme);
891EXPORT_SYMBOL(ieee80211_wx_set_auth);
892EXPORT_SYMBOL(ieee80211_wx_set_encode_ext);
893EXPORT_SYMBOL(ieee80211_wx_get_encode_ext);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700894EXPORT_SYMBOL(ieee80211_wx_get_scan);
895EXPORT_SYMBOL(ieee80211_wx_set_encode);
896EXPORT_SYMBOL(ieee80211_wx_get_encode);