diff options
Diffstat (limited to 'net/mac80211/tx.c')
-rw-r--r-- | net/mac80211/tx.c | 20 |
1 files changed, 16 insertions, 4 deletions
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) | |||
427 | static ieee80211_txrx_result | 428 | static ieee80211_txrx_result |
428 | ieee80211_tx_h_select_key(struct ieee80211_txrx_data *tx) | 429 | ieee80211_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 | ||