diff options
Diffstat (limited to 'net/mac80211/rx.c')
-rw-r--r-- | net/mac80211/rx.c | 20 |
1 files changed, 17 insertions, 3 deletions
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 | } |