aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/ieee80211_ioctl.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes@sipsolutions.net>2007-08-28 17:01:55 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:48:53 -0400
commit11a843b7e16062389c53ba393c7913956e034eb2 (patch)
tree7f557a55220a0de38f0eafe1a5147487ec39b790 /net/mac80211/ieee80211_ioctl.c
parent3aefaa3294193c931b20a574f718efee6baf27d4 (diff)
[MAC80211]: rework key handling
This moves all the key handling code out from ieee80211_ioctl.c into key.c and also does the following changes including documentation updates in mac80211.h: 1) Turn off hardware acceleration for keys when the interface is down. This is necessary because otherwise monitor interfaces could be decrypting frames for other interfaces that are down at the moment. Also, it should go some way towards better suspend/resume support, in any case the routines used here could be used for that as well. Additionally, this makes the driver interface nicer, keys for a specific local MAC address are only ever present while an interface with that MAC address is enabled. 2) Change driver set_key() callback interface to allow only return values of -ENOSPC, -EOPNOTSUPP and 0, warn on all other return values. This allows debugging the stack when a driver notices it's handed a key while it is down. 3) Invert the flag meaning to KEY_FLAG_UPLOADED_TO_HARDWARE. 4) Remove REMOVE_ALL_KEYS command as it isn't used nor do we want to use it, we'll use DISABLE_KEY for each key. It is hard to use REMOVE_ALL_KEYS because we can handle multiple virtual interfaces with different key configuration, so we'd have to keep track of a lot of state for this and that isn't worth it. 5) Warn when disabling a key fails, it musn't. 6) Remove IEEE80211_HW_NO_TKIP_WMM_HWACCEL in favour of per-key IEEE80211_KEY_FLAG_WMM_STA to let driver sort it out itself. 7) Tell driver that a (non-WEP) key is used only for transmission by using an all-zeroes station MAC address when configuring. 8) Change the set_key() callback to have access to the local MAC address the key is being added for. Signed-off-by: Johannes Berg <johannes@sipsolutions.net> Acked-by: Michael Wu <flamingice@sourmilk.net> Signed-off-by: John W. Linville <linville@tuxdriver.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/mac80211/ieee80211_ioctl.c')
-rw-r--r--net/mac80211/ieee80211_ioctl.c177
1 files changed, 14 insertions, 163 deletions
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index dc05bc66fbb8..8296e7de12c7 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -25,28 +25,6 @@
25#include "ieee80211_rate.h" 25#include "ieee80211_rate.h"
26#include "wpa.h" 26#include "wpa.h"
27#include "aes_ccm.h" 27#include "aes_ccm.h"
28#include "debugfs_key.h"
29
30static void ieee80211_set_hw_encryption(struct net_device *dev,
31 struct sta_info *sta, u8 addr[ETH_ALEN],
32 struct ieee80211_key *key)
33{
34 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
35
36 /* default to sw encryption; this will be cleared by low-level
37 * driver if the hw supports requested encryption */
38 if (key)
39 key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
40
41 if (key && local->ops->set_key) {
42 if (local->ops->set_key(local_to_hw(local), SET_KEY, addr,
43 &key->conf)) {
44 key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
45 key->conf.hw_key_idx = HW_KEY_IDX_INVALID;
46 }
47 }
48}
49
50 28
51static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, 29static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
52 int idx, int alg, int set_tx_key, 30 int idx, int alg, int set_tx_key,
@@ -55,8 +33,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
55 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); 33 struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
56 int ret = 0; 34 int ret = 0;
57 struct sta_info *sta; 35 struct sta_info *sta;
58 struct ieee80211_key *key, *old_key; 36 struct ieee80211_key *key;
59 int try_hwaccel = 1;
60 struct ieee80211_sub_if_data *sdata; 37 struct ieee80211_sub_if_data *sdata;
61 38
62 sdata = IEEE80211_DEV_TO_SUB_IF(dev); 39 sdata = IEEE80211_DEV_TO_SUB_IF(dev);
@@ -69,16 +46,6 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
69 return -EINVAL; 46 return -EINVAL;
70 } 47 }
71 key = sdata->keys[idx]; 48 key = sdata->keys[idx];
72
73 /* TODO: consider adding hwaccel support for these; at least
74 * Atheros key cache should be able to handle this since AP is
75 * only transmitting frames with default keys. */
76 /* FIX: hw key cache can be used when only one virtual
77 * STA is associated with each AP. If more than one STA
78 * is associated to the same AP, software encryption
79 * must be used. This should be done automatically
80 * based on configured station devices. For the time
81 * being, this can be only set at compile time. */
82 } else { 49 } else {
83 set_tx_key = 0; 50 set_tx_key = 0;
84 if (idx != 0) { 51 if (idx != 0) {
@@ -101,139 +68,28 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
101 key = sta->key; 68 key = sta->key;
102 } 69 }
103 70
104 /* FIX:
105 * Cannot configure default hwaccel keys with WEP algorithm, if
106 * any of the virtual interfaces is using static WEP
107 * configuration because hwaccel would otherwise try to decrypt
108 * these frames.
109 *
110 * For now, just disable WEP hwaccel for broadcast when there is
111 * possibility of conflict with default keys. This can maybe later be
112 * optimized by using non-default keys (at least with Atheros ar521x).
113 */
114 if (!sta && alg == ALG_WEP &&
115 sdata->type != IEEE80211_IF_TYPE_IBSS &&
116 sdata->type != IEEE80211_IF_TYPE_AP) {
117 try_hwaccel = 0;
118 }
119
120 if (local->hw.flags & IEEE80211_HW_DEVICE_HIDES_WEP) {
121 /* Software encryption cannot be used with devices that hide
122 * encryption from the host system, so always try to use
123 * hardware acceleration with such devices. */
124 try_hwaccel = 1;
125 }
126
127 if ((local->hw.flags & IEEE80211_HW_NO_TKIP_WMM_HWACCEL) &&
128 alg == ALG_TKIP) {
129 if (sta && (sta->flags & WLAN_STA_WME)) {
130 /* Hardware does not support hwaccel with TKIP when using WMM.
131 */
132 try_hwaccel = 0;
133 }
134 else if (sdata->type == IEEE80211_IF_TYPE_STA) {
135 sta = sta_info_get(local, sdata->u.sta.bssid);
136 if (sta) {
137 if (sta->flags & WLAN_STA_WME) {
138 try_hwaccel = 0;
139 }
140 sta_info_put(sta);
141 sta = NULL;
142 }
143 }
144 }
145
146 if (alg == ALG_NONE) { 71 if (alg == ALG_NONE) {
147 if (try_hwaccel && key &&
148 key->conf.hw_key_idx != HW_KEY_IDX_INVALID &&
149 local->ops->set_key &&
150 local->ops->set_key(local_to_hw(local), DISABLE_KEY,
151 sta_addr, &key->conf)) {
152 printk(KERN_DEBUG "%s: set_encrypt - low-level disable"
153 " failed\n", dev->name);
154 ret = -EINVAL;
155 }
156
157 if (set_tx_key || sdata->default_key == key) {
158 ieee80211_debugfs_key_remove_default(sdata);
159 sdata->default_key = NULL;
160 }
161 ieee80211_debugfs_key_remove(key);
162 if (sta)
163 sta->key = NULL;
164 else
165 sdata->keys[idx] = NULL;
166 ieee80211_key_free(key); 72 ieee80211_key_free(key);
167 key = NULL; 73 key = NULL;
168 } else { 74 } else {
169 old_key = key; 75 /*
170 key = ieee80211_key_alloc(sta ? NULL : sdata, idx, key_len, 76 * Need to free it before allocating a new one with
171 GFP_KERNEL); 77 * with the same index or the ordering to the driver's
78 * set_key() callback becomes confused.
79 */
80 ieee80211_key_free(key);
81 key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
172 if (!key) { 82 if (!key) {
173 ret = -ENOMEM; 83 ret = -ENOMEM;
174 goto err_out; 84 goto err_out;
175 } 85 }
176
177 /* default to sw encryption; low-level driver sets these if the
178 * requested encryption is supported */
179 key->conf.hw_key_idx = HW_KEY_IDX_INVALID;
180 key->conf.flags |= IEEE80211_KEY_FORCE_SW_ENCRYPT;
181
182 key->conf.alg = alg;
183 key->conf.keyidx = idx;
184 key->conf.keylen = key_len;
185 memcpy(key->conf.key, _key, key_len);
186
187 if (alg == ALG_CCMP) {
188 /* Initialize AES key state here as an optimization
189 * so that it does not need to be initialized for every
190 * packet. */
191 key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(
192 key->conf.key);
193 if (!key->u.ccmp.tfm) {
194 ret = -ENOMEM;
195 goto err_free;
196 }
197 }
198
199 if (set_tx_key || sdata->default_key == old_key) {
200 ieee80211_debugfs_key_remove_default(sdata);
201 sdata->default_key = NULL;
202 }
203 ieee80211_debugfs_key_remove(old_key);
204 if (sta)
205 sta->key = key;
206 else
207 sdata->keys[idx] = key;
208 ieee80211_key_free(old_key);
209 ieee80211_debugfs_key_add(local, key);
210 if (sta)
211 ieee80211_debugfs_key_sta_link(key, sta);
212
213 if (try_hwaccel &&
214 (alg == ALG_WEP || alg == ALG_TKIP || alg == ALG_CCMP))
215 ieee80211_set_hw_encryption(dev, sta, sta_addr, key);
216 }
217
218 if (set_tx_key || (!sta && !sdata->default_key && key)) {
219 sdata->default_key = key;
220 if (key)
221 ieee80211_debugfs_key_add_default(sdata);
222
223 if (local->ops->set_key_idx &&
224 local->ops->set_key_idx(local_to_hw(local), idx))
225 printk(KERN_DEBUG "%s: failed to set TX key idx for "
226 "low-level driver\n", dev->name);
227 } 86 }
228 87
229 if (sta) 88 if (set_tx_key || (!sta && !sdata->default_key && key))
230 sta_info_put(sta); 89 ieee80211_set_default_key(sdata, idx);
231 90
232 return 0; 91 ret = 0;
233 92 err_out:
234err_free:
235 ieee80211_key_free(key);
236err_out:
237 if (sta) 93 if (sta)
238 sta_info_put(sta); 94 sta_info_put(sta);
239 return ret; 95 return ret;
@@ -1181,12 +1037,7 @@ static int ieee80211_ioctl_siwencode(struct net_device *dev,
1181 alg = ALG_NONE; 1037 alg = ALG_NONE;
1182 else if (erq->length == 0) { 1038 else if (erq->length == 0) {
1183 /* No key data - just set the default TX key index */ 1039 /* No key data - just set the default TX key index */
1184 if (sdata->default_key != sdata->keys[idx]) { 1040 ieee80211_set_default_key(sdata, idx);
1185 ieee80211_debugfs_key_remove_default(sdata);
1186 sdata->default_key = sdata->keys[idx];
1187 if (sdata->default_key)
1188 ieee80211_debugfs_key_add_default(sdata);
1189 }
1190 return 0; 1041 return 0;
1191 } 1042 }
1192 1043
@@ -1232,7 +1083,7 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
1232 } 1083 }
1233 1084
1234 memcpy(key, sdata->keys[idx]->conf.key, 1085 memcpy(key, sdata->keys[idx]->conf.key,
1235 min((int)erq->length, sdata->keys[idx]->conf.keylen)); 1086 min_t(int, erq->length, sdata->keys[idx]->conf.keylen));
1236 erq->length = sdata->keys[idx]->conf.keylen; 1087 erq->length = sdata->keys[idx]->conf.keylen;
1237 erq->flags |= IW_ENCODE_ENABLED; 1088 erq->flags |= IW_ENCODE_ENABLED;
1238 1089