]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - net/mac80211/wext.c
mac80211: Populate HT limitation with TKIP/WEP to the handler for SIOCSIWENCODE too
[linux-2.6-omap-h63xx.git] / net / mac80211 / wext.c
1 /*
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 "led.h"
25 #include "rate.h"
26 #include "wpa.h"
27 #include "aes_ccm.h"
28
29
30 static int ieee80211_set_encryption(struct ieee80211_sub_if_data *sdata, u8 *sta_addr,
31                                     int idx, int alg, int remove,
32                                     int set_tx_key, const u8 *_key,
33                                     size_t key_len)
34 {
35         struct ieee80211_local *local = sdata->local;
36         struct sta_info *sta;
37         struct ieee80211_key *key;
38         int err;
39
40         if (alg == ALG_AES_CMAC) {
41                 if (idx < NUM_DEFAULT_KEYS ||
42                     idx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
43                         printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d "
44                                "(BIP)\n", sdata->dev->name, idx);
45                         return -EINVAL;
46                 }
47         } else if (idx < 0 || idx >= NUM_DEFAULT_KEYS) {
48                 printk(KERN_DEBUG "%s: set_encrypt - invalid idx=%d\n",
49                        sdata->dev->name, idx);
50                 return -EINVAL;
51         }
52
53         if (remove) {
54                 rcu_read_lock();
55
56                 err = 0;
57
58                 if (is_broadcast_ether_addr(sta_addr)) {
59                         key = sdata->keys[idx];
60                 } else {
61                         sta = sta_info_get(local, sta_addr);
62                         if (!sta) {
63                                 err = -ENOENT;
64                                 goto out_unlock;
65                         }
66                         key = sta->key;
67                 }
68
69                 ieee80211_key_free(key);
70         } else {
71                 key = ieee80211_key_alloc(alg, idx, key_len, _key);
72                 if (!key)
73                         return -ENOMEM;
74
75                 sta = NULL;
76                 err = 0;
77
78                 rcu_read_lock();
79
80                 if (!is_broadcast_ether_addr(sta_addr)) {
81                         set_tx_key = 0;
82                         /*
83                          * According to the standard, the key index of a
84                          * pairwise key must be zero. However, some AP are
85                          * broken when it comes to WEP key indices, so we
86                          * work around this.
87                          */
88                         if (idx != 0 && alg != ALG_WEP) {
89                                 ieee80211_key_free(key);
90                                 err = -EINVAL;
91                                 goto out_unlock;
92                         }
93
94                         sta = sta_info_get(local, sta_addr);
95                         if (!sta) {
96                                 ieee80211_key_free(key);
97                                 err = -ENOENT;
98                                 goto out_unlock;
99                         }
100                 }
101
102                 if (alg == ALG_WEP &&
103                         key_len != LEN_WEP40 && key_len != LEN_WEP104) {
104                         ieee80211_key_free(key);
105                         err = -EINVAL;
106                         goto out_unlock;
107                 }
108
109                 ieee80211_key_link(key, sdata, sta);
110
111                 if (set_tx_key || (!sta && !sdata->default_key && key))
112                         ieee80211_set_default_key(sdata, idx);
113                 if (alg == ALG_AES_CMAC &&
114                     (set_tx_key || (!sta && !sdata->default_mgmt_key && key)))
115                         ieee80211_set_default_mgmt_key(sdata, idx);
116         }
117
118  out_unlock:
119         rcu_read_unlock();
120
121         return err;
122 }
123
124 static int ieee80211_ioctl_siwgenie(struct net_device *dev,
125                                     struct iw_request_info *info,
126                                     struct iw_point *data, char *extra)
127 {
128         struct ieee80211_sub_if_data *sdata;
129
130         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
131
132         if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
133                 return -EOPNOTSUPP;
134
135         if (sdata->vif.type == NL80211_IFTYPE_STATION) {
136                 int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
137                 if (ret)
138                         return ret;
139                 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
140                 ieee80211_sta_req_auth(sdata);
141                 return 0;
142         }
143
144         return -EOPNOTSUPP;
145 }
146
147 static int ieee80211_ioctl_siwfreq(struct net_device *dev,
148                                    struct iw_request_info *info,
149                                    struct iw_freq *freq, char *extra)
150 {
151         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
152
153         if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
154                 sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL;
155         else if (sdata->vif.type == NL80211_IFTYPE_STATION)
156                 sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
157
158         /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
159         if (freq->e == 0) {
160                 if (freq->m < 0) {
161                         if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
162                                 sdata->u.ibss.flags |=
163                                         IEEE80211_IBSS_AUTO_CHANNEL_SEL;
164                         else if (sdata->vif.type == NL80211_IFTYPE_STATION)
165                                 sdata->u.mgd.flags |=
166                                         IEEE80211_STA_AUTO_CHANNEL_SEL;
167                         return 0;
168                 } else
169                         return ieee80211_set_freq(sdata,
170                                 ieee80211_channel_to_frequency(freq->m));
171         } else {
172                 int i, div = 1000000;
173                 for (i = 0; i < freq->e; i++)
174                         div /= 10;
175                 if (div > 0)
176                         return ieee80211_set_freq(sdata, freq->m / div);
177                 else
178                         return -EINVAL;
179         }
180 }
181
182
183 static int ieee80211_ioctl_giwfreq(struct net_device *dev,
184                                    struct iw_request_info *info,
185                                    struct iw_freq *freq, char *extra)
186 {
187         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
188
189         freq->m = local->hw.conf.channel->center_freq;
190         freq->e = 6;
191
192         return 0;
193 }
194
195
196 static int ieee80211_ioctl_siwessid(struct net_device *dev,
197                                     struct iw_request_info *info,
198                                     struct iw_point *data, char *ssid)
199 {
200         struct ieee80211_sub_if_data *sdata;
201         size_t len = data->length;
202         int ret;
203
204         /* iwconfig uses nul termination in SSID.. */
205         if (len > 0 && ssid[len - 1] == '\0')
206                 len--;
207
208         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
209         if (sdata->vif.type == NL80211_IFTYPE_STATION) {
210                 if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
211                         if (len > IEEE80211_MAX_SSID_LEN)
212                                 return -EINVAL;
213                         memcpy(sdata->u.mgd.ssid, ssid, len);
214                         sdata->u.mgd.ssid_len = len;
215                         return 0;
216                 }
217
218                 if (data->flags)
219                         sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
220                 else
221                         sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
222
223                 ret = ieee80211_sta_set_ssid(sdata, ssid, len);
224                 if (ret)
225                         return ret;
226
227                 ieee80211_sta_req_auth(sdata);
228                 return 0;
229         } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
230                 return ieee80211_ibss_set_ssid(sdata, ssid, len);
231
232         return -EOPNOTSUPP;
233 }
234
235
236 static int ieee80211_ioctl_giwessid(struct net_device *dev,
237                                     struct iw_request_info *info,
238                                     struct iw_point *data, char *ssid)
239 {
240         size_t len;
241
242         struct ieee80211_sub_if_data *sdata;
243         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
244         if (sdata->vif.type == NL80211_IFTYPE_STATION) {
245                 int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
246                 if (res == 0) {
247                         data->length = len;
248                         data->flags = 1;
249                 } else
250                         data->flags = 0;
251                 return res;
252         } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
253                 int res = ieee80211_ibss_get_ssid(sdata, ssid, &len);
254                 if (res == 0) {
255                         data->length = len;
256                         data->flags = 1;
257                 } else
258                         data->flags = 0;
259                 return res;
260         }
261
262         return -EOPNOTSUPP;
263 }
264
265
266 static int ieee80211_ioctl_siwap(struct net_device *dev,
267                                  struct iw_request_info *info,
268                                  struct sockaddr *ap_addr, char *extra)
269 {
270         struct ieee80211_sub_if_data *sdata;
271
272         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
273         if (sdata->vif.type == NL80211_IFTYPE_STATION) {
274                 int ret;
275                 if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
276                         memcpy(sdata->u.mgd.bssid, (u8 *) &ap_addr->sa_data,
277                                ETH_ALEN);
278                         return 0;
279                 }
280                 if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
281                         sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
282                                 IEEE80211_STA_AUTO_CHANNEL_SEL;
283                 else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
284                         sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
285                 else
286                         sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
287                 ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
288                 if (ret)
289                         return ret;
290                 ieee80211_sta_req_auth(sdata);
291                 return 0;
292         } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
293                 if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
294                         sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL |
295                                                IEEE80211_IBSS_AUTO_CHANNEL_SEL;
296                 else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
297                         sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL;
298                 else
299                         sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL;
300
301                 return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
302         } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
303                 /*
304                  * If it is necessary to update the WDS peer address
305                  * while the interface is running, then we need to do
306                  * more work here, namely if it is running we need to
307                  * add a new and remove the old STA entry, this is
308                  * normally handled by _open() and _stop().
309                  */
310                 if (netif_running(dev))
311                         return -EBUSY;
312
313                 memcpy(&sdata->u.wds.remote_addr, (u8 *) &ap_addr->sa_data,
314                        ETH_ALEN);
315
316                 return 0;
317         }
318
319         return -EOPNOTSUPP;
320 }
321
322
323 static int ieee80211_ioctl_giwap(struct net_device *dev,
324                                  struct iw_request_info *info,
325                                  struct sockaddr *ap_addr, char *extra)
326 {
327         struct ieee80211_sub_if_data *sdata;
328
329         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
330         if (sdata->vif.type == NL80211_IFTYPE_STATION) {
331                 if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) {
332                         ap_addr->sa_family = ARPHRD_ETHER;
333                         memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN);
334                 } else
335                         memset(&ap_addr->sa_data, 0, ETH_ALEN);
336                 return 0;
337         } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
338                 if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) {
339                         ap_addr->sa_family = ARPHRD_ETHER;
340                         memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN);
341                 } else
342                         memset(&ap_addr->sa_data, 0, ETH_ALEN);
343                 return 0;
344         } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
345                 ap_addr->sa_family = ARPHRD_ETHER;
346                 memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
347                 return 0;
348         }
349
350         return -EOPNOTSUPP;
351 }
352
353
354 static int ieee80211_ioctl_siwrate(struct net_device *dev,
355                                   struct iw_request_info *info,
356                                   struct iw_param *rate, char *extra)
357 {
358         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
359         int i, err = -EINVAL;
360         u32 target_rate = rate->value / 100000;
361         struct ieee80211_sub_if_data *sdata;
362         struct ieee80211_supported_band *sband;
363
364         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
365
366         sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
367
368         /* target_rate = -1, rate->fixed = 0 means auto only, so use all rates
369          * target_rate = X, rate->fixed = 1 means only rate X
370          * target_rate = X, rate->fixed = 0 means all rates <= X */
371         sdata->max_ratectrl_rateidx = -1;
372         sdata->force_unicast_rateidx = -1;
373         if (rate->value < 0)
374                 return 0;
375
376         for (i=0; i< sband->n_bitrates; i++) {
377                 struct ieee80211_rate *brate = &sband->bitrates[i];
378                 int this_rate = brate->bitrate;
379
380                 if (target_rate == this_rate) {
381                         sdata->max_ratectrl_rateidx = i;
382                         if (rate->fixed)
383                                 sdata->force_unicast_rateidx = i;
384                         err = 0;
385                         break;
386                 }
387         }
388         return err;
389 }
390
391 static int ieee80211_ioctl_giwrate(struct net_device *dev,
392                                   struct iw_request_info *info,
393                                   struct iw_param *rate, char *extra)
394 {
395         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
396         struct sta_info *sta;
397         struct ieee80211_sub_if_data *sdata;
398         struct ieee80211_supported_band *sband;
399
400         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
401
402         if (sdata->vif.type != NL80211_IFTYPE_STATION)
403                 return -EOPNOTSUPP;
404
405         sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
406
407         rcu_read_lock();
408
409         sta = sta_info_get(local, sdata->u.mgd.bssid);
410
411         if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
412                 rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
413         else
414                 rate->value = 0;
415
416         rcu_read_unlock();
417
418         if (!sta)
419                 return -ENODEV;
420
421         rate->value *= 100000;
422
423         return 0;
424 }
425
426 static int ieee80211_ioctl_siwtxpower(struct net_device *dev,
427                                       struct iw_request_info *info,
428                                       union iwreq_data *data, char *extra)
429 {
430         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
431         struct ieee80211_channel* chan = local->hw.conf.channel;
432         u32 reconf_flags = 0;
433         int new_power_level;
434
435         if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
436                 return -EINVAL;
437         if (data->txpower.flags & IW_TXPOW_RANGE)
438                 return -EINVAL;
439         if (!chan)
440                 return -EINVAL;
441
442         if (data->txpower.fixed)
443                 new_power_level = min(data->txpower.value, chan->max_power);
444         else /* Automatic power level setting */
445                 new_power_level = chan->max_power;
446
447         local->user_power_level = new_power_level;
448         if (local->hw.conf.power_level != new_power_level)
449                 reconf_flags |= IEEE80211_CONF_CHANGE_POWER;
450
451         if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) {
452                 local->hw.conf.radio_enabled = !(data->txpower.disabled);
453                 reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED;
454                 ieee80211_led_radio(local, local->hw.conf.radio_enabled);
455         }
456
457         if (reconf_flags)
458                 ieee80211_hw_config(local, reconf_flags);
459
460         return 0;
461 }
462
463 static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
464                                    struct iw_request_info *info,
465                                    union iwreq_data *data, char *extra)
466 {
467         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
468
469         data->txpower.fixed = 1;
470         data->txpower.disabled = !(local->hw.conf.radio_enabled);
471         data->txpower.value = local->hw.conf.power_level;
472         data->txpower.flags = IW_TXPOW_DBM;
473
474         return 0;
475 }
476
477 static int ieee80211_ioctl_siwrts(struct net_device *dev,
478                                   struct iw_request_info *info,
479                                   struct iw_param *rts, char *extra)
480 {
481         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
482
483         if (rts->disabled)
484                 local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
485         else if (!rts->fixed)
486                 /* if the rts value is not fixed, then take default */
487                 local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD;
488         else if (rts->value < 0 || rts->value > IEEE80211_MAX_RTS_THRESHOLD)
489                 return -EINVAL;
490         else
491                 local->rts_threshold = rts->value;
492
493         /* If the wlan card performs RTS/CTS in hardware/firmware,
494          * configure it here */
495
496         if (local->ops->set_rts_threshold)
497                 local->ops->set_rts_threshold(local_to_hw(local),
498                                              local->rts_threshold);
499
500         return 0;
501 }
502
503 static int ieee80211_ioctl_giwrts(struct net_device *dev,
504                                   struct iw_request_info *info,
505                                   struct iw_param *rts, char *extra)
506 {
507         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
508
509         rts->value = local->rts_threshold;
510         rts->disabled = (rts->value >= IEEE80211_MAX_RTS_THRESHOLD);
511         rts->fixed = 1;
512
513         return 0;
514 }
515
516
517 static int ieee80211_ioctl_siwfrag(struct net_device *dev,
518                                    struct iw_request_info *info,
519                                    struct iw_param *frag, char *extra)
520 {
521         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
522
523         if (frag->disabled)
524                 local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
525         else if (!frag->fixed)
526                 local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD;
527         else if (frag->value < 256 ||
528                  frag->value > IEEE80211_MAX_FRAG_THRESHOLD)
529                 return -EINVAL;
530         else {
531                 /* Fragment length must be even, so strip LSB. */
532                 local->fragmentation_threshold = frag->value & ~0x1;
533         }
534
535         return 0;
536 }
537
538 static int ieee80211_ioctl_giwfrag(struct net_device *dev,
539                                    struct iw_request_info *info,
540                                    struct iw_param *frag, char *extra)
541 {
542         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
543
544         frag->value = local->fragmentation_threshold;
545         frag->disabled = (frag->value >= IEEE80211_MAX_RTS_THRESHOLD);
546         frag->fixed = 1;
547
548         return 0;
549 }
550
551
552 static int ieee80211_ioctl_siwretry(struct net_device *dev,
553                                     struct iw_request_info *info,
554                                     struct iw_param *retry, char *extra)
555 {
556         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
557
558         if (retry->disabled ||
559             (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
560                 return -EINVAL;
561
562         if (retry->flags & IW_RETRY_MAX) {
563                 local->hw.conf.long_frame_max_tx_count = retry->value;
564         } else if (retry->flags & IW_RETRY_MIN) {
565                 local->hw.conf.short_frame_max_tx_count = retry->value;
566         } else {
567                 local->hw.conf.long_frame_max_tx_count = retry->value;
568                 local->hw.conf.short_frame_max_tx_count = retry->value;
569         }
570
571         ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
572
573         return 0;
574 }
575
576
577 static int ieee80211_ioctl_giwretry(struct net_device *dev,
578                                     struct iw_request_info *info,
579                                     struct iw_param *retry, char *extra)
580 {
581         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
582
583         retry->disabled = 0;
584         if (retry->flags == 0 || retry->flags & IW_RETRY_MIN) {
585                 /* first return min value, iwconfig will ask max value
586                  * later if needed */
587                 retry->flags |= IW_RETRY_LIMIT;
588                 retry->value = local->hw.conf.short_frame_max_tx_count;
589                 if (local->hw.conf.long_frame_max_tx_count !=
590                     local->hw.conf.short_frame_max_tx_count)
591                         retry->flags |= IW_RETRY_MIN;
592                 return 0;
593         }
594         if (retry->flags & IW_RETRY_MAX) {
595                 retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
596                 retry->value = local->hw.conf.long_frame_max_tx_count;
597         }
598
599         return 0;
600 }
601
602 static int ieee80211_ioctl_siwmlme(struct net_device *dev,
603                                    struct iw_request_info *info,
604                                    struct iw_point *data, char *extra)
605 {
606         struct ieee80211_sub_if_data *sdata;
607         struct iw_mlme *mlme = (struct iw_mlme *) extra;
608
609         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
610         if (!(sdata->vif.type == NL80211_IFTYPE_STATION))
611                 return -EINVAL;
612
613         switch (mlme->cmd) {
614         case IW_MLME_DEAUTH:
615                 /* TODO: mlme->addr.sa_data */
616                 return ieee80211_sta_deauthenticate(sdata, mlme->reason_code);
617         case IW_MLME_DISASSOC:
618                 /* TODO: mlme->addr.sa_data */
619                 return ieee80211_sta_disassociate(sdata, mlme->reason_code);
620         default:
621                 return -EOPNOTSUPP;
622         }
623 }
624
625
626 static int ieee80211_ioctl_siwencode(struct net_device *dev,
627                                      struct iw_request_info *info,
628                                      struct iw_point *erq, char *keybuf)
629 {
630         struct ieee80211_sub_if_data *sdata;
631         int idx, i, alg = ALG_WEP;
632         u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
633         int remove = 0, ret;
634
635         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
636
637         idx = erq->flags & IW_ENCODE_INDEX;
638         if (idx == 0) {
639                 if (sdata->default_key)
640                         for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
641                                 if (sdata->default_key == sdata->keys[i]) {
642                                         idx = i;
643                                         break;
644                                 }
645                         }
646         } else if (idx < 1 || idx > 4)
647                 return -EINVAL;
648         else
649                 idx--;
650
651         if (erq->flags & IW_ENCODE_DISABLED)
652                 remove = 1;
653         else if (erq->length == 0) {
654                 /* No key data - just set the default TX key index */
655                 ieee80211_set_default_key(sdata, idx);
656                 return 0;
657         }
658
659         ret = ieee80211_set_encryption(
660                 sdata, bcaddr,
661                 idx, alg, remove,
662                 !sdata->default_key,
663                 keybuf, erq->length);
664
665         if (!ret) {
666                 if (remove)
667                         sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED;
668                 else
669                         sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED;
670         }
671
672         return ret;
673 }
674
675
676 static int ieee80211_ioctl_giwencode(struct net_device *dev,
677                                      struct iw_request_info *info,
678                                      struct iw_point *erq, char *key)
679 {
680         struct ieee80211_sub_if_data *sdata;
681         int idx, i;
682
683         sdata = IEEE80211_DEV_TO_SUB_IF(dev);
684
685         idx = erq->flags & IW_ENCODE_INDEX;
686         if (idx < 1 || idx > 4) {
687                 idx = -1;
688                 if (!sdata->default_key)
689                         idx = 0;
690                 else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
691                         if (sdata->default_key == sdata->keys[i]) {
692                                 idx = i;
693                                 break;
694                         }
695                 }
696                 if (idx < 0)
697                         return -EINVAL;
698         } else
699                 idx--;
700
701         erq->flags = idx + 1;
702
703         if (!sdata->keys[idx]) {
704                 erq->length = 0;
705                 erq->flags |= IW_ENCODE_DISABLED;
706                 return 0;
707         }
708
709         memcpy(key, sdata->keys[idx]->conf.key,
710                min_t(int, erq->length, sdata->keys[idx]->conf.keylen));
711         erq->length = sdata->keys[idx]->conf.keylen;
712         erq->flags |= IW_ENCODE_ENABLED;
713
714         if (sdata->vif.type == NL80211_IFTYPE_STATION) {
715                 switch (sdata->u.mgd.auth_alg) {
716                 case WLAN_AUTH_OPEN:
717                 case WLAN_AUTH_LEAP:
718                         erq->flags |= IW_ENCODE_OPEN;
719                         break;
720                 case WLAN_AUTH_SHARED_KEY:
721                         erq->flags |= IW_ENCODE_RESTRICTED;
722                         break;
723                 }
724         }
725
726         return 0;
727 }
728
729 static int ieee80211_ioctl_siwpower(struct net_device *dev,
730                                     struct iw_request_info *info,
731                                     struct iw_param *wrq,
732                                     char *extra)
733 {
734         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
735         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
736         struct ieee80211_conf *conf = &local->hw.conf;
737         int ret = 0, timeout = 0;
738         bool ps;
739
740         if (!(local->hw.flags & IEEE80211_HW_SUPPORTS_PS))
741                 return -EOPNOTSUPP;
742
743         if (sdata->vif.type != NL80211_IFTYPE_STATION)
744                 return -EINVAL;
745
746         if (wrq->disabled) {
747                 ps = false;
748                 timeout = 0;
749                 goto set;
750         }
751
752         switch (wrq->flags & IW_POWER_MODE) {
753         case IW_POWER_ON:       /* If not specified */
754         case IW_POWER_MODE:     /* If set all mask */
755         case IW_POWER_ALL_R:    /* If explicitely state all */
756                 ps = true;
757                 break;
758         default:                /* Otherwise we ignore */
759                 return -EINVAL;
760         }
761
762         if (wrq->flags & ~(IW_POWER_MODE | IW_POWER_TIMEOUT))
763                 return -EINVAL;
764
765         if (wrq->flags & IW_POWER_TIMEOUT)
766                 timeout = wrq->value / 1000;
767
768  set:
769         if (ps == local->powersave && timeout == conf->dynamic_ps_timeout)
770                 return ret;
771
772         local->powersave = ps;
773         conf->dynamic_ps_timeout = timeout;
774
775         if (local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)
776                 ret = ieee80211_hw_config(local,
777                                           IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);
778
779         if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED))
780                 return ret;
781
782         if (conf->dynamic_ps_timeout > 0 &&
783             !(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) {
784                 mod_timer(&local->dynamic_ps_timer, jiffies +
785                           msecs_to_jiffies(conf->dynamic_ps_timeout));
786         } else {
787                 if (local->powersave) {
788                         if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
789                                 ieee80211_send_nullfunc(local, sdata, 1);
790                         conf->flags |= IEEE80211_CONF_PS;
791                         ret = ieee80211_hw_config(local,
792                                         IEEE80211_CONF_CHANGE_PS);
793                 } else {
794                         conf->flags &= ~IEEE80211_CONF_PS;
795                         ret = ieee80211_hw_config(local,
796                                         IEEE80211_CONF_CHANGE_PS);
797                         if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
798                                 ieee80211_send_nullfunc(local, sdata, 0);
799                         del_timer_sync(&local->dynamic_ps_timer);
800                         cancel_work_sync(&local->dynamic_ps_enable_work);
801                 }
802         }
803
804         return ret;
805 }
806
807 static int ieee80211_ioctl_giwpower(struct net_device *dev,
808                                     struct iw_request_info *info,
809                                     union iwreq_data *wrqu,
810                                     char *extra)
811 {
812         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
813
814         wrqu->power.disabled = !local->powersave;
815
816         return 0;
817 }
818
819 static int ieee80211_ioctl_siwauth(struct net_device *dev,
820                                    struct iw_request_info *info,
821                                    struct iw_param *data, char *extra)
822 {
823         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
824         int ret = 0;
825
826         switch (data->flags & IW_AUTH_INDEX) {
827         case IW_AUTH_WPA_VERSION:
828         case IW_AUTH_CIPHER_GROUP:
829         case IW_AUTH_WPA_ENABLED:
830         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
831         case IW_AUTH_KEY_MGMT:
832         case IW_AUTH_CIPHER_GROUP_MGMT:
833                 break;
834         case IW_AUTH_CIPHER_PAIRWISE:
835                 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
836                         if (data->value & (IW_AUTH_CIPHER_WEP40 |
837                             IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP))
838                                 sdata->u.mgd.flags |=
839                                         IEEE80211_STA_TKIP_WEP_USED;
840                         else
841                                 sdata->u.mgd.flags &=
842                                         ~IEEE80211_STA_TKIP_WEP_USED;
843                 }
844                 break;
845         case IW_AUTH_DROP_UNENCRYPTED:
846                 sdata->drop_unencrypted = !!data->value;
847                 break;
848         case IW_AUTH_PRIVACY_INVOKED:
849                 if (sdata->vif.type != NL80211_IFTYPE_STATION)
850                         ret = -EINVAL;
851                 else {
852                         sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
853                         /*
854                          * Privacy invoked by wpa_supplicant, store the
855                          * value and allow associating to a protected
856                          * network without having a key up front.
857                          */
858                         if (data->value)
859                                 sdata->u.mgd.flags |=
860                                         IEEE80211_STA_PRIVACY_INVOKED;
861                 }
862                 break;
863         case IW_AUTH_80211_AUTH_ALG:
864                 if (sdata->vif.type == NL80211_IFTYPE_STATION)
865                         sdata->u.mgd.auth_algs = data->value;
866                 else
867                         ret = -EOPNOTSUPP;
868                 break;
869         case IW_AUTH_MFP:
870                 if (!(sdata->local->hw.flags & IEEE80211_HW_MFP_CAPABLE)) {
871                         ret = -EOPNOTSUPP;
872                         break;
873                 }
874                 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
875                         switch (data->value) {
876                         case IW_AUTH_MFP_DISABLED:
877                                 sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
878                                 break;
879                         case IW_AUTH_MFP_OPTIONAL:
880                                 sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL;
881                                 break;
882                         case IW_AUTH_MFP_REQUIRED:
883                                 sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
884                                 break;
885                         default:
886                                 ret = -EINVAL;
887                         }
888                 } else
889                         ret = -EOPNOTSUPP;
890                 break;
891         default:
892                 ret = -EOPNOTSUPP;
893                 break;
894         }
895         return ret;
896 }
897
898 /* Get wireless statistics.  Called by /proc/net/wireless and by SIOCGIWSTATS */
899 static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev)
900 {
901         struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
902         struct iw_statistics *wstats = &local->wstats;
903         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
904         struct sta_info *sta = NULL;
905
906         rcu_read_lock();
907
908         if (sdata->vif.type == NL80211_IFTYPE_STATION)
909                 sta = sta_info_get(local, sdata->u.mgd.bssid);
910
911         if (!sta) {
912                 wstats->discard.fragment = 0;
913                 wstats->discard.misc = 0;
914                 wstats->qual.qual = 0;
915                 wstats->qual.level = 0;
916                 wstats->qual.noise = 0;
917                 wstats->qual.updated = IW_QUAL_ALL_INVALID;
918         } else {
919                 wstats->qual.updated = 0;
920                 /*
921                  * mirror what cfg80211 does for iwrange/scan results,
922                  * otherwise userspace gets confused.
923                  */
924                 if (local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
925                                        IEEE80211_HW_SIGNAL_DBM)) {
926                         wstats->qual.updated |= IW_QUAL_LEVEL_UPDATED;
927                         wstats->qual.updated |= IW_QUAL_QUAL_UPDATED;
928                 } else {
929                         wstats->qual.updated |= IW_QUAL_LEVEL_INVALID;
930                         wstats->qual.updated |= IW_QUAL_QUAL_INVALID;
931                 }
932
933                 if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
934                         wstats->qual.level = sta->last_signal;
935                         wstats->qual.qual = sta->last_signal;
936                 } else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
937                         int sig = sta->last_signal;
938
939                         wstats->qual.updated |= IW_QUAL_DBM;
940                         wstats->qual.level = sig;
941                         if (sig < -110)
942                                 sig = -110;
943                         else if (sig > -40)
944                                 sig = -40;
945                         wstats->qual.qual = sig + 110;
946                 }
947
948                 if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
949                         /*
950                          * This assumes that if driver reports noise, it also
951                          * reports signal in dBm.
952                          */
953                         wstats->qual.noise = sta->last_noise;
954                         wstats->qual.updated |= IW_QUAL_NOISE_UPDATED;
955                 } else {
956                         wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
957                 }
958         }
959
960         rcu_read_unlock();
961
962         return wstats;
963 }
964
965 static int ieee80211_ioctl_giwauth(struct net_device *dev,
966                                    struct iw_request_info *info,
967                                    struct iw_param *data, char *extra)
968 {
969         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
970         int ret = 0;
971
972         switch (data->flags & IW_AUTH_INDEX) {
973         case IW_AUTH_80211_AUTH_ALG:
974                 if (sdata->vif.type == NL80211_IFTYPE_STATION)
975                         data->value = sdata->u.mgd.auth_algs;
976                 else
977                         ret = -EOPNOTSUPP;
978                 break;
979         default:
980                 ret = -EOPNOTSUPP;
981                 break;
982         }
983         return ret;
984 }
985
986
987 static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
988                                         struct iw_request_info *info,
989                                         struct iw_point *erq, char *extra)
990 {
991         struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
992         struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
993         int uninitialized_var(alg), idx, i, remove = 0;
994
995         switch (ext->alg) {
996         case IW_ENCODE_ALG_NONE:
997                 remove = 1;
998                 break;
999         case IW_ENCODE_ALG_WEP:
1000                 alg = ALG_WEP;
1001                 break;
1002         case IW_ENCODE_ALG_TKIP:
1003                 alg = ALG_TKIP;
1004                 break;
1005         case IW_ENCODE_ALG_CCMP:
1006                 alg = ALG_CCMP;
1007                 break;
1008         case IW_ENCODE_ALG_AES_CMAC:
1009                 alg = ALG_AES_CMAC;
1010                 break;
1011         default:
1012                 return -EOPNOTSUPP;
1013         }
1014
1015         if (erq->flags & IW_ENCODE_DISABLED)
1016                 remove = 1;
1017
1018         idx = erq->flags & IW_ENCODE_INDEX;
1019         if (alg == ALG_AES_CMAC) {
1020                 if (idx < NUM_DEFAULT_KEYS + 1 ||
1021                     idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
1022                         idx = -1;
1023                         if (!sdata->default_mgmt_key)
1024                                 idx = 0;
1025                         else for (i = NUM_DEFAULT_KEYS;
1026                                   i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
1027                                   i++) {
1028                                 if (sdata->default_mgmt_key == sdata->keys[i])
1029                                 {
1030                                         idx = i;
1031                                         break;
1032                                 }
1033                         }
1034                         if (idx < 0)
1035                                 return -EINVAL;
1036                 } else
1037                         idx--;
1038         } else {
1039                 if (idx < 1 || idx > 4) {
1040                         idx = -1;
1041                         if (!sdata->default_key)
1042                                 idx = 0;
1043                         else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
1044                                 if (sdata->default_key == sdata->keys[i]) {
1045                                         idx = i;
1046                                         break;
1047                                 }
1048                         }
1049                         if (idx < 0)
1050                                 return -EINVAL;
1051                 } else
1052                         idx--;
1053         }
1054
1055         return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg,
1056                                         remove,
1057                                         ext->ext_flags &
1058                                         IW_ENCODE_EXT_SET_TX_KEY,
1059                                         ext->key, ext->key_len);
1060 }
1061
1062
1063 /* Structures to export the Wireless Handlers */
1064
1065 static const iw_handler ieee80211_handler[] =
1066 {
1067         (iw_handler) NULL,                              /* SIOCSIWCOMMIT */
1068         (iw_handler) cfg80211_wext_giwname,             /* SIOCGIWNAME */
1069         (iw_handler) NULL,                              /* SIOCSIWNWID */
1070         (iw_handler) NULL,                              /* SIOCGIWNWID */
1071         (iw_handler) ieee80211_ioctl_siwfreq,           /* SIOCSIWFREQ */
1072         (iw_handler) ieee80211_ioctl_giwfreq,           /* SIOCGIWFREQ */
1073         (iw_handler) cfg80211_wext_siwmode,             /* SIOCSIWMODE */
1074         (iw_handler) cfg80211_wext_giwmode,             /* SIOCGIWMODE */
1075         (iw_handler) NULL,                              /* SIOCSIWSENS */
1076         (iw_handler) NULL,                              /* SIOCGIWSENS */
1077         (iw_handler) NULL /* not used */,               /* SIOCSIWRANGE */
1078         (iw_handler) cfg80211_wext_giwrange,            /* SIOCGIWRANGE */
1079         (iw_handler) NULL /* not used */,               /* SIOCSIWPRIV */
1080         (iw_handler) NULL /* kernel code */,            /* SIOCGIWPRIV */
1081         (iw_handler) NULL /* not used */,               /* SIOCSIWSTATS */
1082         (iw_handler) NULL /* kernel code */,            /* SIOCGIWSTATS */
1083         (iw_handler) NULL,                              /* SIOCSIWSPY */
1084         (iw_handler) NULL,                              /* SIOCGIWSPY */
1085         (iw_handler) NULL,                              /* SIOCSIWTHRSPY */
1086         (iw_handler) NULL,                              /* SIOCGIWTHRSPY */
1087         (iw_handler) ieee80211_ioctl_siwap,             /* SIOCSIWAP */
1088         (iw_handler) ieee80211_ioctl_giwap,             /* SIOCGIWAP */
1089         (iw_handler) ieee80211_ioctl_siwmlme,           /* SIOCSIWMLME */
1090         (iw_handler) NULL,                              /* SIOCGIWAPLIST */
1091         (iw_handler) cfg80211_wext_siwscan,             /* SIOCSIWSCAN */
1092         (iw_handler) cfg80211_wext_giwscan,             /* SIOCGIWSCAN */
1093         (iw_handler) ieee80211_ioctl_siwessid,          /* SIOCSIWESSID */
1094         (iw_handler) ieee80211_ioctl_giwessid,          /* SIOCGIWESSID */
1095         (iw_handler) NULL,                              /* SIOCSIWNICKN */
1096         (iw_handler) NULL,                              /* SIOCGIWNICKN */
1097         (iw_handler) NULL,                              /* -- hole -- */
1098         (iw_handler) NULL,                              /* -- hole -- */
1099         (iw_handler) ieee80211_ioctl_siwrate,           /* SIOCSIWRATE */
1100         (iw_handler) ieee80211_ioctl_giwrate,           /* SIOCGIWRATE */
1101         (iw_handler) ieee80211_ioctl_siwrts,            /* SIOCSIWRTS */
1102         (iw_handler) ieee80211_ioctl_giwrts,            /* SIOCGIWRTS */
1103         (iw_handler) ieee80211_ioctl_siwfrag,           /* SIOCSIWFRAG */
1104         (iw_handler) ieee80211_ioctl_giwfrag,           /* SIOCGIWFRAG */
1105         (iw_handler) ieee80211_ioctl_siwtxpower,        /* SIOCSIWTXPOW */
1106         (iw_handler) ieee80211_ioctl_giwtxpower,        /* SIOCGIWTXPOW */
1107         (iw_handler) ieee80211_ioctl_siwretry,          /* SIOCSIWRETRY */
1108         (iw_handler) ieee80211_ioctl_giwretry,          /* SIOCGIWRETRY */
1109         (iw_handler) ieee80211_ioctl_siwencode,         /* SIOCSIWENCODE */
1110         (iw_handler) ieee80211_ioctl_giwencode,         /* SIOCGIWENCODE */
1111         (iw_handler) ieee80211_ioctl_siwpower,          /* SIOCSIWPOWER */
1112         (iw_handler) ieee80211_ioctl_giwpower,          /* SIOCGIWPOWER */
1113         (iw_handler) NULL,                              /* -- hole -- */
1114         (iw_handler) NULL,                              /* -- hole -- */
1115         (iw_handler) ieee80211_ioctl_siwgenie,          /* SIOCSIWGENIE */
1116         (iw_handler) NULL,                              /* SIOCGIWGENIE */
1117         (iw_handler) ieee80211_ioctl_siwauth,           /* SIOCSIWAUTH */
1118         (iw_handler) ieee80211_ioctl_giwauth,           /* SIOCGIWAUTH */
1119         (iw_handler) ieee80211_ioctl_siwencodeext,      /* SIOCSIWENCODEEXT */
1120         (iw_handler) NULL,                              /* SIOCGIWENCODEEXT */
1121         (iw_handler) NULL,                              /* SIOCSIWPMKSA */
1122         (iw_handler) NULL,                              /* -- hole -- */
1123 };
1124
1125 const struct iw_handler_def ieee80211_iw_handler_def =
1126 {
1127         .num_standard   = ARRAY_SIZE(ieee80211_handler),
1128         .standard       = (iw_handler *) ieee80211_handler,
1129         .get_wireless_stats = ieee80211_get_wireless_stats,
1130 };