aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/mac80211/wext.c279
-rw-r--r--net/wireless/core.c6
-rw-r--r--net/wireless/core.h6
-rw-r--r--net/wireless/nl80211.c57
-rw-r--r--net/wireless/util.c45
-rw-r--r--net/wireless/wext-compat.c257
6 files changed, 333 insertions, 317 deletions
diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c
index 6b4eb8d43a4e..d84502644686 100644
--- a/net/mac80211/wext.c
+++ b/net/mac80211/wext.c
@@ -27,100 +27,6 @@
27#include "aes_ccm.h" 27#include "aes_ccm.h"
28 28
29 29
30static 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
124static int ieee80211_ioctl_siwgenie(struct net_device *dev, 30static int ieee80211_ioctl_siwgenie(struct net_device *dev,
125 struct iw_request_info *info, 31 struct iw_request_info *info,
126 struct iw_point *data, char *extra) 32 struct iw_point *data, char *extra)
@@ -472,109 +378,6 @@ static int ieee80211_ioctl_giwtxpower(struct net_device *dev,
472 return 0; 378 return 0;
473} 379}
474 380
475static int ieee80211_ioctl_siwencode(struct net_device *dev,
476 struct iw_request_info *info,
477 struct iw_point *erq, char *keybuf)
478{
479 struct ieee80211_sub_if_data *sdata;
480 int idx, i, alg = ALG_WEP;
481 u8 bcaddr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
482 int remove = 0, ret;
483
484 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
485
486 idx = erq->flags & IW_ENCODE_INDEX;
487 if (idx == 0) {
488 if (sdata->default_key)
489 for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
490 if (sdata->default_key == sdata->keys[i]) {
491 idx = i;
492 break;
493 }
494 }
495 } else if (idx < 1 || idx > 4)
496 return -EINVAL;
497 else
498 idx--;
499
500 if (erq->flags & IW_ENCODE_DISABLED)
501 remove = 1;
502 else if (erq->length == 0) {
503 /* No key data - just set the default TX key index */
504 ieee80211_set_default_key(sdata, idx);
505 return 0;
506 }
507
508 ret = ieee80211_set_encryption(
509 sdata, bcaddr,
510 idx, alg, remove,
511 !sdata->default_key,
512 keybuf, erq->length);
513
514 if (!ret && sdata->vif.type == NL80211_IFTYPE_STATION) {
515 if (remove)
516 sdata->u.mgd.flags &= ~IEEE80211_STA_TKIP_WEP_USED;
517 else
518 sdata->u.mgd.flags |= IEEE80211_STA_TKIP_WEP_USED;
519 }
520
521 return ret;
522}
523
524
525static int ieee80211_ioctl_giwencode(struct net_device *dev,
526 struct iw_request_info *info,
527 struct iw_point *erq, char *key)
528{
529 struct ieee80211_sub_if_data *sdata;
530 int idx, i;
531
532 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
533
534 idx = erq->flags & IW_ENCODE_INDEX;
535 if (idx < 1 || idx > 4) {
536 idx = -1;
537 if (!sdata->default_key)
538 idx = 0;
539 else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
540 if (sdata->default_key == sdata->keys[i]) {
541 idx = i;
542 break;
543 }
544 }
545 if (idx < 0)
546 return -EINVAL;
547 } else
548 idx--;
549
550 erq->flags = idx + 1;
551
552 if (!sdata->keys[idx]) {
553 erq->length = 0;
554 erq->flags |= IW_ENCODE_DISABLED;
555 return 0;
556 }
557
558 memcpy(key, sdata->keys[idx]->conf.key,
559 min_t(int, erq->length, sdata->keys[idx]->conf.keylen));
560 erq->length = sdata->keys[idx]->conf.keylen;
561 erq->flags |= IW_ENCODE_ENABLED;
562
563 if (sdata->vif.type == NL80211_IFTYPE_STATION) {
564 switch (sdata->u.mgd.auth_alg) {
565 case WLAN_AUTH_OPEN:
566 case WLAN_AUTH_LEAP:
567 erq->flags |= IW_ENCODE_OPEN;
568 break;
569 case WLAN_AUTH_SHARED_KEY:
570 erq->flags |= IW_ENCODE_RESTRICTED;
571 break;
572 }
573 }
574
575 return 0;
576}
577
578static int ieee80211_ioctl_siwpower(struct net_device *dev, 381static int ieee80211_ioctl_siwpower(struct net_device *dev,
579 struct iw_request_info *info, 382 struct iw_request_info *info,
580 struct iw_param *wrq, 383 struct iw_param *wrq,
@@ -809,82 +612,6 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev,
809} 612}
810 613
811 614
812static int ieee80211_ioctl_siwencodeext(struct net_device *dev,
813 struct iw_request_info *info,
814 struct iw_point *erq, char *extra)
815{
816 struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
817 struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
818 int uninitialized_var(alg), idx, i, remove = 0;
819
820 switch (ext->alg) {
821 case IW_ENCODE_ALG_NONE:
822 remove = 1;
823 break;
824 case IW_ENCODE_ALG_WEP:
825 alg = ALG_WEP;
826 break;
827 case IW_ENCODE_ALG_TKIP:
828 alg = ALG_TKIP;
829 break;
830 case IW_ENCODE_ALG_CCMP:
831 alg = ALG_CCMP;
832 break;
833 case IW_ENCODE_ALG_AES_CMAC:
834 alg = ALG_AES_CMAC;
835 break;
836 default:
837 return -EOPNOTSUPP;
838 }
839
840 if (erq->flags & IW_ENCODE_DISABLED)
841 remove = 1;
842
843 idx = erq->flags & IW_ENCODE_INDEX;
844 if (alg == ALG_AES_CMAC) {
845 if (idx < NUM_DEFAULT_KEYS + 1 ||
846 idx > NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS) {
847 idx = -1;
848 if (!sdata->default_mgmt_key)
849 idx = 0;
850 else for (i = NUM_DEFAULT_KEYS;
851 i < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS;
852 i++) {
853 if (sdata->default_mgmt_key == sdata->keys[i])
854 {
855 idx = i;
856 break;
857 }
858 }
859 if (idx < 0)
860 return -EINVAL;
861 } else
862 idx--;
863 } else {
864 if (idx < 1 || idx > 4) {
865 idx = -1;
866 if (!sdata->default_key)
867 idx = 0;
868 else for (i = 0; i < NUM_DEFAULT_KEYS; i++) {
869 if (sdata->default_key == sdata->keys[i]) {
870 idx = i;
871 break;
872 }
873 }
874 if (idx < 0)
875 return -EINVAL;
876 } else
877 idx--;
878 }
879
880 return ieee80211_set_encryption(sdata, ext->addr.sa_data, idx, alg,
881 remove,
882 ext->ext_flags &
883 IW_ENCODE_EXT_SET_TX_KEY,
884 ext->key, ext->key_len);
885}
886
887
888/* Structures to export the Wireless Handlers */ 615/* Structures to export the Wireless Handlers */
889 616
890static const iw_handler ieee80211_handler[] = 617static const iw_handler ieee80211_handler[] =
@@ -931,8 +658,8 @@ static const iw_handler ieee80211_handler[] =
931 (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */ 658 (iw_handler) ieee80211_ioctl_giwtxpower, /* SIOCGIWTXPOW */
932 (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */ 659 (iw_handler) cfg80211_wext_siwretry, /* SIOCSIWRETRY */
933 (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */ 660 (iw_handler) cfg80211_wext_giwretry, /* SIOCGIWRETRY */
934 (iw_handler) ieee80211_ioctl_siwencode, /* SIOCSIWENCODE */ 661 (iw_handler) cfg80211_wext_siwencode, /* SIOCSIWENCODE */
935 (iw_handler) ieee80211_ioctl_giwencode, /* SIOCGIWENCODE */ 662 (iw_handler) cfg80211_wext_giwencode, /* SIOCGIWENCODE */
936 (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */ 663 (iw_handler) ieee80211_ioctl_siwpower, /* SIOCSIWPOWER */
937 (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */ 664 (iw_handler) ieee80211_ioctl_giwpower, /* SIOCGIWPOWER */
938 (iw_handler) NULL, /* -- hole -- */ 665 (iw_handler) NULL, /* -- hole -- */
@@ -941,7 +668,7 @@ static const iw_handler ieee80211_handler[] =
941 (iw_handler) NULL, /* SIOCGIWGENIE */ 668 (iw_handler) NULL, /* SIOCGIWGENIE */
942 (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */ 669 (iw_handler) ieee80211_ioctl_siwauth, /* SIOCSIWAUTH */
943 (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */ 670 (iw_handler) ieee80211_ioctl_giwauth, /* SIOCGIWAUTH */
944 (iw_handler) ieee80211_ioctl_siwencodeext, /* SIOCSIWENCODEEXT */ 671 (iw_handler) cfg80211_wext_siwencodeext, /* SIOCSIWENCODEEXT */
945 (iw_handler) NULL, /* SIOCGIWENCODEEXT */ 672 (iw_handler) NULL, /* SIOCGIWENCODEEXT */
946 (iw_handler) NULL, /* SIOCSIWPMKSA */ 673 (iw_handler) NULL, /* SIOCSIWPMKSA */
947 (iw_handler) NULL, /* -- hole -- */ 674 (iw_handler) NULL, /* -- hole -- */
diff --git a/net/wireless/core.c b/net/wireless/core.c
index 15b2a1794805..47c20eb0c04d 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * This is the linux wireless configuration interface. 2 * This is the linux wireless configuration interface.
3 * 3 *
4 * Copyright 2006-2008 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
5 */ 5 */
6 6
7#include <linux/if.h> 7#include <linux/if.h>
@@ -457,6 +457,10 @@ static int cfg80211_netdev_notifier_call(struct notifier_block * nb,
457 "symlink to netdev!\n"); 457 "symlink to netdev!\n");
458 } 458 }
459 dev->ieee80211_ptr->netdev = dev; 459 dev->ieee80211_ptr->netdev = dev;
460#ifdef CONFIG_WIRELESS_EXT
461 dev->ieee80211_ptr->wext.default_key = -1;
462 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
463#endif
460 mutex_unlock(&rdev->devlist_mtx); 464 mutex_unlock(&rdev->devlist_mtx);
461 break; 465 break;
462 case NETDEV_GOING_DOWN: 466 case NETDEV_GOING_DOWN:
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 3e49d3399311..f14b6c5f4221 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * Wireless configuration interface internals. 2 * Wireless configuration interface internals.
3 * 3 *
4 * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
5 */ 5 */
6#ifndef __NET_WIRELESS_CORE_H 6#ifndef __NET_WIRELESS_CORE_H
7#define __NET_WIRELESS_CORE_H 7#define __NET_WIRELESS_CORE_H
@@ -151,4 +151,8 @@ void cfg80211_clear_ibss(struct net_device *dev, bool nowext);
151int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev, 151int cfg80211_leave_ibss(struct cfg80211_registered_device *rdev,
152 struct net_device *dev, bool nowext); 152 struct net_device *dev, bool nowext);
153 153
154/* internal helpers */
155int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
156 const u8 *mac_addr);
157
154#endif /* __NET_WIRELESS_CORE_H */ 158#endif /* __NET_WIRELESS_CORE_H */
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index a39e4644778b..f88dbbec7521 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * This is the new netlink-based wireless configuration interface. 2 * This is the new netlink-based wireless configuration interface.
3 * 3 *
4 * Copyright 2006, 2007 Johannes Berg <johannes@sipsolutions.net> 4 * Copyright 2006-2009 Johannes Berg <johannes@sipsolutions.net>
5 */ 5 */
6 6
7#include <linux/if.h> 7#include <linux/if.h>
@@ -1073,6 +1073,14 @@ static int nl80211_set_key(struct sk_buff *skb, struct genl_info *info)
1073 } 1073 }
1074 1074
1075 err = func(&drv->wiphy, dev, key_idx); 1075 err = func(&drv->wiphy, dev, key_idx);
1076#ifdef CONFIG_WIRELESS_EXT
1077 if (!err) {
1078 if (func == drv->ops->set_default_key)
1079 dev->ieee80211_ptr->wext.default_key = key_idx;
1080 else
1081 dev->ieee80211_ptr->wext.default_mgmt_key = key_idx;
1082 }
1083#endif
1076 1084
1077 out: 1085 out:
1078 cfg80211_put_dev(drv); 1086 cfg80211_put_dev(drv);
@@ -1111,45 +1119,9 @@ static int nl80211_new_key(struct sk_buff *skb, struct genl_info *info)
1111 if (info->attrs[NL80211_ATTR_MAC]) 1119 if (info->attrs[NL80211_ATTR_MAC])
1112 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]); 1120 mac_addr = nla_data(info->attrs[NL80211_ATTR_MAC]);
1113 1121
1114 if (key_idx > 5) 1122 if (cfg80211_validate_key_settings(&params, key_idx, mac_addr))
1115 return -EINVAL; 1123 return -EINVAL;
1116 1124
1117 /*
1118 * Disallow pairwise keys with non-zero index unless it's WEP
1119 * (because current deployments use pairwise WEP keys with
1120 * non-zero indizes but 802.11i clearly specifies to use zero)
1121 */
1122 if (mac_addr && key_idx &&
1123 params.cipher != WLAN_CIPHER_SUITE_WEP40 &&
1124 params.cipher != WLAN_CIPHER_SUITE_WEP104)
1125 return -EINVAL;
1126
1127 /* TODO: add definitions for the lengths to linux/ieee80211.h */
1128 switch (params.cipher) {
1129 case WLAN_CIPHER_SUITE_WEP40:
1130 if (params.key_len != 5)
1131 return -EINVAL;
1132 break;
1133 case WLAN_CIPHER_SUITE_TKIP:
1134 if (params.key_len != 32)
1135 return -EINVAL;
1136 break;
1137 case WLAN_CIPHER_SUITE_CCMP:
1138 if (params.key_len != 16)
1139 return -EINVAL;
1140 break;
1141 case WLAN_CIPHER_SUITE_WEP104:
1142 if (params.key_len != 13)
1143 return -EINVAL;
1144 break;
1145 case WLAN_CIPHER_SUITE_AES_CMAC:
1146 if (params.key_len != 16)
1147 return -EINVAL;
1148 break;
1149 default:
1150 return -EINVAL;
1151 }
1152
1153 rtnl_lock(); 1125 rtnl_lock();
1154 1126
1155 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); 1127 err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
@@ -1210,6 +1182,15 @@ static int nl80211_del_key(struct sk_buff *skb, struct genl_info *info)
1210 1182
1211 err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr); 1183 err = drv->ops->del_key(&drv->wiphy, dev, key_idx, mac_addr);
1212 1184
1185#ifdef CONFIG_WIRELESS_EXT
1186 if (!err) {
1187 if (key_idx == dev->ieee80211_ptr->wext.default_key)
1188 dev->ieee80211_ptr->wext.default_key = -1;
1189 else if (key_idx == dev->ieee80211_ptr->wext.default_mgmt_key)
1190 dev->ieee80211_ptr->wext.default_mgmt_key = -1;
1191 }
1192#endif
1193
1213 out: 1194 out:
1214 cfg80211_put_dev(drv); 1195 cfg80211_put_dev(drv);
1215 dev_put(dev); 1196 dev_put(dev);
diff --git a/net/wireless/util.c b/net/wireless/util.c
index 5f7e997195c7..beb226e78cd7 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -138,3 +138,48 @@ void ieee80211_set_bitrate_flags(struct wiphy *wiphy)
138 if (wiphy->bands[band]) 138 if (wiphy->bands[band])
139 set_mandatory_flags_band(wiphy->bands[band], band); 139 set_mandatory_flags_band(wiphy->bands[band], band);
140} 140}
141
142int cfg80211_validate_key_settings(struct key_params *params, int key_idx,
143 const u8 *mac_addr)
144{
145 if (key_idx > 5)
146 return -EINVAL;
147
148 /*
149 * Disallow pairwise keys with non-zero index unless it's WEP
150 * (because current deployments use pairwise WEP keys with
151 * non-zero indizes but 802.11i clearly specifies to use zero)
152 */
153 if (mac_addr && key_idx &&
154 params->cipher != WLAN_CIPHER_SUITE_WEP40 &&
155 params->cipher != WLAN_CIPHER_SUITE_WEP104)
156 return -EINVAL;
157
158 /* TODO: add definitions for the lengths to linux/ieee80211.h */
159 switch (params->cipher) {
160 case WLAN_CIPHER_SUITE_WEP40:
161 if (params->key_len != 5)
162 return -EINVAL;
163 break;
164 case WLAN_CIPHER_SUITE_TKIP:
165 if (params->key_len != 32)
166 return -EINVAL;
167 break;
168 case WLAN_CIPHER_SUITE_CCMP:
169 if (params->key_len != 16)
170 return -EINVAL;
171 break;
172 case WLAN_CIPHER_SUITE_WEP104:
173 if (params->key_len != 13)
174 return -EINVAL;
175 break;
176 case WLAN_CIPHER_SUITE_AES_CMAC:
177 if (params->key_len != 16)
178 return -EINVAL;
179 break;
180 default:
181 return -EINVAL;
182 }
183
184 return 0;
185}
diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c
index abf6b0a047d8..ffc98a8d6e5c 100644
--- a/net/wireless/wext-compat.c
+++ b/net/wireless/wext-compat.c
@@ -5,12 +5,13 @@
5 * into cfg80211, when that happens all the exports here go away and 5 * into cfg80211, when that happens all the exports here go away and
6 * we directly assign the wireless handlers of wireless interfaces. 6 * we directly assign the wireless handlers of wireless interfaces.
7 * 7 *
8 * Copyright 2008 Johannes Berg <johannes@sipsolutions.net> 8 * Copyright 2008-2009 Johannes Berg <johannes@sipsolutions.net>
9 */ 9 */
10 10
11#include <linux/wireless.h> 11#include <linux/wireless.h>
12#include <linux/nl80211.h> 12#include <linux/nl80211.h>
13#include <linux/if_arp.h> 13#include <linux/if_arp.h>
14#include <linux/etherdevice.h>
14#include <net/iw_handler.h> 15#include <net/iw_handler.h>
15#include <net/cfg80211.h> 16#include <net/cfg80211.h>
16#include "core.h" 17#include "core.h"
@@ -477,3 +478,257 @@ int cfg80211_wext_giwretry(struct net_device *dev,
477 return 0; 478 return 0;
478} 479}
479EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry); 480EXPORT_SYMBOL_GPL(cfg80211_wext_giwretry);
481
482static int cfg80211_set_encryption(struct cfg80211_registered_device *rdev,
483 struct net_device *dev, const u8 *addr,
484 bool remove, bool tx_key, int idx,
485 struct key_params *params)
486{
487 struct wireless_dev *wdev = dev->ieee80211_ptr;
488 int err;
489
490 if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
491 if (!rdev->ops->set_default_mgmt_key)
492 return -EOPNOTSUPP;
493
494 if (idx < 4 || idx > 5)
495 return -EINVAL;
496 } else if (idx < 0 || idx > 3)
497 return -EINVAL;
498
499 if (remove) {
500 err = rdev->ops->del_key(&rdev->wiphy, dev, idx, addr);
501 if (!err) {
502 if (idx == wdev->wext.default_key)
503 wdev->wext.default_key = -1;
504 else if (idx == wdev->wext.default_mgmt_key)
505 wdev->wext.default_mgmt_key = -1;
506 }
507 return err;
508 } else {
509 if (addr)
510 tx_key = false;
511
512 if (cfg80211_validate_key_settings(params, idx, addr))
513 return -EINVAL;
514
515 err = rdev->ops->add_key(&rdev->wiphy, dev, idx, addr, params);
516 if (err)
517 return err;
518
519 if (tx_key || (!addr && wdev->wext.default_key == -1)) {
520 err = rdev->ops->set_default_key(&rdev->wiphy,
521 dev, idx);
522 if (!err)
523 wdev->wext.default_key = idx;
524 return err;
525 }
526
527 if (params->cipher == WLAN_CIPHER_SUITE_AES_CMAC &&
528 (tx_key || (!addr && wdev->wext.default_mgmt_key == -1))) {
529 err = rdev->ops->set_default_mgmt_key(&rdev->wiphy,
530 dev, idx);
531 if (!err)
532 wdev->wext.default_mgmt_key = idx;
533 return err;
534 }
535
536 return 0;
537 }
538}
539
540int cfg80211_wext_siwencode(struct net_device *dev,
541 struct iw_request_info *info,
542 struct iw_point *erq, char *keybuf)
543{
544 struct wireless_dev *wdev = dev->ieee80211_ptr;
545 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
546 int idx, err;
547 bool remove = false;
548 struct key_params params;
549
550 /* no use -- only MFP (set_default_mgmt_key) is optional */
551 if (!rdev->ops->del_key ||
552 !rdev->ops->add_key ||
553 !rdev->ops->set_default_key)
554 return -EOPNOTSUPP;
555
556 idx = erq->flags & IW_ENCODE_INDEX;
557 if (idx == 0) {
558 idx = wdev->wext.default_key;
559 if (idx < 0)
560 idx = 0;
561 } else if (idx < 1 || idx > 4)
562 return -EINVAL;
563 else
564 idx--;
565
566 if (erq->flags & IW_ENCODE_DISABLED)
567 remove = true;
568 else if (erq->length == 0) {
569 /* No key data - just set the default TX key index */
570 err = rdev->ops->set_default_key(&rdev->wiphy, dev, idx);
571 if (!err)
572 wdev->wext.default_key = idx;
573 return err;
574 }
575
576 memset(&params, 0, sizeof(params));
577 params.key = keybuf;
578 params.key_len = erq->length;
579 if (erq->length == 5)
580 params.cipher = WLAN_CIPHER_SUITE_WEP40;
581 else if (erq->length == 13)
582 params.cipher = WLAN_CIPHER_SUITE_WEP104;
583 else if (!remove)
584 return -EINVAL;
585
586 return cfg80211_set_encryption(rdev, dev, NULL, remove,
587 wdev->wext.default_key == -1,
588 idx, &params);
589}
590EXPORT_SYMBOL_GPL(cfg80211_wext_siwencode);
591
592int cfg80211_wext_siwencodeext(struct net_device *dev,
593 struct iw_request_info *info,
594 struct iw_point *erq, char *extra)
595{
596 struct wireless_dev *wdev = dev->ieee80211_ptr;
597 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
598 struct iw_encode_ext *ext = (struct iw_encode_ext *) extra;
599 const u8 *addr;
600 int idx;
601 bool remove = false;
602 struct key_params params;
603 u32 cipher;
604
605 /* no use -- only MFP (set_default_mgmt_key) is optional */
606 if (!rdev->ops->del_key ||
607 !rdev->ops->add_key ||
608 !rdev->ops->set_default_key)
609 return -EOPNOTSUPP;
610
611 switch (ext->alg) {
612 case IW_ENCODE_ALG_NONE:
613 remove = true;
614 cipher = 0;
615 break;
616 case IW_ENCODE_ALG_WEP:
617 if (ext->key_len == 5)
618 cipher = WLAN_CIPHER_SUITE_WEP40;
619 else if (ext->key_len == 13)
620 cipher = WLAN_CIPHER_SUITE_WEP104;
621 else
622 return -EINVAL;
623 break;
624 case IW_ENCODE_ALG_TKIP:
625 cipher = WLAN_CIPHER_SUITE_TKIP;
626 break;
627 case IW_ENCODE_ALG_CCMP:
628 cipher = WLAN_CIPHER_SUITE_CCMP;
629 break;
630 case IW_ENCODE_ALG_AES_CMAC:
631 cipher = WLAN_CIPHER_SUITE_AES_CMAC;
632 break;
633 default:
634 return -EOPNOTSUPP;
635 }
636
637 if (erq->flags & IW_ENCODE_DISABLED)
638 remove = true;
639
640 idx = erq->flags & IW_ENCODE_INDEX;
641 if (cipher == WLAN_CIPHER_SUITE_AES_CMAC) {
642 if (idx < 4 || idx > 5) {
643 idx = wdev->wext.default_mgmt_key;
644 if (idx < 0)
645 return -EINVAL;
646 } else
647 idx--;
648 } else {
649 if (idx < 1 || idx > 4) {
650 idx = wdev->wext.default_key;
651 if (idx < 0)
652 return -EINVAL;
653 } else
654 idx--;
655 }
656
657 addr = ext->addr.sa_data;
658 if (is_broadcast_ether_addr(addr))
659 addr = NULL;
660
661 memset(&params, 0, sizeof(params));
662 params.key = ext->key;
663 params.key_len = ext->key_len;
664 params.cipher = cipher;
665
666 return cfg80211_set_encryption(
667 rdev, dev, addr, remove,
668 ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY,
669 idx, &params);
670}
671EXPORT_SYMBOL_GPL(cfg80211_wext_siwencodeext);
672
673struct giwencode_cookie {
674 size_t buflen;
675 char *keybuf;
676};
677
678static void giwencode_get_key_cb(void *cookie, struct key_params *params)
679{
680 struct giwencode_cookie *data = cookie;
681
682 if (!params->key) {
683 data->buflen = 0;
684 return;
685 }
686
687 data->buflen = min_t(size_t, data->buflen, params->key_len);
688 memcpy(data->keybuf, params->key, data->buflen);
689}
690
691int cfg80211_wext_giwencode(struct net_device *dev,
692 struct iw_request_info *info,
693 struct iw_point *erq, char *keybuf)
694{
695 struct wireless_dev *wdev = dev->ieee80211_ptr;
696 struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
697 int idx, err;
698 struct giwencode_cookie data = {
699 .keybuf = keybuf,
700 .buflen = erq->length,
701 };
702
703 if (!rdev->ops->get_key)
704 return -EOPNOTSUPP;
705
706 idx = erq->flags & IW_ENCODE_INDEX;
707 if (idx == 0) {
708 idx = wdev->wext.default_key;
709 if (idx < 0)
710 idx = 0;
711 } else if (idx < 1 || idx > 4)
712 return -EINVAL;
713 else
714 idx--;
715
716 erq->flags = idx + 1;
717
718 err = rdev->ops->get_key(&rdev->wiphy, dev, idx, NULL, &data,
719 giwencode_get_key_cb);
720 if (!err) {
721 erq->length = data.buflen;
722 erq->flags |= IW_ENCODE_ENABLED;
723 return 0;
724 }
725
726 if (err == -ENOENT) {
727 erq->flags |= IW_ENCODE_DISABLED;
728 erq->length = 0;
729 return 0;
730 }
731
732 return err;
733}
734EXPORT_SYMBOL_GPL(cfg80211_wext_giwencode);