diff options
Diffstat (limited to 'net/mac80211/ieee80211_ioctl.c')
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 177 |
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 | |||
30 | static 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 | ||
51 | static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | 29 | static 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: | |
234 | err_free: | ||
235 | ieee80211_key_free(key); | ||
236 | err_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 | ||