aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/mac80211/cfg.c44
-rw-r--r--net/mac80211/debugfs_key.c37
-rw-r--r--net/mac80211/debugfs_key.h11
-rw-r--r--net/mac80211/ieee80211.c6
-rw-r--r--net/mac80211/ieee80211_i.h4
-rw-r--r--net/mac80211/ieee80211_ioctl.c26
-rw-r--r--net/mac80211/ieee80211_key.h20
-rw-r--r--net/mac80211/ieee80211_sta.c9
-rw-r--r--net/mac80211/key.c408
-rw-r--r--net/mac80211/sta_info.c48
-rw-r--r--net/mac80211/sta_info.h1
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
173static int ieee80211_del_key(struct wiphy *wiphy, struct net_device *dev, 181static 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
206static int ieee80211_get_key(struct wiphy *wiphy, struct net_device *dev, 223static 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
187void ieee80211_debugfs_key_add(struct ieee80211_local *local, 187void 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}
261void 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
275void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, 274void 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
5void ieee80211_debugfs_key_add(struct ieee80211_local *local, 5void ieee80211_debugfs_key_add(struct ieee80211_key *key);
6 struct ieee80211_key *key);
7void ieee80211_debugfs_key_remove(struct ieee80211_key *key); 6void ieee80211_debugfs_key_remove(struct ieee80211_key *key);
8void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata); 7void ieee80211_debugfs_key_add_default(struct ieee80211_sub_if_data *sdata);
9void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata); 8void ieee80211_debugfs_key_remove_default(struct ieee80211_sub_if_data *sdata);
10void ieee80211_debugfs_key_sta_link(struct ieee80211_key *key,
11 struct sta_info *sta);
12void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, 9void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key,
13 struct sta_info *sta); 10 struct sta_info *sta);
14#else 11#else
15static inline void ieee80211_debugfs_key_add(struct ieee80211_local *local, 12static inline void ieee80211_debugfs_key_add(struct ieee80211_key *key)
16 struct ieee80211_key *key)
17{} 13{}
18static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key) 14static inline void ieee80211_debugfs_key_remove(struct ieee80211_key *key)
19{} 15{}
@@ -23,9 +19,6 @@ static inline void ieee80211_debugfs_key_add_default(
23static inline void ieee80211_debugfs_key_remove_default( 19static inline void ieee80211_debugfs_key_remove_default(
24 struct ieee80211_sub_if_data *sdata) 20 struct ieee80211_sub_if_data *sdata)
25{} 21{}
26static inline void ieee80211_debugfs_key_sta_link(
27 struct ieee80211_key *key, struct sta_info *sta)
28{}
29static inline void ieee80211_debugfs_key_sta_del(struct ieee80211_key *key, 22static 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
96static int ieee80211_ioctl_siwgenie(struct net_device *dev, 110static 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 */
58enum ieee80211_internal_key_flags { 61enum 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
63struct ieee80211_key { 69struct 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);
142void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata); 152void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata);
143void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata); 153void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata);
144 154
155void 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
44static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; 49static const u8 bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
45static const u8 zero_addr[ETH_ALEN]; 50static const u8 zero_addr[ETH_ALEN];
46 51
52/* key mutex: used to synchronise todo runners */
53static DEFINE_MUTEX(key_mutex);
54static DEFINE_SPINLOCK(todo_lock);
55static LIST_HEAD(todo_list);
56
57static void key_todo(struct work_struct *work)
58{
59 ieee80211_key_todo();
60}
61
62static 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 */
70static 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 */
90static 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 */
98static void ieee80211_key_unlock(void)
99{
100 mutex_unlock(&key_mutex);
101}
102
103static void assert_key_lock(void)
104{
105 WARN_ON(!mutex_is_locked(&key_mutex));
106}
107
47static const u8 *get_mac_for_key(struct ieee80211_key *key) 108static 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
101static 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
109static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) 159static 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
195static 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
209void 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
219static 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
138struct ieee80211_key *ieee80211_key_alloc(enum ieee80211_key_alg alg, 258struct 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
179static 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
219void ieee80211_key_link(struct ieee80211_key *key, 300void 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
282void ieee80211_key_free(struct ieee80211_key *key) 361void 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 /* 381void 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
325void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx) 398void 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
342void ieee80211_free_keys(struct ieee80211_sub_if_data *sdata) 412static 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
354void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata) 426static 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
368void ieee80211_disable_keys(struct ieee80211_sub_if_data *sdata) 475void 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(); 482void 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
655void __ieee80211_run_pending_flush(struct ieee80211_local *local) 651static 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);
359int sta_info_flush(struct ieee80211_local *local, 359int sta_info_flush(struct ieee80211_local *local,
360 struct ieee80211_sub_if_data *sdata); 360 struct ieee80211_sub_if_data *sdata);
361void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata); 361void sta_info_flush_delayed(struct ieee80211_sub_if_data *sdata);
362void __ieee80211_run_pending_flush(struct ieee80211_local *local);
363 362
364#endif /* STA_INFO_H */ 363#endif /* STA_INFO_H */