aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/mesh.c
diff options
context:
space:
mode:
authorThomas Pedersen <thomas@cozybit.com>2013-06-13 18:54:41 -0400
committerJohannes Berg <johannes.berg@intel.com>2013-06-18 09:57:27 -0400
commitf81a9dedaff434604c7fc3d9c299d277b76db0a8 (patch)
tree0e11854521a0f93738bd451455046cbc0b986381 /net/mac80211/mesh.c
parenta1193be83b4bb173228f04870afd6a4174b19130 (diff)
mac80211: update mesh beacon on workqueue
Instead of updating the mesh beacon immediately when requested (which would require the sdata_lock()), defer it to the mac80211 workqueue. Fixes yet another deadlock on calling sta_info_flush() with the sdata_lock() held from ieee80211_stop_mesh(). We could just drop the sdata_lock() around the mesh_sta_cleanup() call, but this path is also taken from several non-locked error paths. Signed-off-by: Thomas Pedersen <thomas@cozybit.com> [fix comment position] Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'net/mac80211/mesh.c')
-rw-r--r--net/mac80211/mesh.c53
1 files changed, 41 insertions, 12 deletions
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 6c33af482df4..d5dea94216e4 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -161,11 +161,8 @@ void mesh_sta_cleanup(struct sta_info *sta)
161 del_timer_sync(&sta->plink_timer); 161 del_timer_sync(&sta->plink_timer);
162 } 162 }
163 163
164 if (changed) { 164 if (changed)
165 sdata_lock(sdata);
166 ieee80211_mbss_info_change_notify(sdata, changed); 165 ieee80211_mbss_info_change_notify(sdata, changed);
167 sdata_unlock(sdata);
168 }
169} 166}
170 167
171int mesh_rmc_init(struct ieee80211_sub_if_data *sdata) 168int mesh_rmc_init(struct ieee80211_sub_if_data *sdata)
@@ -719,14 +716,18 @@ ieee80211_mesh_rebuild_beacon(struct ieee80211_sub_if_data *sdata)
719void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata, 716void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
720 u32 changed) 717 u32 changed)
721{ 718{
722 if (sdata->vif.bss_conf.enable_beacon && 719 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
723 (changed & (BSS_CHANGED_BEACON | 720 unsigned long bits = changed;
724 BSS_CHANGED_HT | 721 u32 bit;
725 BSS_CHANGED_BASIC_RATES | 722
726 BSS_CHANGED_BEACON_INT))) 723 if (!bits)
727 if (ieee80211_mesh_rebuild_beacon(sdata)) 724 return;
728 return; 725
729 ieee80211_bss_info_change_notify(sdata, changed); 726 /* if we race with running work, worst case this work becomes a noop */
727 for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
728 set_bit(bit, &ifmsh->mbss_changed);
729 set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
730 ieee80211_queue_work(&sdata->local->hw, &sdata->work);
730} 731}
731 732
732int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata) 733int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
@@ -799,6 +800,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata)
799 del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); 800 del_timer_sync(&sdata->u.mesh.mesh_path_root_timer);
800 del_timer_sync(&sdata->u.mesh.mesh_path_timer); 801 del_timer_sync(&sdata->u.mesh.mesh_path_timer);
801 802
803 /* clear any mesh work (for next join) we may have accrued */
804 ifmsh->wrkq_flags = 0;
805 ifmsh->mbss_changed = 0;
806
802 local->fif_other_bss--; 807 local->fif_other_bss--;
803 atomic_dec(&local->iff_allmultis); 808 atomic_dec(&local->iff_allmultis);
804 ieee80211_configure_filter(local); 809 ieee80211_configure_filter(local);
@@ -965,6 +970,28 @@ out:
965 sdata_unlock(sdata); 970 sdata_unlock(sdata);
966} 971}
967 972
973static void mesh_bss_info_changed(struct ieee80211_sub_if_data *sdata)
974{
975 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
976 u32 bit, changed = 0;
977
978 for_each_set_bit(bit, &ifmsh->mbss_changed,
979 sizeof(changed) * BITS_PER_BYTE) {
980 clear_bit(bit, &ifmsh->mbss_changed);
981 changed |= BIT(bit);
982 }
983
984 if (sdata->vif.bss_conf.enable_beacon &&
985 (changed & (BSS_CHANGED_BEACON |
986 BSS_CHANGED_HT |
987 BSS_CHANGED_BASIC_RATES |
988 BSS_CHANGED_BEACON_INT)))
989 if (ieee80211_mesh_rebuild_beacon(sdata))
990 return;
991
992 ieee80211_bss_info_change_notify(sdata, changed);
993}
994
968void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) 995void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
969{ 996{
970 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; 997 struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
@@ -995,6 +1022,8 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata)
995 if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) 1022 if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags))
996 mesh_sync_adjust_tbtt(sdata); 1023 mesh_sync_adjust_tbtt(sdata);
997 1024
1025 if (test_and_clear_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags))
1026 mesh_bss_info_changed(sdata);
998out: 1027out:
999 sdata_unlock(sdata); 1028 sdata_unlock(sdata);
1000} 1029}