blob: ea2e0f958ac39298ff1ac7987f4eadb86365b535 [file] [log] [blame]
Jiri Bencf0706e82007-05-05 11:45:53 -07001/*
2 * Copyright 2002-2005, Instant802 Networks, Inc.
3 * Copyright 2005-2006, Devicescape Software, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 */
9
10#include <linux/module.h>
11#include <linux/init.h>
12#include <linux/netdevice.h>
13#include <linux/types.h>
14#include <linux/slab.h>
15#include <linux/skbuff.h>
16#include <linux/etherdevice.h>
17#include <linux/if_arp.h>
18#include <linux/wireless.h>
19#include <net/iw_handler.h>
20#include <asm/uaccess.h>
21
22#include <net/mac80211.h>
23#include "ieee80211_i.h"
24#include "hostapd_ioctl.h"
25#include "ieee80211_rate.h"
26#include "wpa.h"
27#include "aes_ccm.h"
Jiri Bence9f207f2007-05-05 11:46:38 -070028#include "debugfs_key.h"
Jiri Bencf0706e82007-05-05 11:45:53 -070029
Jiri Bencf0706e82007-05-05 11:45:53 -070030static void ieee80211_set_hw_encryption(struct net_device *dev,
31 struct sta_info *sta, u8 addr[ETH_ALEN],
32 struct ieee80211_key *key)
33{
34 struct ieee80211_key_conf *keyconf = NULL;
35 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
36
37 /* default to sw encryption; this will be cleared by low-level
38 * driver if the hw supports requested encryption */
39 if (key)
40 key->force_sw_encrypt = 1;
41
42 if (key && local->ops->set_key &&
43 (keyconf = ieee80211_key_data2conf(local, key))) {
44 if (local->ops->set_key(local_to_hw(local), SET_KEY, addr,
45 keyconf, sta ? sta->aid : 0)) {
46 key->force_sw_encrypt = 1;
47 key->hw_key_idx = HW_KEY_IDX_INVALID;
48 } else {
49 key->force_sw_encrypt =
50 !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
51 key->hw_key_idx =
52 keyconf->hw_key_idx;
53
54 }
55 }
56 kfree(keyconf);
57}
58
59
60static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
61 int idx, int alg, int set_tx_key,
62 const u8 *_key, size_t key_len)
63{
64 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
65 int ret = 0;
66 struct sta_info *sta;
67 struct ieee80211_key *key, *old_key;
68 int try_hwaccel = 1;
69 struct ieee80211_key_conf *keyconf;
70 struct ieee80211_sub_if_data *sdata;
71
72 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
73
74 if (is_broadcast_ether_addr(sta_addr)) {
75 sta = NULL;
76 if (idx >= NUM_DEFAULT_KEYS) {
77 printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
78 dev->name, idx);
79 return -EINVAL;
80 }
81 key = sdata->keys[idx];
82
83 /* TODO: consider adding hwaccel support for these; at least
84 * Atheros key cache should be able to handle this since AP is
85 * only transmitting frames with default keys. */
86 /* FIX: hw key cache can be used when only one virtual
87 * STA is associated with each AP. If more than one STA
88 * is associated to the same AP, software encryption
89 * must be used. This should be done automatically
90 * based on configured station devices. For the time
91 * being, this can be only set at compile time. */
92 } else {
93 set_tx_key = 0;
94 if (idx != 0) {
95 printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
96 "individual key\n", dev->name);
97 return -EINVAL;
98 }
99
100 sta = sta_info_get(local, sta_addr);
101 if (!sta) {
102#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
103 printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
104 MAC_FMT "\n",
105 dev->name, MAC_ARG(sta_addr));
106#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
107
108 return -ENOENT;
109 }
110
111 key = sta->key;
112 }
113
114 /* FIX:
115 * Cannot configure default hwaccel keys with WEP algorithm, if
116 * any of the virtual interfaces is using static WEP
117 * configuration because hwaccel would otherwise try to decrypt
118 * these frames.
119 *
120 * For now, just disable WEP hwaccel for broadcast when there is
121 * possibility of conflict with default keys. This can maybe later be
122 * optimized by using non-default keys (at least with Atheros ar521x).
123 */
124 if (!sta && alg == ALG_WEP && !local->default_wep_only &&
125 sdata->type != IEEE80211_IF_TYPE_IBSS &&
126 sdata->type != IEEE80211_IF_TYPE_AP) {
127 try_hwaccel = 0;
128 }
129
130 if (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) {
131 /* Software encryption cannot be used with devices that hide
132 * encryption from the host system, so always try to use
133 * hardware acceleration with such devices. */
134 try_hwaccel = 1;
135 }
136
137 if ((local->hw.flags & IEEE80211_HW_NO_TKIP_WMM_HWACCEL) &&
138 alg == ALG_TKIP) {
139 if (sta && (sta->flags & WLAN_STA_WME)) {
140 /* Hardware does not support hwaccel with TKIP when using WMM.
141 */
142 try_hwaccel = 0;
143 }
144 else if (sdata->type == IEEE80211_IF_TYPE_STA) {
145 sta = sta_info_get(local, sdata->u.sta.bssid);
146 if (sta) {
147 if (sta->flags & WLAN_STA_WME) {
148 try_hwaccel = 0;
149 }
150 sta_info_put(sta);
151 sta = NULL;
152 }
153 }
154 }
155
156 if (alg == ALG_NONE) {
157 keyconf = NULL;
158 if (try_hwaccel && key &&
159 key->hw_key_idx != HW_KEY_IDX_INVALID &&
160 local->ops->set_key &&
161 (keyconf = ieee80211_key_data2conf(local, key)) != NULL &&
162 local->ops->set_key(local_to_hw(local), DISABLE_KEY,
163 sta_addr, keyconf, sta ? sta->aid : 0)) {
164 printk(KERN_DEBUG "%s: set_encrypt - low-level disable"
165 " failed\n", dev->name);
166 ret = -EINVAL;
167 }
168 kfree(keyconf);
169
Jiri Bence9f207f2007-05-05 11:46:38 -0700170 if (set_tx_key || sdata->default_key == key) {
171 ieee80211_debugfs_key_remove_default(sdata);
Jiri Bencf0706e82007-05-05 11:45:53 -0700172 sdata->default_key = NULL;
Jiri Bence9f207f2007-05-05 11:46:38 -0700173 }
174 ieee80211_debugfs_key_remove(key);
Jiri Bencf0706e82007-05-05 11:45:53 -0700175 if (sta)
176 sta->key = NULL;
177 else
178 sdata->keys[idx] = NULL;
179 ieee80211_key_free(key);
180 key = NULL;
181 } else {
182 old_key = key;
183 key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len,
184 GFP_KERNEL);
185 if (!key) {
186 ret = -ENOMEM;
187 goto err_out;
188 }
189
190 /* default to sw encryption; low-level driver sets these if the
191 * requested encryption is supported */
192 key->hw_key_idx = HW_KEY_IDX_INVALID;
193 key->force_sw_encrypt = 1;
194
195 key->alg = alg;
196 key->keyidx = idx;
197 key->keylen = key_len;
198 memcpy(key->key, _key, key_len);
199 if (set_tx_key)
200 key->default_tx_key = 1;
201
202 if (alg == ALG_CCMP) {
203 /* Initialize AES key state here as an optimization
204 * so that it does not need to be initialized for every
205 * packet. */
206 key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
207 key->key);
208 if (!key->u.ccmp.tfm) {
209 ret = -ENOMEM;
210 goto err_free;
211 }
212 }
213
Jiri Bence9f207f2007-05-05 11:46:38 -0700214 if (set_tx_key || sdata->default_key == old_key) {
215 ieee80211_debugfs_key_remove_default(sdata);
Jiri Bencf0706e82007-05-05 11:45:53 -0700216 sdata->default_key = NULL;
Jiri Bence9f207f2007-05-05 11:46:38 -0700217 }
218 ieee80211_debugfs_key_remove(old_key);
Jiri Bencf0706e82007-05-05 11:45:53 -0700219 if (sta)
220 sta->key = key;
221 else
222 sdata->keys[idx] = key;
223 ieee80211_key_free(old_key);
Jiri Bence9f207f2007-05-05 11:46:38 -0700224 ieee80211_debugfs_key_add(local, key);
225 if (sta)
226 ieee80211_debugfs_key_sta_link(key, sta);
Jiri Bencf0706e82007-05-05 11:45:53 -0700227
228 if (try_hwaccel &&
229 (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP))
230 ieee80211_set_hw_encryption(dev, sta, sta_addr, key);
231 }
232
233 if (set_tx_key || (!sta && !sdata->default_key && key)) {
234 sdata->default_key = key;
Jiri Bence9f207f2007-05-05 11:46:38 -0700235 if (key)
236 ieee80211_debugfs_key_add_default(sdata);
Jiri Bencf0706e82007-05-05 11:45:53 -0700237
238 if (local->ops->set_key_idx &&
239 local->ops->set_key_idx(local_to_hw(local), idx))
240 printk(KERN_DEBUG "%s: failed to set TX key idx for "
241 "low-level driver\n", dev->name);
242 }
243
244 if (sta)
245 sta_info_put(sta);
246
247 return 0;
248
249err_free:
250 ieee80211_key_free(key);
251err_out:
252 if (sta)
253 sta_info_put(sta);
254 return ret;
255}
256
257static int ieee80211_ioctl_siwgenie(struct net_device *dev,
258 struct iw_request_info *info,
259 struct iw_point *data, char *extra)
260{
261 struct ieee80211_sub_if_data *sdata;
262 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
263
264 if (local->user_space_mlme)
265 return -EOPNOTSUPP;
266
267 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
268 if (sdata->type == IEEE80211_IF_TYPE_STA ||
269 sdata->type == IEEE80211_IF_TYPE_IBSS) {
270 int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
271 if (ret)
272 return ret;
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400273 sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
Jiri Bencf0706e82007-05-05 11:45:53 -0700274 ieee80211_sta_req_auth(dev, &sdata->u.sta);
275 return 0;
276 }
277
278 if (sdata->type == IEEE80211_IF_TYPE_AP) {
279 kfree(sdata->u.ap.generic_elem);
280 sdata->u.ap.generic_elem = kmalloc(data->length, GFP_KERNEL);
281 if (!sdata->u.ap.generic_elem)
282 return -ENOMEM;
283 memcpy(sdata->u.ap.generic_elem, extra, data->length);
284 sdata->u.ap.generic_elem_len = data->length;
285 return ieee80211_if_config(dev);
286 }
287 return -EOPNOTSUPP;
288}
289
Jiri Bencf0706e82007-05-05 11:45:53 -0700290static int ieee80211_ioctl_giwname(struct net_device *dev,
291 struct iw_request_info *info,
292 char *name, char *extra)
293{
294 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
295
296 switch (local->hw.conf.phymode) {
297 case MODE_IEEE80211A:
298 strcpy(name, "IEEE 802.11a");
299 break;
300 case MODE_IEEE80211B:
301 strcpy(name, "IEEE 802.11b");
302 break;
303 case MODE_IEEE80211G:
304 strcpy(name, "IEEE 802.11g");
305 break;
306 case MODE_ATHEROS_TURBO:
307 strcpy(name, "5GHz Turbo");
308 break;
309 default:
310 strcpy(name, "IEEE 802.11");
311 break;
312 }
313
314 return 0;
315}
316
317
318static int ieee80211_ioctl_giwrange(struct net_device *dev,
319 struct iw_request_info *info,
320 struct iw_point *data, char *extra)
321{
322 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
323 struct iw_range *range = (struct iw_range *) extra;
Hong Liu333af2f2007-07-10 19:32:08 +0200324 struct ieee80211_hw_mode *mode = NULL;
325 int c = 0;
Jiri Bencf0706e82007-05-05 11:45:53 -0700326
327 data->length = sizeof(struct iw_range);
328 memset(range, 0, sizeof(struct iw_range));
329
330 range->we_version_compiled = WIRELESS_EXT;
331 range->we_version_source = 21;
332 range->retry_capa = IW_RETRY_LIMIT;
333 range->retry_flags = IW_RETRY_LIMIT;
334 range->min_retry = 0;
335 range->max_retry = 255;
336 range->min_rts = 0;
337 range->max_rts = 2347;
338 range->min_frag = 256;
339 range->max_frag = 2346;
340
341 range->encoding_size[0] = 5;
342 range->encoding_size[1] = 13;
343 range->num_encoding_sizes = 2;
344 range->max_encoding_tokens = NUM_DEFAULT_KEYS;
345
346 range->max_qual.qual = local->hw.max_signal;
347 range->max_qual.level = local->hw.max_rssi;
348 range->max_qual.noise = local->hw.max_noise;
349 range->max_qual.updated = local->wstats_flags;
350
351 range->avg_qual.qual = local->hw.max_signal/2;
352 range->avg_qual.level = 0;
353 range->avg_qual.noise = 0;
354 range->avg_qual.updated = local->wstats_flags;
355
356 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
357 IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
358
Hong Liu333af2f2007-07-10 19:32:08 +0200359 list_for_each_entry(mode, &local->modes_list, list) {
360 int i = 0;
361
362 if (!(local->enabled_modes & (1 << mode->mode)) ||
363 (local->hw_modes & local->enabled_modes &
364 (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
365 continue;
366
367 while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
368 struct ieee80211_channel *chan = &mode->channels[i];
369
370 if (chan->flag & IEEE80211_CHAN_W_SCAN) {
371 range->freq[c].i = chan->chan;
372 range->freq[c].m = chan->freq * 100000;
373 range->freq[c].e = 1;
374 c++;
375 }
376 i++;
377 }
378 }
379 range->num_channels = c;
380 range->num_frequency = c;
381
Jiri Bencf0706e82007-05-05 11:45:53 -0700382 IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
383 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
384 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
385 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
386
387 return 0;
388}
389
390
Jiri Bencf0706e82007-05-05 11:45:53 -0700391static int ieee80211_ioctl_siwmode(struct net_device *dev,
392 struct iw_request_info *info,
393 __u32 *mode, char *extra)
394{
395 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
396 int type;
397
398 if (sdata->type == IEEE80211_IF_TYPE_VLAN)
399 return -EOPNOTSUPP;
400
401 switch (*mode) {
402 case IW_MODE_INFRA:
403 type = IEEE80211_IF_TYPE_STA;
404 break;
405 case IW_MODE_ADHOC:
406 type = IEEE80211_IF_TYPE_IBSS;
407 break;
408 case IW_MODE_MONITOR:
409 type = IEEE80211_IF_TYPE_MNTR;
410 break;
411 default:
412 return -EINVAL;
413 }
414
415 if (type == sdata->type)
416 return 0;
417 if (netif_running(dev))
418 return -EBUSY;
419
420 ieee80211_if_reinit(dev);
421 ieee80211_if_set_type(dev, type);
422
423 return 0;
424}
425
426
427static int ieee80211_ioctl_giwmode(struct net_device *dev,
428 struct iw_request_info *info,
429 __u32 *mode, char *extra)
430{
431 struct ieee80211_sub_if_data *sdata;
432
433 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
434 switch (sdata->type) {
435 case IEEE80211_IF_TYPE_AP:
436 *mode = IW_MODE_MASTER;
437 break;
438 case IEEE80211_IF_TYPE_STA:
439 *mode = IW_MODE_INFRA;
440 break;
441 case IEEE80211_IF_TYPE_IBSS:
442 *mode = IW_MODE_ADHOC;
443 break;
444 case IEEE80211_IF_TYPE_MNTR:
445 *mode = IW_MODE_MONITOR;
446 break;
447 case IEEE80211_IF_TYPE_WDS:
448 *mode = IW_MODE_REPEAT;
449 break;
450 case IEEE80211_IF_TYPE_VLAN:
451 *mode = IW_MODE_SECOND; /* FIXME */
452 break;
453 default:
454 *mode = IW_MODE_AUTO;
455 break;
456 }
457 return 0;
458}
459
460int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
461{
462 struct ieee80211_hw_mode *mode;
463 int c, set = 0;
464 int ret = -EINVAL;
465
466 list_for_each_entry(mode, &local->modes_list, list) {
467 if (!(local->enabled_modes & (1 << mode->mode)))
468 continue;
469 for (c = 0; c < mode->num_channels; c++) {
470 struct ieee80211_channel *chan = &mode->channels[c];
471 if (chan->flag & IEEE80211_CHAN_W_SCAN &&
472 ((chan->chan == channel) || (chan->freq == freq))) {
473 /* Use next_mode as the mode preference to
474 * resolve non-unique channel numbers. */
475 if (set && mode->mode != local->next_mode)
476 continue;
477
478 local->oper_channel = chan;
479 local->oper_hw_mode = mode;
480 set++;
481 }
482 }
483 }
484
485 if (set) {
486 if (local->sta_scanning)
487 ret = 0;
488 else
489 ret = ieee80211_hw_config(local);
490
491 rate_control_clear(local);
492 }
493
494 return ret;
495}
496
497static int ieee80211_ioctl_siwfreq(struct net_device *dev,
498 struct iw_request_info *info,
499 struct iw_freq *freq, char *extra)
500{
501 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
502 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
503
504 if (sdata->type == IEEE80211_IF_TYPE_STA)
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400505 sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
Jiri Bencf0706e82007-05-05 11:45:53 -0700506
507 /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
508 if (freq->e == 0) {
509 if (freq->m < 0) {
510 if (sdata->type == IEEE80211_IF_TYPE_STA)
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400511 sdata->u.sta.flags |=
512 IEEE80211_STA_AUTO_CHANNEL_SEL;
Jiri Bencf0706e82007-05-05 11:45:53 -0700513 return 0;
514 } else
515 return ieee80211_set_channel(local, freq->m, -1);
516 } else {
517 int i, div = 1000000;
518 for (i = 0; i < freq->e; i++)
519 div /= 10;
520 if (div > 0)
521 return ieee80211_set_channel(local, -1, freq->m / div);
522 else
523 return -EINVAL;
524 }
525}
526
527
528static int ieee80211_ioctl_giwfreq(struct net_device *dev,
529 struct iw_request_info *info,
530 struct iw_freq *freq, char *extra)
531{
532 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
533
534 /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
535 * driver for the current channel with firmware-based management */
536
537 freq->m = local->hw.conf.freq;
538 freq->e = 6;
539
540 return 0;
541}
542
543
544static int ieee80211_ioctl_siwessid(struct net_device *dev,
545 struct iw_request_info *info,
546 struct iw_point *data, char *ssid)
547{
548 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
549 struct ieee80211_sub_if_data *sdata;
550 size_t len = data->length;
551
552 /* iwconfig uses nul termination in SSID.. */
553 if (len > 0 && ssid[len - 1] == '\0')
554 len--;
555
556 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
557 if (sdata->type == IEEE80211_IF_TYPE_STA ||
558 sdata->type == IEEE80211_IF_TYPE_IBSS) {
559 int ret;
560 if (local->user_space_mlme) {
561 if (len > IEEE80211_MAX_SSID_LEN)
562 return -EINVAL;
563 memcpy(sdata->u.sta.ssid, ssid, len);
564 sdata->u.sta.ssid_len = len;
565 return 0;
566 }
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400567 if (data->flags)
568 sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
569 else
570 sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL;
Jiri Bencf0706e82007-05-05 11:45:53 -0700571 ret = ieee80211_sta_set_ssid(dev, ssid, len);
572 if (ret)
573 return ret;
574 ieee80211_sta_req_auth(dev, &sdata->u.sta);
575 return 0;
576 }
577
578 if (sdata->type == IEEE80211_IF_TYPE_AP) {
579 memcpy(sdata->u.ap.ssid, ssid, len);
580 memset(sdata->u.ap.ssid + len, 0,
581 IEEE80211_MAX_SSID_LEN - len);
582 sdata->u.ap.ssid_len = len;
583 return ieee80211_if_config(dev);
584 }
585 return -EOPNOTSUPP;
586}
587
588
589static int ieee80211_ioctl_giwessid(struct net_device *dev,
590 struct iw_request_info *info,
591 struct iw_point *data, char *ssid)
592{
593 size_t len;
594
595 struct ieee80211_sub_if_data *sdata;
596 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
597 if (sdata->type == IEEE80211_IF_TYPE_STA ||
598 sdata->type == IEEE80211_IF_TYPE_IBSS) {
599 int res = ieee80211_sta_get_ssid(dev, ssid, &len);
600 if (res == 0) {
601 data->length = len;
602 data->flags = 1;
603 } else
604 data->flags = 0;
605 return res;
606 }
607
608 if (sdata->type == IEEE80211_IF_TYPE_AP) {
609 len = sdata->u.ap.ssid_len;
610 if (len > IW_ESSID_MAX_SIZE)
611 len = IW_ESSID_MAX_SIZE;
612 memcpy(ssid, sdata->u.ap.ssid, len);
613 data->length = len;
614 data->flags = 1;
615 return 0;
616 }
617 return -EOPNOTSUPP;
618}
619
620
621static int ieee80211_ioctl_siwap(struct net_device *dev,
622 struct iw_request_info *info,
623 struct sockaddr *ap_addr, char *extra)
624{
625 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
626 struct ieee80211_sub_if_data *sdata;
627
628 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
629 if (sdata->type == IEEE80211_IF_TYPE_STA ||
630 sdata->type == IEEE80211_IF_TYPE_IBSS) {
631 int ret;
632 if (local->user_space_mlme) {
633 memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
634 ETH_ALEN);
635 return 0;
636 }
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400637 if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
638 sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
639 IEEE80211_STA_AUTO_CHANNEL_SEL;
640 else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
641 sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
Jiri Bencf0706e82007-05-05 11:45:53 -0700642 else
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400643 sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
Jiri Bencf0706e82007-05-05 11:45:53 -0700644 ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
645 if (ret)
646 return ret;
647 ieee80211_sta_req_auth(dev, &sdata->u.sta);
648 return 0;
649 } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
650 if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
651 ETH_ALEN) == 0)
652 return 0;
653 return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data);
654 }
655
656 return -EOPNOTSUPP;
657}
658
659
660static int ieee80211_ioctl_giwap(struct net_device *dev,
661 struct iw_request_info *info,
662 struct sockaddr *ap_addr, char *extra)
663{
664 struct ieee80211_sub_if_data *sdata;
665
666 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
667 if (sdata->type == IEEE80211_IF_TYPE_STA ||
668 sdata->type == IEEE80211_IF_TYPE_IBSS) {
669 ap_addr->sa_family = ARPHRD_ETHER;
670 memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
671 return 0;
672 } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
673 ap_addr->sa_family = ARPHRD_ETHER;
674 memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
675 return 0;
676 }
677
678 return -EOPNOTSUPP;
679}
680
681
682static int ieee80211_ioctl_siwscan(struct net_device *dev,
683 struct iw_request_info *info,
684 struct iw_point *data, char *extra)
685{
686 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
687 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
688 u8 *ssid = NULL;
689 size_t ssid_len = 0;
690
691 if (!netif_running(dev))
692 return -ENETDOWN;
693
Daniel Drakef27b62d2007-07-27 15:43:24 +0200694 switch (sdata->type) {
695 case IEEE80211_IF_TYPE_STA:
696 case IEEE80211_IF_TYPE_IBSS:
697 if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
Jiri Bencf0706e82007-05-05 11:45:53 -0700698 ssid = sdata->u.sta.ssid;
699 ssid_len = sdata->u.sta.ssid_len;
Daniel Drakef27b62d2007-07-27 15:43:24 +0200700 }
701 break;
702 case IEEE80211_IF_TYPE_AP:
703 if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
Jiri Bencf0706e82007-05-05 11:45:53 -0700704 ssid = sdata->u.ap.ssid;
705 ssid_len = sdata->u.ap.ssid_len;
Daniel Drakef27b62d2007-07-27 15:43:24 +0200706 }
707 break;
708 default:
709 return -EOPNOTSUPP;
Jiri Bencf0706e82007-05-05 11:45:53 -0700710 }
Daniel Drakef27b62d2007-07-27 15:43:24 +0200711
Jiri Bencf0706e82007-05-05 11:45:53 -0700712 return ieee80211_sta_req_scan(dev, ssid, ssid_len);
713}
714
715
716static int ieee80211_ioctl_giwscan(struct net_device *dev,
717 struct iw_request_info *info,
718 struct iw_point *data, char *extra)
719{
720 int res;
721 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
722 if (local->sta_scanning)
723 return -EAGAIN;
724 res = ieee80211_sta_scan_results(dev, extra, data->length);
725 if (res >= 0) {
726 data->length = res;
727 return 0;
728 }
729 data->length = 0;
730 return res;
731}
732
733
Larry Finger1fd5e582007-07-10 19:32:10 +0200734static int ieee80211_ioctl_siwrate(struct net_device *dev,
735 struct iw_request_info *info,
736 struct iw_param *rate, char *extra)
737{
738 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
739 struct ieee80211_hw_mode *mode;
740 int i;
741 u32 target_rate = rate->value / 100000;
742 struct ieee80211_sub_if_data *sdata;
743
744 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
745 if (!sdata->bss)
746 return -ENODEV;
747 mode = local->oper_hw_mode;
748 /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
749 * target_rate = X, rate->fixed = 1 means only rate X
750 * target_rate = X, rate->fixed = 0 means all rates <= X */
751 sdata->bss->max_ratectrl_rateidx = -1;
752 sdata->bss->force_unicast_rateidx = -1;
753 if (rate->value < 0)
754 return 0;
755 for (i=0; i< mode->num_rates; i++) {
756 struct ieee80211_rate *rates = &mode->rates[i];
757 int this_rate = rates->rate;
758
759 if (mode->mode == MODE_ATHEROS_TURBO ||
760 mode->mode == MODE_ATHEROS_TURBOG)
761 this_rate *= 2;
762 if (target_rate == this_rate) {
763 sdata->bss->max_ratectrl_rateidx = i;
764 if (rate->fixed)
765 sdata->bss->force_unicast_rateidx = i;
766 break;
767 }
768 }
769 return 0;
770}
771
Larry Fingerb3d88ad2007-06-10 17:57:33 -0700772static int ieee80211_ioctl_giwrate(struct net_device *dev,
773 struct iw_request_info *info,
774 struct iw_param *rate, char *extra)
775{
776 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
777 struct sta_info *sta;
778 struct ieee80211_sub_if_data *sdata;
779
780 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
781 if (sdata->type == IEEE80211_IF_TYPE_STA)
782 sta = sta_info_get(local, sdata->u.sta.bssid);
783 else
784 return -EOPNOTSUPP;
785 if (!sta)
786 return -ENODEV;
787 if (sta->txrate < local->oper_hw_mode->num_rates)
788 rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
789 else
790 rate->value = 0;
791 sta_info_put(sta);
792 return 0;
793}
794
Larry Fingerfe6aa302007-08-10 11:23:20 -0500795static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
796 struct iw_request_info *info,
797 union iwreq_data *data, char *extra)
798{
799 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
800
801 data->txpower.fixed = 1;
802 data->txpower.disabled = !(local->hw.conf.radio_enabled);
803 data->txpower.value = local->hw.conf.power_level;
804 data->txpower.flags = IW_TXPOW_DBM;
805
806 return 0;
807}
808
Jiri Bencf0706e82007-05-05 11:45:53 -0700809static int ieee80211_ioctl_siwrts(struct net_device *dev,
810 struct iw_request_info *info,
811 struct iw_param *rts, char *extra)
812{
813 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
814
815 if (rts->disabled)
816 local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
817 else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
818 return -EINVAL;
819 else
820 local->rts_threshold = rts->value;
821
822 /* If the wlan card performs RTS/CTS in hardware/firmware,
823 * configure it here */
824
825 if (local->ops->set_rts_threshold)
826 local->ops->set_rts_threshold(local_to_hw(local),
827 local->rts_threshold);
828
829 return 0;
830}
831
832static int ieee80211_ioctl_giwrts(struct net_device *dev,
833 struct iw_request_info *info,
834 struct iw_param *rts, char *extra)
835{
836 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
837
838 rts->value = local->rts_threshold;
839 rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD);
840 rts->fixed = 1;
841
842 return 0;
843}
844
845
846static int ieee80211_ioctl_siwfrag(struct net_device *dev,
847 struct iw_request_info *info,
848 struct iw_param *frag, char *extra)
849{
850 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
851
852 if (frag->disabled)
853 local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
854 else if (frag->value < 256 ||
855 frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
856 return -EINVAL;
857 else {
858 /* Fragment length must be even, so strip LSB. */
859 local->fragmentation_threshold = frag->value & ~0x1;
860 }
861
862 /* If the wlan card performs fragmentation in hardware/firmware,
863 * configure it here */
864
865 if (local->ops->set_frag_threshold)
866 local->ops->set_frag_threshold(
867 local_to_hw(local),
868 local->fragmentation_threshold);
869
870 return 0;
871}
872
873static int ieee80211_ioctl_giwfrag(struct net_device *dev,
874 struct iw_request_info *info,
875 struct iw_param *frag, char *extra)
876{
877 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
878
879 frag->value = local->fragmentation_threshold;
880 frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD);
881 frag->fixed = 1;
882
883 return 0;
884}
885
886
887static int ieee80211_ioctl_siwretry(struct net_device *dev,
888 struct iw_request_info *info,
889 struct iw_param *retry, char *extra)
890{
891 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
892
893 if (retry->disabled ||
894 (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
895 return -EINVAL;
896
897 if (retry->flags & IW_RETRY_MAX)
898 local->long_retry_limit = retry->value;
899 else if (retry->flags & IW_RETRY_MIN)
900 local->short_retry_limit = retry->value;
901 else {
902 local->long_retry_limit = retry->value;
903 local->short_retry_limit = retry->value;
904 }
905
906 if (local->ops->set_retry_limit) {
907 return local->ops->set_retry_limit(
908 local_to_hw(local),
909 local->short_retry_limit,
910 local->long_retry_limit);
911 }
912
913 return 0;
914}
915
916
917static int ieee80211_ioctl_giwretry(struct net_device *dev,
918 struct iw_request_info *info,
919 struct iw_param *retry, char *extra)
920{
921 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
922
923 retry->disabled = 0;
924 if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) {
925 /* first return min value, iwconfig will ask max value
926 * later if needed */
927 retry->flags |= IW_RETRY_LIMIT;
928 retry->value = local->short_retry_limit;
929 if (local->long_retry_limit != local->short_retry_limit)
930 retry->flags |= IW_RETRY_MIN;
931 return 0;
932 }
933 if (retry->flags & IW_RETRY_MAX) {
934 retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
935 retry->value = local->long_retry_limit;
936 }
937
938 return 0;
939}
940
Jiri Bencf0706e82007-05-05 11:45:53 -0700941static void ieee80211_key_enable_hwaccel(struct ieee80211_local *local,
942 struct ieee80211_key *key)
943{
944 struct ieee80211_key_conf *keyconf;
945 u8 addr[ETH_ALEN];
946
947 if (!key || key->alg != ALG_WEP || !key->force_sw_encrypt ||
948 (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
949 return;
950
951 memset(addr, 0xff, ETH_ALEN);
952 keyconf = ieee80211_key_data2conf(local, key);
953 if (keyconf && local->ops->set_key &&
954 local->ops->set_key(local_to_hw(local),
955 SET_KEY, addr, keyconf, 0) == 0) {
956 key->force_sw_encrypt =
957 !!(keyconf->flags & IEEE80211_KEY_FORCE_SW_ENCRYPT);
958 key->hw_key_idx = keyconf->hw_key_idx;
959 }
960 kfree(keyconf);
961}
962
963
964static void ieee80211_key_disable_hwaccel(struct ieee80211_local *local,
965 struct ieee80211_key *key)
966{
967 struct ieee80211_key_conf *keyconf;
968 u8 addr[ETH_ALEN];
969
970 if (!key || key->alg != ALG_WEP || key->force_sw_encrypt ||
971 (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP))
972 return;
973
974 memset(addr, 0xff, ETH_ALEN);
975 keyconf = ieee80211_key_data2conf(local, key);
976 if (keyconf && local->ops->set_key)
977 local->ops->set_key(local_to_hw(local), DISABLE_KEY,
978 addr, keyconf, 0);
979 kfree(keyconf);
980 key->force_sw_encrypt = 1;
981}
982
983
984static int ieee80211_ioctl_default_wep_only(struct ieee80211_local *local,
985 int value)
986{
987 int i;
988 struct ieee80211_sub_if_data *sdata;
989
990 local->default_wep_only = value;
991 read_lock(&local->sub_if_lock);
992 list_for_each_entry(sdata, &local->sub_if_list, list)
993 for (i = 0; i < NUM_DEFAULT_KEYS; i++)
994 if (value)
995 ieee80211_key_enable_hwaccel(local,
996 sdata->keys[i]);
997 else
998 ieee80211_key_disable_hwaccel(local,
999 sdata->keys[i]);
1000 read_unlock(&local->sub_if_lock);
1001
1002 return 0;
1003}
1004
1005
1006void ieee80211_update_default_wep_only(struct ieee80211_local *local)
1007{
1008 int i = 0;
1009 struct ieee80211_sub_if_data *sdata;
1010
1011 read_lock(&local->sub_if_lock);
1012 list_for_each_entry(sdata, &local->sub_if_list, list) {
1013
1014 if (sdata->dev == local->mdev)
1015 continue;
1016
1017 /* If there is an AP interface then depend on userspace to
1018 set default_wep_only correctly. */
1019 if (sdata->type == IEEE80211_IF_TYPE_AP) {
1020 read_unlock(&local->sub_if_lock);
1021 return;
1022 }
1023
1024 i++;
1025 }
1026
1027 read_unlock(&local->sub_if_lock);
1028
1029 if (i <= 1)
1030 ieee80211_ioctl_default_wep_only(local, 1);
1031 else
1032 ieee80211_ioctl_default_wep_only(local, 0);
1033}
1034
1035
1036static int ieee80211_ioctl_prism2_param(struct net_device *dev,
1037 struct iw_request_info *info,
1038 void *wrqu, char *extra)
1039{
1040 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1041 struct ieee80211_sub_if_data *sdata;
1042 int *i = (int *) extra;
1043 int param = *i;
1044 int value = *(i + 1);
1045 int ret = 0;
1046
1047 if (!capable(CAP_NET_ADMIN))
1048 return -EPERM;
1049
1050 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1051
1052 switch (param) {
1053 case PRISM2_PARAM_IEEE_802_1X:
1054 if (local->ops->set_ieee8021x)
1055 ret = local->ops->set_ieee8021x(local_to_hw(local),
1056 value);
1057 if (ret)
1058 printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) "
1059 "for low-level driver\n", dev->name, value);
1060 else
1061 sdata->ieee802_1x = value;
1062 break;
1063
Jiri Bencf0706e82007-05-05 11:45:53 -07001064 case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
Daniel Draked9430a32007-07-27 15:43:24 +02001065 if (sdata->type == IEEE80211_IF_TYPE_AP) {
1066 sdata->use_protection = !!value;
1067 ieee80211_erp_info_change_notify(dev, IEEE80211_ERP_CHANGE_PROTECTION);
1068 } else {
Daniel Drake63fc33c2007-07-10 19:32:11 +02001069 ret = -ENOENT;
Daniel Draked9430a32007-07-27 15:43:24 +02001070 }
Jiri Bencf0706e82007-05-05 11:45:53 -07001071 break;
1072
Jiri Bencf0706e82007-05-05 11:45:53 -07001073 case PRISM2_PARAM_PREAMBLE:
Daniel Draked9430a32007-07-27 15:43:24 +02001074 if (sdata->type != IEEE80211_IF_TYPE_AP) {
1075 sdata->short_preamble = !!value;
1076 ieee80211_erp_info_change_notify(dev, IEEE80211_ERP_CHANGE_PREAMBLE);
1077 } else {
Daniel Drake7e9ed182007-07-27 15:43:24 +02001078 ret = -ENOENT;
Daniel Draked9430a32007-07-27 15:43:24 +02001079 }
Jiri Bencf0706e82007-05-05 11:45:53 -07001080 break;
1081
Jiri Bencf0706e82007-05-05 11:45:53 -07001082 case PRISM2_PARAM_SHORT_SLOT_TIME:
1083 if (value)
1084 local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME;
1085 else
1086 local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME;
1087 if (ieee80211_hw_config(local))
1088 ret = -EINVAL;
1089 break;
1090
1091 case PRISM2_PARAM_NEXT_MODE:
1092 local->next_mode = value;
1093 break;
1094
Jiri Bencf0706e82007-05-05 11:45:53 -07001095 case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
1096 local->key_tx_rx_threshold = value;
1097 break;
1098
Jiri Bencf0706e82007-05-05 11:45:53 -07001099 case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
1100 local->wifi_wme_noack_test = value;
1101 break;
1102
1103 case PRISM2_PARAM_SCAN_FLAGS:
1104 local->scan_flags = value;
1105 break;
1106
1107 case PRISM2_PARAM_MIXED_CELL:
1108 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1109 sdata->type != IEEE80211_IF_TYPE_IBSS)
1110 ret = -EINVAL;
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001111 else {
1112 if (value)
1113 sdata->u.sta.flags |= IEEE80211_STA_MIXED_CELL;
1114 else
1115 sdata->u.sta.flags &= ~IEEE80211_STA_MIXED_CELL;
1116 }
Jiri Bencf0706e82007-05-05 11:45:53 -07001117 break;
1118
1119 case PRISM2_PARAM_HW_MODES:
1120 local->enabled_modes = value;
1121 break;
1122
1123 case PRISM2_PARAM_CREATE_IBSS:
1124 if (sdata->type != IEEE80211_IF_TYPE_IBSS)
1125 ret = -EINVAL;
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001126 else {
1127 if (value)
1128 sdata->u.sta.flags |= IEEE80211_STA_CREATE_IBSS;
1129 else
1130 sdata->u.sta.flags &= ~IEEE80211_STA_CREATE_IBSS;
1131 }
Jiri Bencf0706e82007-05-05 11:45:53 -07001132 break;
1133 case PRISM2_PARAM_WMM_ENABLED:
1134 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1135 sdata->type != IEEE80211_IF_TYPE_IBSS)
1136 ret = -EINVAL;
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001137 else {
1138 if (value)
1139 sdata->u.sta.flags |= IEEE80211_STA_WMM_ENABLED;
1140 else
1141 sdata->u.sta.flags &= ~IEEE80211_STA_WMM_ENABLED;
1142 }
Jiri Bencf0706e82007-05-05 11:45:53 -07001143 break;
Jiri Bencf0706e82007-05-05 11:45:53 -07001144 default:
1145 ret = -EOPNOTSUPP;
1146 break;
1147 }
1148
1149 return ret;
1150}
1151
1152
1153static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
1154 struct iw_request_info *info,
1155 void *wrqu, char *extra)
1156{
1157 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1158 struct ieee80211_sub_if_data *sdata;
1159 int *param = (int *) extra;
1160 int ret = 0;
1161
1162 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1163
1164 switch (*param) {
1165 case PRISM2_PARAM_IEEE_802_1X:
1166 *param = sdata->ieee802_1x;
1167 break;
1168
Jiri Bencf0706e82007-05-05 11:45:53 -07001169 case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
Daniel Drake63fc33c2007-07-10 19:32:11 +02001170 *param = sdata->use_protection;
Jiri Bencf0706e82007-05-05 11:45:53 -07001171 break;
1172
Jiri Bencf0706e82007-05-05 11:45:53 -07001173 case PRISM2_PARAM_PREAMBLE:
Daniel Drake7e9ed182007-07-27 15:43:24 +02001174 *param = sdata->short_preamble;
Jiri Bencf0706e82007-05-05 11:45:53 -07001175 break;
1176
Jiri Bencf0706e82007-05-05 11:45:53 -07001177 case PRISM2_PARAM_SHORT_SLOT_TIME:
1178 *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME);
1179 break;
1180
1181 case PRISM2_PARAM_NEXT_MODE:
1182 *param = local->next_mode;
1183 break;
1184
Jiri Bencf0706e82007-05-05 11:45:53 -07001185 case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
1186 *param = local->key_tx_rx_threshold;
1187 break;
1188
Jiri Bencf0706e82007-05-05 11:45:53 -07001189 case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
1190 *param = local->wifi_wme_noack_test;
1191 break;
1192
1193 case PRISM2_PARAM_SCAN_FLAGS:
1194 *param = local->scan_flags;
1195 break;
1196
1197 case PRISM2_PARAM_HW_MODES:
1198 *param = local->enabled_modes;
1199 break;
1200
1201 case PRISM2_PARAM_CREATE_IBSS:
1202 if (sdata->type != IEEE80211_IF_TYPE_IBSS)
1203 ret = -EINVAL;
1204 else
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001205 *param = !!(sdata->u.sta.flags &
1206 IEEE80211_STA_CREATE_IBSS);
Jiri Bencf0706e82007-05-05 11:45:53 -07001207 break;
1208
1209 case PRISM2_PARAM_MIXED_CELL:
1210 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1211 sdata->type != IEEE80211_IF_TYPE_IBSS)
1212 ret = -EINVAL;
1213 else
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001214 *param = !!(sdata->u.sta.flags &
1215 IEEE80211_STA_MIXED_CELL);
Jiri Bencf0706e82007-05-05 11:45:53 -07001216 break;
1217 case PRISM2_PARAM_WMM_ENABLED:
1218 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1219 sdata->type != IEEE80211_IF_TYPE_IBSS)
1220 ret = -EINVAL;
1221 else
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001222 *param = !!(sdata->u.sta.flags &
1223 IEEE80211_STA_WMM_ENABLED);
Jiri Bencf0706e82007-05-05 11:45:53 -07001224 break;
1225 default:
1226 ret = -EOPNOTSUPP;
1227 break;
1228 }
1229
1230 return ret;
1231}
1232
1233static int ieee80211_ioctl_siwmlme(struct net_device *dev,
1234 struct iw_request_info *info,
1235 struct iw_point *data, char *extra)
1236{
1237 struct ieee80211_sub_if_data *sdata;
1238 struct iw_mlme *mlme = (struct iw_mlme *) extra;
1239
1240 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1241 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1242 sdata->type != IEEE80211_IF_TYPE_IBSS)
1243 return -EINVAL;
1244
1245 switch (mlme->cmd) {
1246 case IW_MLME_DEAUTH:
1247 /* TODO: mlme->addr.sa_data */
1248 return ieee80211_sta_deauthenticate(dev, mlme->reason_code);
1249 case IW_MLME_DISASSOC:
1250 /* TODO: mlme->addr.sa_data */
1251 return ieee80211_sta_disassociate(dev, mlme->reason_code);
1252 default:
1253 return -EOPNOTSUPP;
1254 }
1255}
1256
1257
1258static int ieee80211_ioctl_siwencode(struct net_device *dev,
1259 struct iw_request_info *info,
1260 struct iw_point *erq, char *keybuf)
1261{
1262 struct ieee80211_sub_if_data *sdata;
1263 int idx, i, alg = ALG_WEP;
1264 u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1265
1266 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1267
1268 idx = erq->flags & IW_ENCODE_INDEX;
1269 if (idx == 0) {
1270 if (sdata->default_key)
1271 for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
1272 if (sdata->default_key == sdata->keys[i]) {
1273 idx = i;
1274 break;
1275 }
1276 }
1277 } else if (idx < 1 || idx > 4)
1278 return -EINVAL;
1279 else
1280 idx--;
1281
1282 if (erq->flags & IW_ENCODE_DISABLED)
1283 alg = ALG_NONE;
1284 else if (erq->length == 0) {
1285 /* No key data - just set the default TX key index */
Jiri Bence9f207f2007-05-05 11:46:38 -07001286 if (sdata->default_key != sdata->keys[idx]) {
1287 ieee80211_debugfs_key_remove_default(sdata);
Jiri Bencf0706e82007-05-05 11:45:53 -07001288 sdata->default_key = sdata->keys[idx];
Jiri Bence9f207f2007-05-05 11:46:38 -07001289 if (sdata->default_key)
1290 ieee80211_debugfs_key_add_default(sdata);
1291 }
Jiri Bencf0706e82007-05-05 11:45:53 -07001292 return 0;
1293 }
1294
1295 return ieee80211_set_encryption(
1296 dev, bcaddr,
1297 idx, alg,
1298 !sdata->default_key,
1299 keybuf, erq->length);
1300}
1301
1302
1303static int ieee80211_ioctl_giwencode(struct net_device *dev,
1304 struct iw_request_info *info,
1305 struct iw_point *erq, char *key)
1306{
1307 struct ieee80211_sub_if_data *sdata;
1308 int idx, i;
1309
1310 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1311
1312 idx = erq->flags & IW_ENCODE_INDEX;
1313 if (idx < 1 || idx > 4) {
1314 idx = -1;
1315 if (!sdata->default_key)
1316 idx = 0;
1317 else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
1318 if (sdata->default_key == sdata->keys[i]) {
1319 idx = i;
1320 break;
1321 }
1322 }
1323 if (idx < 0)
1324 return -EINVAL;
1325 } else
1326 idx--;
1327
1328 erq->flags = idx + 1;
1329
1330 if (!sdata->keys[idx]) {
1331 erq->length = 0;
1332 erq->flags |= IW_ENCODE_DISABLED;
1333 return 0;
1334 }
1335
1336 memcpy(key, sdata->keys[idx]->key,
1337 min((int)erq->length, sdata->keys[idx]->keylen));
1338 erq->length = sdata->keys[idx]->keylen;
1339 erq->flags |= IW_ENCODE_ENABLED;
1340
1341 return 0;
1342}
1343
1344static int ieee80211_ioctl_siwauth(struct net_device *dev,
1345 struct iw_request_info *info,
1346 struct iw_param *data, char *extra)
1347{
1348 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1349 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1350 int ret = 0;
1351
1352 switch (data->flags & IW_AUTH_INDEX) {
1353 case IW_AUTH_WPA_VERSION:
1354 case IW_AUTH_CIPHER_PAIRWISE:
1355 case IW_AUTH_CIPHER_GROUP:
1356 case IW_AUTH_WPA_ENABLED:
1357 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1358 break;
1359 case IW_AUTH_KEY_MGMT:
1360 if (sdata->type != IEEE80211_IF_TYPE_STA)
1361 ret = -EINVAL;
1362 else {
1363 /*
Johannes Berg808718c2007-08-28 17:01:53 -04001364 * Key management was set by wpa_supplicant,
1365 * we only need this to associate to a network
1366 * that has privacy enabled regardless of not
1367 * having a key.
Jiri Bencf0706e82007-05-05 11:45:53 -07001368 */
Johannes Berg808718c2007-08-28 17:01:53 -04001369 sdata->u.sta.key_management_enabled = !!data->value;
Jiri Bencf0706e82007-05-05 11:45:53 -07001370 }
1371 break;
1372 case IW_AUTH_80211_AUTH_ALG:
1373 if (sdata->type == IEEE80211_IF_TYPE_STA ||
1374 sdata->type == IEEE80211_IF_TYPE_IBSS)
1375 sdata->u.sta.auth_algs = data->value;
1376 else
1377 ret = -EOPNOTSUPP;
1378 break;
1379 case IW_AUTH_PRIVACY_INVOKED:
1380 if (local->ops->set_privacy_invoked)
1381 ret = local->ops->set_privacy_invoked(
1382 local_to_hw(local), data->value);
1383 break;
1384 default:
1385 ret = -EOPNOTSUPP;
1386 break;
1387 }
1388 return ret;
1389}
1390
1391/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
1392static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
1393{
1394 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1395 struct iw_statistics *wstats = &local->wstats;
1396 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1397 struct sta_info *sta = NULL;
1398
1399 if (sdata->type == IEEE80211_IF_TYPE_STA ||
1400 sdata->type == IEEE80211_IF_TYPE_IBSS)
1401 sta = sta_info_get(local, sdata->u.sta.bssid);
1402 if (!sta) {
1403 wstats->discard.fragment = 0;
1404 wstats->discard.misc = 0;
1405 wstats->qual.qual = 0;
1406 wstats->qual.level = 0;
1407 wstats->qual.noise = 0;
1408 wstats->qual.updated = IW_QUAL_ALL_INVALID;
1409 } else {
1410 wstats->qual.level = sta->last_rssi;
1411 wstats->qual.qual = sta->last_signal;
1412 wstats->qual.noise = sta->last_noise;
1413 wstats->qual.updated = local->wstats_flags;
1414 sta_info_put(sta);
1415 }
1416 return wstats;
1417}
1418
1419static int ieee80211_ioctl_giwauth(struct net_device *dev,
1420 struct iw_request_info *info,
1421 struct iw_param *data, char *extra)
1422{
1423 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1424 int ret = 0;
1425
1426 switch (data->flags & IW_AUTH_INDEX) {
1427 case IW_AUTH_80211_AUTH_ALG:
1428 if (sdata->type == IEEE80211_IF_TYPE_STA ||
1429 sdata->type == IEEE80211_IF_TYPE_IBSS)
1430 data->value = sdata->u.sta.auth_algs;
1431 else
1432 ret = -EOPNOTSUPP;
1433 break;
1434 default:
1435 ret = -EOPNOTSUPP;
1436 break;
1437 }
1438 return ret;
1439}
1440
1441
1442static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
1443 struct iw_request_info *info,
1444 struct iw_point *erq, char *extra)
1445{
1446 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1447 struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
1448 int alg, idx, i;
1449
1450 switch (ext->alg) {
1451 case IW_ENCODE_ALG_NONE:
1452 alg = ALG_NONE;
1453 break;
1454 case IW_ENCODE_ALG_WEP:
1455 alg = ALG_WEP;
1456 break;
1457 case IW_ENCODE_ALG_TKIP:
1458 alg = ALG_TKIP;
1459 break;
1460 case IW_ENCODE_ALG_CCMP:
1461 alg = ALG_CCMP;
1462 break;
1463 default:
1464 return -EOPNOTSUPP;
1465 }
1466
1467 if (erq->flags & IW_ENCODE_DISABLED)
1468 alg = ALG_NONE;
1469
1470 idx = erq->flags & IW_ENCODE_INDEX;
1471 if (idx < 1 || idx > 4) {
1472 idx = -1;
1473 if (!sdata->default_key)
1474 idx = 0;
1475 else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
1476 if (sdata->default_key == sdata->keys[i]) {
1477 idx = i;
1478 break;
1479 }
1480 }
1481 if (idx < 0)
1482 return -EINVAL;
1483 } else
1484 idx--;
1485
1486 return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
1487 ext->ext_flags &
1488 IW_ENCODE_EXT_SET_TX_KEY,
1489 ext->key, ext->key_len);
1490}
1491
1492
1493static const struct iw_priv_args ieee80211_ioctl_priv[] = {
1494 { PRISM2_IOCTL_PRISM2_PARAM,
1495 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
1496 { PRISM2_IOCTL_GET_PRISM2_PARAM,
1497 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1498 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
1499};
1500
1501/* Structures to export the Wireless Handlers */
1502
1503static const iw_handler ieee80211_handler[] =
1504{
1505 (iw_handler) NULL, /* SIOCSIWCOMMIT */
1506 (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */
1507 (iw_handler) NULL, /* SIOCSIWNWID */
1508 (iw_handler) NULL, /* SIOCGIWNWID */
1509 (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */
1510 (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */
1511 (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */
1512 (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */
1513 (iw_handler) NULL, /* SIOCSIWSENS */
1514 (iw_handler) NULL, /* SIOCGIWSENS */
1515 (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
1516 (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */
1517 (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
1518 (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
1519 (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
1520 (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
1521 iw_handler_set_spy, /* SIOCSIWSPY */
1522 iw_handler_get_spy, /* SIOCGIWSPY */
1523 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
1524 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
1525 (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */
1526 (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
1527 (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */
1528 (iw_handler) NULL, /* SIOCGIWAPLIST */
1529 (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */
1530 (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */
1531 (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
1532 (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
1533 (iw_handler) NULL, /* SIOCSIWNICKN */
1534 (iw_handler) NULL, /* SIOCGIWNICKN */
1535 (iw_handler) NULL, /* -- hole -- */
1536 (iw_handler) NULL, /* -- hole -- */
Larry Finger1fd5e582007-07-10 19:32:10 +02001537 (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */
Larry Fingerb3d88ad2007-06-10 17:57:33 -07001538 (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */
Jiri Bencf0706e82007-05-05 11:45:53 -07001539 (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */
1540 (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
1541 (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */
1542 (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */
1543 (iw_handler) NULL, /* SIOCSIWTXPOW */
Larry Fingerfe6aa302007-08-10 11:23:20 -05001544 (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
Jiri Bencf0706e82007-05-05 11:45:53 -07001545 (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */
1546 (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
1547 (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */
1548 (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */
1549 (iw_handler) NULL, /* SIOCSIWPOWER */
1550 (iw_handler) NULL, /* SIOCGIWPOWER */
1551 (iw_handler) NULL, /* -- hole -- */
1552 (iw_handler) NULL, /* -- hole -- */
1553 (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */
1554 (iw_handler) NULL, /* SIOCGIWGENIE */
1555 (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */
1556 (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */
1557 (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */
1558 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
1559 (iw_handler) NULL, /* SIOCSIWPMKSA */
1560 (iw_handler) NULL, /* -- hole -- */
1561};
1562
1563static const iw_handler ieee80211_private_handler[] =
1564{ /* SIOCIWFIRSTPRIV + */
1565 (iw_handler) ieee80211_ioctl_prism2_param, /* 0 */
1566 (iw_handler) ieee80211_ioctl_get_prism2_param, /* 1 */
1567};
1568
1569const struct iw_handler_def ieee80211_iw_handler_def =
1570{
1571 .num_standard = ARRAY_SIZE(ieee80211_handler),
1572 .num_private = ARRAY_SIZE(ieee80211_private_handler),
1573 .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
1574 .standard = (iw_handler *) ieee80211_handler,
1575 .private = (iw_handler *) ieee80211_private_handler,
1576 .private_args = (struct iw_priv_args *) ieee80211_ioctl_priv,
1577 .get_wireless_stats = ieee80211_get_wireless_stats,
1578};