diff options
author | Javier Cardona <javier@cozybit.com> | 2011-08-29 16:23:04 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2011-09-13 15:42:32 -0400 |
commit | ece1a2e7e86078c8379937b546e32cb7f25fcb6c (patch) | |
tree | f15c838069746175237e3639f85e800d712f88b9 /net/mac80211 | |
parent | af089c15cb13e1c5d984e41f495c8363dd5b1e30 (diff) |
mac80211: Remove mesh paths when an interface is removed
When an interface is removed, the mesh paths associated with it should
also be removed.
This fixes a bug we observed when reloading a device driver module
without reloading mac80211s.
Signed-off-by: Javier Cardona <javier@cozybit.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/mac80211')
-rw-r--r-- | net/mac80211/cfg.c | 2 | ||||
-rw-r--r-- | net/mac80211/iface.c | 6 | ||||
-rw-r--r-- | net/mac80211/mesh.h | 2 | ||||
-rw-r--r-- | net/mac80211/mesh_pathtbl.c | 40 |
4 files changed, 47 insertions, 3 deletions
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 0baaaecf4558..5c0d8fab0e88 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c | |||
@@ -921,7 +921,7 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev, | |||
921 | if (dst) | 921 | if (dst) |
922 | return mesh_path_del(dst, sdata); | 922 | return mesh_path_del(dst, sdata); |
923 | 923 | ||
924 | mesh_path_flush(sdata); | 924 | mesh_path_flush_by_iface(sdata); |
925 | return 0; | 925 | return 0; |
926 | } | 926 | } |
927 | 927 | ||
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 556e7e6ddf0a..eaa80a3d412b 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c | |||
@@ -1214,6 +1214,9 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata) | |||
1214 | list_del_rcu(&sdata->list); | 1214 | list_del_rcu(&sdata->list); |
1215 | mutex_unlock(&sdata->local->iflist_mtx); | 1215 | mutex_unlock(&sdata->local->iflist_mtx); |
1216 | 1216 | ||
1217 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
1218 | mesh_path_flush_by_iface(sdata); | ||
1219 | |||
1217 | synchronize_rcu(); | 1220 | synchronize_rcu(); |
1218 | unregister_netdevice(sdata->dev); | 1221 | unregister_netdevice(sdata->dev); |
1219 | } | 1222 | } |
@@ -1233,6 +1236,9 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local) | |||
1233 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { | 1236 | list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) { |
1234 | list_del(&sdata->list); | 1237 | list_del(&sdata->list); |
1235 | 1238 | ||
1239 | if (ieee80211_vif_is_mesh(&sdata->vif)) | ||
1240 | mesh_path_flush_by_iface(sdata); | ||
1241 | |||
1236 | unregister_netdevice_queue(sdata->dev, &unreg_list); | 1242 | unregister_netdevice_queue(sdata->dev, &unreg_list); |
1237 | } | 1243 | } |
1238 | mutex_unlock(&local->iflist_mtx); | 1244 | mutex_unlock(&local->iflist_mtx); |
diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index 20272072171f..57a2ad021bee 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h | |||
@@ -238,7 +238,6 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx, | |||
238 | struct ieee80211_sub_if_data *sdata); | 238 | struct ieee80211_sub_if_data *sdata); |
239 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); | 239 | void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop); |
240 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); | 240 | void mesh_path_expire(struct ieee80211_sub_if_data *sdata); |
241 | void mesh_path_flush(struct ieee80211_sub_if_data *sdata); | ||
242 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, | 241 | void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata, |
243 | struct ieee80211_mgmt *mgmt, size_t len); | 242 | struct ieee80211_mgmt *mgmt, size_t len); |
244 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); | 243 | int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata); |
@@ -275,6 +274,7 @@ void mesh_pathtbl_unregister(void); | |||
275 | int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata); | 274 | int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata); |
276 | void mesh_path_timer(unsigned long data); | 275 | void mesh_path_timer(unsigned long data); |
277 | void mesh_path_flush_by_nexthop(struct sta_info *sta); | 276 | void mesh_path_flush_by_nexthop(struct sta_info *sta); |
277 | void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata); | ||
278 | void mesh_path_discard_frame(struct sk_buff *skb, | 278 | void mesh_path_discard_frame(struct sk_buff *skb, |
279 | struct ieee80211_sub_if_data *sdata); | 279 | struct ieee80211_sub_if_data *sdata); |
280 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); | 280 | void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata); |
diff --git a/net/mac80211/mesh_pathtbl.c b/net/mac80211/mesh_pathtbl.c index 2218eaf48bcb..d07279911a0c 100644 --- a/net/mac80211/mesh_pathtbl.c +++ b/net/mac80211/mesh_pathtbl.c | |||
@@ -821,7 +821,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) | |||
821 | rcu_read_unlock(); | 821 | rcu_read_unlock(); |
822 | } | 822 | } |
823 | 823 | ||
824 | void mesh_path_flush(struct ieee80211_sub_if_data *sdata) | 824 | static void mesh_path_flush(struct ieee80211_sub_if_data *sdata) |
825 | { | 825 | { |
826 | struct mesh_table *tbl; | 826 | struct mesh_table *tbl; |
827 | struct mesh_path *mpath; | 827 | struct mesh_path *mpath; |
@@ -850,6 +850,44 @@ static void mesh_path_node_reclaim(struct rcu_head *rp) | |||
850 | kfree(node); | 850 | kfree(node); |
851 | } | 851 | } |
852 | 852 | ||
853 | static void mpp_path_flush(struct ieee80211_sub_if_data *sdata) | ||
854 | { | ||
855 | struct mesh_table *tbl; | ||
856 | struct mesh_path *mpath; | ||
857 | struct mpath_node *node; | ||
858 | struct hlist_node *p; | ||
859 | int i; | ||
860 | |||
861 | read_lock_bh(&pathtbl_resize_lock); | ||
862 | tbl = rcu_dereference_protected(mpp_paths, | ||
863 | lockdep_is_held(pathtbl_resize_lock)); | ||
864 | for_each_mesh_entry(tbl, p, node, i) { | ||
865 | mpath = node->mpath; | ||
866 | if (mpath->sdata != sdata) | ||
867 | continue; | ||
868 | spin_lock_bh(&tbl->hashwlock[i]); | ||
869 | spin_lock_bh(&mpath->state_lock); | ||
870 | call_rcu(&node->rcu, mesh_path_node_reclaim); | ||
871 | atomic_dec(&tbl->entries); | ||
872 | spin_unlock_bh(&tbl->hashwlock[i]); | ||
873 | } | ||
874 | read_unlock_bh(&pathtbl_resize_lock); | ||
875 | } | ||
876 | |||
877 | /** | ||
878 | * mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface | ||
879 | * | ||
880 | * This function deletes both mesh paths as well as mesh portal paths. | ||
881 | * | ||
882 | * @sdata - interface data to match | ||
883 | * | ||
884 | */ | ||
885 | void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata) | ||
886 | { | ||
887 | mesh_path_flush(sdata); | ||
888 | mpp_path_flush(sdata); | ||
889 | } | ||
890 | |||
853 | /** | 891 | /** |
854 | * mesh_path_del - delete a mesh path from the table | 892 | * mesh_path_del - delete a mesh path from the table |
855 | * | 893 | * |