[wireless] build fixes after merging WE-19
[deliverable/linux.git] / net / ieee80211 / ieee80211_wx.c
CommitLineData
b453872c
JG
1/******************************************************************************
2
3 Copyright(c) 2004 Intel Corporation. All rights reserved.
4
5 Portions of this file are based on the WEP enablement code provided by the
6 Host AP project hostap-drivers v0.1.3
7 Copyright (c) 2001-2002, SSH Communications Security Corp and Jouni Malinen
8 <jkmaline@cc.hut.fi>
9 Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
10
11 This program is free software; you can redistribute it and/or modify it
12 under the terms of version 2 of the GNU General Public License as
13 published by the Free Software Foundation.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 more details.
19
20 You should have received a copy of the GNU General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59
22 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 The full GNU General Public License is included in this distribution in the
25 file called LICENSE.
26
27 Contact Information:
28 James P. Ketrenos <ipw2100-admin@linux.intel.com>
29 Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30
31******************************************************************************/
bbeec90b 32
b453872c
JG
33#include <linux/kmod.h>
34#include <linux/module.h>
35
36#include <net/ieee80211.h>
bbeec90b
JG
37#include <linux/wireless.h>
38
b453872c
JG
39static const char *ieee80211_modes[] = {
40 "?", "a", "b", "ab", "g", "ag", "bg", "abg"
41};
42
43#define MAX_CUSTOM_LEN 64
44static inline char *ipw2100_translate_scan(struct ieee80211_device *ieee,
45 char *start, char *stop,
46 struct ieee80211_network *network)
47{
48 char custom[MAX_CUSTOM_LEN];
49 char *p;
50 struct iw_event iwe;
51 int i, j;
52 u8 max_rate, rate;
53
54 /* First entry *MUST* be the AP MAC address */
55 iwe.cmd = SIOCGIWAP;
56 iwe.u.ap_addr.sa_family = ARPHRD_ETHER;
57 memcpy(iwe.u.ap_addr.sa_data, network->bssid, ETH_ALEN);
58 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_ADDR_LEN);
59
60 /* Remaining entries will be displayed in the order we provide them */
61
62 /* Add the ESSID */
63 iwe.cmd = SIOCGIWESSID;
64 iwe.u.data.flags = 1;
65 if (network->flags & NETWORK_EMPTY_ESSID) {
66 iwe.u.data.length = sizeof("<hidden>");
67 start = iwe_stream_add_point(start, stop, &iwe, "<hidden>");
68 } else {
69 iwe.u.data.length = min(network->ssid_len, (u8)32);
70 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
71 }
72
73 /* Add the protocol name */
74 iwe.cmd = SIOCGIWNAME;
75 snprintf(iwe.u.name, IFNAMSIZ, "IEEE 802.11%s", ieee80211_modes[network->mode]);
76 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_CHAR_LEN);
77
78 /* Add mode */
79 iwe.cmd = SIOCGIWMODE;
80 if (network->capability &
1b5cca3a
JG
81 (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)) {
82 if (network->capability & WLAN_CAPABILITY_ESS)
b453872c
JG
83 iwe.u.mode = IW_MODE_MASTER;
84 else
85 iwe.u.mode = IW_MODE_ADHOC;
86
87 start = iwe_stream_add_event(start, stop, &iwe,
88 IW_EV_UINT_LEN);
89 }
90
91 /* Add frequency/channel */
92 iwe.cmd = SIOCGIWFREQ;
93/* iwe.u.freq.m = ieee80211_frequency(network->channel, network->mode);
94 iwe.u.freq.e = 3; */
95 iwe.u.freq.m = network->channel;
96 iwe.u.freq.e = 0;
97 iwe.u.freq.i = 0;
98 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_FREQ_LEN);
99
100 /* Add encryption capability */
101 iwe.cmd = SIOCGIWENCODE;
102 if (network->capability & WLAN_CAPABILITY_PRIVACY)
103 iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY;
104 else
105 iwe.u.data.flags = IW_ENCODE_DISABLED;
106 iwe.u.data.length = 0;
107 start = iwe_stream_add_point(start, stop, &iwe, network->ssid);
108
109 /* Add basic and extended rates */
110 max_rate = 0;
111 p = custom;
112 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom), " Rates (Mb/s): ");
113 for (i = 0, j = 0; i < network->rates_len; ) {
114 if (j < network->rates_ex_len &&
115 ((network->rates_ex[j] & 0x7F) <
116 (network->rates[i] & 0x7F)))
117 rate = network->rates_ex[j++] & 0x7F;
118 else
119 rate = network->rates[i++] & 0x7F;
120 if (rate > max_rate)
121 max_rate = rate;
122 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
123 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
124 }
125 for (; j < network->rates_ex_len; j++) {
126 rate = network->rates_ex[j] & 0x7F;
127 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
128 "%d%s ", rate >> 1, (rate & 1) ? ".5" : "");
129 if (rate > max_rate)
130 max_rate = rate;
131 }
132
133 iwe.cmd = SIOCGIWRATE;
134 iwe.u.bitrate.fixed = iwe.u.bitrate.disabled = 0;
135 iwe.u.bitrate.value = max_rate * 500000;
136 start = iwe_stream_add_event(start, stop, &iwe,
137 IW_EV_PARAM_LEN);
138
139 iwe.cmd = IWEVCUSTOM;
140 iwe.u.data.length = p - custom;
141 if (iwe.u.data.length)
142 start = iwe_stream_add_point(start, stop, &iwe, custom);
143
144 /* Add quality statistics */
145 /* TODO: Fix these values... */
146 iwe.cmd = IWEVQUAL;
147 iwe.u.qual.qual = network->stats.signal;
148 iwe.u.qual.level = network->stats.rssi;
149 iwe.u.qual.noise = network->stats.noise;
150 iwe.u.qual.updated = network->stats.mask & IEEE80211_STATMASK_WEMASK;
151 if (!(network->stats.mask & IEEE80211_STATMASK_RSSI))
152 iwe.u.qual.updated |= IW_QUAL_LEVEL_INVALID;
153 if (!(network->stats.mask & IEEE80211_STATMASK_NOISE))
154 iwe.u.qual.updated |= IW_QUAL_NOISE_INVALID;
155 if (!(network->stats.mask & IEEE80211_STATMASK_SIGNAL))
156 iwe.u.qual.updated |= IW_QUAL_QUAL_INVALID;
157
158 start = iwe_stream_add_event(start, stop, &iwe, IW_EV_QUAL_LEN);
159
160 iwe.cmd = IWEVCUSTOM;
161 p = custom;
162
163 iwe.u.data.length = p - custom;
164 if (iwe.u.data.length)
165 start = iwe_stream_add_point(start, stop, &iwe, custom);
166
167 if (ieee->wpa_enabled && network->wpa_ie_len){
168 char buf[MAX_WPA_IE_LEN * 2 + 30];
169
170 u8 *p = buf;
171 p += sprintf(p, "wpa_ie=");
172 for (i = 0; i < network->wpa_ie_len; i++) {
173 p += sprintf(p, "%02x", network->wpa_ie[i]);
174 }
175
176 memset(&iwe, 0, sizeof(iwe));
177 iwe.cmd = IWEVCUSTOM;
178 iwe.u.data.length = strlen(buf);
179 start = iwe_stream_add_point(start, stop, &iwe, buf);
180 }
181
182 if (ieee->wpa_enabled && network->rsn_ie_len){
183 char buf[MAX_WPA_IE_LEN * 2 + 30];
184
185 u8 *p = buf;
186 p += sprintf(p, "rsn_ie=");
187 for (i = 0; i < network->rsn_ie_len; i++) {
188 p += sprintf(p, "%02x", network->rsn_ie[i]);
189 }
190
191 memset(&iwe, 0, sizeof(iwe));
192 iwe.cmd = IWEVCUSTOM;
193 iwe.u.data.length = strlen(buf);
194 start = iwe_stream_add_point(start, stop, &iwe, buf);
195 }
196
197 /* Add EXTRA: Age to display seconds since last beacon/probe response
198 * for given network. */
199 iwe.cmd = IWEVCUSTOM;
200 p = custom;
201 p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
202 " Last beacon: %lums ago", (jiffies - network->last_scanned) / (HZ / 100));
203 iwe.u.data.length = p - custom;
204 if (iwe.u.data.length)
205 start = iwe_stream_add_point(start, stop, &iwe, custom);
206
207
208 return start;
209}
210
211int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
212 struct iw_request_info *info,
213 union iwreq_data *wrqu, char *extra)
214{
215 struct ieee80211_network *network;
216 unsigned long flags;
217
218 char *ev = extra;
219 char *stop = ev + IW_SCAN_MAX_DATA;
220 int i = 0;
221
222 IEEE80211_DEBUG_WX("Getting scan\n");
223
224 spin_lock_irqsave(&ieee->lock, flags);
225
226 list_for_each_entry(network, &ieee->network_list, list) {
227 i++;
228 if (ieee->scan_age == 0 ||
229 time_after(network->last_scanned + ieee->scan_age, jiffies))
230 ev = ipw2100_translate_scan(ieee, ev, stop, network);
231 else
232 IEEE80211_DEBUG_SCAN(
233 "Not showing network '%s ("
234 MAC_FMT ")' due to age (%lums).\n",
235 escape_essid(network->ssid,
236 network->ssid_len),
237 MAC_ARG(network->bssid),
238 (jiffies - network->last_scanned) / (HZ / 100));
239 }
240
241 spin_unlock_irqrestore(&ieee->lock, flags);
242
243 wrqu->data.length = ev - extra;
244 wrqu->data.flags = 0;
245
246 IEEE80211_DEBUG_WX("exit: %d networks returned.\n", i);
247
248 return 0;
249}
250
251int ieee80211_wx_set_encode(struct ieee80211_device *ieee,
252 struct iw_request_info *info,
253 union iwreq_data *wrqu, char *keybuf)
254{
255 struct iw_point *erq = &(wrqu->encoding);
256 struct net_device *dev = ieee->dev;
257 struct ieee80211_security sec = {
258 .flags = 0
259 };
260 int i, key, key_provided, len;
261 struct ieee80211_crypt_data **crypt;
262
263 IEEE80211_DEBUG_WX("SET_ENCODE\n");
264
265 key = erq->flags & IW_ENCODE_INDEX;
266 if (key) {
267 if (key > WEP_KEYS)
268 return -EINVAL;
269 key--;
270 key_provided = 1;
271 } else {
272 key_provided = 0;
273 key = ieee->tx_keyidx;
274 }
275
276 IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ?
277 "provided" : "default");
278
279 crypt = &ieee->crypt[key];
280
281 if (erq->flags & IW_ENCODE_DISABLED) {
282 if (key_provided && *crypt) {
283 IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n",
284 key);
285 ieee80211_crypt_delayed_deinit(ieee, crypt);
286 } else
287 IEEE80211_DEBUG_WX("Disabling encryption.\n");
288
289 /* Check all the keys to see if any are still configured,
290 * and if no key index was provided, de-init them all */
291 for (i = 0; i < WEP_KEYS; i++) {
292 if (ieee->crypt[i] != NULL) {
293 if (key_provided)
294 break;
295 ieee80211_crypt_delayed_deinit(
296 ieee, &ieee->crypt[i]);
297 }
298 }
299
300 if (i == WEP_KEYS) {
301 sec.enabled = 0;
302 sec.level = SEC_LEVEL_0;
303 sec.flags |= SEC_ENABLED | SEC_LEVEL;
304 }
305
306 goto done;
307 }
308
309
310
311 sec.enabled = 1;
312 sec.flags |= SEC_ENABLED;
313
314 if (*crypt != NULL && (*crypt)->ops != NULL &&
315 strcmp((*crypt)->ops->name, "WEP") != 0) {
316 /* changing to use WEP; deinit previously used algorithm
317 * on this key */
318 ieee80211_crypt_delayed_deinit(ieee, crypt);
319 }
320
321 if (*crypt == NULL) {
322 struct ieee80211_crypt_data *new_crypt;
323
324 /* take WEP into use */
325 new_crypt = kmalloc(sizeof(struct ieee80211_crypt_data),
326 GFP_KERNEL);
327 if (new_crypt == NULL)
328 return -ENOMEM;
329 memset(new_crypt, 0, sizeof(struct ieee80211_crypt_data));
330 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
331 if (!new_crypt->ops) {
332 request_module("ieee80211_crypt_wep");
333 new_crypt->ops = ieee80211_get_crypto_ops("WEP");
334 }
335
336 if (new_crypt->ops && try_module_get(new_crypt->ops->owner))
337 new_crypt->priv = new_crypt->ops->init(key);
338
339 if (!new_crypt->ops || !new_crypt->priv) {
340 kfree(new_crypt);
341 new_crypt = NULL;
342
343 printk(KERN_WARNING "%s: could not initialize WEP: "
344 "load module ieee80211_crypt_wep\n",
345 dev->name);
346 return -EOPNOTSUPP;
347 }
348 *crypt = new_crypt;
349 }
350
351 /* If a new key was provided, set it up */
352 if (erq->length > 0) {
353 len = erq->length <= 5 ? 5 : 13;
354 memcpy(sec.keys[key], keybuf, erq->length);
355 if (len > erq->length)
356 memset(sec.keys[key] + erq->length, 0,
357 len - erq->length);
358 IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n",
359 key, escape_essid(sec.keys[key], len),
360 erq->length, len);
361 sec.key_sizes[key] = len;
362 (*crypt)->ops->set_key(sec.keys[key], len, NULL,
363 (*crypt)->priv);
364 sec.flags |= (1 << key);
365 /* This ensures a key will be activated if no key is
366 * explicitely set */
367 if (key == sec.active_key)
368 sec.flags |= SEC_ACTIVE_KEY;
369 } else {
370 len = (*crypt)->ops->get_key(sec.keys[key], WEP_KEY_LEN,
371 NULL, (*crypt)->priv);
372 if (len == 0) {
373 /* Set a default key of all 0 */
374 IEEE80211_DEBUG_WX("Setting key %d to all zero.\n",
375 key);
376 memset(sec.keys[key], 0, 13);
377 (*crypt)->ops->set_key(sec.keys[key], 13, NULL,
378 (*crypt)->priv);
379 sec.key_sizes[key] = 13;
380 sec.flags |= (1 << key);
381 }
382
383 /* No key data - just set the default TX key index */
384 if (key_provided) {
385 IEEE80211_DEBUG_WX(
386 "Setting key %d to default Tx key.\n", key);
387 ieee->tx_keyidx = key;
388 sec.active_key = key;
389 sec.flags |= SEC_ACTIVE_KEY;
390 }
391 }
392
393 done:
394 ieee->open_wep = !(erq->flags & IW_ENCODE_RESTRICTED);
395 sec.auth_mode = ieee->open_wep ? WLAN_AUTH_OPEN : WLAN_AUTH_SHARED_KEY;
396 sec.flags |= SEC_AUTH_MODE;
397 IEEE80211_DEBUG_WX("Auth: %s\n", sec.auth_mode == WLAN_AUTH_OPEN ?
398 "OPEN" : "SHARED KEY");
399
400 /* For now we just support WEP, so only set that security level...
401 * TODO: When WPA is added this is one place that needs to change */
402 sec.flags |= SEC_LEVEL;
403 sec.level = SEC_LEVEL_1; /* 40 and 104 bit WEP */
404
405 if (ieee->set_security)
406 ieee->set_security(dev, &sec);
407
408 /* Do not reset port if card is in Managed mode since resetting will
409 * generate new IEEE 802.11 authentication which may end up in looping
410 * with IEEE 802.1X. If your hardware requires a reset after WEP
411 * configuration (for example... Prism2), implement the reset_port in
412 * the callbacks structures used to initialize the 802.11 stack. */
413 if (ieee->reset_on_keychange &&
414 ieee->iw_mode != IW_MODE_INFRA &&
415 ieee->reset_port && ieee->reset_port(dev)) {
416 printk(KERN_DEBUG "%s: reset_port failed\n", dev->name);
417 return -EINVAL;
418 }
419 return 0;
420}
421
422int ieee80211_wx_get_encode(struct ieee80211_device *ieee,
423 struct iw_request_info *info,
424 union iwreq_data *wrqu, char *keybuf)
425{
426 struct iw_point *erq = &(wrqu->encoding);
427 int len, key;
428 struct ieee80211_crypt_data *crypt;
429
430 IEEE80211_DEBUG_WX("GET_ENCODE\n");
431
432 key = erq->flags & IW_ENCODE_INDEX;
433 if (key) {
434 if (key > WEP_KEYS)
435 return -EINVAL;
436 key--;
437 } else
438 key = ieee->tx_keyidx;
439
440 crypt = ieee->crypt[key];
441 erq->flags = key + 1;
442
443 if (crypt == NULL || crypt->ops == NULL) {
444 erq->length = 0;
445 erq->flags |= IW_ENCODE_DISABLED;
446 return 0;
447 }
448
449 if (strcmp(crypt->ops->name, "WEP") != 0) {
450 /* only WEP is supported with wireless extensions, so just
451 * report that encryption is used */
452 erq->length = 0;
453 erq->flags |= IW_ENCODE_ENABLED;
454 return 0;
455 }
456
457 len = crypt->ops->get_key(keybuf, WEP_KEY_LEN, NULL, crypt->priv);
458 erq->length = (len >= 0 ? len : 0);
459
460 erq->flags |= IW_ENCODE_ENABLED;
461
462 if (ieee->open_wep)
463 erq->flags |= IW_ENCODE_OPEN;
464 else
465 erq->flags |= IW_ENCODE_RESTRICTED;
466
467 return 0;
468}
469
470EXPORT_SYMBOL(ieee80211_wx_get_scan);
471EXPORT_SYMBOL(ieee80211_wx_set_encode);
472EXPORT_SYMBOL(ieee80211_wx_get_encode);
This page took 0.048298 seconds and 5 git commands to generate.