blob: 10775902433540e063de4e5370555e078232a9a1 [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;
Stoyan Gaydarovb6ac1612009-07-21 22:02:27 -050090 for(i=0; i<ARRAY_SIZE(ieee80211_modes); i++) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070091 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
Bartlomiej Zolnierkiewiczf59d0122009-07-13 20:14:34 +0200544 sec.flags |= SEC_ENABLED;
545
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700546 if ((encoding->flags & IW_ENCODE_DISABLED) ||
547 ext->alg == IW_ENCODE_ALG_NONE) {
548 if (*crypt)
549 ieee80211_crypt_delayed_deinit(ieee, crypt);
550
551 for (i = 0; i < WEP_KEYS; i++)
552
553 if (ieee->crypt[i] != NULL)
554
555 break;
556
557 if (i == WEP_KEYS) {
558 sec.enabled = 0;
559 // sec.encrypt = 0;
560 sec.level = SEC_LEVEL_0;
561 sec.flags |= SEC_LEVEL;
562 }
563 //printk("disabled: flag:%x\n", encoding->flags);
564 goto done;
565 }
566
567 sec.enabled = 1;
568 // sec.encrypt = 1;
Bartlomiej Zolnierkiewicz35c1b462009-07-03 16:08:32 +0200569
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700570 switch (ext->alg) {
571 case IW_ENCODE_ALG_WEP:
572 alg = "WEP";
573 module = "ieee80211_crypt_wep";
574 break;
575 case IW_ENCODE_ALG_TKIP:
576 alg = "TKIP";
577 module = "ieee80211_crypt_tkip";
578 break;
579 case IW_ENCODE_ALG_CCMP:
580 alg = "CCMP";
581 module = "ieee80211_crypt_ccmp";
582 break;
583 default:
584 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
585 dev->name, ext->alg);
586 ret = -EINVAL;
587 goto done;
588 }
589 printk("alg name:%s\n",alg);
590
591 ops = ieee80211_get_crypto_ops(alg);
592 if (ops == NULL) {
Greg Kroah-Hartman36dbd402009-06-04 11:29:54 -0700593 request_module("%s", module);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700594 ops = ieee80211_get_crypto_ops(alg);
595 }
596 if (ops == NULL) {
597 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
598 dev->name, ext->alg);
599 printk("========>unknown crypto alg %d\n", ext->alg);
600 ret = -EINVAL;
601 goto done;
602 }
603
604 if (*crypt == NULL || (*crypt)->ops != ops) {
605 struct ieee80211_crypt_data *new_crypt;
606
607 ieee80211_crypt_delayed_deinit(ieee, crypt);
608
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700609 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700610 if (new_crypt == NULL) {
611 ret = -ENOMEM;
612 goto done;
613 }
614 new_crypt->ops = ops;
615 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
616 new_crypt->priv = new_crypt->ops->init(idx);
617 if (new_crypt->priv == NULL) {
618 kfree(new_crypt);
619 ret = -EINVAL;
620 goto done;
621 }
622 *crypt = new_crypt;
623
624 }
625
626 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
627 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
628 (*crypt)->priv) < 0) {
629 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
630 printk("key setting failed\n");
631 ret = -EINVAL;
632 goto done;
633 }
634#if 1
635 //skip_host_crypt:
636 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
637 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
638 ieee->tx_keyidx = idx;
639 sec.active_key = idx;
640 sec.flags |= SEC_ACTIVE_KEY;
641 }
642
643 if (ext->alg != IW_ENCODE_ALG_NONE) {
644 //memcpy(sec.keys[idx], ext->key, ext->key_len);
645 sec.key_sizes[idx] = ext->key_len;
646 sec.flags |= (1 << idx);
647 if (ext->alg == IW_ENCODE_ALG_WEP) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700648 sec.flags |= SEC_LEVEL;
649 sec.level = SEC_LEVEL_1;
650 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700651 sec.flags |= SEC_LEVEL;
652 sec.level = SEC_LEVEL_2;
653 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700654 sec.flags |= SEC_LEVEL;
655 sec.level = SEC_LEVEL_3;
656 }
657 /* Don't set sec level for group keys. */
658 if (group_key)
659 sec.flags &= ~SEC_LEVEL;
660 }
661#endif
662done:
663 if (ieee->set_security)
664 ieee->set_security(ieee->dev, &sec);
665
666 if (ieee->reset_on_keychange &&
667 ieee->iw_mode != IW_MODE_INFRA &&
668 ieee->reset_port && ieee->reset_port(dev)) {
669 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
670 return -EINVAL;
671 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200672
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700673 return ret;
674}
675
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700676int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
677 struct iw_request_info *info,
678 union iwreq_data *wrqu, char *extra)
679{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700680 struct iw_mlme *mlme = (struct iw_mlme *) extra;
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200681
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700682 switch (mlme->cmd) {
683 case IW_MLME_DEAUTH:
684 case IW_MLME_DISASSOC:
685 ieee80211_disassociate(ieee);
686 break;
687 default:
688 return -EOPNOTSUPP;
689 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200690
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700691 return 0;
692}
693
694int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
695 struct iw_request_info *info,
696 struct iw_param *data, char *extra)
697{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700698 switch (data->flags & IW_AUTH_INDEX) {
699 case IW_AUTH_WPA_VERSION:
700 /*need to support wpa2 here*/
701 //printk("wpa version:%x\n", data->value);
702 break;
703 case IW_AUTH_CIPHER_PAIRWISE:
704 case IW_AUTH_CIPHER_GROUP:
705 case IW_AUTH_KEY_MGMT:
706 /*
707 * * Host AP driver does not use these parameters and allows
708 * * wpa_supplicant to control them internally.
709 * */
710 break;
711 case IW_AUTH_TKIP_COUNTERMEASURES:
712 ieee->tkip_countermeasures = data->value;
713 break;
714 case IW_AUTH_DROP_UNENCRYPTED:
715 ieee->drop_unencrypted = data->value;
716 break;
717
718 case IW_AUTH_80211_AUTH_ALG:
719 //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
720 // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
721 if(data->value & IW_AUTH_ALG_SHARED_KEY){
722 ieee->open_wep = 0;
723 ieee->auth_mode = 1;
724 }
725 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
726 ieee->open_wep = 1;
727 ieee->auth_mode = 0;
728 }
729 else if(data->value & IW_AUTH_ALG_LEAP){
730 ieee->open_wep = 1;
731 ieee->auth_mode = 2;
732 //printk("hahahaa:LEAP\n");
733 }
734 else
735 return -EINVAL;
736 //printk("open_wep:%d\n", ieee->open_wep);
737 break;
738
739#if 1
740 case IW_AUTH_WPA_ENABLED:
741 ieee->wpa_enabled = (data->value)?1:0;
742 //printk("enalbe wpa:%d\n", ieee->wpa_enabled);
743 break;
744
745#endif
746 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
747 ieee->ieee802_1x = data->value;
748 break;
749 case IW_AUTH_PRIVACY_INVOKED:
750 ieee->privacy_invoked = data->value;
751 break;
752 default:
753 return -EOPNOTSUPP;
754 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200755
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700756 return 0;
757}
Bartlomiej Zolnierkiewicz3bd709f2009-06-13 18:35:58 +0200758
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700759#if 1
760int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
761{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700762 u8 *buf;
763
764 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
765 {
766 // printk("return error out, len:%d\n", len);
767 return -EINVAL;
768 }
769
770
771 if (len)
772 {
773 if (len != ie[1]+2)
774 {
Jeff Mahoney859ebd92009-08-04 10:26:20 -0400775 printk("len: %Zd, ie:%d\n", len, ie[1]);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700776 return -EINVAL;
777 }
778 buf = kmalloc(len, GFP_KERNEL);
779 if (buf == NULL)
780 return -ENOMEM;
781 memcpy(buf, ie, len);
782 kfree(ieee->wpa_ie);
783 ieee->wpa_ie = buf;
784 ieee->wpa_ie_len = len;
785 }
786 else{
787 if (ieee->wpa_ie)
788 kfree(ieee->wpa_ie);
789 ieee->wpa_ie = NULL;
790 ieee->wpa_ie_len = 0;
791 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200792
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700793 return 0;
794
795}
796#endif