aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211')
-rw-r--r--net/mac80211/ieee80211_ioctl.c5
-rw-r--r--net/mac80211/key.c43
-rw-r--r--net/mac80211/rx.c20
-rw-r--r--net/mac80211/tx.c20
4 files changed, 61 insertions, 27 deletions
diff --git a/net/mac80211/ieee80211_ioctl.c b/net/mac80211/ieee80211_ioctl.c
index 1d585cc2c8c7..10ec05624a67 100644
--- a/net/mac80211/ieee80211_ioctl.c
+++ b/net/mac80211/ieee80211_ioctl.c
@@ -73,11 +73,8 @@ static int ieee80211_set_encryption(struct net_device *dev, u8 *sta_addr,
73 key = NULL; 73 key = NULL;
74 } else { 74 } else {
75 /* 75 /*
76 * Need to free it before allocating a new one with 76 * Automatically frees any old key if present.
77 * with the same index or the ordering to the driver's
78 * set_key() callback becomes confused.
79 */ 77 */
80 ieee80211_key_free(key);
81 key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key); 78 key = ieee80211_key_alloc(sdata, sta, alg, idx, key_len, _key);
82 if (!key) { 79 if (!key) {
83 ret = -ENOMEM; 80 ret = -ENOMEM;
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index 178f00cf61b9..19e77f626d84 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -12,6 +12,7 @@
12#include <linux/if_ether.h> 12#include <linux/if_ether.h>
13#include <linux/etherdevice.h> 13#include <linux/etherdevice.h>
14#include <linux/list.h> 14#include <linux/list.h>
15#include <linux/rcupdate.h>
15#include <net/mac80211.h> 16#include <net/mac80211.h>
16#include "ieee80211_i.h" 17#include "ieee80211_i.h"
17#include "debugfs_key.h" 18#include "debugfs_key.h"
@@ -120,6 +121,7 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
120{ 121{
121 struct ieee80211_key *key; 122 struct ieee80211_key *key;
122 123
124 BUG_ON(idx < 0 || idx >= NUM_DEFAULT_KEYS);
123 BUG_ON(alg == ALG_NONE); 125 BUG_ON(alg == ALG_NONE);
124 126
125 key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL); 127 key = kzalloc(sizeof(struct ieee80211_key) + key_len, GFP_KERNEL);
@@ -157,9 +159,15 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
157 159
158 ieee80211_debugfs_key_add(key->local, key); 160 ieee80211_debugfs_key_add(key->local, key);
159 161
162 /* remove key first */
163 if (sta)
164 ieee80211_key_free(sta->key);
165 else
166 ieee80211_key_free(sdata->keys[idx]);
167
160 if (sta) { 168 if (sta) {
161 ieee80211_debugfs_key_sta_link(key, sta); 169 ieee80211_debugfs_key_sta_link(key, sta);
162 sta->key = key; 170
163 /* 171 /*
164 * some hardware cannot handle TKIP with QoS, so 172 * some hardware cannot handle TKIP with QoS, so
165 * we indicate whether QoS could be in use. 173 * we indicate whether QoS could be in use.
@@ -179,21 +187,19 @@ struct ieee80211_key *ieee80211_key_alloc(struct ieee80211_sub_if_data *sdata,
179 sta_info_put(ap); 187 sta_info_put(ap);
180 } 188 }
181 } 189 }
182
183 if (idx >= 0 && idx < NUM_DEFAULT_KEYS) {
184 if (!sdata->keys[idx])
185 sdata->keys[idx] = key;
186 else
187 WARN_ON(1);
188 } else
189 WARN_ON(1);
190 } 190 }
191 191
192 list_add(&key->list, &sdata->key_list); 192 /* enable hwaccel if appropriate */
193
194 if (netif_running(key->sdata->dev)) 193 if (netif_running(key->sdata->dev))
195 ieee80211_key_enable_hw_accel(key); 194 ieee80211_key_enable_hw_accel(key);
196 195
196 if (sta)
197 rcu_assign_pointer(sta->key, key);
198 else
199 rcu_assign_pointer(sdata->keys[idx], key);
200
201 list_add(&key->list, &sdata->key_list);
202
197 return key; 203 return key;
198} 204}
199 205
@@ -202,20 +208,25 @@ void ieee80211_key_free(struct ieee80211_key *key)
202 if (!key) 208 if (!key)
203 return; 209 return;
204 210
205 ieee80211_key_disable_hw_accel(key);
206
207 if (key->sta) { 211 if (key->sta) {
208 key->sta->key = NULL; 212 rcu_assign_pointer(key->sta->key, NULL);
209 } else { 213 } else {
210 if (key->sdata->default_key == key) 214 if (key->sdata->default_key == key)
211 ieee80211_set_default_key(key->sdata, -1); 215 ieee80211_set_default_key(key->sdata, -1);
212 if (key->conf.keyidx >= 0 && 216 if (key->conf.keyidx >= 0 &&
213 key->conf.keyidx < NUM_DEFAULT_KEYS) 217 key->conf.keyidx < NUM_DEFAULT_KEYS)
214 key->sdata->keys[key->conf.keyidx] = NULL; 218 rcu_assign_pointer(key->sdata->keys[key->conf.keyidx],
219 NULL);
215 else 220 else
216 WARN_ON(1); 221 WARN_ON(1);
217 } 222 }
218 223
224 /* wait for all key users to complete */
225 synchronize_rcu();
226
227 /* remove from hwaccel if appropriate */
228 ieee80211_key_disable_hw_accel(key);
229
219 if (key->conf.alg == ALG_CCMP) 230 if (key->conf.alg == ALG_CCMP)
220 ieee80211_aes_key_free(key->u.ccmp.tfm); 231 ieee80211_aes_key_free(key->u.ccmp.tfm);
221 ieee80211_debugfs_key_remove(key); 232 ieee80211_debugfs_key_remove(key);
@@ -235,7 +246,7 @@ void ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, int idx)
235 if (sdata->default_key != key) { 246 if (sdata->default_key != key) {
236 ieee80211_debugfs_key_remove_default(sdata); 247 ieee80211_debugfs_key_remove_default(sdata);
237 248
238 sdata->default_key = key; 249 rcu_assign_pointer(sdata->default_key, key);
239 250
240 if (sdata->default_key) 251 if (sdata->default_key)
241 ieee80211_debugfs_key_add_default(sdata); 252 ieee80211_debugfs_key_add_default(sdata);
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 4fb8c7026f11..91b7886bf797 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -13,6 +13,7 @@
13#include <linux/skbuff.h> 13#include <linux/skbuff.h>
14#include <linux/netdevice.h> 14#include <linux/netdevice.h>
15#include <linux/etherdevice.h> 15#include <linux/etherdevice.h>
16#include <linux/rcupdate.h>
16#include <net/mac80211.h> 17#include <net/mac80211.h>
17#include <net/ieee80211_radiotap.h> 18#include <net/ieee80211_radiotap.h>
18 19
@@ -311,6 +312,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
311 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data; 312 struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) rx->skb->data;
312 int keyidx; 313 int keyidx;
313 int hdrlen; 314 int hdrlen;
315 struct ieee80211_key *stakey = NULL;
314 316
315 /* 317 /*
316 * Key selection 101 318 * Key selection 101
@@ -348,8 +350,11 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
348 if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH)) 350 if (!(rx->flags & IEEE80211_TXRXD_RXRA_MATCH))
349 return TXRX_CONTINUE; 351 return TXRX_CONTINUE;
350 352
351 if (!is_multicast_ether_addr(hdr->addr1) && rx->sta && rx->sta->key) { 353 if (rx->sta)
352 rx->key = rx->sta->key; 354 stakey = rcu_dereference(rx->sta->key);
355
356 if (!is_multicast_ether_addr(hdr->addr1) && stakey) {
357 rx->key = stakey;
353 } else { 358 } else {
354 /* 359 /*
355 * The device doesn't give us the IV so we won't be 360 * The device doesn't give us the IV so we won't be
@@ -374,7 +379,7 @@ ieee80211_rx_h_load_key(struct ieee80211_txrx_data *rx)
374 */ 379 */
375 keyidx = rx->skb->data[hdrlen + 3] >> 6; 380 keyidx = rx->skb->data[hdrlen + 3] >> 6;
376 381
377 rx->key = rx->sdata->keys[keyidx]; 382 rx->key = rcu_dereference(rx->sdata->keys[keyidx]);
378 383
379 /* 384 /*
380 * RSNA-protected unicast frames should always be sent with 385 * RSNA-protected unicast frames should always be sent with
@@ -1364,6 +1369,12 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1364 skb_pull(skb, radiotap_len); 1369 skb_pull(skb, radiotap_len);
1365 } 1370 }
1366 1371
1372 /*
1373 * key references are protected using RCU and this requires that
1374 * we are in a read-site RCU section during receive processing
1375 */
1376 rcu_read_lock();
1377
1367 hdr = (struct ieee80211_hdr *) skb->data; 1378 hdr = (struct ieee80211_hdr *) skb->data;
1368 memset(&rx, 0, sizeof(rx)); 1379 memset(&rx, 0, sizeof(rx));
1369 rx.skb = skb; 1380 rx.skb = skb;
@@ -1404,6 +1415,7 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1404 ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx, 1415 ieee80211_invoke_rx_handlers(local, local->rx_handlers, &rx,
1405 rx.sta); 1416 rx.sta);
1406 sta_info_put(sta); 1417 sta_info_put(sta);
1418 rcu_read_unlock();
1407 return; 1419 return;
1408 } 1420 }
1409 1421
@@ -1465,6 +1477,8 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb,
1465 read_unlock(&local->sub_if_lock); 1477 read_unlock(&local->sub_if_lock);
1466 1478
1467 end: 1479 end:
1480 rcu_read_unlock();
1481
1468 if (sta) 1482 if (sta)
1469 sta_info_put(sta); 1483 sta_info_put(sta);
1470} 1484}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 0820f127da2b..b29dc70b2f01 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -17,6 +17,7 @@
17#include <linux/skbuff.h> 17#include <linux/skbuff.h>
18#include <linux/etherdevice.h> 18#include <linux/etherdevice.h>
19#include <linux/bitmap.h> 19#include <linux/bitmap.h>
20#include <linux/rcupdate.h>
20#include <net/net_namespace.h> 21#include <net/net_namespace.h>
21#include <net/ieee80211_radiotap.h> 22#include <net/ieee80211_radiotap.h>
22#include <net/cfg80211.h> 23#include <net/cfg80211.h>
@@ -427,14 +428,16 @@ ieee80211_tx_h_ps_buf(struct ieee80211_txrx_data *tx)
427static ieee80211_txrx_result 428static ieee80211_txrx_result
428ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) 429ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx)
429{ 430{
431 struct ieee80211_key *key;
432
430 tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID; 433 tx->u.tx.control->key_idx = HW_KEY_IDX_INVALID;
431 434
432 if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT)) 435 if (unlikely(tx->u.tx.control->flags & IEEE80211_TXCTL_DO_NOT_ENCRYPT))
433 tx->key = NULL; 436 tx->key = NULL;
434 else if (tx->sta && tx->sta->key) 437 else if (tx->sta && (key = rcu_dereference(tx->sta->key)))
435 tx->key = tx->sta->key; 438 tx->key = key;
436 else if (tx->sdata->default_key) 439 else if ((key = rcu_dereference(tx->sdata->default_key)))
437 tx->key = tx->sdata->default_key; 440 tx->key = key;
438 else if (tx->sdata->drop_unencrypted && 441 else if (tx->sdata->drop_unencrypted &&
439 !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) { 442 !(tx->sdata->eapol && ieee80211_is_eapol(tx->skb))) {
440 I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted); 443 I802_DEBUG_INC(tx->local->tx_handlers_drop_unencrypted);
@@ -1112,6 +1115,12 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
1112 return 0; 1115 return 0;
1113 } 1116 }
1114 1117
1118 /*
1119 * key references are protected using RCU and this requires that
1120 * we are in a read-site RCU section during receive processing
1121 */
1122 rcu_read_lock();
1123
1115 sta = tx.sta; 1124 sta = tx.sta;
1116 tx.u.tx.mgmt_interface = mgmt; 1125 tx.u.tx.mgmt_interface = mgmt;
1117 tx.u.tx.mode = local->hw.conf.mode; 1126 tx.u.tx.mode = local->hw.conf.mode;
@@ -1139,6 +1148,7 @@ static int ieee80211_tx(struct net_device *dev, struct sk_buff *skb,
1139 1148
1140 if (unlikely(res == TXRX_QUEUED)) { 1149 if (unlikely(res == TXRX_QUEUED)) {
1141 I802_DEBUG_INC(local->tx_handlers_queued); 1150 I802_DEBUG_INC(local->tx_handlers_queued);
1151 rcu_read_unlock();
1142 return 0; 1152 return 0;
1143 } 1153 }
1144 1154
@@ -1196,6 +1206,7 @@ retry:
1196 store->last_frag_rate_ctrl_probe = 1206 store->last_frag_rate_ctrl_probe =
1197 !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG); 1207 !!(tx.flags & IEEE80211_TXRXD_TXPROBE_LAST_FRAG);
1198 } 1208 }
1209 rcu_read_unlock();
1199 return 0; 1210 return 0;
1200 1211
1201 drop: 1212 drop:
@@ -1205,6 +1216,7 @@ retry:
1205 if (tx.u.tx.extra_frag[i]) 1216 if (tx.u.tx.extra_frag[i])
1206 dev_kfree_skb(tx.u.tx.extra_frag[i]); 1217 dev_kfree_skb(tx.u.tx.extra_frag[i]);
1207 kfree(tx.u.tx.extra_frag); 1218 kfree(tx.u.tx.extra_frag);
1219 rcu_read_unlock();
1208 return 0; 1220 return 0;
1209} 1221}
1210 1222