aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2009-05-11 07:54:58 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-05-13 15:44:32 -0400
commit08645126dd24872c2e27014f93968f7312e29176 (patch)
tree2011cb3cb2f70d35278ef3b39ea696a058fb7b29 /net
parent7be69c0b9aa93ef655db4d46e5654996489d62f5 (diff)
cfg80211: implement wext key handling
Move key handling wireless extension ioctls from mac80211 to cfg80211 so that all drivers that implement the cfg80211 operations get wext compatibility. Note that this drops the SIOCGIWENCODE ioctl support for getting IW_ENCODE_RESTRICTED/IW_ENCODE_OPEN. This means that iwconfig will no longer report "Security mode:open" or "Security mode:restricted" for mac80211. However, what we displayed there (the authentication algo used) was actually wrong -- linux/wireless.h states that this setting is meant to differentiate between "Refuse non-encoded packets" and "Accept non-encoded packets". (Combined with "cfg80211: fix a couple of bugs with key ioctls". -- JWL) Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Signed-off-by: John W. Linville <linville@tuxdriver.com>
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);