diff options
-rw-r--r-- | net/mac80211/cfg.c | 44 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.c | 37 | ||||
-rw-r--r-- | net/mac80211/debugfs_key.h | 11 | ||||
-rw-r--r-- | net/mac80211/ieee80211.c | 6 | ||||
-rw-r--r-- | net/mac80211/ieee80211_i.h | 4 | ||||
-rw-r--r-- | net/mac80211/ieee80211_ioctl.c | 26 | ||||
-rw-r--r-- | net/mac80211/ieee80211_key.h | 20 | ||||
-rw-r--r-- | net/mac80211/ieee80211_sta.c | 9 | ||||
-rw-r--r-- | net/mac80211/key.c | 408 | ||||
-rw-r--r-- | net/mac80211/sta_info.c | 48 | ||||
-rw-r--r-- | net/mac80211/sta_info.h | 1 |
11 files changed, 385 insertions, 229 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 5f8db5cab65d..fe05a7b85dc6 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -135,6 +135,7 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
135 | struct sta_info *sta = NULL; | 135 | struct sta_info *sta = NULL; |
136 | enum ieee80211_key_alg alg; | 136 | enum ieee80211_key_alg alg; |
137 | struct ieee80211_key *key; | 137 | struct ieee80211_key *key; |
138 | int err; | ||
138 | 139 | ||
139 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 140 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
140 | 141 | ||
@@ -157,17 +158,24 @@ static int ieee80211_add_key(struct wiphy *wiphy, struct net_device *dev, | |||
157 | if (!key) | 158 | if (!key) |
158 | return -ENOMEM; | 159 | return -ENOMEM; |
159 | 160 | ||
161 | rcu_read_lock(); | ||
162 | |||
160 | if (mac_addr) { | 163 | if (mac_addr) { |
161 | sta = sta_info_get(sdata->local, mac_addr); | 164 | sta = sta_info_get(sdata->local, mac_addr); |
162 | if (!sta) { | 165 | if (!sta) { |
163 | ieee80211_key_free(key); | 166 | ieee80211_key_free(key); |
164 | return -ENOENT; | 167 | err = -ENOENT; |
168 | goto out_unlock; | ||
165 | } | 169 | } |
166 | } | 170 | } |
167 | 171 | ||
168 | ieee80211_key_link(key, sdata, sta); | 172 | ieee80211_key_link(key, sdata, sta); |
169 | 173 | ||
170 | return 0; | 174 | err = 0; |
175 | out_unlock: | ||
176 | rcu_read_unlock(); | ||
177 | |||
178 | return err; | ||
171 | } | 179 | } |
172 | 180 | ||
173 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | 181 | static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, |
@@ -179,28 +187,37 @@ static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, | |||
179 | 187 | ||
180 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 188 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
181 | 189 | ||
190 | rcu_read_lock(); | ||
191 | |||
182 | if (mac_addr) { | 192 | if (mac_addr) { |
193 | ret = -ENOENT; | ||
194 | |||
183 | sta = sta_info_get(sdata->local, mac_addr); | 195 | sta = sta_info_get(sdata->local, mac_addr); |
184 | if (!sta) | 196 | if (!sta) |
185 | return -ENOENT; | 197 | goto out_unlock; |
186 | 198 | ||
187 | ret = 0; | ||
188 | if (sta->key) { | 199 | if (sta->key) { |
189 | ieee80211_key_free(sta->key); | 200 | ieee80211_key_free(sta->key); |
190 | WARN_ON(sta->key); | 201 | WARN_ON(sta->key); |
191 | } else | 202 | ret = 0; |
192 | ret = -ENOENT; | 203 | } |
193 | 204 | ||
194 | return ret; | 205 | goto out_unlock; |
195 | } | 206 | } |
196 | 207 | ||
197 | if (!sdata->keys[key_idx]) | 208 | if (!sdata->keys[key_idx]) { |
198 | return -ENOENT; | 209 | ret = -ENOENT; |
210 | goto out_unlock; | ||
211 | } | ||
199 | 212 | ||
200 | ieee80211_key_free(sdata->keys[key_idx]); | 213 | ieee80211_key_free(sdata->keys[key_idx]); |
201 | WARN_ON(sdata->keys[key_idx]); | 214 | WARN_ON(sdata->keys[key_idx]); |
202 | 215 | ||
203 | return 0; | 216 | ret = 0; |
217 | out_unlock: | ||
218 | rcu_read_unlock(); | ||
219 | |||
220 | return ret; | ||
204 | } | 221 | } |
205 | 222 | ||
206 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | 223 | static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, |
@@ -217,6 +234,8 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
217 | u16 iv16; | 234 | u16 iv16; |
218 | int err = -ENOENT; | 235 | int err = -ENOENT; |
219 | 236 | ||
237 | rcu_read_lock(); | ||
238 | |||
220 | if (mac_addr) { | 239 | if (mac_addr) { |
221 | sta = sta_info_get(sdata->local, mac_addr); | 240 | sta = sta_info_get(sdata->local, mac_addr); |
222 | if (!sta) | 241 | if (!sta) |
@@ -280,6 +299,7 @@ static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, | |||
280 | err = 0; | 299 | err = 0; |
281 | 300 | ||
282 | out: | 301 | out: |
302 | rcu_read_unlock(); | ||
283 | return err; | 303 | return err; |
284 | } | 304 | } |
285 | 305 | ||
@@ -289,9 +309,13 @@ static int ieee80211_config_default_key(struct wiphy *wiphy, | |||
289 | { | 309 | { |
290 | struct ieee80211_sub_if_data *sdata; | 310 | struct ieee80211_sub_if_data *sdata; |
291 | 311 | ||
312 | rcu_read_lock(); | ||
313 | |||
292 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 314 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
293 | ieee80211_set_default_key(sdata, key_idx); | 315 | ieee80211_set_default_key(sdata, key_idx); |
294 | 316 | ||
317 | rcu_read_unlock(); | ||
318 | |||
295 | return 0; | 319 | return 0; |
296 | } | 320 | } |
297 | 321 | ||
diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index c881524c8725..459f0767fae5 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c | |||
@@ -184,23 +184,35 @@ KEY_OPS(key); | |||
184 | key->debugfs.name = debugfs_create_file(#name, 0400,\ | 184 | key->debugfs.name = debugfs_create_file(#name, 0400,\ |
185 | key->debugfs.dir, key, &key_##name##_ops); | 185 | key->debugfs.dir, key, &key_##name##_ops); |
186 | 186 | ||
187 | void ieee80211_debugfs_key_add(struct ieee80211_local *local, | 187 | void ieee80211_debugfs_key_add(struct ieee80211_key *key) |
188 | struct ieee80211_key *key) | 188 | { |
189 | { | ||
190 | static int keycount; | 189 | static int keycount; |
191 | char buf[20]; | 190 | char buf[50]; |
191 | DECLARE_MAC_BUF(mac); | ||
192 | struct sta_info *sta; | ||
192 | 193 | ||
193 | if (!local->debugfs.keys) | 194 | if (!key->local->debugfs.keys) |
194 | return; | 195 | return; |
195 | 196 | ||
196 | sprintf(buf, "%d", keycount); | 197 | sprintf(buf, "%d", keycount); |
197 | keycount++; | 198 | keycount++; |
198 | key->debugfs.dir = debugfs_create_dir(buf, | 199 | key->debugfs.dir = debugfs_create_dir(buf, |
199 | local->debugfs.keys); | 200 | key->local->debugfs.keys); |
200 | 201 | ||
201 | if (!key->debugfs.dir) | 202 | if (!key->debugfs.dir) |
202 | return; | 203 | return; |
203 | 204 | ||
205 | rcu_read_lock(); | ||
206 | sta = rcu_dereference(key->sta); | ||
207 | if (sta) | ||
208 | sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); | ||
209 | rcu_read_unlock(); | ||
210 | |||
211 | /* using sta as a boolean is fine outside RCU lock */ | ||
212 | if (sta) | ||
213 | key->debugfs.stalink = | ||
214 | debugfs_create_symlink("station", key->debugfs.dir, buf); | ||
215 | |||
204 | DEBUGFS_ADD(keylen); | 216 | DEBUGFS_ADD(keylen); |
205 | DEBUGFS_ADD(flags); | 217 | DEBUGFS_ADD(flags); |
206 | DEBUGFS_ADD(keyidx); | 218 | DEBUGFS_ADD(keyidx); |
@@ -258,19 +270,6 @@ void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata) | |||
258 | debugfs_remove(sdata->debugfs.default_key); | 270 | debugfs_remove(sdata->debugfs.default_key); |
259 | sdata->debugfs.default_key = NULL; | 271 | sdata->debugfs.default_key = NULL; |
260 | } | 272 | } |
261 | void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, | ||
262 | struct sta_info *sta) | ||
263 | { | ||
264 | char buf[50]; | ||
265 | DECLARE_MAC_BUF(mac); | ||
266 | |||
267 | if (!key->debugfs.dir) | ||
268 | return; | ||
269 | |||
270 | sprintf(buf, "../../stations/%s", print_mac(mac, sta->addr)); | ||
271 | key->debugfs.stalink = | ||
272 | debugfs_create_symlink("station", key->debugfs.dir, buf); | ||
273 | } | ||
274 | 273 | ||
275 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | 274 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
276 | struct sta_info *sta) | 275 | struct sta_info *sta) |
diff --git a/net/mac80211/debugfs_key.h b/net/mac80211/debugfs_key.h index aecfce395da6..b1a3754ee240 100644 --- a/net/mac80211/debugfs_key.h +++ b/net/mac80211/debugfs_key.h | |||
@@ -2,18 +2,14 @@ | |||
2 | #define __MAC80211_DEBUGFS_KEY_H | 2 | #define __MAC80211_DEBUGFS_KEY_H |
3 | 3 | ||
4 | #ifdef CONFIG_MAC80211_DEBUGFS | 4 | #ifdef CONFIG_MAC80211_DEBUGFS |
5 | void ieee80211_debugfs_key_add(struct ieee80211_local *local, | 5 | void ieee80211_debugfs_key_add(struct ieee80211_key *key); |
6 | struct ieee80211_key *key); | ||
7 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); | 6 | void ieee80211_debugfs_key_remove(struct ieee80211_key *key); |
8 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); | 7 | void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); |
9 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); | 8 | void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); |
10 | void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key, | ||
11 | struct sta_info *sta); | ||
12 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | 9 | void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
13 | struct sta_info *sta); | 10 | struct sta_info *sta); |
14 | #else | 11 | #else |
15 | static inline void ieee80211_debugfs_key_add(struct ieee80211_local *local, | 12 | static inline void ieee80211_debugfs_key_add(struct ieee80211_key *key) |
16 | struct ieee80211_key *key) | ||
17 | {} | 13 | {} |
18 | static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key) | 14 | static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key) |
19 | {} | 15 | {} |
@@ -23,9 +19,6 @@ static inline void ieee80211_debugfs_key_add_default( | |||
23 | static inline void ieee80211_debugfs_key_remove_default( | 19 | static inline void ieee80211_debugfs_key_remove_default( |
24 | struct ieee80211_sub_if_data *sdata) | 20 | struct ieee80211_sub_if_data *sdata) |
25 | {} | 21 | {} |
26 | static inline void ieee80211_debugfs_key_sta_link( | ||
27 | struct ieee80211_key *key, struct sta_info *sta) | ||
28 | {} | ||
29 | static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, | 22 | static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, |
30 | struct sta_info *sta) | 23 | struct sta_info *sta) |
31 | {} | 24 | {} |
diff --git a/net/mac80211/ieee80211.c b/net/mac80211/ieee80211.c index b3cf69edeed9..dbe993af8034 100644 --- a/net/mac80211/ieee80211.c +++ b/net/mac80211/ieee80211.c | |||
@@ -1868,6 +1868,12 @@ static void __exit ieee80211_exit(void) | |||
1868 | { | 1868 | { |
1869 | rc80211_pid_exit(); | 1869 | rc80211_pid_exit(); |
1870 | 1870 | ||
1871 | /* | ||
1872 | * For key todo, it'll be empty by now but the work | ||
1873 | * might still be scheduled. | ||
1874 | */ | ||
1875 | flush_scheduled_work(); | ||
1876 | |||
1871 | if (mesh_allocated) | 1877 | if (mesh_allocated) |
1872 | ieee80211s_stop(); | 1878 | ieee80211s_stop(); |
1873 | 1879 | ||
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 8614c35544bb..7f4e7f93ee47 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h | |||
@@ -600,8 +600,8 @@ struct ieee80211_local { | |||
600 | /* | 600 | /* |
601 | * The lock only protects the list, hash, timer and counter | 601 | * The lock only protects the list, hash, timer and counter |
602 | * against manipulation, reads are done in RCU. Additionally, | 602 | * against manipulation, reads are done in RCU. Additionally, |
603 | * the lock protects each BSS's TIM bitmap and a few items | 603 | * the lock protects each BSS's TIM bitmap, a few items in |
604 | * in a STA info structure. | 604 | * STA info structures and various key pointers. |
605 | */ | 605 | */ |
606 | spinlock_t sta_lock; | 606 | spinlock_t sta_lock; |
607 | unsigned long num_sta; | 607 | unsigned long num_sta; |
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c index 41130b303170..a611c8bc76bd 100644 --- a/net/mac80211/ieee80211_ioctl.c +++ b/net/mac80211/ieee80211_ioctl.c | |||
@@ -36,6 +36,7 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
36 | struct sta_info *sta; | 36 | struct sta_info *sta; |
37 | struct ieee80211_key *key; | 37 | struct ieee80211_key *key; |
38 | struct ieee80211_sub_if_data *sdata; | 38 | struct ieee80211_sub_if_data *sdata; |
39 | int err; | ||
39 | 40 | ||
40 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); | 41 | sdata = IEEE80211_DEV_TO_SUB_IF(dev); |
41 | 42 | ||
@@ -46,23 +47,31 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
46 | } | 47 | } |
47 | 48 | ||
48 | if (remove) { | 49 | if (remove) { |
50 | rcu_read_lock(); | ||
51 | |||
52 | err = 0; | ||
53 | |||
49 | if (is_broadcast_ether_addr(sta_addr)) { | 54 | if (is_broadcast_ether_addr(sta_addr)) { |
50 | key = sdata->keys[idx]; | 55 | key = sdata->keys[idx]; |
51 | } else { | 56 | } else { |
52 | sta = sta_info_get(local, sta_addr); | 57 | sta = sta_info_get(local, sta_addr); |
53 | if (!sta) | 58 | if (!sta) { |
54 | return -ENOENT; | 59 | err = -ENOENT; |
60 | goto out_unlock; | ||
61 | } | ||
55 | key = sta->key; | 62 | key = sta->key; |
56 | } | 63 | } |
57 | 64 | ||
58 | ieee80211_key_free(key); | 65 | ieee80211_key_free(key); |
59 | return 0; | ||
60 | } else { | 66 | } else { |
61 | key = ieee80211_key_alloc(alg, idx, key_len, _key); | 67 | key = ieee80211_key_alloc(alg, idx, key_len, _key); |
62 | if (!key) | 68 | if (!key) |
63 | return -ENOMEM; | 69 | return -ENOMEM; |
64 | 70 | ||
65 | sta = NULL; | 71 | sta = NULL; |
72 | err = 0; | ||
73 | |||
74 | rcu_read_lock(); | ||
66 | 75 | ||
67 | if (!is_broadcast_ether_addr(sta_addr)) { | 76 | if (!is_broadcast_ether_addr(sta_addr)) { |
68 | set_tx_key = 0; | 77 | set_tx_key = 0; |
@@ -74,13 +83,15 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
74 | */ | 83 | */ |
75 | if (idx != 0 && alg != ALG_WEP) { | 84 | if (idx != 0 && alg != ALG_WEP) { |
76 | ieee80211_key_free(key); | 85 | ieee80211_key_free(key); |
77 | return -EINVAL; | 86 | err = -EINVAL; |
87 | goto out_unlock; | ||
78 | } | 88 | } |
79 | 89 | ||
80 | sta = sta_info_get(local, sta_addr); | 90 | sta = sta_info_get(local, sta_addr); |
81 | if (!sta) { | 91 | if (!sta) { |
82 | ieee80211_key_free(key); | 92 | ieee80211_key_free(key); |
83 | return -ENOENT; | 93 | err = -ENOENT; |
94 | goto out_unlock; | ||
84 | } | 95 | } |
85 | } | 96 | } |
86 | 97 | ||
@@ -90,7 +101,10 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr, | |||
90 | ieee80211_set_default_key(sdata, idx); | 101 | ieee80211_set_default_key(sdata, idx); |
91 | } | 102 | } |
92 | 103 | ||
93 | return 0; | 104 | out_unlock: |
105 | rcu_read_unlock(); | ||
106 | |||
107 | return err; | ||
94 | } | 108 | } |
95 | 109 | ||
96 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, | 110 | static int ieee80211_ioctl_siwgenie(struct net_device *dev, |
diff --git a/net/mac80211/ieee80211_key.h b/net/mac80211/ieee80211_key.h index d670e6dbfa39..467890c6fe81 100644 --- a/net/mac80211/ieee80211_key.h +++ b/net/mac80211/ieee80211_key.h | |||
@@ -51,13 +51,19 @@ struct sta_info; | |||
51 | * | 51 | * |
52 | * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present | 52 | * @KEY_FLAG_UPLOADED_TO_HARDWARE: Indicates that this key is present |
53 | * in the hardware for TX crypto hardware acceleration. | 53 | * in the hardware for TX crypto hardware acceleration. |
54 | * @KEY_FLAG_REMOVE_FROM_HARDWARE: Indicates to the key code that this | 54 | * @KEY_FLAG_TODO_DELETE: Key is marked for deletion and will, after an |
55 | * key is present in the hardware (but it cannot be used for | 55 | * RCU grace period, no longer be reachable other than from the |
56 | * hardware acceleration any more!) | 56 | * todo list. |
57 | * @KEY_FLAG_TODO_HWACCEL: Key needs to be added to hardware acceleration. | ||
58 | * @KEY_FLAG_TODO_DEFKEY: Key is default key and debugfs needs to be updated. | ||
59 | * @KEY_FLAG_TODO_ADD_DEBUGFS: Key needs to be added to debugfs. | ||
57 | */ | 60 | */ |
58 | enum ieee80211_internal_key_flags { | 61 | enum ieee80211_internal_key_flags { |
59 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), | 62 | KEY_FLAG_UPLOADED_TO_HARDWARE = BIT(0), |
60 | KEY_FLAG_REMOVE_FROM_HARDWARE = BIT(1), | 63 | KEY_FLAG_TODO_DELETE = BIT(1), |
64 | KEY_FLAG_TODO_HWACCEL = BIT(2), | ||
65 | KEY_FLAG_TODO_DEFKEY = BIT(3), | ||
66 | KEY_FLAG_TODO_ADD_DEBUGFS = BIT(4), | ||
61 | }; | 67 | }; |
62 | 68 | ||
63 | struct ieee80211_key { | 69 | struct ieee80211_key { |
@@ -65,8 +71,12 @@ struct ieee80211_key { | |||
65 | struct ieee80211_sub_if_data *sdata; | 71 | struct ieee80211_sub_if_data *sdata; |
66 | struct sta_info *sta; | 72 | struct sta_info *sta; |
67 | 73 | ||
74 | /* for sdata list */ | ||
68 | struct list_head list; | 75 | struct list_head list; |
76 | /* for todo list */ | ||
77 | struct list_head todo; | ||
69 | 78 | ||
79 | /* protected by todo lock! */ | ||
70 | unsigned int flags; | 80 | unsigned int flags; |
71 | 81 | ||
72 | union { | 82 | union { |
@@ -142,4 +152,6 @@ void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata); | |||
142 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); | 152 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); |
143 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); | 153 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); |
144 | 154 | ||
155 | void ieee80211_key_todo(void); | ||
156 | |||
145 | #endif /* IEEE80211_KEY_H */ | 157 | #endif /* IEEE80211_KEY_H */ |
diff --git a/net/mac80211/ieee80211_sta.c b/net/mac80211/ieee80211_sta.c index 2a3f8a8e9a43..3584a2bf0186 100644 --- a/net/mac80211/ieee80211_sta.c +++ b/net/mac80211/ieee80211_sta.c | |||
@@ -952,11 +952,8 @@ static void ieee80211_associated(struct net_device *dev, | |||
952 | 952 | ||
953 | rcu_read_unlock(); | 953 | rcu_read_unlock(); |
954 | 954 | ||
955 | if (disassoc && sta) { | 955 | if (disassoc && sta) |
956 | rtnl_lock(); | ||
957 | sta_info_destroy(sta); | 956 | sta_info_destroy(sta); |
958 | rtnl_unlock(); | ||
959 | } | ||
960 | 957 | ||
961 | if (disassoc) { | 958 | if (disassoc) { |
962 | ifsta->state = IEEE80211_DISABLED; | 959 | ifsta->state = IEEE80211_DISABLED; |
@@ -3104,12 +3101,8 @@ static void ieee80211_sta_expire(struct net_device *dev, unsigned long exp_time) | |||
3104 | } | 3101 | } |
3105 | spin_unlock_irqrestore(&local->sta_lock, flags); | 3102 | spin_unlock_irqrestore(&local->sta_lock, flags); |
3106 | 3103 | ||
3107 | synchronize_rcu(); | ||
3108 | |||
3109 | rtnl_lock(); | ||
3110 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) | 3104 | list_for_each_entry_safe(sta, tmp, &tmp_list, list) |
3111 | sta_info_destroy(sta); | 3105 | sta_info_destroy(sta); |
3112 | rtnl_unlock(); | ||
3113 | } | 3106 | } |
3114 | 3107 | ||
3115 | 3108 | ||
diff --git a/net/mac80211/key.c b/net/mac80211/key.c index 5df9e0cc009f..711e36e54ff8 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c | |||
@@ -2,7 +2,7 @@ | |||
2 | * Copyright 2002-2005, Instant802 Networks, Inc. | 2 | * Copyright 2002-2005, Instant802 Networks, Inc. |
3 | * Copyright 2005-2006, Devicescape Software, Inc. | 3 | * Copyright 2005-2006, Devicescape Software, Inc. |
4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> | 4 | * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> |
5 | * Copyright 2007 Johannes Berg <johannes@sipsolutions.net> | 5 | * Copyright 2007-2008 Johannes Berg <johannes@sipsolutions.net> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as | 8 | * it under the terms of the GNU General Public License version 2 as |
@@ -33,17 +33,78 @@ | |||
33 | * There is currently no way of knowing this except by looking into | 33 | * There is currently no way of knowing this except by looking into |
34 | * debugfs. | 34 | * debugfs. |
35 | * | 35 | * |
36 | * All operations here are called under RTNL so no extra locking is | 36 | * All key operations are protected internally so you can call them at |
37 | * required. | 37 | * any time. |
38 | * | 38 | * |
39 | * NOTE: This code requires that sta info *destruction* is done under | 39 | * Within mac80211, key references are, just as STA structure references, |
40 | * RTNL, otherwise it can try to access already freed STA structs | 40 | * protected by RCU. Note, however, that some things are unprotected, |
41 | * when a STA key is being freed. | 41 | * namely the key->sta dereferences within the hardware acceleration |
42 | * functions. This means that sta_info_destroy() must flush the key todo | ||
43 | * list. | ||
44 | * | ||
45 | * All the direct key list manipulation functions must not sleep because | ||
46 | * they can operate on STA info structs that are protected by RCU. | ||
42 | */ | 47 | */ |
43 | 48 | ||
44 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; | 49 | static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; |
45 | static const u8 zero_addr[ETH_ALEN]; | 50 | static const u8 zero_addr[ETH_ALEN]; |
46 | 51 | ||
52 | /* key mutex: used to synchronise todo runners */ | ||
53 | static DEFINE_MUTEX(key_mutex); | ||
54 | static DEFINE_SPINLOCK(todo_lock); | ||
55 | static LIST_HEAD(todo_list); | ||
56 | |||
57 | static void key_todo(struct work_struct *work) | ||
58 | { | ||
59 | ieee80211_key_todo(); | ||
60 | } | ||
61 | |||
62 | static DECLARE_WORK(todo_work, key_todo); | ||
63 | |||
64 | /** | ||
65 | * add_todo - add todo item for a key | ||
66 | * | ||
67 | * @key: key to add to do item for | ||
68 | * @flag: todo flag(s) | ||
69 | */ | ||
70 | static void add_todo(struct ieee80211_key *key, u32 flag) | ||
71 | { | ||
72 | if (!key) | ||
73 | return; | ||
74 | |||
75 | spin_lock(&todo_lock); | ||
76 | key->flags |= flag; | ||
77 | /* only add if not already added */ | ||
78 | if (list_empty(&key->todo)) | ||
79 | list_add(&key->todo, &todo_list); | ||
80 | schedule_work(&todo_work); | ||
81 | spin_unlock(&todo_lock); | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * ieee80211_key_lock - lock the mac80211 key operation lock | ||
86 | * | ||
87 | * This locks the (global) mac80211 key operation lock, all | ||
88 | * key operations must be done under this lock. | ||
89 | */ | ||
90 | static void ieee80211_key_lock(void) | ||
91 | { | ||
92 | mutex_lock(&key_mutex); | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * ieee80211_key_unlock - unlock the mac80211 key operation lock | ||
97 | */ | ||
98 | static void ieee80211_key_unlock(void) | ||
99 | { | ||
100 | mutex_unlock(&key_mutex); | ||
101 | } | ||
102 | |||
103 | static void assert_key_lock(void) | ||
104 | { | ||
105 | WARN_ON(!mutex_is_locked(&key_mutex)); | ||
106 | } | ||
107 | |||
47 | static const u8 *get_mac_for_key(struct ieee80211_key *key) | 108 | static const u8 *get_mac_for_key(struct ieee80211_key *key) |
48 | { | 109 | { |
49 | const u8 *addr = bcast_addr; | 110 | const u8 *addr = bcast_addr; |
@@ -70,26 +131,23 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
70 | int ret; | 131 | int ret; |
71 | DECLARE_MAC_BUF(mac); | 132 | DECLARE_MAC_BUF(mac); |
72 | 133 | ||
134 | assert_key_lock(); | ||
135 | might_sleep(); | ||
136 | |||
73 | if (!key->local->ops->set_key) | 137 | if (!key->local->ops->set_key) |
74 | return; | 138 | return; |
75 | 139 | ||
76 | /* | ||
77 | * This makes sure that all pending flushes have | ||
78 | * actually completed prior to uploading new key | ||
79 | * material to the hardware. That is necessary to | ||
80 | * avoid races between flushing STAs and adding | ||
81 | * new keys for them. | ||
82 | */ | ||
83 | __ieee80211_run_pending_flush(key->local); | ||
84 | |||
85 | addr = get_mac_for_key(key); | 140 | addr = get_mac_for_key(key); |
86 | 141 | ||
87 | ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, | 142 | ret = key->local->ops->set_key(local_to_hw(key->local), SET_KEY, |
88 | key->sdata->dev->dev_addr, addr, | 143 | key->sdata->dev->dev_addr, addr, |
89 | &key->conf); | 144 | &key->conf); |
90 | 145 | ||
91 | if (!ret) | 146 | if (!ret) { |
147 | spin_lock(&todo_lock); | ||
92 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; | 148 | key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE; |
149 | spin_unlock(&todo_lock); | ||
150 | } | ||
93 | 151 | ||
94 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) | 152 | if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) |
95 | printk(KERN_ERR "mac80211-%s: failed to set key " | 153 | printk(KERN_ERR "mac80211-%s: failed to set key " |
@@ -98,26 +156,24 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) | |||
98 | key->conf.keyidx, print_mac(mac, addr), ret); | 156 | key->conf.keyidx, print_mac(mac, addr), ret); |
99 | } | 157 | } |
100 | 158 | ||
101 | static void ieee80211_key_mark_hw_accel_off(struct ieee80211_key *key) | ||
102 | { | ||
103 | if (key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) { | ||
104 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; | ||
105 | key->flags |= KEY_FLAG_REMOVE_FROM_HARDWARE; | ||
106 | } | ||
107 | } | ||
108 | |||
109 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | 159 | static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) |
110 | { | 160 | { |
111 | const u8 *addr; | 161 | const u8 *addr; |
112 | int ret; | 162 | int ret; |
113 | DECLARE_MAC_BUF(mac); | 163 | DECLARE_MAC_BUF(mac); |
114 | 164 | ||
165 | assert_key_lock(); | ||
166 | might_sleep(); | ||
167 | |||
115 | if (!key || !key->local->ops->set_key) | 168 | if (!key || !key->local->ops->set_key) |
116 | return; | 169 | return; |
117 | 170 | ||
118 | if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) && | 171 | spin_lock(&todo_lock); |
119 | !(key->flags & KEY_FLAG_REMOVE_FROM_HARDWARE)) | 172 | if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE)) { |
173 | spin_unlock(&todo_lock); | ||
120 | return; | 174 | return; |
175 | } | ||
176 | spin_unlock(&todo_lock); | ||
121 | 177 | ||
122 | addr = get_mac_for_key(key); | 178 | addr = get_mac_for_key(key); |
123 | 179 | ||
@@ -131,8 +187,72 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) | |||
131 | wiphy_name(key->local->hw.wiphy), | 187 | wiphy_name(key->local->hw.wiphy), |
132 | key->conf.keyidx, print_mac(mac, addr), ret); | 188 | key->conf.keyidx, print_mac(mac, addr), ret); |
133 | 189 | ||
134 | key->flags &= ~(KEY_FLAG_UPLOADED_TO_HARDWARE | | 190 | spin_lock(&todo_lock); |
135 | KEY_FLAG_REMOVE_FROM_HARDWARE); | 191 | key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; |
192 | spin_unlock(&todo_lock); | ||
193 | } | ||
194 | |||
195 | static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, | ||
196 | int idx) | ||
197 | { | ||
198 | struct ieee80211_key *key = NULL; | ||
199 | |||
200 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | ||
201 | key = sdata->keys[idx]; | ||
202 | |||
203 | rcu_assign_pointer(sdata->default_key, key); | ||
204 | |||
205 | if (key) | ||
206 | add_todo(key, KEY_FLAG_TODO_DEFKEY); | ||
207 | } | ||
208 | |||
209 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | ||
210 | { | ||
211 | unsigned long flags; | ||
212 | |||
213 | spin_lock_irqsave(&sdata->local->sta_lock, flags); | ||
214 | __ieee80211_set_default_key(sdata, idx); | ||
215 | spin_unlock_irqrestore(&sdata->local->sta_lock, flags); | ||
216 | } | ||
217 | |||
218 | |||
219 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | ||
220 | struct sta_info *sta, | ||
221 | struct ieee80211_key *old, | ||
222 | struct ieee80211_key *new) | ||
223 | { | ||
224 | int idx, defkey; | ||
225 | |||
226 | if (new) | ||
227 | list_add(&new->list, &sdata->key_list); | ||
228 | |||
229 | if (sta) { | ||
230 | rcu_assign_pointer(sta->key, new); | ||
231 | } else { | ||
232 | WARN_ON(new && old && new->conf.keyidx != old->conf.keyidx); | ||
233 | |||
234 | if (old) | ||
235 | idx = old->conf.keyidx; | ||
236 | else | ||
237 | idx = new->conf.keyidx; | ||
238 | |||
239 | defkey = old && sdata->default_key == old; | ||
240 | |||
241 | if (defkey && !new) | ||
242 | __ieee80211_set_default_key(sdata, -1); | ||
243 | |||
244 | rcu_assign_pointer(sdata->keys[idx], new); | ||
245 | if (defkey && new) | ||
246 | __ieee80211_set_default_key(sdata, new->conf.keyidx); | ||
247 | } | ||
248 | |||
249 | if (old) { | ||
250 | /* | ||
251 | * We'll use an empty list to indicate that the key | ||
252 | * has already been removed. | ||
253 | */ | ||
254 | list_del_init(&old->list); | ||
255 | } | ||
136 | } | 256 | } |
137 | 257 | ||
138 | struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | 258 | struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, |
@@ -160,6 +280,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
160 | key->conf.keylen = key_len; | 280 | key->conf.keylen = key_len; |
161 | memcpy(key->conf.key, key_data, key_len); | 281 | memcpy(key->conf.key, key_data, key_len); |
162 | INIT_LIST_HEAD(&key->list); | 282 | INIT_LIST_HEAD(&key->list); |
283 | INIT_LIST_HEAD(&key->todo); | ||
163 | 284 | ||
164 | if (alg == ALG_CCMP) { | 285 | if (alg == ALG_CCMP) { |
165 | /* | 286 | /* |
@@ -168,7 +289,7 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
168 | */ | 289 | */ |
169 | key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); | 290 | key->u.ccmp.tfm = ieee80211_aes_key_setup_encrypt(key_data); |
170 | if (!key->u.ccmp.tfm) { | 291 | if (!key->u.ccmp.tfm) { |
171 | ieee80211_key_free(key); | 292 | kfree(key); |
172 | return NULL; | 293 | return NULL; |
173 | } | 294 | } |
174 | } | 295 | } |
@@ -176,56 +297,14 @@ struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, | |||
176 | return key; | 297 | return key; |
177 | } | 298 | } |
178 | 299 | ||
179 | static void __ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, | ||
180 | struct sta_info *sta, | ||
181 | struct ieee80211_key *key, | ||
182 | struct ieee80211_key *new) | ||
183 | { | ||
184 | int idx, defkey; | ||
185 | |||
186 | if (new) | ||
187 | list_add(&new->list, &sdata->key_list); | ||
188 | |||
189 | if (sta) { | ||
190 | rcu_assign_pointer(sta->key, new); | ||
191 | } else { | ||
192 | WARN_ON(new && key && new->conf.keyidx != key->conf.keyidx); | ||
193 | |||
194 | if (key) | ||
195 | idx = key->conf.keyidx; | ||
196 | else | ||
197 | idx = new->conf.keyidx; | ||
198 | |||
199 | defkey = key && sdata->default_key == key; | ||
200 | |||
201 | if (defkey && !new) | ||
202 | ieee80211_set_default_key(sdata, -1); | ||
203 | |||
204 | rcu_assign_pointer(sdata->keys[idx], new); | ||
205 | if (defkey && new) | ||
206 | ieee80211_set_default_key(sdata, new->conf.keyidx); | ||
207 | } | ||
208 | |||
209 | if (key) { | ||
210 | ieee80211_key_mark_hw_accel_off(key); | ||
211 | /* | ||
212 | * We'll use an empty list to indicate that the key | ||
213 | * has already been removed. | ||
214 | */ | ||
215 | list_del_init(&key->list); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | void ieee80211_key_link(struct ieee80211_key *key, | 300 | void ieee80211_key_link(struct ieee80211_key *key, |
220 | struct ieee80211_sub_if_data *sdata, | 301 | struct ieee80211_sub_if_data *sdata, |
221 | struct sta_info *sta) | 302 | struct sta_info *sta) |
222 | { | 303 | { |
223 | struct ieee80211_key *old_key; | 304 | struct ieee80211_key *old_key; |
305 | unsigned long flags; | ||
224 | int idx; | 306 | int idx; |
225 | 307 | ||
226 | ASSERT_RTNL(); | ||
227 | might_sleep(); | ||
228 | |||
229 | BUG_ON(!sdata); | 308 | BUG_ON(!sdata); |
230 | BUG_ON(!key); | 309 | BUG_ON(!key); |
231 | 310 | ||
@@ -234,11 +313,7 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
234 | key->sdata = sdata; | 313 | key->sdata = sdata; |
235 | key->sta = sta; | 314 | key->sta = sta; |
236 | 315 | ||
237 | ieee80211_debugfs_key_add(key->local, key); | ||
238 | |||
239 | if (sta) { | 316 | if (sta) { |
240 | ieee80211_debugfs_key_sta_link(key, sta); | ||
241 | |||
242 | /* | 317 | /* |
243 | * some hardware cannot handle TKIP with QoS, so | 318 | * some hardware cannot handle TKIP with QoS, so |
244 | * we indicate whether QoS could be in use. | 319 | * we indicate whether QoS could be in use. |
@@ -249,7 +324,10 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
249 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { | 324 | if (sdata->vif.type == IEEE80211_IF_TYPE_STA) { |
250 | struct sta_info *ap; | 325 | struct sta_info *ap; |
251 | 326 | ||
252 | rcu_read_lock(); | 327 | /* |
328 | * We're getting a sta pointer in, | ||
329 | * so must be under RCU read lock. | ||
330 | */ | ||
253 | 331 | ||
254 | /* same here, the AP could be using QoS */ | 332 | /* same here, the AP could be using QoS */ |
255 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); | 333 | ap = sta_info_get(key->local, key->sdata->u.sta.bssid); |
@@ -258,11 +336,11 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
258 | key->conf.flags |= | 336 | key->conf.flags |= |
259 | IEEE80211_KEY_FLAG_WMM_STA; | 337 | IEEE80211_KEY_FLAG_WMM_STA; |
260 | } | 338 | } |
261 | |||
262 | rcu_read_unlock(); | ||
263 | } | 339 | } |
264 | } | 340 | } |
265 | 341 | ||
342 | spin_lock_irqsave(&sdata->local->sta_lock, flags); | ||
343 | |||
266 | if (sta) | 344 | if (sta) |
267 | old_key = sta->key; | 345 | old_key = sta->key; |
268 | else | 346 | else |
@@ -270,108 +348,150 @@ void ieee80211_key_link(struct ieee80211_key *key, | |||
270 | 348 | ||
271 | __ieee80211_key_replace(sdata, sta, old_key, key); | 349 | __ieee80211_key_replace(sdata, sta, old_key, key); |
272 | 350 | ||
273 | if (old_key) { | 351 | spin_unlock_irqrestore(&sdata->local->sta_lock, flags); |
274 | synchronize_rcu(); | 352 | |
275 | ieee80211_key_free(old_key); | 353 | /* free old key later */ |
276 | } | 354 | add_todo(old_key, KEY_FLAG_TODO_DELETE); |
277 | 355 | ||
356 | add_todo(key, KEY_FLAG_TODO_ADD_DEBUGFS); | ||
278 | if (netif_running(sdata->dev)) | 357 | if (netif_running(sdata->dev)) |
279 | ieee80211_key_enable_hw_accel(key); | 358 | add_todo(key, KEY_FLAG_TODO_HWACCEL); |
280 | } | 359 | } |
281 | 360 | ||
282 | void ieee80211_key_free(struct ieee80211_key *key) | 361 | void ieee80211_key_free(struct ieee80211_key *key) |
283 | { | 362 | { |
284 | ASSERT_RTNL(); | 363 | unsigned long flags; |
285 | might_sleep(); | ||
286 | 364 | ||
287 | if (!key) | 365 | if (!key) |
288 | return; | 366 | return; |
289 | 367 | ||
368 | /* | ||
369 | * Replace key with nothingness if it was ever used. | ||
370 | */ | ||
290 | if (key->sdata) { | 371 | if (key->sdata) { |
291 | /* | 372 | spin_lock_irqsave(&key->sdata->local->sta_lock, flags); |
292 | * Replace key with nothingness. | 373 | __ieee80211_key_replace(key->sdata, key->sta, |
293 | * | 374 | key, NULL); |
294 | * Because other code may have key reference (RCU protected) | 375 | spin_unlock_irqrestore(&key->sdata->local->sta_lock, flags); |
295 | * right now, we then wait for a grace period before freeing | 376 | } |
296 | * it. | ||
297 | * An empty list indicates it was never added to the key list | ||
298 | * or has been removed already. It may, however, still be in | ||
299 | * hardware for acceleration. | ||
300 | */ | ||
301 | if (!list_empty(&key->list)) | ||
302 | __ieee80211_key_replace(key->sdata, key->sta, | ||
303 | key, NULL); | ||
304 | 377 | ||
305 | /* | 378 | add_todo(key, KEY_FLAG_TODO_DELETE); |
306 | * Do NOT remove this without looking at sta_info_destroy() | 379 | } |
307 | */ | ||
308 | synchronize_rcu(); | ||
309 | 380 | ||
310 | /* | 381 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) |
311 | * Remove from hwaccel if appropriate, this will | 382 | { |
312 | * only happen when the key is actually unlinked, | 383 | struct ieee80211_key *key; |
313 | * it will already be done when the key was replaced. | ||
314 | */ | ||
315 | ieee80211_key_disable_hw_accel(key); | ||
316 | } | ||
317 | 384 | ||
318 | if (key->conf.alg == ALG_CCMP) | 385 | might_sleep(); |
319 | ieee80211_aes_key_free(key->u.ccmp.tfm); | ||
320 | ieee80211_debugfs_key_remove(key); | ||
321 | 386 | ||
322 | kfree(key); | 387 | if (WARN_ON(!netif_running(sdata->dev))) |
388 | return; | ||
389 | |||
390 | ieee80211_key_lock(); | ||
391 | |||
392 | list_for_each_entry(key, &sdata->key_list, list) | ||
393 | ieee80211_key_enable_hw_accel(key); | ||
394 | |||
395 | ieee80211_key_unlock(); | ||
323 | } | 396 | } |
324 | 397 | ||
325 | void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) | 398 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) |
326 | { | 399 | { |
327 | struct ieee80211_key *key = NULL; | 400 | struct ieee80211_key *key; |
328 | 401 | ||
329 | if (idx >= 0 && idx < NUM_DEFAULT_KEYS) | 402 | might_sleep(); |
330 | key = sdata->keys[idx]; | ||
331 | 403 | ||
332 | if (sdata->default_key != key) { | 404 | ieee80211_key_lock(); |
333 | ieee80211_debugfs_key_remove_default(sdata); | ||
334 | 405 | ||
335 | rcu_assign_pointer(sdata->default_key, key); | 406 | list_for_each_entry(key, &sdata->key_list, list) |
407 | ieee80211_key_disable_hw_accel(key); | ||
336 | 408 | ||
337 | if (sdata->default_key) | 409 | ieee80211_key_unlock(); |
338 | ieee80211_debugfs_key_add_default(sdata); | ||
339 | } | ||
340 | } | 410 | } |
341 | 411 | ||
342 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) | 412 | static void __ieee80211_key_free(struct ieee80211_key *key) |
343 | { | 413 | { |
344 | struct ieee80211_key *key, *tmp; | 414 | if (!key) |
345 | LIST_HEAD(tmp_list); | 415 | return; |
346 | 416 | ||
347 | ASSERT_RTNL(); | 417 | ieee80211_key_disable_hw_accel(key); |
348 | might_sleep(); | ||
349 | 418 | ||
350 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | 419 | if (key->conf.alg == ALG_CCMP) |
351 | ieee80211_key_free(key); | 420 | ieee80211_aes_key_free(key->u.ccmp.tfm); |
421 | ieee80211_debugfs_key_remove(key); | ||
422 | |||
423 | kfree(key); | ||
352 | } | 424 | } |
353 | 425 | ||
354 | void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) | 426 | static void __ieee80211_key_todo(void) |
355 | { | 427 | { |
356 | struct ieee80211_key *key; | 428 | struct ieee80211_key *key; |
429 | bool work_done; | ||
430 | u32 todoflags; | ||
357 | 431 | ||
358 | ASSERT_RTNL(); | 432 | /* |
359 | might_sleep(); | 433 | * NB: sta_info_destroy relies on this! |
434 | */ | ||
435 | synchronize_rcu(); | ||
436 | |||
437 | spin_lock(&todo_lock); | ||
438 | while (!list_empty(&todo_list)) { | ||
439 | key = list_first_entry(&todo_list, struct ieee80211_key, todo); | ||
440 | list_del_init(&key->todo); | ||
441 | todoflags = key->flags & (KEY_FLAG_TODO_ADD_DEBUGFS | | ||
442 | KEY_FLAG_TODO_DEFKEY | | ||
443 | KEY_FLAG_TODO_HWACCEL | | ||
444 | KEY_FLAG_TODO_DELETE); | ||
445 | key->flags &= ~todoflags; | ||
446 | spin_unlock(&todo_lock); | ||
447 | |||
448 | work_done = false; | ||
449 | |||
450 | if (todoflags & KEY_FLAG_TODO_ADD_DEBUGFS) { | ||
451 | ieee80211_debugfs_key_add(key); | ||
452 | work_done = true; | ||
453 | } | ||
454 | if (todoflags & KEY_FLAG_TODO_DEFKEY) { | ||
455 | ieee80211_debugfs_key_remove_default(key->sdata); | ||
456 | ieee80211_debugfs_key_add_default(key->sdata); | ||
457 | work_done = true; | ||
458 | } | ||
459 | if (todoflags & KEY_FLAG_TODO_HWACCEL) { | ||
460 | ieee80211_key_enable_hw_accel(key); | ||
461 | work_done = true; | ||
462 | } | ||
463 | if (todoflags & KEY_FLAG_TODO_DELETE) { | ||
464 | __ieee80211_key_free(key); | ||
465 | work_done = true; | ||
466 | } | ||
360 | 467 | ||
361 | if (WARN_ON(!netif_running(sdata->dev))) | 468 | WARN_ON(!work_done); |
362 | return; | ||
363 | 469 | ||
364 | list_for_each_entry(key, &sdata->key_list, list) | 470 | spin_lock(&todo_lock); |
365 | ieee80211_key_enable_hw_accel(key); | 471 | } |
472 | spin_unlock(&todo_lock); | ||
366 | } | 473 | } |
367 | 474 | ||
368 | void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) | 475 | void ieee80211_key_todo(void) |
369 | { | 476 | { |
370 | struct ieee80211_key *key; | 477 | ieee80211_key_lock(); |
478 | __ieee80211_key_todo(); | ||
479 | ieee80211_key_unlock(); | ||
480 | } | ||
371 | 481 | ||
372 | ASSERT_RTNL(); | 482 | void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) |
373 | might_sleep(); | 483 | { |
484 | struct ieee80211_key *key, *tmp; | ||
485 | LIST_HEAD(tmp_list); | ||
374 | 486 | ||
375 | list_for_each_entry(key, &sdata->key_list, list) | 487 | ieee80211_key_lock(); |
376 | ieee80211_key_disable_hw_accel(key); | 488 | |
489 | ieee80211_debugfs_key_remove_default(sdata); | ||
490 | |||
491 | list_for_each_entry_safe(key, tmp, &sdata->key_list, list) | ||
492 | ieee80211_key_free(key); | ||
493 | |||
494 | __ieee80211_key_todo(); | ||
495 | |||
496 | ieee80211_key_unlock(); | ||
377 | } | 497 | } |
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index cedd73a0c875..5540cbf7c445 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c | |||
@@ -51,17 +51,15 @@ | |||
51 | * | 51 | * |
52 | * In order to remove a STA info structure, the caller needs to first | 52 | * In order to remove a STA info structure, the caller needs to first |
53 | * unlink it (sta_info_unlink()) from the list and hash tables and | 53 | * unlink it (sta_info_unlink()) from the list and hash tables and |
54 | * then destroy it while holding the RTNL; sta_info_destroy() will wait | 54 | * then destroy it; sta_info_destroy() will wait for an RCU grace period |
55 | * for an RCU grace period to elapse before actually freeing it. Due to | 55 | * to elapse before actually freeing it. Due to the pinning and the |
56 | * the pinning and the possibility of multiple callers trying to remove | 56 | * possibility of multiple callers trying to remove the same STA info at |
57 | * the same STA info at the same time, sta_info_unlink() can clear the | 57 | * the same time, sta_info_unlink() can clear the STA info pointer it is |
58 | * STA info pointer it is passed to indicate that the STA info is owned | 58 | * passed to indicate that the STA info is owned by somebody else now. |
59 | * by somebody else now. | ||
60 | * | 59 | * |
61 | * If sta_info_unlink() did not clear the pointer then the caller owns | 60 | * If sta_info_unlink() did not clear the pointer then the caller owns |
62 | * the STA info structure now and is responsible of destroying it with | 61 | * the STA info structure now and is responsible of destroying it with |
63 | * a call to sta_info_destroy(), not before RCU synchronisation, of | 62 | * a call to sta_info_destroy(). |
64 | * course. Note that sta_info_destroy() must be protected by the RTNL. | ||
65 | * | 63 | * |
66 | * In all other cases, there is no concept of ownership on a STA entry, | 64 | * In all other cases, there is no concept of ownership on a STA entry, |
67 | * each structure is owned by the global hash table/list until it is | 65 | * each structure is owned by the global hash table/list until it is |
@@ -164,7 +162,6 @@ void sta_info_destroy(struct sta_info *sta) | |||
164 | struct sk_buff *skb; | 162 | struct sk_buff *skb; |
165 | int i; | 163 | int i; |
166 | 164 | ||
167 | ASSERT_RTNL(); | ||
168 | might_sleep(); | 165 | might_sleep(); |
169 | 166 | ||
170 | if (!sta) | 167 | if (!sta) |
@@ -180,22 +177,16 @@ void sta_info_destroy(struct sta_info *sta) | |||
180 | mesh_plink_deactivate(sta); | 177 | mesh_plink_deactivate(sta); |
181 | #endif | 178 | #endif |
182 | 179 | ||
183 | if (sta->key) { | 180 | /* |
184 | /* | 181 | * We have only unlinked the key, and actually destroying it |
185 | * NOTE: This will call synchronize_rcu() internally to | 182 | * may mean it is removed from hardware which requires that |
186 | * make sure no key references can be in use. We rely on | 183 | * the key->sta pointer is still valid, so flush the key todo |
187 | * that when we take this branch to make sure nobody can | 184 | * list here. |
188 | * reference this STA struct any longer! | 185 | * |
189 | */ | 186 | * ieee80211_key_todo() will synchronize_rcu() so after this |
190 | ieee80211_key_free(sta->key); | 187 | * nothing can reference this sta struct any more. |
191 | WARN_ON(sta->key); | 188 | */ |
192 | } else { | 189 | ieee80211_key_todo(); |
193 | /* | ||
194 | * Make sure that nobody can reference this STA struct | ||
195 | * any longer. | ||
196 | */ | ||
197 | synchronize_rcu(); | ||
198 | } | ||
199 | 190 | ||
200 | #ifdef CONFIG_MAC80211_MESH | 191 | #ifdef CONFIG_MAC80211_MESH |
201 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) | 192 | if (ieee80211_vif_is_mesh(&sta->sdata->vif)) |
@@ -439,6 +430,11 @@ void __sta_info_unlink(struct sta_info **sta) | |||
439 | return; | 430 | return; |
440 | } | 431 | } |
441 | 432 | ||
433 | if ((*sta)->key) { | ||
434 | ieee80211_key_free((*sta)->key); | ||
435 | WARN_ON((*sta)->key); | ||
436 | } | ||
437 | |||
442 | list_del(&(*sta)->list); | 438 | list_del(&(*sta)->list); |
443 | 439 | ||
444 | if ((*sta)->flags & WLAN_STA_PS) { | 440 | if ((*sta)->flags & WLAN_STA_PS) { |
@@ -652,7 +648,7 @@ static void sta_info_debugfs_add_work(struct work_struct *work) | |||
652 | } | 648 | } |
653 | #endif | 649 | #endif |
654 | 650 | ||
655 | void __ieee80211_run_pending_flush(struct ieee80211_local *local) | 651 | static void __ieee80211_run_pending_flush(struct ieee80211_local *local) |
656 | { | 652 | { |
657 | struct sta_info *sta; | 653 | struct sta_info *sta; |
658 | unsigned long flags; | 654 | unsigned long flags; |
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index ebb7b2b4d0b9..30fd328e9991 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h | |||
@@ -359,6 +359,5 @@ void sta_info_stop(struct ieee80211_local *local); | |||
359 | int sta_info_flush(struct ieee80211_local *local, | 359 | int sta_info_flush(struct ieee80211_local *local, |
360 | struct ieee80211_sub_if_data *sdata); | 360 | struct ieee80211_sub_if_data *sdata); |
361 | void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata); | 361 | void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata); |
362 | void __ieee80211_run_pending_flush(struct ieee80211_local *local); | ||
363 | 362 | ||
364 | #endif /* STA_INFO_H */ | 363 | #endif /* STA_INFO_H */ |