Skip to content

Commit

Permalink
mac80211: Remove mesh paths when an interface is removed
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Javier Cardona authored and John W. Linville committed Sep 13, 2011
1 parent af089c1 commit ece1a2e
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 3 deletions.
2 changes: 1 addition & 1 deletion net/mac80211/cfg.c
Original file line number Diff line number Diff line change
Expand Up @@ -921,7 +921,7 @@ static int ieee80211_del_mpath(struct wiphy *wiphy, struct net_device *dev,
if (dst)
return mesh_path_del(dst, sdata);

mesh_path_flush(sdata);
mesh_path_flush_by_iface(sdata);
return 0;
}

Expand Down
6 changes: 6 additions & 0 deletions net/mac80211/iface.c
Original file line number Diff line number Diff line change
Expand Up @@ -1214,6 +1214,9 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);

if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_path_flush_by_iface(sdata);

synchronize_rcu();
unregister_netdevice(sdata->dev);
}
Expand All @@ -1233,6 +1236,9 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
list_for_each_entry_safe(sdata, tmp, &local->interfaces, list) {
list_del(&sdata->list);

if (ieee80211_vif_is_mesh(&sdata->vif))
mesh_path_flush_by_iface(sdata);

unregister_netdevice_queue(sdata->dev, &unreg_list);
}
mutex_unlock(&local->iflist_mtx);
Expand Down
2 changes: 1 addition & 1 deletion net/mac80211/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,6 @@ struct mesh_path *mesh_path_lookup_by_idx(int idx,
struct ieee80211_sub_if_data *sdata);
void mesh_path_fix_nexthop(struct mesh_path *mpath, struct sta_info *next_hop);
void mesh_path_expire(struct ieee80211_sub_if_data *sdata);
void mesh_path_flush(struct ieee80211_sub_if_data *sdata);
void mesh_rx_path_sel_frame(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt, size_t len);
int mesh_path_add(u8 *dst, struct ieee80211_sub_if_data *sdata);
Expand Down Expand Up @@ -275,6 +274,7 @@ void mesh_pathtbl_unregister(void);
int mesh_path_del(u8 *addr, struct ieee80211_sub_if_data *sdata);
void mesh_path_timer(unsigned long data);
void mesh_path_flush_by_nexthop(struct sta_info *sta);
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata);
void mesh_path_discard_frame(struct sk_buff *skb,
struct ieee80211_sub_if_data *sdata);
void mesh_path_quiesce(struct ieee80211_sub_if_data *sdata);
Expand Down
40 changes: 39 additions & 1 deletion net/mac80211/mesh_pathtbl.c
Original file line number Diff line number Diff line change
Expand Up @@ -821,7 +821,7 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
rcu_read_unlock();
}

void mesh_path_flush(struct ieee80211_sub_if_data *sdata)
static void mesh_path_flush(struct ieee80211_sub_if_data *sdata)
{
struct mesh_table *tbl;
struct mesh_path *mpath;
Expand Down Expand Up @@ -850,6 +850,44 @@ static void mesh_path_node_reclaim(struct rcu_head *rp)
kfree(node);
}

static void mpp_path_flush(struct ieee80211_sub_if_data *sdata)
{
struct mesh_table *tbl;
struct mesh_path *mpath;
struct mpath_node *node;
struct hlist_node *p;
int i;

read_lock_bh(&pathtbl_resize_lock);
tbl = rcu_dereference_protected(mpp_paths,
lockdep_is_held(pathtbl_resize_lock));
for_each_mesh_entry(tbl, p, node, i) {
mpath = node->mpath;
if (mpath->sdata != sdata)
continue;
spin_lock_bh(&tbl->hashwlock[i]);
spin_lock_bh(&mpath->state_lock);
call_rcu(&node->rcu, mesh_path_node_reclaim);
atomic_dec(&tbl->entries);
spin_unlock_bh(&tbl->hashwlock[i]);
}
read_unlock_bh(&pathtbl_resize_lock);
}

/**
* mesh_path_flush_by_iface - Deletes all mesh paths associated with a given iface
*
* This function deletes both mesh paths as well as mesh portal paths.
*
* @sdata - interface data to match
*
*/
void mesh_path_flush_by_iface(struct ieee80211_sub_if_data *sdata)
{
mesh_path_flush(sdata);
mpp_path_flush(sdata);
}

/**
* mesh_path_del - delete a mesh path from the table
*
Expand Down

0 comments on commit ece1a2e

Please sign in to comment.