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