diff options
author | John W. Linville <linville@tuxdriver.com> | 2010-06-21 17:14:07 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2010-06-24 15:42:30 -0400 |
commit | c937019761a758f2749b1f3a032b7a91fb044753 (patch) | |
tree | 8305297e2d93794fa3a70e28dcb99990c9050ecb /net/mac80211/mesh_plink.c | |
parent | de66bfd85c817146825eaafb39d5872463c09e8c (diff) |
mac80211: avoid scheduling while atomic in mesh_rx_plink_frame
While mesh_rx_plink_frame holds sta->lock...
mesh_rx_plink_frame ->
mesh_plink_inc_estab_count ->
ieee80211_bss_info_change_notify
...but ieee80211_bss_info_change_notify is allowed to sleep. A driver
taking advantage of that allowance can cause a scheduling while
atomic bug. Similar paths exist for mesh_plink_dec_estab_count,
so work around those as well.
http://bugzilla.kernel.org/show_bug.cgi?id=16099
Also, correct a minor kerneldoc comment error (mismatched function names).
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Cc: stable@kernel.org
Diffstat (limited to 'net/mac80211/mesh_plink.c')
-rw-r--r-- | net/mac80211/mesh_plink.c | 42 |
1 files changed, 31 insertions, 11 deletions
diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 3cd5f7b5d693..ea13a80a476c 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c | |||
@@ -65,7 +65,6 @@ void mesh_plink_inc_estab_count(struct ieee80211_sub_if_data *sdata) | |||
65 | { | 65 | { |
66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); | 66 | atomic_inc(&sdata->u.mesh.mshstats.estab_plinks); |
67 | mesh_accept_plinks_update(sdata); | 67 | mesh_accept_plinks_update(sdata); |
68 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
69 | } | 68 | } |
70 | 69 | ||
71 | static inline | 70 | static inline |
@@ -73,7 +72,6 @@ void mesh_plink_dec_estab_count(struct ieee80211_sub_if_data *sdata) | |||
73 | { | 72 | { |
74 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); | 73 | atomic_dec(&sdata->u.mesh.mshstats.estab_plinks); |
75 | mesh_accept_plinks_update(sdata); | 74 | mesh_accept_plinks_update(sdata); |
76 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
77 | } | 75 | } |
78 | 76 | ||
79 | /** | 77 | /** |
@@ -115,7 +113,7 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
115 | } | 113 | } |
116 | 114 | ||
117 | /** | 115 | /** |
118 | * mesh_plink_deactivate - deactivate mesh peer link | 116 | * __mesh_plink_deactivate - deactivate mesh peer link |
119 | * | 117 | * |
120 | * @sta: mesh peer link to deactivate | 118 | * @sta: mesh peer link to deactivate |
121 | * | 119 | * |
@@ -123,18 +121,23 @@ static struct sta_info *mesh_plink_alloc(struct ieee80211_sub_if_data *sdata, | |||
123 | * | 121 | * |
124 | * Locking: the caller must hold sta->lock | 122 | * Locking: the caller must hold sta->lock |
125 | */ | 123 | */ |
126 | static void __mesh_plink_deactivate(struct sta_info *sta) | 124 | static bool __mesh_plink_deactivate(struct sta_info *sta) |
127 | { | 125 | { |
128 | struct ieee80211_sub_if_data *sdata = sta->sdata; | 126 | struct ieee80211_sub_if_data *sdata = sta->sdata; |
127 | bool deactivated = false; | ||
129 | 128 | ||
130 | if (sta->plink_state == PLINK_ESTAB) | 129 | if (sta->plink_state == PLINK_ESTAB) { |
131 | mesh_plink_dec_estab_count(sdata); | 130 | mesh_plink_dec_estab_count(sdata); |
131 | deactivated = true; | ||
132 | } | ||
132 | sta->plink_state = PLINK_BLOCKED; | 133 | sta->plink_state = PLINK_BLOCKED; |
133 | mesh_path_flush_by_nexthop(sta); | 134 | mesh_path_flush_by_nexthop(sta); |
135 | |||
136 | return deactivated; | ||
134 | } | 137 | } |
135 | 138 | ||
136 | /** | 139 | /** |
137 | * __mesh_plink_deactivate - deactivate mesh peer link | 140 | * mesh_plink_deactivate - deactivate mesh peer link |
138 | * | 141 | * |
139 | * @sta: mesh peer link to deactivate | 142 | * @sta: mesh peer link to deactivate |
140 | * | 143 | * |
@@ -142,9 +145,15 @@ static void __mesh_plink_deactivate(struct sta_info *sta) | |||
142 | */ | 145 | */ |
143 | void mesh_plink_deactivate(struct sta_info *sta) | 146 | void mesh_plink_deactivate(struct sta_info *sta) |
144 | { | 147 | { |
148 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
149 | bool deactivated; | ||
150 | |||
145 | spin_lock_bh(&sta->lock); | 151 | spin_lock_bh(&sta->lock); |
146 | __mesh_plink_deactivate(sta); | 152 | deactivated = __mesh_plink_deactivate(sta); |
147 | spin_unlock_bh(&sta->lock); | 153 | spin_unlock_bh(&sta->lock); |
154 | |||
155 | if (deactivated) | ||
156 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
148 | } | 157 | } |
149 | 158 | ||
150 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, | 159 | static int mesh_plink_frame_tx(struct ieee80211_sub_if_data *sdata, |
@@ -381,10 +390,16 @@ int mesh_plink_open(struct sta_info *sta) | |||
381 | 390 | ||
382 | void mesh_plink_block(struct sta_info *sta) | 391 | void mesh_plink_block(struct sta_info *sta) |
383 | { | 392 | { |
393 | struct ieee80211_sub_if_data *sdata = sta->sdata; | ||
394 | bool deactivated; | ||
395 | |||
384 | spin_lock_bh(&sta->lock); | 396 | spin_lock_bh(&sta->lock); |
385 | __mesh_plink_deactivate(sta); | 397 | deactivated = __mesh_plink_deactivate(sta); |
386 | sta->plink_state = PLINK_BLOCKED; | 398 | sta->plink_state = PLINK_BLOCKED; |
387 | spin_unlock_bh(&sta->lock); | 399 | spin_unlock_bh(&sta->lock); |
400 | |||
401 | if (deactivated) | ||
402 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
388 | } | 403 | } |
389 | 404 | ||
390 | 405 | ||
@@ -397,6 +412,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
397 | enum plink_event event; | 412 | enum plink_event event; |
398 | enum plink_frame_type ftype; | 413 | enum plink_frame_type ftype; |
399 | size_t baselen; | 414 | size_t baselen; |
415 | bool deactivated; | ||
400 | u8 ie_len; | 416 | u8 ie_len; |
401 | u8 *baseaddr; | 417 | u8 *baseaddr; |
402 | __le16 plid, llid, reason; | 418 | __le16 plid, llid, reason; |
@@ -651,8 +667,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
651 | case CNF_ACPT: | 667 | case CNF_ACPT: |
652 | del_timer(&sta->plink_timer); | 668 | del_timer(&sta->plink_timer); |
653 | sta->plink_state = PLINK_ESTAB; | 669 | sta->plink_state = PLINK_ESTAB; |
654 | mesh_plink_inc_estab_count(sdata); | ||
655 | spin_unlock_bh(&sta->lock); | 670 | spin_unlock_bh(&sta->lock); |
671 | mesh_plink_inc_estab_count(sdata); | ||
672 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
656 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", | 673 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", |
657 | sta->sta.addr); | 674 | sta->sta.addr); |
658 | break; | 675 | break; |
@@ -684,8 +701,9 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
684 | case OPN_ACPT: | 701 | case OPN_ACPT: |
685 | del_timer(&sta->plink_timer); | 702 | del_timer(&sta->plink_timer); |
686 | sta->plink_state = PLINK_ESTAB; | 703 | sta->plink_state = PLINK_ESTAB; |
687 | mesh_plink_inc_estab_count(sdata); | ||
688 | spin_unlock_bh(&sta->lock); | 704 | spin_unlock_bh(&sta->lock); |
705 | mesh_plink_inc_estab_count(sdata); | ||
706 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
689 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", | 707 | mpl_dbg("Mesh plink with %pM ESTABLISHED\n", |
690 | sta->sta.addr); | 708 | sta->sta.addr); |
691 | mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, | 709 | mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, |
@@ -702,11 +720,13 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m | |||
702 | case CLS_ACPT: | 720 | case CLS_ACPT: |
703 | reason = cpu_to_le16(MESH_CLOSE_RCVD); | 721 | reason = cpu_to_le16(MESH_CLOSE_RCVD); |
704 | sta->reason = reason; | 722 | sta->reason = reason; |
705 | __mesh_plink_deactivate(sta); | 723 | deactivated = __mesh_plink_deactivate(sta); |
706 | sta->plink_state = PLINK_HOLDING; | 724 | sta->plink_state = PLINK_HOLDING; |
707 | llid = sta->llid; | 725 | llid = sta->llid; |
708 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); | 726 | mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata)); |
709 | spin_unlock_bh(&sta->lock); | 727 | spin_unlock_bh(&sta->lock); |
728 | if (deactivated) | ||
729 | ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON); | ||
710 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, | 730 | mesh_plink_frame_tx(sdata, PLINK_CLOSE, sta->sta.addr, llid, |
711 | plid, reason); | 731 | plid, reason); |
712 | break; | 732 | break; |