cfg80211: managed mode wext compatibility
[linux-2.6.git] / net / wireless / wext-compat.c
1 /*
2  * cfg80211 - wext compat code
3  *
4  * This is temporary code until all wireless functionality is migrated
5  * into cfg80211, when that happens all the exports here go away and
6  * we directly assign the wireless handlers of wireless interfaces.
7  *
8  * Copyright 2008-2009  Johannes Berg <johannes@sipsolutions.net>
9  */
10
11 #include <linux/wireless.h>
12 #include <linux/nl80211.h>
13 #include <linux/if_arp.h>
14 #include <linux/etherdevice.h>
15 #include <net/iw_handler.h>
16 #include <net/cfg80211.h>
17 #include "core.h"
18
19 int cfg80211_wext_giwname(struct net_device *dev,
20                           struct iw_request_info *info,
21                           char *name, char *extra)
22 {
23         struct wireless_dev *wdev = dev->ieee80211_ptr;
24         struct ieee80211_supported_band *sband;
25         bool is_ht = false, is_a = false, is_b = false, is_g = false;
26
27         if (!wdev)
28                 return -EOPNOTSUPP;
29
30         sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
31         if (sband) {
32                 is_a = true;
33                 is_ht |= sband->ht_cap.ht_supported;
34         }
35
36         sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
37         if (sband) {
38                 int i;
39                 /* Check for mandatory rates */
40                 for (i = 0; i < sband->n_bitrates; i++) {
41                         if (sband->bitrates[i].bitrate == 10)
42                                 is_b = true;
43                         if (sband->bitrates[i].bitrate == 60)
44                                 is_g = true;
45                 }
46                 is_ht |= sband->ht_cap.ht_supported;
47         }
48
49         strcpy(name, "IEEE 802.11");
50         if (is_a)
51                 strcat(name, "a");
52         if (is_b)
53                 strcat(name, "b");
54         if (is_g)
55                 strcat(name, "g");
56         if (is_ht)
57                 strcat(name, "n");
58
59         return 0;
60 }
61 EXPORT_SYMBOL_GPL(cfg80211_wext_giwname);
62
63 int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info,
64                           u32 *mode, char *extra)
65 {
66         struct wireless_dev *wdev = dev->ieee80211_ptr;
67         struct cfg80211_registered_device *rdev;
68         struct vif_params vifparams;
69         enum nl80211_iftype type;
70         int ret;
71
72         if (!wdev)
73                 return -EOPNOTSUPP;
74
75         rdev = wiphy_to_dev(wdev->wiphy);
76
77         if (!rdev->ops->change_virtual_intf)
78                 return -EOPNOTSUPP;
79
80         /* don't support changing VLANs, you just re-create them */
81         if (wdev->iftype == NL80211_IFTYPE_AP_VLAN)
82                 return -EOPNOTSUPP;
83
84         switch (*mode) {
85         case IW_MODE_INFRA:
86                 type = NL80211_IFTYPE_STATION;
87                 break;
88         case IW_MODE_ADHOC:
89                 type = NL80211_IFTYPE_ADHOC;
90                 break;
91         case IW_MODE_REPEAT:
92                 type = NL80211_IFTYPE_WDS;
93                 break;
94         case IW_MODE_MONITOR:
95                 type = NL80211_IFTYPE_MONITOR;
96                 break;
97         default:
98                 return -EINVAL;
99         }
100
101         if (type == wdev->iftype)
102                 return 0;
103
104         memset(&vifparams, 0, sizeof(vifparams));
105
106         ret = rdev->ops->change_virtual_intf(wdev->wiphy, dev, type,
107                                              NULL, &vifparams);
108         WARN_ON(!ret && wdev->iftype != type);
109
110         return ret;
111 }
112 EXPORT_SYMBOL_GPL(cfg80211_wext_siwmode);
113
114 int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
115                           u32 *mode, char *extra)
116 {
117         struct wireless_dev *wdev = dev->ieee80211_ptr;
118
119         if (!wdev)
120                 return -EOPNOTSUPP;
121
122         switch (wdev->iftype) {
123         case NL80211_IFTYPE_AP:
124                 *mode = IW_MODE_MASTER;
125                 break;
126         case NL80211_IFTYPE_STATION:
127                 *mode = IW_MODE_INFRA;
128                 break;
129         case NL80211_IFTYPE_ADHOC:
130                 *mode = IW_MODE_ADHOC;
131                 break;
132         case NL80211_IFTYPE_MONITOR:
133                 *mode = IW_MODE_MONITOR;
134                 break;
135         case NL80211_IFTYPE_WDS:
136                 *mode = IW_MODE_REPEAT;
137                 break;
138         case NL80211_IFTYPE_AP_VLAN:
139                 *mode = IW_MODE_SECOND;         /* FIXME */
140                 break;
141         default:
142                 *mode = IW_MODE_AUTO;
143                 break;
144         }
145         return 0;
146 }
147 EXPORT_SYMBOL_GPL(cfg80211_wext_giwmode);
148
149
150 int cfg80211_wext_giwrange(struct net_device *dev,
151                            struct iw_request_info *info,
152                            struct iw_point *data, char *extra)
153 {
154         struct wireless_dev *wdev = dev->ieee80211_ptr;
155         struct iw_range *range = (struct iw_range *) extra;
156         enum ieee80211_band band;
157         int c = 0;
158
159         if (!wdev)
160                 return -EOPNOTSUPP;
161
162         data->length = sizeof(struct iw_range);
163         memset(range, 0, sizeof(struct iw_range));
164
165         range->we_version_compiled = WIRELESS_EXT;
166         range->we_version_source = 21;
167         range->retry_capa = IW_RETRY_LIMIT;
168         range->retry_flags = IW_RETRY_LIMIT;
169         range->min_retry = 0;
170         range->max_retry = 255;
171         range->min_rts = 0;
172         range->max_rts = 2347;
173         range->min_frag = 256;
174         range->max_frag = 2346;
175
176         range->max_encoding_tokens = 4;
177
178         range->max_qual.updated = IW_QUAL_NOISE_INVALID;
179
180         switch (wdev->wiphy->signal_type) {
181         case CFG80211_SIGNAL_TYPE_NONE:
182                 break;
183         case CFG80211_SIGNAL_TYPE_MBM:
184                 range->max_qual.level = -110;
185                 range->max_qual.qual = 70;
186                 range->avg_qual.qual = 35;
187                 range->max_qual.updated |= IW_QUAL_DBM;
188                 range->max_qual.updated |= IW_QUAL_QUAL_UPDATED;
189                 range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED;
190                 break;
191         case CFG80211_SIGNAL_TYPE_UNSPEC:
192                 range->max_qual.level = 100;
193                 range->max_qual.qual = 100;
194                 range->avg_qual.qual = 50;
195                 range->max_qual.updated |= IW_QUAL_QUAL_UPDATED;
196                 range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED;
197                 break;
198         }
199
200         range->avg_qual.level = range->max_qual.level / 2;
201         range->avg_qual.noise = range->max_qual.noise / 2;
202         range->avg_qual.updated = range->max_qual.updated;
203
204         for (c = 0; c < wdev->wiphy->n_cipher_suites; c++) {
205                 switch (wdev->wiphy->cipher_suites[c]) {
206                 case WLAN_CIPHER_SUITE_TKIP:
207                         range->enc_capa |= (IW_ENC_CAPA_CIPHER_TKIP |
208                                             IW_ENC_CAPA_WPA);
209                         break;
210
211                 case WLAN_CIPHER_SUITE_CCMP:
212                         range->enc_capa |= (IW_ENC_CAPA_CIPHER_CCMP |
213                                             IW_ENC_CAPA_WPA2);
214                         break;
215
216                 case WLAN_CIPHER_SUITE_WEP40:
217                         range->encoding_size[range->num_encoding_sizes++] =
218                                 WLAN_KEY_LEN_WEP40;
219                         break;
220
221                 case WLAN_CIPHER_SUITE_WEP104:
222                         range->encoding_size[range->num_encoding_sizes++] =
223                                 WLAN_KEY_LEN_WEP104;
224                         break;
225                 }
226         }
227
228         for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
229                 int i;
230                 struct ieee80211_supported_band *sband;
231
232                 sband = wdev->wiphy->bands[band];
233
234                 if (!sband)
235                         continue;
236
237                 for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
238                         struct ieee80211_channel *chan = &sband->channels[i];
239
240                         if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
241                                 range->freq[c].i =
242                                         ieee80211_frequency_to_channel(
243                                                 chan->center_freq);
244                                 range->freq[c].m = chan->center_freq;
245                                 range->freq[c].e = 6;
246                                 c++;
247                         }
248                 }
249         }
250         range->num_channels = c;
251         range->num_frequency = c;
252
253         IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
254         IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
255         IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
256
257         if (wdev->wiphy->max_scan_ssids > 0)
258                 range->scan_capa |= IW_SCAN_CAPA_ESSID;
259
260         return 0;
261 }
262 EXPORT_SYMBOL_GPL(cfg80211_wext_giwrange);
263
264
265 /**
266  * cfg80211_wext_freq - get wext frequency for non-"auto"
267  * @wiphy: the wiphy
268  * @freq: the wext freq encoding
269  *
270  * Returns a channel, %NULL for auto, or an ERR_PTR for errors!
271  */
272 struct ieee80211_channel *cfg80211_wext_freq(struct wiphy *wiphy,
273                                              struct iw_freq *freq)
274 {
275         struct ieee80211_channel *chan;
276         int f;
277
278         /*
279          * Parse frequency - return NULL for auto and
280          * -EINVAL for impossible things.
281          */
282         if (freq->e == 0) {
283                 if (freq->m < 0)
284                         return NULL;
285                 f = ieee80211_channel_to_frequency(freq->m);
286         } else {
287                 int i, div = 1000000;
288                 for (i = 0; i < freq->e; i++)
289                         div /= 10;
290                 if (div <= 0)
291                         return ERR_PTR(-EINVAL);
292                 f = freq->m / div;
293         }
294
295         /*
296          * Look up channel struct and return -EINVAL when
297          * it cannot be found.
298          */
299         chan = ieee80211_get_channel(wiphy, f);
300         if (!chan)
301                 return ERR_PTR(-EINVAL);
302         return chan;
303 }
304 EXPORT_SYMBOL_GPL(cfg80211_wext_freq);
305
306 int cfg80211_wext_siwrts(struct net_device *dev,
307                          struct iw_request_info *info,
308                          struct iw_param *rts, char *extra)
309 {
310         struct wireless_dev *wdev = dev->ieee80211_ptr;
311         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
312         u32 orts = wdev->wiphy->rts_threshold;
313         int err;
314
315         if (rts->disabled || !rts->fixed)
316                 wdev->wiphy->rts_threshold = (u32) -1;
317         else if (rts->value < 0)
318                 return -EINVAL;
319         else
320                 wdev->wiphy->rts_threshold = rts->value;
321
322         err = rdev->ops->set_wiphy_params(wdev->wiphy,
323                                           WIPHY_PARAM_RTS_THRESHOLD);
324         if (err)
325                 wdev->wiphy->rts_threshold = orts;
326
327         return err;
328 }
329 EXPORT_SYMBOL_GPL(cfg80211_wext_siwrts);
330
331 int cfg80211_wext_giwrts(struct net_device *dev,
332                          struct iw_request_info *info,
333                          struct iw_param *rts, char *extra)
334 {
335         struct wireless_dev *wdev = dev->ieee80211_ptr;
336
337         rts->value = wdev->wiphy->rts_threshold;
338         rts->disabled = rts->value == (u32) -1;
339         rts->fixed = 1;
340
341         return 0;
342 }
343 EXPORT_SYMBOL_GPL(cfg80211_wext_giwrts);
344
345 int cfg80211_wext_siwfrag(struct net_device *dev,
346                           struct iw_request_info *info,
347                           struct iw_param *frag, char *extra)
348 {
349         struct wireless_dev *wdev = dev->ieee80211_ptr;
350         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
351         u32 ofrag = wdev->wiphy->frag_threshold;
352         int err;
353
354         if (frag->disabled || !frag->fixed)
355                 wdev->wiphy->frag_threshold = (u32) -1;
356         else if (frag->value < 256)
357                 return -EINVAL;
358         else {
359                 /* Fragment length must be even, so strip LSB. */
360                 wdev->wiphy->frag_threshold = frag->value & ~0x1;
361         }
362
363         err = rdev->ops->set_wiphy_params(wdev->wiphy,
364                                           WIPHY_PARAM_FRAG_THRESHOLD);
365         if (err)
366                 wdev->wiphy->frag_threshold = ofrag;
367
368         return err;
369 }
370 EXPORT_SYMBOL_GPL(cfg80211_wext_siwfrag);
371
372 int cfg80211_wext_giwfrag(struct net_device *dev,
373                           struct iw_request_info *info,
374                           struct iw_param *frag, char *extra)
375 {
376         struct wireless_dev *wdev = dev->ieee80211_ptr;
377
378         frag->value = wdev->wiphy->frag_threshold;
379         frag->disabled = frag->value == (u32) -1;
380         frag->fixed = 1;
381
382         return 0;
383 }
384 EXPORT_SYMBOL_GPL(cfg80211_wext_giwfrag);
385
386 int cfg80211_wext_siwretry(struct net_device *dev,
387                            struct iw_request_info *info,
388                            struct iw_param *retry, char *extra)
389 {
390         struct wireless_dev *wdev = dev->ieee80211_ptr;
391         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
392         u32 changed = 0;
393         u8 olong = wdev->wiphy->retry_long;
394         u8 oshort = wdev->wiphy->retry_short;
395         int err;
396
397         if (retry->disabled ||
398             (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT)
399                 return -EINVAL;
400
401         if (retry->flags & IW_RETRY_LONG) {
402                 wdev->wiphy->retry_long = retry->value;
403                 changed |= WIPHY_PARAM_RETRY_LONG;
404         } else if (retry->flags & IW_RETRY_SHORT) {
405                 wdev->wiphy->retry_short = retry->value;
406                 changed |= WIPHY_PARAM_RETRY_SHORT;
407         } else {
408                 wdev->wiphy->retry_short = retry->value;
409                 wdev->wiphy->retry_long = retry->value;
410                 changed |= WIPHY_PARAM_RETRY_LONG;
411                 changed |= WIPHY_PARAM_RETRY_SHORT;
412         }
413
414         if (!changed)
415                 return 0;
416
417         err = rdev->ops->set_wiphy_params(wdev->wiphy, changed);
418         if (err) {
419                 wdev->wiphy->retry_short = oshort;
420                 wdev->wiphy->retry_long = olong;
421         }
422
423         return err;
424 }
425 EXPORT_SYMBOL_GPL(cfg80211_wext_siwretry);
426
427 int cfg80211_wext_giwretry(struct net_device *dev,
428                            struct iw_request_info *info,
429                            struct iw_param *retry, char *extra)
430 {
431         struct wireless_dev *wdev = dev->ieee80211_ptr;
432
433         retry->disabled = 0;
434
435         if (retry->flags == 0 || (retry->flags & IW_RETRY_SHORT)) {
436                 /*
437                  * First return short value, iwconfig will ask long value
438                  * later if needed
439                  */
440                 retry->flags |= IW_RETRY_LIMIT;
441                 retry->value = wdev->wiphy->retry_short;
442                 if (wdev->wiphy->retry_long != wdev->wiphy->retry_short)
443                         retry->flags |= IW_RETRY_LONG;
444
445                 return 0;
446         }
447
448         if (retry->flags & IW_RETRY_LONG) {
449                 retry->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
450                 retry->value = wdev->wiphy->retry_long;
451         }
452
453         return 0;
454 }
455 EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
456
457 static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
458                                    struct net_device *dev, const u8 *addr,
459                                    bool remove, bool tx_key, int idx,
460                                    struct key_params *params)
461 {
462         struct wireless_dev *wdev = dev->ieee80211_ptr;
463         int err;
464
465         if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
466                 if (!rdev->ops->set_default_mgmt_key)
467                         return -EOPNOTSUPP;
468
469                 if (idx < 4 || idx > 5)
470                         return -EINVAL;
471         } else if (idx < 0 || idx > 3)
472                 return -EINVAL;
473
474         if (remove) {
475                 err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
476                 if (!err) {
477                         if (idx == wdev->wext.default_key)
478                                 wdev->wext.default_key = -1;
479                         else if (idx == wdev->wext.default_mgmt_key)
480                                 wdev->wext.default_mgmt_key = -1;
481                 }
482                 /*
483                  * Applications using wireless extensions expect to be
484                  * able to delete keys that don't exist, so allow that.
485                  */
486                 if (err == -ENOENT)
487                         return 0;
488
489                 return err;
490         } else {
491                 if (addr)
492                         tx_key = false;
493
494                 if (cfg80211_validate_key_settings(params, idx, addr))
495                         return -EINVAL;
496
497                 err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
498                 if (err)
499                         return err;
500
501                 if (tx_key || (!addr && wdev->wext.default_key == -1)) {
502                         err = rdev->ops->set_default_key(&rdev->wiphy,
503                                                          dev, idx);
504                         if (!err)
505                                 wdev->wext.default_key = idx;
506                         return err;
507                 }
508
509                 if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
510                     (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
511                         err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
512                                                               dev, idx);
513                         if (!err)
514                                 wdev->wext.default_mgmt_key = idx;
515                         return err;
516                 }
517
518                 return 0;
519         }
520 }
521
522 int cfg80211_wext_siwencode(struct net_device *dev,
523                             struct iw_request_info *info,
524                             struct iw_point *erq, char *keybuf)
525 {
526         struct wireless_dev *wdev = dev->ieee80211_ptr;
527         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
528         int idx, err;
529         bool remove = false;
530         struct key_params params;
531
532         /* no use -- only MFP (set_default_mgmt_key) is optional */
533         if (!rdev->ops->del_key ||
534             !rdev->ops->add_key ||
535             !rdev->ops->set_default_key)
536                 return -EOPNOTSUPP;
537
538         idx = erq->flags & IW_ENCODE_INDEX;
539         if (idx == 0) {
540                 idx = wdev->wext.default_key;
541                 if (idx < 0)
542                         idx = 0;
543         } else if (idx < 1 || idx > 4)
544                 return -EINVAL;
545         else
546                 idx--;
547
548         if (erq->flags & IW_ENCODE_DISABLED)
549                 remove = true;
550         else if (erq->length == 0) {
551                 /* No key data - just set the default TX key index */
552                 err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
553                 if (!err)
554                         wdev->wext.default_key = idx;
555                 return err;
556         }
557
558         memset(&params, 0, sizeof(params));
559         params.key = keybuf;
560         params.key_len = erq->length;
561         if (erq->length == 5)
562                 params.cipher = WLAN_CIPHER_SUITE_WEP40;
563         else if (erq->length == 13)
564                 params.cipher = WLAN_CIPHER_SUITE_WEP104;
565         else if (!remove)
566                 return -EINVAL;
567
568         return cfg80211_set_encryption(rdev, dev, NULL, remove,
569                                        wdev->wext.default_key == -1,
570                                        idx, &params);
571 }
572 EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode);
573
574 int cfg80211_wext_siwencodeext(struct net_device *dev,
575                                struct iw_request_info *info,
576                                struct iw_point *erq, char *extra)
577 {
578         struct wireless_dev *wdev = dev->ieee80211_ptr;
579         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
580         struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
581         const u8 *addr;
582         int idx;
583         bool remove = false;
584         struct key_params params;
585         u32 cipher;
586
587         /* no use -- only MFP (set_default_mgmt_key) is optional */
588         if (!rdev->ops->del_key ||
589             !rdev->ops->add_key ||
590             !rdev->ops->set_default_key)
591                 return -EOPNOTSUPP;
592
593         switch (ext->alg) {
594         case IW_ENCODE_ALG_NONE:
595                 remove = true;
596                 cipher = 0;
597                 break;
598         case IW_ENCODE_ALG_WEP:
599                 if (ext->key_len == 5)
600                         cipher = WLAN_CIPHER_SUITE_WEP40;
601                 else if (ext->key_len == 13)
602                         cipher = WLAN_CIPHER_SUITE_WEP104;
603                 else
604                         return -EINVAL;
605                 break;
606         case IW_ENCODE_ALG_TKIP:
607                 cipher = WLAN_CIPHER_SUITE_TKIP;
608                 break;
609         case IW_ENCODE_ALG_CCMP:
610                 cipher = WLAN_CIPHER_SUITE_CCMP;
611                 break;
612         case IW_ENCODE_ALG_AES_CMAC:
613                 cipher = WLAN_CIPHER_SUITE_AES_CMAC;
614                 break;
615         default:
616                 return -EOPNOTSUPP;
617         }
618
619         if (erq->flags & IW_ENCODE_DISABLED)
620                 remove = true;
621
622         idx = erq->flags & IW_ENCODE_INDEX;
623         if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
624                 if (idx < 4 || idx > 5) {
625                         idx = wdev->wext.default_mgmt_key;
626                         if (idx < 0)
627                                 return -EINVAL;
628                 } else
629                         idx--;
630         } else {
631                 if (idx < 1 || idx > 4) {
632                         idx = wdev->wext.default_key;
633                         if (idx < 0)
634                                 return -EINVAL;
635                 } else
636                         idx--;
637         }
638
639         addr = ext->addr.sa_data;
640         if (is_broadcast_ether_addr(addr))
641                 addr = NULL;
642
643         memset(&params, 0, sizeof(params));
644         params.key = ext->key;
645         params.key_len = ext->key_len;
646         params.cipher = cipher;
647
648         if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) {
649                 params.seq = ext->rx_seq;
650                 params.seq_len = 6;
651         }
652
653         return cfg80211_set_encryption(
654                         rdev, dev, addr, remove,
655                         ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
656                         idx, &params);
657 }
658 EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
659
660 struct giwencode_cookie {
661         size_t buflen;
662         char *keybuf;
663 };
664
665 static void giwencode_get_key_cb(void *cookie, struct key_params *params)
666 {
667         struct giwencode_cookie *data = cookie;
668
669         if (!params->key) {
670                 data->buflen = 0;
671                 return;
672         }
673
674         data->buflen = min_t(size_t, data->buflen, params->key_len);
675         memcpy(data->keybuf, params->key, data->buflen);
676 }
677
678 int cfg80211_wext_giwencode(struct net_device *dev,
679                             struct iw_request_info *info,
680                             struct iw_point *erq, char *keybuf)
681 {
682         struct wireless_dev *wdev = dev->ieee80211_ptr;
683         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
684         int idx, err;
685         struct giwencode_cookie data = {
686                 .keybuf = keybuf,
687                 .buflen = erq->length,
688         };
689
690         if (!rdev->ops->get_key)
691                 return -EOPNOTSUPP;
692
693         idx = erq->flags & IW_ENCODE_INDEX;
694         if (idx == 0) {
695                 idx = wdev->wext.default_key;
696                 if (idx < 0)
697                         idx = 0;
698         } else if (idx < 1 || idx > 4)
699                 return -EINVAL;
700         else
701                 idx--;
702
703         erq->flags = idx + 1;
704
705         err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
706                                  giwencode_get_key_cb);
707         if (!err) {
708                 erq->length = data.buflen;
709                 erq->flags |= IW_ENCODE_ENABLED;
710                 return 0;
711         }
712
713         if (err == -ENOENT) {
714                 erq->flags |= IW_ENCODE_DISABLED;
715                 erq->length = 0;
716                 return 0;
717         }
718
719         return err;
720 }
721 EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);
722
723 int cfg80211_wext_siwtxpower(struct net_device *dev,
724                              struct iw_request_info *info,
725                              union iwreq_data *data, char *extra)
726 {
727         struct wireless_dev *wdev = dev->ieee80211_ptr;
728         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
729         enum tx_power_setting type;
730         int dbm = 0;
731
732         if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
733                 return -EINVAL;
734         if (data->txpower.flags & IW_TXPOW_RANGE)
735                 return -EINVAL;
736
737         if (!rdev->ops->set_tx_power)
738                 return -EOPNOTSUPP;
739
740         /* only change when not disabling */
741         if (!data->txpower.disabled) {
742                 rfkill_set_sw_state(rdev->rfkill, false);
743
744                 if (data->txpower.fixed) {
745                         /*
746                          * wext doesn't support negative values, see
747                          * below where it's for automatic
748                          */
749                         if (data->txpower.value < 0)
750                                 return -EINVAL;
751                         dbm = data->txpower.value;
752                         type = TX_POWER_FIXED;
753                         /* TODO: do regulatory check! */
754                 } else {
755                         /*
756                          * Automatic power level setting, max being the value
757                          * passed in from userland.
758                          */
759                         if (data->txpower.value < 0) {
760                                 type = TX_POWER_AUTOMATIC;
761                         } else {
762                                 dbm = data->txpower.value;
763                                 type = TX_POWER_LIMITED;
764                         }
765                 }
766         } else {
767                 rfkill_set_sw_state(rdev->rfkill, true);
768                 schedule_work(&rdev->rfkill_sync);
769                 return 0;
770         }
771
772         return rdev->ops->set_tx_power(wdev->wiphy, type, dbm);;
773 }
774 EXPORT_SYMBOL_GPL(cfg80211_wext_siwtxpower);
775
776 int cfg80211_wext_giwtxpower(struct net_device *dev,
777                              struct iw_request_info *info,
778                              union iwreq_data *data, char *extra)
779 {
780         struct wireless_dev *wdev = dev->ieee80211_ptr;
781         struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
782         int err, val;
783
784         if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM)
785                 return -EINVAL;
786         if (data->txpower.flags & IW_TXPOW_RANGE)
787                 return -EINVAL;
788
789         if (!rdev->ops->get_tx_power)
790                 return -EOPNOTSUPP;
791
792         err = rdev->ops->get_tx_power(wdev->wiphy, &val);
793         if (err)
794                 return err;
795
796         /* well... oh well */
797         data->txpower.fixed = 1;
798         data->txpower.disabled = rfkill_blocked(rdev->rfkill);
799         data->txpower.value = val;
800         data->txpower.flags = IW_TXPOW_DBM;
801
802         return 0;
803 }
804 EXPORT_SYMBOL_GPL(cfg80211_wext_giwtxpower);
805
806 static int cfg80211_set_auth_alg(struct wireless_dev *wdev,
807                                  s32 auth_alg)
808 {
809         int nr_alg = 0;
810
811         if (!auth_alg)
812                 return -EINVAL;
813
814         if (auth_alg & ~(IW_AUTH_ALG_OPEN_SYSTEM |
815                          IW_AUTH_ALG_SHARED_KEY |
816                          IW_AUTH_ALG_LEAP))
817                 return -EINVAL;
818
819         if (auth_alg & IW_AUTH_ALG_OPEN_SYSTEM) {
820                 nr_alg++;
821                 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_OPEN_SYSTEM;
822         }
823
824         if (auth_alg & IW_AUTH_ALG_SHARED_KEY) {
825                 nr_alg++;
826                 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_SHARED_KEY;
827         }
828
829         if (auth_alg & IW_AUTH_ALG_LEAP) {
830                 nr_alg++;
831                 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_NETWORK_EAP;
832         }
833
834         if (nr_alg > 1)
835                 wdev->wext.connect.auth_type = NL80211_AUTHTYPE_AUTOMATIC;
836
837         return 0;
838 }
839
840 static int cfg80211_set_wpa_version(struct wireless_dev *wdev, u32 wpa_versions)
841 {
842         wdev->wext.connect.crypto.wpa_versions = 0;
843
844         if (wpa_versions & ~(IW_AUTH_WPA_VERSION_WPA |
845                              IW_AUTH_WPA_VERSION_WPA2))
846                 return -EINVAL;
847
848         if (wpa_versions & IW_AUTH_WPA_VERSION_WPA)
849                 wdev->wext.connect.crypto.wpa_versions |=
850                         NL80211_WPA_VERSION_1;
851
852         if (wpa_versions & IW_AUTH_WPA_VERSION_WPA2)
853                 wdev->wext.connect.crypto.wpa_versions |=
854                         NL80211_WPA_VERSION_2;
855
856         return 0;
857 }
858
859 int cfg80211_set_cipher_group(struct wireless_dev *wdev, u32 cipher)
860 {
861         wdev->wext.connect.crypto.cipher_group = 0;
862
863         if (cipher & IW_AUTH_CIPHER_WEP40)
864                 wdev->wext.connect.crypto.cipher_group =
865                         WLAN_CIPHER_SUITE_WEP40;
866         else if (cipher & IW_AUTH_CIPHER_WEP104)
867                 wdev->wext.connect.crypto.cipher_group =
868                         WLAN_CIPHER_SUITE_WEP104;
869         else if (cipher & IW_AUTH_CIPHER_TKIP)
870                 wdev->wext.connect.crypto.cipher_group =
871                         WLAN_CIPHER_SUITE_TKIP;
872         else if (cipher & IW_AUTH_CIPHER_CCMP)
873                 wdev->wext.connect.crypto.cipher_group =
874                         WLAN_CIPHER_SUITE_CCMP;
875         else if (cipher & IW_AUTH_CIPHER_AES_CMAC)
876                 wdev->wext.connect.crypto.cipher_group =
877                         WLAN_CIPHER_SUITE_AES_CMAC;
878         else
879                 return -EINVAL;
880
881         return 0;
882 }
883
884 int cfg80211_set_cipher_pairwise(struct wireless_dev *wdev, u32 cipher)
885 {
886         int nr_ciphers = 0;
887         u32 *ciphers_pairwise = wdev->wext.connect.crypto.ciphers_pairwise;
888
889         if (cipher & IW_AUTH_CIPHER_WEP40) {
890                 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP40;
891                 nr_ciphers++;
892         }
893
894         if (cipher & IW_AUTH_CIPHER_WEP104) {
895                 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_WEP104;
896                 nr_ciphers++;
897         }
898
899         if (cipher & IW_AUTH_CIPHER_TKIP) {
900                 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_TKIP;
901                 nr_ciphers++;
902         }
903
904         if (cipher & IW_AUTH_CIPHER_CCMP) {
905                 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_CCMP;
906                 nr_ciphers++;
907         }
908
909         if (cipher & IW_AUTH_CIPHER_AES_CMAC) {
910                 ciphers_pairwise[nr_ciphers] = WLAN_CIPHER_SUITE_AES_CMAC;
911                 nr_ciphers++;
912         }
913
914         BUILD_BUG_ON(NL80211_MAX_NR_CIPHER_SUITES < 5);
915
916         wdev->wext.connect.crypto.n_ciphers_pairwise = nr_ciphers;
917
918         return 0;
919 }
920
921
922 int cfg80211_set_key_mgt(struct wireless_dev *wdev, u32 key_mgt)
923 {
924         int nr_akm_suites = 0;
925
926         if (key_mgt & ~(IW_AUTH_KEY_MGMT_802_1X |
927                         IW_AUTH_KEY_MGMT_PSK))
928                 return -EINVAL;
929
930         if (key_mgt & IW_AUTH_KEY_MGMT_802_1X) {
931                 wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
932                         WLAN_AKM_SUITE_8021X;
933                 nr_akm_suites++;
934         }
935
936         if (key_mgt & IW_AUTH_KEY_MGMT_PSK) {
937                 wdev->wext.connect.crypto.akm_suites[nr_akm_suites] =
938                         WLAN_AKM_SUITE_PSK;
939                 nr_akm_suites++;
940         }
941
942         wdev->wext.connect.crypto.n_akm_suites = nr_akm_suites;
943
944         return 0;
945 }
946
947 int cfg80211_wext_siwauth(struct net_device *dev,
948                           struct iw_request_info *info,
949                           struct iw_param *data, char *extra)
950 {
951         struct wireless_dev *wdev = dev->ieee80211_ptr;
952
953         if (wdev->iftype != NL80211_IFTYPE_STATION)
954                 return -EOPNOTSUPP;
955
956         switch (data->flags & IW_AUTH_INDEX) {
957         case IW_AUTH_PRIVACY_INVOKED:
958                 wdev->wext.connect.privacy = data->value;
959                 return 0;
960         case IW_AUTH_WPA_VERSION:
961                 return cfg80211_set_wpa_version(wdev, data->value);
962         case IW_AUTH_CIPHER_GROUP:
963                 return cfg80211_set_cipher_group(wdev, data->value);
964         case IW_AUTH_KEY_MGMT:
965                 return cfg80211_set_key_mgt(wdev, data->value);
966         case IW_AUTH_CIPHER_PAIRWISE:
967                 return cfg80211_set_cipher_pairwise(wdev, data->value);
968         case IW_AUTH_80211_AUTH_ALG:
969                 return cfg80211_set_auth_alg(wdev, data->value);
970         case IW_AUTH_WPA_ENABLED:
971         case IW_AUTH_RX_UNENCRYPTED_EAPOL:
972         case IW_AUTH_DROP_UNENCRYPTED:
973         case IW_AUTH_MFP:
974                 return 0;
975         default:
976                 return -EOPNOTSUPP;
977         }
978 }
979 EXPORT_SYMBOL_GPL(cfg80211_wext_siwauth);
980
981 int cfg80211_wext_giwauth(struct net_device *dev,
982                           struct iw_request_info *info,
983                           struct iw_param *data, char *extra)
984 {
985         /* XXX: what do we need? */
986
987         return -EOPNOTSUPP;
988 }
989 EXPORT_SYMBOL_GPL(cfg80211_wext_giwauth);