blob: dc05bc66fbb882f3bb2777b4fa85e785879cb0ec [file] [log] [blame]
Jiri Bencf0706e822007-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 Bencf0706e822007-05-05 11:45:53 -070029
Jiri Bencf0706e822007-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{
Jiri Bencf0706e822007-05-05 11:45:53 -070034 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
35
36 /* default to sw encryption; this will be cleared by low-level
37 * driver if the hw supports requested encryption */
38 if (key)
Johannes Berg8f20fc22007-08-28 17:01:54 -040039 key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
Jiri Bencf0706e822007-05-05 11:45:53 -070040
Johannes Berg8f20fc22007-08-28 17:01:54 -040041 if (key && local->ops->set_key) {
Jiri Bencf0706e822007-05-05 11:45:53 -070042 if (local->ops->set_key(local_to_hw(local), SET_KEY, addr,
Johannes Bergf658eb92007-08-28 17:01:54 -040043 &key->conf)) {
Johannes Berg8f20fc22007-08-28 17:01:54 -040044 key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
45 key->conf.hw_key_idx = HW_KEY_IDX_INVALID;
Jiri Bencf0706e822007-05-05 11:45:53 -070046 }
47 }
Jiri Bencf0706e822007-05-05 11:45:53 -070048}
49
50
51static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
52 int idx, int alg, int set_tx_key,
53 const u8 *_key, size_t key_len)
54{
55 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
56 int ret = 0;
57 struct sta_info *sta;
58 struct ieee80211_key *key, *old_key;
59 int try_hwaccel = 1;
Jiri Bencf0706e822007-05-05 11:45:53 -070060 struct ieee80211_sub_if_data *sdata;
61
62 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
63
64 if (is_broadcast_ether_addr(sta_addr)) {
65 sta = NULL;
66 if (idx >= NUM_DEFAULT_KEYS) {
67 printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
68 dev->name, idx);
69 return -EINVAL;
70 }
71 key = sdata->keys[idx];
72
73 /* TODO: consider adding hwaccel support for these; at least
74 * Atheros key cache should be able to handle this since AP is
75 * only transmitting frames with default keys. */
76 /* FIX: hw key cache can be used when only one virtual
77 * STA is associated with each AP. If more than one STA
78 * is associated to the same AP, software encryption
79 * must be used. This should be done automatically
80 * based on configured station devices. For the time
81 * being, this can be only set at compile time. */
82 } else {
83 set_tx_key = 0;
84 if (idx != 0) {
85 printk(KERN_DEBUG "%s: set_encrypt - non-zero idx for "
86 "individual key\n", dev->name);
87 return -EINVAL;
88 }
89
90 sta = sta_info_get(local, sta_addr);
91 if (!sta) {
92#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
93 printk(KERN_DEBUG "%s: set_encrypt - unknown addr "
94 MAC_FMT "\n",
95 dev->name, MAC_ARG(sta_addr));
96#endif /* CONFIG_MAC80211_VERBOSE_DEBUG */
97
98 return -ENOENT;
99 }
100
101 key = sta->key;
102 }
103
104 /* FIX:
105 * Cannot configure default hwaccel keys with WEP algorithm, if
106 * any of the virtual interfaces is using static WEP
107 * configuration because hwaccel would otherwise try to decrypt
108 * these frames.
109 *
110 * For now, just disable WEP hwaccel for broadcast when there is
111 * possibility of conflict with default keys. This can maybe later be
112 * optimized by using non-default keys (at least with Atheros ar521x).
113 */
Johannes Bergf658eb92007-08-28 17:01:54 -0400114 if (!sta && alg == ALG_WEP &&
Jiri Bencf0706e822007-05-05 11:45:53 -0700115 sdata->type != IEEE80211_IF_TYPE_IBSS &&
116 sdata->type != IEEE80211_IF_TYPE_AP) {
117 try_hwaccel = 0;
118 }
119
120 if (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) {
121 /* Software encryption cannot be used with devices that hide
122 * encryption from the host system, so always try to use
123 * hardware acceleration with such devices. */
124 try_hwaccel = 1;
125 }
126
127 if ((local->hw.flags & IEEE80211_HW_NO_TKIP_WMM_HWACCEL) &&
128 alg == ALG_TKIP) {
129 if (sta && (sta->flags & WLAN_STA_WME)) {
130 /* Hardware does not support hwaccel with TKIP when using WMM.
131 */
132 try_hwaccel = 0;
133 }
134 else if (sdata->type == IEEE80211_IF_TYPE_STA) {
135 sta = sta_info_get(local, sdata->u.sta.bssid);
136 if (sta) {
137 if (sta->flags & WLAN_STA_WME) {
138 try_hwaccel = 0;
139 }
140 sta_info_put(sta);
141 sta = NULL;
142 }
143 }
144 }
145
146 if (alg == ALG_NONE) {
Jiri Bencf0706e822007-05-05 11:45:53 -0700147 if (try_hwaccel && key &&
Johannes Berg8f20fc22007-08-28 17:01:54 -0400148 key->conf.hw_key_idx != HW_KEY_IDX_INVALID &&
Jiri Bencf0706e822007-05-05 11:45:53 -0700149 local->ops->set_key &&
Jiri Bencf0706e822007-05-05 11:45:53 -0700150 local->ops->set_key(local_to_hw(local), DISABLE_KEY,
Johannes Bergf658eb92007-08-28 17:01:54 -0400151 sta_addr, &key->conf)) {
Jiri Bencf0706e822007-05-05 11:45:53 -0700152 printk(KERN_DEBUG "%s: set_encrypt - low-level disable"
153 " failed\n", dev->name);
154 ret = -EINVAL;
155 }
Jiri Bencf0706e822007-05-05 11:45:53 -0700156
Jiri Bence9f207f2007-05-05 11:46:38 -0700157 if (set_tx_key || sdata->default_key == key) {
158 ieee80211_debugfs_key_remove_default(sdata);
Jiri Bencf0706e822007-05-05 11:45:53 -0700159 sdata->default_key = NULL;
Jiri Bence9f207f2007-05-05 11:46:38 -0700160 }
161 ieee80211_debugfs_key_remove(key);
Jiri Bencf0706e822007-05-05 11:45:53 -0700162 if (sta)
163 sta->key = NULL;
164 else
165 sdata->keys[idx] = NULL;
166 ieee80211_key_free(key);
167 key = NULL;
168 } else {
169 old_key = key;
170 key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len,
171 GFP_KERNEL);
172 if (!key) {
173 ret = -ENOMEM;
174 goto err_out;
175 }
176
177 /* default to sw encryption; low-level driver sets these if the
178 * requested encryption is supported */
Johannes Berg8f20fc22007-08-28 17:01:54 -0400179 key->conf.hw_key_idx = HW_KEY_IDX_INVALID;
180 key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
Jiri Bencf0706e822007-05-05 11:45:53 -0700181
Johannes Berg8f20fc22007-08-28 17:01:54 -0400182 key->conf.alg = alg;
183 key->conf.keyidx = idx;
184 key->conf.keylen = key_len;
185 memcpy(key->conf.key, _key, key_len);
Jiri Bencf0706e822007-05-05 11:45:53 -0700186
187 if (alg == ALG_CCMP) {
188 /* Initialize AES key state here as an optimization
189 * so that it does not need to be initialized for every
190 * packet. */
191 key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
Johannes Berg8f20fc22007-08-28 17:01:54 -0400192 key->conf.key);
Jiri Bencf0706e822007-05-05 11:45:53 -0700193 if (!key->u.ccmp.tfm) {
194 ret = -ENOMEM;
195 goto err_free;
196 }
197 }
198
Jiri Bence9f207f2007-05-05 11:46:38 -0700199 if (set_tx_key || sdata->default_key == old_key) {
200 ieee80211_debugfs_key_remove_default(sdata);
Jiri Bencf0706e822007-05-05 11:45:53 -0700201 sdata->default_key = NULL;
Jiri Bence9f207f2007-05-05 11:46:38 -0700202 }
203 ieee80211_debugfs_key_remove(old_key);
Jiri Bencf0706e822007-05-05 11:45:53 -0700204 if (sta)
205 sta->key = key;
206 else
207 sdata->keys[idx] = key;
208 ieee80211_key_free(old_key);
Jiri Bence9f207f2007-05-05 11:46:38 -0700209 ieee80211_debugfs_key_add(local, key);
210 if (sta)
211 ieee80211_debugfs_key_sta_link(key, sta);
Jiri Bencf0706e822007-05-05 11:45:53 -0700212
213 if (try_hwaccel &&
214 (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP))
215 ieee80211_set_hw_encryption(dev, sta, sta_addr, key);
216 }
217
218 if (set_tx_key || (!sta && !sdata->default_key && key)) {
219 sdata->default_key = key;
Jiri Bence9f207f2007-05-05 11:46:38 -0700220 if (key)
221 ieee80211_debugfs_key_add_default(sdata);
Jiri Bencf0706e822007-05-05 11:45:53 -0700222
223 if (local->ops->set_key_idx &&
224 local->ops->set_key_idx(local_to_hw(local), idx))
225 printk(KERN_DEBUG "%s: failed to set TX key idx for "
226 "low-level driver\n", dev->name);
227 }
228
229 if (sta)
230 sta_info_put(sta);
231
232 return 0;
233
234err_free:
235 ieee80211_key_free(key);
236err_out:
237 if (sta)
238 sta_info_put(sta);
239 return ret;
240}
241
242static int ieee80211_ioctl_siwgenie(struct net_device *dev,
243 struct iw_request_info *info,
244 struct iw_point *data, char *extra)
245{
246 struct ieee80211_sub_if_data *sdata;
247 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
248
249 if (local->user_space_mlme)
250 return -EOPNOTSUPP;
251
252 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
253 if (sdata->type == IEEE80211_IF_TYPE_STA ||
254 sdata->type == IEEE80211_IF_TYPE_IBSS) {
255 int ret = ieee80211_sta_set_extra_ie(dev, extra, data->length);
256 if (ret)
257 return ret;
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400258 sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
Jiri Bencf0706e822007-05-05 11:45:53 -0700259 ieee80211_sta_req_auth(dev, &sdata->u.sta);
260 return 0;
261 }
262
263 if (sdata->type == IEEE80211_IF_TYPE_AP) {
264 kfree(sdata->u.ap.generic_elem);
265 sdata->u.ap.generic_elem = kmalloc(data->length, GFP_KERNEL);
266 if (!sdata->u.ap.generic_elem)
267 return -ENOMEM;
268 memcpy(sdata->u.ap.generic_elem, extra, data->length);
269 sdata->u.ap.generic_elem_len = data->length;
270 return ieee80211_if_config(dev);
271 }
272 return -EOPNOTSUPP;
273}
274
Jiri Bencf0706e822007-05-05 11:45:53 -0700275static int ieee80211_ioctl_giwname(struct net_device *dev,
276 struct iw_request_info *info,
277 char *name, char *extra)
278{
279 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
280
281 switch (local->hw.conf.phymode) {
282 case MODE_IEEE80211A:
283 strcpy(name, "IEEE 802.11a");
284 break;
285 case MODE_IEEE80211B:
286 strcpy(name, "IEEE 802.11b");
287 break;
288 case MODE_IEEE80211G:
289 strcpy(name, "IEEE 802.11g");
290 break;
291 case MODE_ATHEROS_TURBO:
292 strcpy(name, "5GHz Turbo");
293 break;
294 default:
295 strcpy(name, "IEEE 802.11");
296 break;
297 }
298
299 return 0;
300}
301
302
303static int ieee80211_ioctl_giwrange(struct net_device *dev,
304 struct iw_request_info *info,
305 struct iw_point *data, char *extra)
306{
307 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
308 struct iw_range *range = (struct iw_range *) extra;
Hong Liu333af2f2007-07-10 19:32:08 +0200309 struct ieee80211_hw_mode *mode = NULL;
310 int c = 0;
Jiri Bencf0706e822007-05-05 11:45:53 -0700311
312 data->length = sizeof(struct iw_range);
313 memset(range, 0, sizeof(struct iw_range));
314
315 range->we_version_compiled = WIRELESS_EXT;
316 range->we_version_source = 21;
317 range->retry_capa = IW_RETRY_LIMIT;
318 range->retry_flags = IW_RETRY_LIMIT;
319 range->min_retry = 0;
320 range->max_retry = 255;
321 range->min_rts = 0;
322 range->max_rts = 2347;
323 range->min_frag = 256;
324 range->max_frag = 2346;
325
326 range->encoding_size[0] = 5;
327 range->encoding_size[1] = 13;
328 range->num_encoding_sizes = 2;
329 range->max_encoding_tokens = NUM_DEFAULT_KEYS;
330
331 range->max_qual.qual = local->hw.max_signal;
332 range->max_qual.level = local->hw.max_rssi;
333 range->max_qual.noise = local->hw.max_noise;
334 range->max_qual.updated = local->wstats_flags;
335
336 range->avg_qual.qual = local->hw.max_signal/2;
337 range->avg_qual.level = 0;
338 range->avg_qual.noise = 0;
339 range->avg_qual.updated = local->wstats_flags;
340
341 range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
342 IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
343
Hong Liu333af2f2007-07-10 19:32:08 +0200344 list_for_each_entry(mode, &local->modes_list, list) {
345 int i = 0;
346
347 if (!(local->enabled_modes & (1 << mode->mode)) ||
348 (local->hw_modes & local->enabled_modes &
349 (1 << MODE_IEEE80211G) && mode->mode == MODE_IEEE80211B))
350 continue;
351
352 while (i < mode->num_channels && c < IW_MAX_FREQUENCIES) {
353 struct ieee80211_channel *chan = &mode->channels[i];
354
355 if (chan->flag & IEEE80211_CHAN_W_SCAN) {
356 range->freq[c].i = chan->chan;
357 range->freq[c].m = chan->freq * 100000;
358 range->freq[c].e = 1;
359 c++;
360 }
361 i++;
362 }
363 }
364 range->num_channels = c;
365 range->num_frequency = c;
366
Jiri Bencf0706e822007-05-05 11:45:53 -0700367 IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
368 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWTHRSPY);
369 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
370 IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
371
372 return 0;
373}
374
375
Jiri Bencf0706e822007-05-05 11:45:53 -0700376static int ieee80211_ioctl_siwmode(struct net_device *dev,
377 struct iw_request_info *info,
378 __u32 *mode, char *extra)
379{
380 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
381 int type;
382
383 if (sdata->type == IEEE80211_IF_TYPE_VLAN)
384 return -EOPNOTSUPP;
385
386 switch (*mode) {
387 case IW_MODE_INFRA:
388 type = IEEE80211_IF_TYPE_STA;
389 break;
390 case IW_MODE_ADHOC:
391 type = IEEE80211_IF_TYPE_IBSS;
392 break;
393 case IW_MODE_MONITOR:
394 type = IEEE80211_IF_TYPE_MNTR;
395 break;
396 default:
397 return -EINVAL;
398 }
399
400 if (type == sdata->type)
401 return 0;
402 if (netif_running(dev))
403 return -EBUSY;
404
405 ieee80211_if_reinit(dev);
406 ieee80211_if_set_type(dev, type);
407
408 return 0;
409}
410
411
412static int ieee80211_ioctl_giwmode(struct net_device *dev,
413 struct iw_request_info *info,
414 __u32 *mode, char *extra)
415{
416 struct ieee80211_sub_if_data *sdata;
417
418 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
419 switch (sdata->type) {
420 case IEEE80211_IF_TYPE_AP:
421 *mode = IW_MODE_MASTER;
422 break;
423 case IEEE80211_IF_TYPE_STA:
424 *mode = IW_MODE_INFRA;
425 break;
426 case IEEE80211_IF_TYPE_IBSS:
427 *mode = IW_MODE_ADHOC;
428 break;
429 case IEEE80211_IF_TYPE_MNTR:
430 *mode = IW_MODE_MONITOR;
431 break;
432 case IEEE80211_IF_TYPE_WDS:
433 *mode = IW_MODE_REPEAT;
434 break;
435 case IEEE80211_IF_TYPE_VLAN:
436 *mode = IW_MODE_SECOND; /* FIXME */
437 break;
438 default:
439 *mode = IW_MODE_AUTO;
440 break;
441 }
442 return 0;
443}
444
445int ieee80211_set_channel(struct ieee80211_local *local, int channel, int freq)
446{
447 struct ieee80211_hw_mode *mode;
448 int c, set = 0;
449 int ret = -EINVAL;
450
451 list_for_each_entry(mode, &local->modes_list, list) {
452 if (!(local->enabled_modes & (1 << mode->mode)))
453 continue;
454 for (c = 0; c < mode->num_channels; c++) {
455 struct ieee80211_channel *chan = &mode->channels[c];
456 if (chan->flag & IEEE80211_CHAN_W_SCAN &&
457 ((chan->chan == channel) || (chan->freq == freq))) {
458 /* Use next_mode as the mode preference to
459 * resolve non-unique channel numbers. */
460 if (set && mode->mode != local->next_mode)
461 continue;
462
463 local->oper_channel = chan;
464 local->oper_hw_mode = mode;
465 set++;
466 }
467 }
468 }
469
470 if (set) {
471 if (local->sta_scanning)
472 ret = 0;
473 else
474 ret = ieee80211_hw_config(local);
475
476 rate_control_clear(local);
477 }
478
479 return ret;
480}
481
482static int ieee80211_ioctl_siwfreq(struct net_device *dev,
483 struct iw_request_info *info,
484 struct iw_freq *freq, char *extra)
485{
486 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
487 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
488
489 if (sdata->type == IEEE80211_IF_TYPE_STA)
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400490 sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
Jiri Bencf0706e822007-05-05 11:45:53 -0700491
492 /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
493 if (freq->e == 0) {
494 if (freq->m < 0) {
495 if (sdata->type == IEEE80211_IF_TYPE_STA)
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400496 sdata->u.sta.flags |=
497 IEEE80211_STA_AUTO_CHANNEL_SEL;
Jiri Bencf0706e822007-05-05 11:45:53 -0700498 return 0;
499 } else
500 return ieee80211_set_channel(local, freq->m, -1);
501 } else {
502 int i, div = 1000000;
503 for (i = 0; i < freq->e; i++)
504 div /= 10;
505 if (div > 0)
506 return ieee80211_set_channel(local, -1, freq->m / div);
507 else
508 return -EINVAL;
509 }
510}
511
512
513static int ieee80211_ioctl_giwfreq(struct net_device *dev,
514 struct iw_request_info *info,
515 struct iw_freq *freq, char *extra)
516{
517 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
518
519 /* TODO: in station mode (Managed/Ad-hoc) might need to poll low-level
520 * driver for the current channel with firmware-based management */
521
522 freq->m = local->hw.conf.freq;
523 freq->e = 6;
524
525 return 0;
526}
527
528
529static int ieee80211_ioctl_siwessid(struct net_device *dev,
530 struct iw_request_info *info,
531 struct iw_point *data, char *ssid)
532{
533 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
534 struct ieee80211_sub_if_data *sdata;
535 size_t len = data->length;
536
537 /* iwconfig uses nul termination in SSID.. */
538 if (len > 0 && ssid[len - 1] == '\0')
539 len--;
540
541 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
542 if (sdata->type == IEEE80211_IF_TYPE_STA ||
543 sdata->type == IEEE80211_IF_TYPE_IBSS) {
544 int ret;
545 if (local->user_space_mlme) {
546 if (len > IEEE80211_MAX_SSID_LEN)
547 return -EINVAL;
548 memcpy(sdata->u.sta.ssid, ssid, len);
549 sdata->u.sta.ssid_len = len;
550 return 0;
551 }
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400552 if (data->flags)
553 sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
554 else
555 sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL;
Jiri Bencf0706e822007-05-05 11:45:53 -0700556 ret = ieee80211_sta_set_ssid(dev, ssid, len);
557 if (ret)
558 return ret;
559 ieee80211_sta_req_auth(dev, &sdata->u.sta);
560 return 0;
561 }
562
563 if (sdata->type == IEEE80211_IF_TYPE_AP) {
564 memcpy(sdata->u.ap.ssid, ssid, len);
565 memset(sdata->u.ap.ssid + len, 0,
566 IEEE80211_MAX_SSID_LEN - len);
567 sdata->u.ap.ssid_len = len;
568 return ieee80211_if_config(dev);
569 }
570 return -EOPNOTSUPP;
571}
572
573
574static int ieee80211_ioctl_giwessid(struct net_device *dev,
575 struct iw_request_info *info,
576 struct iw_point *data, char *ssid)
577{
578 size_t len;
579
580 struct ieee80211_sub_if_data *sdata;
581 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
582 if (sdata->type == IEEE80211_IF_TYPE_STA ||
583 sdata->type == IEEE80211_IF_TYPE_IBSS) {
584 int res = ieee80211_sta_get_ssid(dev, ssid, &len);
585 if (res == 0) {
586 data->length = len;
587 data->flags = 1;
588 } else
589 data->flags = 0;
590 return res;
591 }
592
593 if (sdata->type == IEEE80211_IF_TYPE_AP) {
594 len = sdata->u.ap.ssid_len;
595 if (len > IW_ESSID_MAX_SIZE)
596 len = IW_ESSID_MAX_SIZE;
597 memcpy(ssid, sdata->u.ap.ssid, len);
598 data->length = len;
599 data->flags = 1;
600 return 0;
601 }
602 return -EOPNOTSUPP;
603}
604
605
606static int ieee80211_ioctl_siwap(struct net_device *dev,
607 struct iw_request_info *info,
608 struct sockaddr *ap_addr, char *extra)
609{
610 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
611 struct ieee80211_sub_if_data *sdata;
612
613 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
614 if (sdata->type == IEEE80211_IF_TYPE_STA ||
615 sdata->type == IEEE80211_IF_TYPE_IBSS) {
616 int ret;
617 if (local->user_space_mlme) {
618 memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
619 ETH_ALEN);
620 return 0;
621 }
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400622 if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
623 sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
624 IEEE80211_STA_AUTO_CHANNEL_SEL;
625 else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
626 sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
Jiri Bencf0706e822007-05-05 11:45:53 -0700627 else
Jiri Slabyd6f2da52007-08-28 17:01:54 -0400628 sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
Jiri Bencf0706e822007-05-05 11:45:53 -0700629 ret = ieee80211_sta_set_bssid(dev, (u8 *) &ap_addr->sa_data);
630 if (ret)
631 return ret;
632 ieee80211_sta_req_auth(dev, &sdata->u.sta);
633 return 0;
634 } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
635 if (memcmp(sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
636 ETH_ALEN) == 0)
637 return 0;
638 return ieee80211_if_update_wds(dev, (u8 *) &ap_addr->sa_data);
639 }
640
641 return -EOPNOTSUPP;
642}
643
644
645static int ieee80211_ioctl_giwap(struct net_device *dev,
646 struct iw_request_info *info,
647 struct sockaddr *ap_addr, char *extra)
648{
649 struct ieee80211_sub_if_data *sdata;
650
651 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
652 if (sdata->type == IEEE80211_IF_TYPE_STA ||
653 sdata->type == IEEE80211_IF_TYPE_IBSS) {
654 ap_addr->sa_family = ARPHRD_ETHER;
655 memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
656 return 0;
657 } else if (sdata->type == IEEE80211_IF_TYPE_WDS) {
658 ap_addr->sa_family = ARPHRD_ETHER;
659 memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
660 return 0;
661 }
662
663 return -EOPNOTSUPP;
664}
665
666
667static int ieee80211_ioctl_siwscan(struct net_device *dev,
668 struct iw_request_info *info,
669 struct iw_point *data, char *extra)
670{
671 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
672 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
673 u8 *ssid = NULL;
674 size_t ssid_len = 0;
675
676 if (!netif_running(dev))
677 return -ENETDOWN;
678
Daniel Drakef27b62d2007-07-27 15:43:24 +0200679 switch (sdata->type) {
680 case IEEE80211_IF_TYPE_STA:
681 case IEEE80211_IF_TYPE_IBSS:
682 if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
Jiri Bencf0706e822007-05-05 11:45:53 -0700683 ssid = sdata->u.sta.ssid;
684 ssid_len = sdata->u.sta.ssid_len;
Daniel Drakef27b62d2007-07-27 15:43:24 +0200685 }
686 break;
687 case IEEE80211_IF_TYPE_AP:
688 if (local->scan_flags & IEEE80211_SCAN_MATCH_SSID) {
Jiri Bencf0706e822007-05-05 11:45:53 -0700689 ssid = sdata->u.ap.ssid;
690 ssid_len = sdata->u.ap.ssid_len;
Daniel Drakef27b62d2007-07-27 15:43:24 +0200691 }
692 break;
693 default:
694 return -EOPNOTSUPP;
Jiri Bencf0706e822007-05-05 11:45:53 -0700695 }
Daniel Drakef27b62d2007-07-27 15:43:24 +0200696
Jiri Bencf0706e822007-05-05 11:45:53 -0700697 return ieee80211_sta_req_scan(dev, ssid, ssid_len);
698}
699
700
701static int ieee80211_ioctl_giwscan(struct net_device *dev,
702 struct iw_request_info *info,
703 struct iw_point *data, char *extra)
704{
705 int res;
706 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
707 if (local->sta_scanning)
708 return -EAGAIN;
709 res = ieee80211_sta_scan_results(dev, extra, data->length);
710 if (res >= 0) {
711 data->length = res;
712 return 0;
713 }
714 data->length = 0;
715 return res;
716}
717
718
Larry Finger1fd5e582007-07-10 19:32:10 +0200719static int ieee80211_ioctl_siwrate(struct net_device *dev,
720 struct iw_request_info *info,
721 struct iw_param *rate, char *extra)
722{
723 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
724 struct ieee80211_hw_mode *mode;
725 int i;
726 u32 target_rate = rate->value / 100000;
727 struct ieee80211_sub_if_data *sdata;
728
729 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
730 if (!sdata->bss)
731 return -ENODEV;
732 mode = local->oper_hw_mode;
733 /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
734 * target_rate = X, rate->fixed = 1 means only rate X
735 * target_rate = X, rate->fixed = 0 means all rates <= X */
736 sdata->bss->max_ratectrl_rateidx = -1;
737 sdata->bss->force_unicast_rateidx = -1;
738 if (rate->value < 0)
739 return 0;
740 for (i=0; i< mode->num_rates; i++) {
741 struct ieee80211_rate *rates = &mode->rates[i];
742 int this_rate = rates->rate;
743
744 if (mode->mode == MODE_ATHEROS_TURBO ||
745 mode->mode == MODE_ATHEROS_TURBOG)
746 this_rate *= 2;
747 if (target_rate == this_rate) {
748 sdata->bss->max_ratectrl_rateidx = i;
749 if (rate->fixed)
750 sdata->bss->force_unicast_rateidx = i;
751 break;
752 }
753 }
754 return 0;
755}
756
Larry Fingerb3d88ad2007-06-10 17:57:33 -0700757static int ieee80211_ioctl_giwrate(struct net_device *dev,
758 struct iw_request_info *info,
759 struct iw_param *rate, char *extra)
760{
761 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
762 struct sta_info *sta;
763 struct ieee80211_sub_if_data *sdata;
764
765 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
766 if (sdata->type == IEEE80211_IF_TYPE_STA)
767 sta = sta_info_get(local, sdata->u.sta.bssid);
768 else
769 return -EOPNOTSUPP;
770 if (!sta)
771 return -ENODEV;
772 if (sta->txrate < local->oper_hw_mode->num_rates)
773 rate->value = local->oper_hw_mode->rates[sta->txrate].rate * 100000;
774 else
775 rate->value = 0;
776 sta_info_put(sta);
777 return 0;
778}
779
Larry Fingerfe6aa302007-08-10 11:23:20 -0500780static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
781 struct iw_request_info *info,
782 union iwreq_data *data, char *extra)
783{
784 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
785
786 data->txpower.fixed = 1;
787 data->txpower.disabled = !(local->hw.conf.radio_enabled);
788 data->txpower.value = local->hw.conf.power_level;
789 data->txpower.flags = IW_TXPOW_DBM;
790
791 return 0;
792}
793
Jiri Bencf0706e822007-05-05 11:45:53 -0700794static int ieee80211_ioctl_siwrts(struct net_device *dev,
795 struct iw_request_info *info,
796 struct iw_param *rts, char *extra)
797{
798 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
799
800 if (rts->disabled)
801 local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
802 else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
803 return -EINVAL;
804 else
805 local->rts_threshold = rts->value;
806
807 /* If the wlan card performs RTS/CTS in hardware/firmware,
808 * configure it here */
809
810 if (local->ops->set_rts_threshold)
811 local->ops->set_rts_threshold(local_to_hw(local),
812 local->rts_threshold);
813
814 return 0;
815}
816
817static int ieee80211_ioctl_giwrts(struct net_device *dev,
818 struct iw_request_info *info,
819 struct iw_param *rts, char *extra)
820{
821 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
822
823 rts->value = local->rts_threshold;
824 rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD);
825 rts->fixed = 1;
826
827 return 0;
828}
829
830
831static int ieee80211_ioctl_siwfrag(struct net_device *dev,
832 struct iw_request_info *info,
833 struct iw_param *frag, char *extra)
834{
835 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
836
837 if (frag->disabled)
838 local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
839 else if (frag->value < 256 ||
840 frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
841 return -EINVAL;
842 else {
843 /* Fragment length must be even, so strip LSB. */
844 local->fragmentation_threshold = frag->value & ~0x1;
845 }
846
847 /* If the wlan card performs fragmentation in hardware/firmware,
848 * configure it here */
849
850 if (local->ops->set_frag_threshold)
851 local->ops->set_frag_threshold(
852 local_to_hw(local),
853 local->fragmentation_threshold);
854
855 return 0;
856}
857
858static int ieee80211_ioctl_giwfrag(struct net_device *dev,
859 struct iw_request_info *info,
860 struct iw_param *frag, char *extra)
861{
862 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
863
864 frag->value = local->fragmentation_threshold;
865 frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD);
866 frag->fixed = 1;
867
868 return 0;
869}
870
871
872static int ieee80211_ioctl_siwretry(struct net_device *dev,
873 struct iw_request_info *info,
874 struct iw_param *retry, char *extra)
875{
876 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
877
878 if (retry->disabled ||
879 (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
880 return -EINVAL;
881
882 if (retry->flags & IW_RETRY_MAX)
883 local->long_retry_limit = retry->value;
884 else if (retry->flags & IW_RETRY_MIN)
885 local->short_retry_limit = retry->value;
886 else {
887 local->long_retry_limit = retry->value;
888 local->short_retry_limit = retry->value;
889 }
890
891 if (local->ops->set_retry_limit) {
892 return local->ops->set_retry_limit(
893 local_to_hw(local),
894 local->short_retry_limit,
895 local->long_retry_limit);
896 }
897
898 return 0;
899}
900
901
902static int ieee80211_ioctl_giwretry(struct net_device *dev,
903 struct iw_request_info *info,
904 struct iw_param *retry, char *extra)
905{
906 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
907
908 retry->disabled = 0;
909 if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) {
910 /* first return min value, iwconfig will ask max value
911 * later if needed */
912 retry->flags |= IW_RETRY_LIMIT;
913 retry->value = local->short_retry_limit;
914 if (local->long_retry_limit != local->short_retry_limit)
915 retry->flags |= IW_RETRY_MIN;
916 return 0;
917 }
918 if (retry->flags & IW_RETRY_MAX) {
919 retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
920 retry->value = local->long_retry_limit;
921 }
922
923 return 0;
924}
925
Jiri Bencf0706e822007-05-05 11:45:53 -0700926static int ieee80211_ioctl_prism2_param(struct net_device *dev,
927 struct iw_request_info *info,
928 void *wrqu, char *extra)
929{
930 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
931 struct ieee80211_sub_if_data *sdata;
932 int *i = (int *) extra;
933 int param = *i;
934 int value = *(i + 1);
935 int ret = 0;
936
937 if (!capable(CAP_NET_ADMIN))
938 return -EPERM;
939
940 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
941
942 switch (param) {
943 case PRISM2_PARAM_IEEE_802_1X:
944 if (local->ops->set_ieee8021x)
945 ret = local->ops->set_ieee8021x(local_to_hw(local),
946 value);
947 if (ret)
948 printk(KERN_DEBUG "%s: failed to set IEEE 802.1X (%d) "
949 "for low-level driver\n", dev->name, value);
950 else
951 sdata->ieee802_1x = value;
952 break;
953
Jiri Bencf0706e822007-05-05 11:45:53 -0700954 case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
Daniel Draked9430a32007-07-27 15:43:24 +0200955 if (sdata->type == IEEE80211_IF_TYPE_AP) {
Jiri Slaby13262ff2007-08-28 17:01:54 -0400956 if (value)
957 sdata->flags |= IEEE80211_SDATA_USE_PROTECTION;
958 else
959 sdata->flags &= ~IEEE80211_SDATA_USE_PROTECTION;
960 ieee80211_erp_info_change_notify(dev,
961 IEEE80211_ERP_CHANGE_PROTECTION);
Daniel Draked9430a32007-07-27 15:43:24 +0200962 } else {
Daniel Drake63fc33c2007-07-10 19:32:11 +0200963 ret = -ENOENT;
Daniel Draked9430a32007-07-27 15:43:24 +0200964 }
Jiri Bencf0706e822007-05-05 11:45:53 -0700965 break;
966
Jiri Bencf0706e822007-05-05 11:45:53 -0700967 case PRISM2_PARAM_PREAMBLE:
Daniel Draked9430a32007-07-27 15:43:24 +0200968 if (sdata->type != IEEE80211_IF_TYPE_AP) {
Jiri Slaby13262ff2007-08-28 17:01:54 -0400969 if (value)
970 sdata->flags |= IEEE80211_SDATA_SHORT_PREAMBLE;
971 else
972 sdata->flags &= ~IEEE80211_SDATA_SHORT_PREAMBLE;
973 ieee80211_erp_info_change_notify(dev,
974 IEEE80211_ERP_CHANGE_PREAMBLE);
Daniel Draked9430a32007-07-27 15:43:24 +0200975 } else {
Daniel Drake7e9ed182007-07-27 15:43:24 +0200976 ret = -ENOENT;
Daniel Draked9430a32007-07-27 15:43:24 +0200977 }
Jiri Bencf0706e822007-05-05 11:45:53 -0700978 break;
979
Jiri Bencf0706e822007-05-05 11:45:53 -0700980 case PRISM2_PARAM_SHORT_SLOT_TIME:
981 if (value)
982 local->hw.conf.flags |= IEEE80211_CONF_SHORT_SLOT_TIME;
983 else
984 local->hw.conf.flags &= ~IEEE80211_CONF_SHORT_SLOT_TIME;
985 if (ieee80211_hw_config(local))
986 ret = -EINVAL;
987 break;
988
989 case PRISM2_PARAM_NEXT_MODE:
990 local->next_mode = value;
991 break;
992
Jiri Bencf0706e822007-05-05 11:45:53 -0700993 case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
994 local->key_tx_rx_threshold = value;
995 break;
996
Jiri Bencf0706e822007-05-05 11:45:53 -0700997 case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
998 local->wifi_wme_noack_test = value;
999 break;
1000
1001 case PRISM2_PARAM_SCAN_FLAGS:
1002 local->scan_flags = value;
1003 break;
1004
1005 case PRISM2_PARAM_MIXED_CELL:
1006 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1007 sdata->type != IEEE80211_IF_TYPE_IBSS)
1008 ret = -EINVAL;
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001009 else {
1010 if (value)
1011 sdata->u.sta.flags |= IEEE80211_STA_MIXED_CELL;
1012 else
1013 sdata->u.sta.flags &= ~IEEE80211_STA_MIXED_CELL;
1014 }
Jiri Bencf0706e822007-05-05 11:45:53 -07001015 break;
1016
1017 case PRISM2_PARAM_HW_MODES:
1018 local->enabled_modes = value;
1019 break;
1020
1021 case PRISM2_PARAM_CREATE_IBSS:
1022 if (sdata->type != IEEE80211_IF_TYPE_IBSS)
1023 ret = -EINVAL;
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001024 else {
1025 if (value)
1026 sdata->u.sta.flags |= IEEE80211_STA_CREATE_IBSS;
1027 else
1028 sdata->u.sta.flags &= ~IEEE80211_STA_CREATE_IBSS;
1029 }
Jiri Bencf0706e822007-05-05 11:45:53 -07001030 break;
1031 case PRISM2_PARAM_WMM_ENABLED:
1032 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1033 sdata->type != IEEE80211_IF_TYPE_IBSS)
1034 ret = -EINVAL;
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001035 else {
1036 if (value)
1037 sdata->u.sta.flags |= IEEE80211_STA_WMM_ENABLED;
1038 else
1039 sdata->u.sta.flags &= ~IEEE80211_STA_WMM_ENABLED;
1040 }
Jiri Bencf0706e822007-05-05 11:45:53 -07001041 break;
Jiri Bencf0706e822007-05-05 11:45:53 -07001042 default:
1043 ret = -EOPNOTSUPP;
1044 break;
1045 }
1046
1047 return ret;
1048}
1049
1050
1051static int ieee80211_ioctl_get_prism2_param(struct net_device *dev,
1052 struct iw_request_info *info,
1053 void *wrqu, char *extra)
1054{
1055 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1056 struct ieee80211_sub_if_data *sdata;
1057 int *param = (int *) extra;
1058 int ret = 0;
1059
1060 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1061
1062 switch (*param) {
1063 case PRISM2_PARAM_IEEE_802_1X:
1064 *param = sdata->ieee802_1x;
1065 break;
1066
Jiri Bencf0706e822007-05-05 11:45:53 -07001067 case PRISM2_PARAM_CTS_PROTECT_ERP_FRAMES:
Jiri Slaby13262ff2007-08-28 17:01:54 -04001068 *param = !!(sdata->flags & IEEE80211_SDATA_USE_PROTECTION);
Jiri Bencf0706e822007-05-05 11:45:53 -07001069 break;
1070
Jiri Bencf0706e822007-05-05 11:45:53 -07001071 case PRISM2_PARAM_PREAMBLE:
Jiri Slaby13262ff2007-08-28 17:01:54 -04001072 *param = !!(sdata->flags & IEEE80211_SDATA_SHORT_PREAMBLE);
Jiri Bencf0706e822007-05-05 11:45:53 -07001073 break;
1074
Jiri Bencf0706e822007-05-05 11:45:53 -07001075 case PRISM2_PARAM_SHORT_SLOT_TIME:
1076 *param = !!(local->hw.conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME);
1077 break;
1078
1079 case PRISM2_PARAM_NEXT_MODE:
1080 *param = local->next_mode;
1081 break;
1082
Jiri Bencf0706e822007-05-05 11:45:53 -07001083 case PRISM2_PARAM_KEY_TX_RX_THRESHOLD:
1084 *param = local->key_tx_rx_threshold;
1085 break;
1086
Jiri Bencf0706e822007-05-05 11:45:53 -07001087 case PRISM2_PARAM_WIFI_WME_NOACK_TEST:
1088 *param = local->wifi_wme_noack_test;
1089 break;
1090
1091 case PRISM2_PARAM_SCAN_FLAGS:
1092 *param = local->scan_flags;
1093 break;
1094
1095 case PRISM2_PARAM_HW_MODES:
1096 *param = local->enabled_modes;
1097 break;
1098
1099 case PRISM2_PARAM_CREATE_IBSS:
1100 if (sdata->type != IEEE80211_IF_TYPE_IBSS)
1101 ret = -EINVAL;
1102 else
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001103 *param = !!(sdata->u.sta.flags &
1104 IEEE80211_STA_CREATE_IBSS);
Jiri Bencf0706e822007-05-05 11:45:53 -07001105 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;
1111 else
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001112 *param = !!(sdata->u.sta.flags &
1113 IEEE80211_STA_MIXED_CELL);
Jiri Bencf0706e822007-05-05 11:45:53 -07001114 break;
1115 case PRISM2_PARAM_WMM_ENABLED:
1116 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1117 sdata->type != IEEE80211_IF_TYPE_IBSS)
1118 ret = -EINVAL;
1119 else
Jiri Slabyd6f2da52007-08-28 17:01:54 -04001120 *param = !!(sdata->u.sta.flags &
1121 IEEE80211_STA_WMM_ENABLED);
Jiri Bencf0706e822007-05-05 11:45:53 -07001122 break;
1123 default:
1124 ret = -EOPNOTSUPP;
1125 break;
1126 }
1127
1128 return ret;
1129}
1130
1131static int ieee80211_ioctl_siwmlme(struct net_device *dev,
1132 struct iw_request_info *info,
1133 struct iw_point *data, char *extra)
1134{
1135 struct ieee80211_sub_if_data *sdata;
1136 struct iw_mlme *mlme = (struct iw_mlme *) extra;
1137
1138 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1139 if (sdata->type != IEEE80211_IF_TYPE_STA &&
1140 sdata->type != IEEE80211_IF_TYPE_IBSS)
1141 return -EINVAL;
1142
1143 switch (mlme->cmd) {
1144 case IW_MLME_DEAUTH:
1145 /* TODO: mlme->addr.sa_data */
1146 return ieee80211_sta_deauthenticate(dev, mlme->reason_code);
1147 case IW_MLME_DISASSOC:
1148 /* TODO: mlme->addr.sa_data */
1149 return ieee80211_sta_disassociate(dev, mlme->reason_code);
1150 default:
1151 return -EOPNOTSUPP;
1152 }
1153}
1154
1155
1156static int ieee80211_ioctl_siwencode(struct net_device *dev,
1157 struct iw_request_info *info,
1158 struct iw_point *erq, char *keybuf)
1159{
1160 struct ieee80211_sub_if_data *sdata;
1161 int idx, i, alg = ALG_WEP;
1162 u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
1163
1164 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1165
1166 idx = erq->flags & IW_ENCODE_INDEX;
1167 if (idx == 0) {
1168 if (sdata->default_key)
1169 for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
1170 if (sdata->default_key == sdata->keys[i]) {
1171 idx = i;
1172 break;
1173 }
1174 }
1175 } else if (idx < 1 || idx > 4)
1176 return -EINVAL;
1177 else
1178 idx--;
1179
1180 if (erq->flags & IW_ENCODE_DISABLED)
1181 alg = ALG_NONE;
1182 else if (erq->length == 0) {
1183 /* No key data - just set the default TX key index */
Jiri Bence9f207f2007-05-05 11:46:38 -07001184 if (sdata->default_key != sdata->keys[idx]) {
1185 ieee80211_debugfs_key_remove_default(sdata);
Jiri Bencf0706e822007-05-05 11:45:53 -07001186 sdata->default_key = sdata->keys[idx];
Jiri Bence9f207f2007-05-05 11:46:38 -07001187 if (sdata->default_key)
1188 ieee80211_debugfs_key_add_default(sdata);
1189 }
Jiri Bencf0706e822007-05-05 11:45:53 -07001190 return 0;
1191 }
1192
1193 return ieee80211_set_encryption(
1194 dev, bcaddr,
1195 idx, alg,
1196 !sdata->default_key,
1197 keybuf, erq->length);
1198}
1199
1200
1201static int ieee80211_ioctl_giwencode(struct net_device *dev,
1202 struct iw_request_info *info,
1203 struct iw_point *erq, char *key)
1204{
1205 struct ieee80211_sub_if_data *sdata;
1206 int idx, i;
1207
1208 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1209
1210 idx = erq->flags & IW_ENCODE_INDEX;
1211 if (idx < 1 || idx > 4) {
1212 idx = -1;
1213 if (!sdata->default_key)
1214 idx = 0;
1215 else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
1216 if (sdata->default_key == sdata->keys[i]) {
1217 idx = i;
1218 break;
1219 }
1220 }
1221 if (idx < 0)
1222 return -EINVAL;
1223 } else
1224 idx--;
1225
1226 erq->flags = idx + 1;
1227
1228 if (!sdata->keys[idx]) {
1229 erq->length = 0;
1230 erq->flags |= IW_ENCODE_DISABLED;
1231 return 0;
1232 }
1233
Johannes Berg8f20fc22007-08-28 17:01:54 -04001234 memcpy(key, sdata->keys[idx]->conf.key,
1235 min((int)erq->length, sdata->keys[idx]->conf.keylen));
1236 erq->length = sdata->keys[idx]->conf.keylen;
Jiri Bencf0706e822007-05-05 11:45:53 -07001237 erq->flags |= IW_ENCODE_ENABLED;
1238
1239 return 0;
1240}
1241
1242static int ieee80211_ioctl_siwauth(struct net_device *dev,
1243 struct iw_request_info *info,
1244 struct iw_param *data, char *extra)
1245{
1246 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1247 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1248 int ret = 0;
1249
1250 switch (data->flags & IW_AUTH_INDEX) {
1251 case IW_AUTH_WPA_VERSION:
1252 case IW_AUTH_CIPHER_PAIRWISE:
1253 case IW_AUTH_CIPHER_GROUP:
1254 case IW_AUTH_WPA_ENABLED:
1255 case IW_AUTH_RX_UNENCRYPTED_EAPOL:
1256 break;
1257 case IW_AUTH_KEY_MGMT:
1258 if (sdata->type != IEEE80211_IF_TYPE_STA)
1259 ret = -EINVAL;
1260 else {
1261 /*
Johannes Berg808718c2007-08-28 17:01:53 -04001262 * Key management was set by wpa_supplicant,
1263 * we only need this to associate to a network
1264 * that has privacy enabled regardless of not
1265 * having a key.
Jiri Bencf0706e822007-05-05 11:45:53 -07001266 */
Johannes Berg808718c2007-08-28 17:01:53 -04001267 sdata->u.sta.key_management_enabled = !!data->value;
Jiri Bencf0706e822007-05-05 11:45:53 -07001268 }
1269 break;
1270 case IW_AUTH_80211_AUTH_ALG:
1271 if (sdata->type == IEEE80211_IF_TYPE_STA ||
1272 sdata->type == IEEE80211_IF_TYPE_IBSS)
1273 sdata->u.sta.auth_algs = data->value;
1274 else
1275 ret = -EOPNOTSUPP;
1276 break;
1277 case IW_AUTH_PRIVACY_INVOKED:
1278 if (local->ops->set_privacy_invoked)
1279 ret = local->ops->set_privacy_invoked(
1280 local_to_hw(local), data->value);
1281 break;
1282 default:
1283 ret = -EOPNOTSUPP;
1284 break;
1285 }
1286 return ret;
1287}
1288
1289/* Get wireless statistics. Called by /proc/net/wireless and by SIOCGIWSTATS */
1290static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
1291{
1292 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
1293 struct iw_statistics *wstats = &local->wstats;
1294 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1295 struct sta_info *sta = NULL;
1296
1297 if (sdata->type == IEEE80211_IF_TYPE_STA ||
1298 sdata->type == IEEE80211_IF_TYPE_IBSS)
1299 sta = sta_info_get(local, sdata->u.sta.bssid);
1300 if (!sta) {
1301 wstats->discard.fragment = 0;
1302 wstats->discard.misc = 0;
1303 wstats->qual.qual = 0;
1304 wstats->qual.level = 0;
1305 wstats->qual.noise = 0;
1306 wstats->qual.updated = IW_QUAL_ALL_INVALID;
1307 } else {
1308 wstats->qual.level = sta->last_rssi;
1309 wstats->qual.qual = sta->last_signal;
1310 wstats->qual.noise = sta->last_noise;
1311 wstats->qual.updated = local->wstats_flags;
1312 sta_info_put(sta);
1313 }
1314 return wstats;
1315}
1316
1317static int ieee80211_ioctl_giwauth(struct net_device *dev,
1318 struct iw_request_info *info,
1319 struct iw_param *data, char *extra)
1320{
1321 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1322 int ret = 0;
1323
1324 switch (data->flags & IW_AUTH_INDEX) {
1325 case IW_AUTH_80211_AUTH_ALG:
1326 if (sdata->type == IEEE80211_IF_TYPE_STA ||
1327 sdata->type == IEEE80211_IF_TYPE_IBSS)
1328 data->value = sdata->u.sta.auth_algs;
1329 else
1330 ret = -EOPNOTSUPP;
1331 break;
1332 default:
1333 ret = -EOPNOTSUPP;
1334 break;
1335 }
1336 return ret;
1337}
1338
1339
1340static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
1341 struct iw_request_info *info,
1342 struct iw_point *erq, char *extra)
1343{
1344 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
1345 struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
1346 int alg, idx, i;
1347
1348 switch (ext->alg) {
1349 case IW_ENCODE_ALG_NONE:
1350 alg = ALG_NONE;
1351 break;
1352 case IW_ENCODE_ALG_WEP:
1353 alg = ALG_WEP;
1354 break;
1355 case IW_ENCODE_ALG_TKIP:
1356 alg = ALG_TKIP;
1357 break;
1358 case IW_ENCODE_ALG_CCMP:
1359 alg = ALG_CCMP;
1360 break;
1361 default:
1362 return -EOPNOTSUPP;
1363 }
1364
1365 if (erq->flags & IW_ENCODE_DISABLED)
1366 alg = ALG_NONE;
1367
1368 idx = erq->flags & IW_ENCODE_INDEX;
1369 if (idx < 1 || idx > 4) {
1370 idx = -1;
1371 if (!sdata->default_key)
1372 idx = 0;
1373 else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
1374 if (sdata->default_key == sdata->keys[i]) {
1375 idx = i;
1376 break;
1377 }
1378 }
1379 if (idx < 0)
1380 return -EINVAL;
1381 } else
1382 idx--;
1383
1384 return ieee80211_set_encryption(dev, ext->addr.sa_data, idx, alg,
1385 ext->ext_flags &
1386 IW_ENCODE_EXT_SET_TX_KEY,
1387 ext->key, ext->key_len);
1388}
1389
1390
1391static const struct iw_priv_args ieee80211_ioctl_priv[] = {
1392 { PRISM2_IOCTL_PRISM2_PARAM,
1393 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 2, 0, "param" },
1394 { PRISM2_IOCTL_GET_PRISM2_PARAM,
1395 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1,
1396 IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "get_param" },
1397};
1398
1399/* Structures to export the Wireless Handlers */
1400
1401static const iw_handler ieee80211_handler[] =
1402{
1403 (iw_handler) NULL, /* SIOCSIWCOMMIT */
1404 (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */
1405 (iw_handler) NULL, /* SIOCSIWNWID */
1406 (iw_handler) NULL, /* SIOCGIWNWID */
1407 (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */
1408 (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */
1409 (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */
1410 (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */
1411 (iw_handler) NULL, /* SIOCSIWSENS */
1412 (iw_handler) NULL, /* SIOCGIWSENS */
1413 (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */
1414 (iw_handler) ieee80211_ioctl_giwrange, /* SIOCGIWRANGE */
1415 (iw_handler) NULL /* not used */, /* SIOCSIWPRIV */
1416 (iw_handler) NULL /* kernel code */, /* SIOCGIWPRIV */
1417 (iw_handler) NULL /* not used */, /* SIOCSIWSTATS */
1418 (iw_handler) NULL /* kernel code */, /* SIOCGIWSTATS */
1419 iw_handler_set_spy, /* SIOCSIWSPY */
1420 iw_handler_get_spy, /* SIOCGIWSPY */
1421 iw_handler_set_thrspy, /* SIOCSIWTHRSPY */
1422 iw_handler_get_thrspy, /* SIOCGIWTHRSPY */
1423 (iw_handler) ieee80211_ioctl_siwap, /* SIOCSIWAP */
1424 (iw_handler) ieee80211_ioctl_giwap, /* SIOCGIWAP */
1425 (iw_handler) ieee80211_ioctl_siwmlme, /* SIOCSIWMLME */
1426 (iw_handler) NULL, /* SIOCGIWAPLIST */
1427 (iw_handler) ieee80211_ioctl_siwscan, /* SIOCSIWSCAN */
1428 (iw_handler) ieee80211_ioctl_giwscan, /* SIOCGIWSCAN */
1429 (iw_handler) ieee80211_ioctl_siwessid, /* SIOCSIWESSID */
1430 (iw_handler) ieee80211_ioctl_giwessid, /* SIOCGIWESSID */
1431 (iw_handler) NULL, /* SIOCSIWNICKN */
1432 (iw_handler) NULL, /* SIOCGIWNICKN */
1433 (iw_handler) NULL, /* -- hole -- */
1434 (iw_handler) NULL, /* -- hole -- */
Larry Finger1fd5e582007-07-10 19:32:10 +02001435 (iw_handler) ieee80211_ioctl_siwrate, /* SIOCSIWRATE */
Larry Fingerb3d88ad2007-06-10 17:57:33 -07001436 (iw_handler) ieee80211_ioctl_giwrate, /* SIOCGIWRATE */
Jiri Bencf0706e822007-05-05 11:45:53 -07001437 (iw_handler) ieee80211_ioctl_siwrts, /* SIOCSIWRTS */
1438 (iw_handler) ieee80211_ioctl_giwrts, /* SIOCGIWRTS */
1439 (iw_handler) ieee80211_ioctl_siwfrag, /* SIOCSIWFRAG */
1440 (iw_handler) ieee80211_ioctl_giwfrag, /* SIOCGIWFRAG */
1441 (iw_handler) NULL, /* SIOCSIWTXPOW */
Larry Fingerfe6aa302007-08-10 11:23:20 -05001442 (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
Jiri Bencf0706e822007-05-05 11:45:53 -07001443 (iw_handler) ieee80211_ioctl_siwretry, /* SIOCSIWRETRY */
1444 (iw_handler) ieee80211_ioctl_giwretry, /* SIOCGIWRETRY */
1445 (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */
1446 (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */
1447 (iw_handler) NULL, /* SIOCSIWPOWER */
1448 (iw_handler) NULL, /* SIOCGIWPOWER */
1449 (iw_handler) NULL, /* -- hole -- */
1450 (iw_handler) NULL, /* -- hole -- */
1451 (iw_handler) ieee80211_ioctl_siwgenie, /* SIOCSIWGENIE */
1452 (iw_handler) NULL, /* SIOCGIWGENIE */
1453 (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */
1454 (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */
1455 (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */
1456 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
1457 (iw_handler) NULL, /* SIOCSIWPMKSA */
1458 (iw_handler) NULL, /* -- hole -- */
1459};
1460
1461static const iw_handler ieee80211_private_handler[] =
1462{ /* SIOCIWFIRSTPRIV + */
1463 (iw_handler) ieee80211_ioctl_prism2_param, /* 0 */
1464 (iw_handler) ieee80211_ioctl_get_prism2_param, /* 1 */
1465};
1466
1467const struct iw_handler_def ieee80211_iw_handler_def =
1468{
1469 .num_standard = ARRAY_SIZE(ieee80211_handler),
1470 .num_private = ARRAY_SIZE(ieee80211_private_handler),
1471 .num_private_args = ARRAY_SIZE(ieee80211_ioctl_priv),
1472 .standard = (iw_handler *) ieee80211_handler,
1473 .private = (iw_handler *) ieee80211_private_handler,
1474 .private_args = (struct iw_priv_args *) ieee80211_ioctl_priv,
1475 .get_wireless_stats = ieee80211_get_wireless_stats,
1476};