blob: 727cc552c5eef4e93d65b226ade2bbd8836125e6 [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>
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070033#include <linux/kmod.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090034#include <linux/slab.h>
Jerry Chuang5f53d8c2009-05-21 22:16:02 -070035#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 ("
Joe Perches0ee9f672009-12-06 11:34:52 -0800265 "%pM)' due to age (%lums).\n",
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700266 escape_essid(network->ssid,
267 network->ssid_len),
Joe Perches0ee9f672009-12-06 11:34:52 -0800268 network->bssid,
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700269 (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");
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -0300361 if (!new_crypt->ops)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700362 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -0300363 if (new_crypt->ops)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700364 new_crypt->priv = new_crypt->ops->init(key);
365
366 if (!new_crypt->ops || !new_crypt->priv) {
367 kfree(new_crypt);
368 new_crypt = NULL;
369
370 printk(KERN_WARNING "%s: could not initialize WEP: "
371 "load module ieee80211_crypt_wep\n",
372 dev->name);
373 return -EOPNOTSUPP;
374 }
375 *crypt = new_crypt;
376 }
377
378 /* If a new key was provided, set it up */
379 if (erq->length > 0) {
380 len = erq->length <= 5 ? 5 : 13;
381 memcpy(sec.keys[key], keybuf, erq->length);
382 if (len > erq->length)
383 memset(sec.keys[key] + erq->length, 0,
384 len - erq->length);
385 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
386 key, escape_essid(sec.keys[key], len),
387 erq->length, len);
388 sec.key_sizes[key] = len;
389 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
390 (*crypt)->priv);
391 sec.flags |= (1 << key);
392 /* This ensures a key will be activated if no key is
393 * explicitely set */
394 if (key == sec.active_key)
395 sec.flags |= SEC_ACTIVE_KEY;
396 ieee->tx_keyidx = key;
397
398 } else {
399 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
400 NULL, (*crypt)->priv);
401 if (len == 0) {
402 /* Set a default key of all 0 */
403 printk("Setting key %d to all zero.\n",
404 key);
405
406 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
407 key);
408 memset(sec.keys[key], 0, 13);
409 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
410 (*crypt)->priv);
411 sec.key_sizes[key] = 13;
412 sec.flags |= (1 << key);
413 }
414
415 /* No key data - just set the default TX key index */
416 if (key_provided) {
417 IEEE80211_DEBUG_WX(
418 "Setting key %d to default Tx key.\n", key);
419 ieee->tx_keyidx = key;
420 sec.active_key = key;
421 sec.flags |= SEC_ACTIVE_KEY;
422 }
423 }
424
425 done:
426 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
427 ieee->auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
428 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
429 sec.flags |= SEC_AUTH_MODE;
430 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
431 "OPEN" : "SHARED KEY");
432
433 /* For now we just support WEP, so only set that security level...
434 * TODO: When WPA is added this is one place that needs to change */
435 sec.flags |= SEC_LEVEL;
436 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
437
438 if (ieee->set_security)
439 ieee->set_security(dev, &sec);
440
441 /* Do not reset port if card is in Managed mode since resetting will
442 * generate new IEEE 802.11 authentication which may end up in looping
443 * with IEEE 802.1X. If your hardware requires a reset after WEP
444 * configuration (for example... Prism2), implement the reset_port in
445 * the callbacks structures used to initialize the 802.11 stack. */
446 if (ieee->reset_on_keychange &&
447 ieee->iw_mode != IW_MODE_INFRA &&
448 ieee->reset_port && ieee->reset_port(dev)) {
449 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
450 return -EINVAL;
451 }
452 return 0;
453}
454
455int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
456 struct iw_request_info *info,
457 union iwreq_data *wrqu, char *keybuf)
458{
459 struct iw_point *erq = &(wrqu->encoding);
460 int len, key;
461 struct ieee80211_crypt_data *crypt;
462
463 IEEE80211_DEBUG_WX("GET_ENCODE\n");
464
465 if(ieee->iw_mode == IW_MODE_MONITOR)
466 return -1;
467
468 key = erq->flags & IW_ENCODE_INDEX;
469 if (key) {
470 if (key > WEP_KEYS)
471 return -EINVAL;
472 key--;
473 } else
474 key = ieee->tx_keyidx;
475
476 crypt = ieee->crypt[key];
477 erq->flags = key + 1;
478
479 if (crypt == NULL || crypt->ops == NULL) {
480 erq->length = 0;
481 erq->flags |= IW_ENCODE_DISABLED;
482 return 0;
483 }
Bartlomiej Zolnierkiewicz35c1b462009-07-03 16:08:32 +0200484
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700485 len = crypt->ops->get_key(keybuf, SCM_KEY_LEN, NULL, crypt->priv);
486 erq->length = (len >= 0 ? len : 0);
487
488 erq->flags |= IW_ENCODE_ENABLED;
489
490 if (ieee->open_wep)
491 erq->flags |= IW_ENCODE_OPEN;
492 else
493 erq->flags |= IW_ENCODE_RESTRICTED;
494
495 return 0;
496}
Bartlomiej Zolnierkiewicz3bd709f2009-06-13 18:35:58 +0200497
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700498int ieee80211_wx_set_encode_ext(struct ieee80211_device *ieee,
499 struct iw_request_info *info,
500 union iwreq_data *wrqu, char *extra)
501{
502 int ret = 0;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700503 struct net_device *dev = ieee->dev;
504 struct iw_point *encoding = &wrqu->encoding;
505 struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
506 int i, idx;
507 int group_key = 0;
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -0300508 const char *alg;
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700509 struct ieee80211_crypto_ops *ops;
510 struct ieee80211_crypt_data **crypt;
511
512 struct ieee80211_security sec = {
513 .flags = 0,
514 };
515 //printk("======>encoding flag:%x,ext flag:%x, ext alg:%d\n", encoding->flags,ext->ext_flags, ext->alg);
516 idx = encoding->flags & IW_ENCODE_INDEX;
517 if (idx) {
518 if (idx < 1 || idx > WEP_KEYS)
519 return -EINVAL;
520 idx--;
521 } else
522 idx = ieee->tx_keyidx;
523
524 if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) {
525
526 crypt = &ieee->crypt[idx];
527
528 group_key = 1;
529 } else {
530 /* some Cisco APs use idx>0 for unicast in dynamic WEP */
531 //printk("not group key, flags:%x, ext->alg:%d\n", ext->ext_flags, ext->alg);
532 if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP)
533 return -EINVAL;
534 if (ieee->iw_mode == IW_MODE_INFRA)
535
536 crypt = &ieee->crypt[idx];
537
538 else
539 return -EINVAL;
540 }
541
Bartlomiej Zolnierkiewiczf59d0122009-07-13 20:14:34 +0200542 sec.flags |= SEC_ENABLED;
543
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700544 if ((encoding->flags & IW_ENCODE_DISABLED) ||
545 ext->alg == IW_ENCODE_ALG_NONE) {
546 if (*crypt)
547 ieee80211_crypt_delayed_deinit(ieee, crypt);
548
549 for (i = 0; i < WEP_KEYS; i++)
550
551 if (ieee->crypt[i] != NULL)
552
553 break;
554
555 if (i == WEP_KEYS) {
556 sec.enabled = 0;
557 // sec.encrypt = 0;
558 sec.level = SEC_LEVEL_0;
559 sec.flags |= SEC_LEVEL;
560 }
561 //printk("disabled: flag:%x\n", encoding->flags);
562 goto done;
563 }
564
565 sec.enabled = 1;
566 // sec.encrypt = 1;
Bartlomiej Zolnierkiewicz35c1b462009-07-03 16:08:32 +0200567
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700568 switch (ext->alg) {
569 case IW_ENCODE_ALG_WEP:
570 alg = "WEP";
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700571 break;
572 case IW_ENCODE_ALG_TKIP:
573 alg = "TKIP";
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700574 break;
575 case IW_ENCODE_ALG_CCMP:
576 alg = "CCMP";
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700577 break;
578 default:
579 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
580 dev->name, ext->alg);
581 ret = -EINVAL;
582 goto done;
583 }
584 printk("alg name:%s\n",alg);
585
586 ops = ieee80211_get_crypto_ops(alg);
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -0300587 if (ops == NULL)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700588 ops = ieee80211_get_crypto_ops(alg);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700589 if (ops == NULL) {
590 IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n",
591 dev->name, ext->alg);
592 printk("========>unknown crypto alg %d\n", ext->alg);
593 ret = -EINVAL;
594 goto done;
595 }
596
597 if (*crypt == NULL || (*crypt)->ops != ops) {
598 struct ieee80211_crypt_data *new_crypt;
599
600 ieee80211_crypt_delayed_deinit(ieee, crypt);
601
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700602 new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700603 if (new_crypt == NULL) {
604 ret = -ENOMEM;
605 goto done;
606 }
607 new_crypt->ops = ops;
Herton Ronaldo Krzesinskia010a332009-10-02 11:03:38 -0300608 if (new_crypt->ops)
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700609 new_crypt->priv = new_crypt->ops->init(idx);
610 if (new_crypt->priv == NULL) {
611 kfree(new_crypt);
612 ret = -EINVAL;
613 goto done;
614 }
615 *crypt = new_crypt;
616
617 }
618
619 if (ext->key_len > 0 && (*crypt)->ops->set_key &&
620 (*crypt)->ops->set_key(ext->key, ext->key_len, ext->rx_seq,
621 (*crypt)->priv) < 0) {
622 IEEE80211_DEBUG_WX("%s: key setting failed\n", dev->name);
623 printk("key setting failed\n");
624 ret = -EINVAL;
625 goto done;
626 }
627#if 1
628 //skip_host_crypt:
629 //printk("skip_host_crypt:ext_flags:%x\n", ext->ext_flags);
630 if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) {
631 ieee->tx_keyidx = idx;
632 sec.active_key = idx;
633 sec.flags |= SEC_ACTIVE_KEY;
634 }
635
636 if (ext->alg != IW_ENCODE_ALG_NONE) {
637 //memcpy(sec.keys[idx], ext->key, ext->key_len);
638 sec.key_sizes[idx] = ext->key_len;
639 sec.flags |= (1 << idx);
640 if (ext->alg == IW_ENCODE_ALG_WEP) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700641 sec.flags |= SEC_LEVEL;
642 sec.level = SEC_LEVEL_1;
643 } else if (ext->alg == IW_ENCODE_ALG_TKIP) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700644 sec.flags |= SEC_LEVEL;
645 sec.level = SEC_LEVEL_2;
646 } else if (ext->alg == IW_ENCODE_ALG_CCMP) {
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700647 sec.flags |= SEC_LEVEL;
648 sec.level = SEC_LEVEL_3;
649 }
650 /* Don't set sec level for group keys. */
651 if (group_key)
652 sec.flags &= ~SEC_LEVEL;
653 }
654#endif
655done:
656 if (ieee->set_security)
657 ieee->set_security(ieee->dev, &sec);
658
659 if (ieee->reset_on_keychange &&
660 ieee->iw_mode != IW_MODE_INFRA &&
661 ieee->reset_port && ieee->reset_port(dev)) {
662 IEEE80211_DEBUG_WX("%s: reset_port failed\n", dev->name);
663 return -EINVAL;
664 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200665
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700666 return ret;
667}
668
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700669int ieee80211_wx_set_mlme(struct ieee80211_device *ieee,
670 struct iw_request_info *info,
671 union iwreq_data *wrqu, char *extra)
672{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700673 struct iw_mlme *mlme = (struct iw_mlme *) extra;
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200674
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700675 switch (mlme->cmd) {
676 case IW_MLME_DEAUTH:
677 case IW_MLME_DISASSOC:
678 ieee80211_disassociate(ieee);
679 break;
680 default:
681 return -EOPNOTSUPP;
682 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200683
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700684 return 0;
685}
686
687int ieee80211_wx_set_auth(struct ieee80211_device *ieee,
688 struct iw_request_info *info,
689 struct iw_param *data, char *extra)
690{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700691 switch (data->flags & IW_AUTH_INDEX) {
692 case IW_AUTH_WPA_VERSION:
693 /*need to support wpa2 here*/
694 //printk("wpa version:%x\n", data->value);
695 break;
696 case IW_AUTH_CIPHER_PAIRWISE:
697 case IW_AUTH_CIPHER_GROUP:
698 case IW_AUTH_KEY_MGMT:
699 /*
700 * * Host AP driver does not use these parameters and allows
701 * * wpa_supplicant to control them internally.
702 * */
703 break;
704 case IW_AUTH_TKIP_COUNTERMEASURES:
705 ieee->tkip_countermeasures = data->value;
706 break;
707 case IW_AUTH_DROP_UNENCRYPTED:
708 ieee->drop_unencrypted = data->value;
709 break;
710
711 case IW_AUTH_80211_AUTH_ALG:
712 //printk("======>%s():data->value is %d\n",__FUNCTION__,data->value);
713 // ieee->open_wep = (data->value&IW_AUTH_ALG_OPEN_SYSTEM)?1:0;
714 if(data->value & IW_AUTH_ALG_SHARED_KEY){
715 ieee->open_wep = 0;
716 ieee->auth_mode = 1;
717 }
718 else if(data->value & IW_AUTH_ALG_OPEN_SYSTEM){
719 ieee->open_wep = 1;
720 ieee->auth_mode = 0;
721 }
722 else if(data->value & IW_AUTH_ALG_LEAP){
723 ieee->open_wep = 1;
724 ieee->auth_mode = 2;
725 //printk("hahahaa:LEAP\n");
726 }
727 else
728 return -EINVAL;
729 //printk("open_wep:%d\n", ieee->open_wep);
730 break;
731
732#if 1
733 case IW_AUTH_WPA_ENABLED:
734 ieee->wpa_enabled = (data->value)?1:0;
Uwe Kleine-König18326642010-01-12 15:57:56 +0100735 //printk("enable wpa:%d\n", ieee->wpa_enabled);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700736 break;
737
738#endif
739 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
740 ieee->ieee802_1x = data->value;
741 break;
742 case IW_AUTH_PRIVACY_INVOKED:
743 ieee->privacy_invoked = data->value;
744 break;
745 default:
746 return -EOPNOTSUPP;
747 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200748
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700749 return 0;
750}
Bartlomiej Zolnierkiewicz3bd709f2009-06-13 18:35:58 +0200751
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700752#if 1
753int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len)
754{
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700755 u8 *buf;
756
757 if (len>MAX_WPA_IE_LEN || (len && ie == NULL))
758 {
759 // printk("return error out, len:%d\n", len);
760 return -EINVAL;
761 }
762
763
764 if (len)
765 {
766 if (len != ie[1]+2)
767 {
Jeff Mahoney859ebd92009-08-04 10:26:20 -0400768 printk("len: %Zd, ie:%d\n", len, ie[1]);
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700769 return -EINVAL;
770 }
771 buf = kmalloc(len, GFP_KERNEL);
772 if (buf == NULL)
773 return -ENOMEM;
774 memcpy(buf, ie, len);
775 kfree(ieee->wpa_ie);
776 ieee->wpa_ie = buf;
777 ieee->wpa_ie_len = len;
778 }
779 else{
780 if (ieee->wpa_ie)
781 kfree(ieee->wpa_ie);
782 ieee->wpa_ie = NULL;
783 ieee->wpa_ie_len = 0;
784 }
Bartlomiej Zolnierkiewicz1ec9e482009-06-13 18:35:04 +0200785
Jerry Chuang5f53d8c2009-05-21 22:16:02 -0700786 return 0;
787
788}
789#endif