Commit a31687e8 authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2019-02-15' of...

Merge tag 'mac80211-for-davem-2019-02-15' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes Berg says:

====================
Just a few fixes this time:
 * mesh rhashtable fixes from Herbert
 * a small error path fix when starting AP interfaces
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 24f0a487 83e37e0b
...@@ -941,6 +941,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -941,6 +941,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
BSS_CHANGED_P2P_PS | BSS_CHANGED_P2P_PS |
BSS_CHANGED_TXPOWER; BSS_CHANGED_TXPOWER;
int err; int err;
int prev_beacon_int;
old = sdata_dereference(sdata->u.ap.beacon, sdata); old = sdata_dereference(sdata->u.ap.beacon, sdata);
if (old) if (old)
...@@ -963,6 +964,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -963,6 +964,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
sdata->needed_rx_chains = sdata->local->rx_chains; sdata->needed_rx_chains = sdata->local->rx_chains;
prev_beacon_int = sdata->vif.bss_conf.beacon_int;
sdata->vif.bss_conf.beacon_int = params->beacon_interval; sdata->vif.bss_conf.beacon_int = params->beacon_interval;
if (params->he_cap) if (params->he_cap)
...@@ -974,8 +976,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev, ...@@ -974,8 +976,10 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
if (!err) if (!err)
ieee80211_vif_copy_chanctx_to_vlans(sdata, false); ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
mutex_unlock(&local->mtx); mutex_unlock(&local->mtx);
if (err) if (err) {
sdata->vif.bss_conf.beacon_int = prev_beacon_int;
return err; return err;
}
/* /*
* Apply control port protocol, this allows us to * Apply control port protocol, this allows us to
......
...@@ -70,6 +70,7 @@ enum mesh_deferred_task_flags { ...@@ -70,6 +70,7 @@ enum mesh_deferred_task_flags {
* @dst: mesh path destination mac address * @dst: mesh path destination mac address
* @mpp: mesh proxy mac address * @mpp: mesh proxy mac address
* @rhash: rhashtable list pointer * @rhash: rhashtable list pointer
* @walk_list: linked list containing all mesh_path objects.
* @gate_list: list pointer for known gates list * @gate_list: list pointer for known gates list
* @sdata: mesh subif * @sdata: mesh subif
* @next_hop: mesh neighbor to which frames for this destination will be * @next_hop: mesh neighbor to which frames for this destination will be
...@@ -105,6 +106,7 @@ struct mesh_path { ...@@ -105,6 +106,7 @@ struct mesh_path {
u8 dst[ETH_ALEN]; u8 dst[ETH_ALEN];
u8 mpp[ETH_ALEN]; /* used for MPP or MAP */ u8 mpp[ETH_ALEN]; /* used for MPP or MAP */
struct rhash_head rhash; struct rhash_head rhash;
struct hlist_node walk_list;
struct hlist_node gate_list; struct hlist_node gate_list;
struct ieee80211_sub_if_data *sdata; struct ieee80211_sub_if_data *sdata;
struct sta_info __rcu *next_hop; struct sta_info __rcu *next_hop;
...@@ -133,12 +135,16 @@ struct mesh_path { ...@@ -133,12 +135,16 @@ struct mesh_path {
* gate's mpath may or may not be resolved and active. * gate's mpath may or may not be resolved and active.
* @gates_lock: protects updates to known_gates * @gates_lock: protects updates to known_gates
* @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr * @rhead: the rhashtable containing struct mesh_paths, keyed by dest addr
* @walk_head: linked list containging all mesh_path objects
* @walk_lock: lock protecting walk_head
* @entries: number of entries in the table * @entries: number of entries in the table
*/ */
struct mesh_table { struct mesh_table {
struct hlist_head known_gates; struct hlist_head known_gates;
spinlock_t gates_lock; spinlock_t gates_lock;
struct rhashtable rhead; struct rhashtable rhead;
struct hlist_head walk_head;
spinlock_t walk_lock;
atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */ atomic_t entries; /* Up to MAX_MESH_NEIGHBOURS */
}; };
......
...@@ -59,8 +59,10 @@ static struct mesh_table *mesh_table_alloc(void) ...@@ -59,8 +59,10 @@ static struct mesh_table *mesh_table_alloc(void)
return NULL; return NULL;
INIT_HLIST_HEAD(&newtbl->known_gates); INIT_HLIST_HEAD(&newtbl->known_gates);
INIT_HLIST_HEAD(&newtbl->walk_head);
atomic_set(&newtbl->entries, 0); atomic_set(&newtbl->entries, 0);
spin_lock_init(&newtbl->gates_lock); spin_lock_init(&newtbl->gates_lock);
spin_lock_init(&newtbl->walk_lock);
return newtbl; return newtbl;
} }
...@@ -249,28 +251,15 @@ mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst) ...@@ -249,28 +251,15 @@ mpp_path_lookup(struct ieee80211_sub_if_data *sdata, const u8 *dst)
static struct mesh_path * static struct mesh_path *
__mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx) __mesh_path_lookup_by_idx(struct mesh_table *tbl, int idx)
{ {
int i = 0, ret; int i = 0;
struct mesh_path *mpath = NULL; struct mesh_path *mpath;
struct rhashtable_iter iter;
ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
if (ret)
return NULL;
rhashtable_walk_start(&iter);
while ((mpath = rhashtable_walk_next(&iter))) { hlist_for_each_entry_rcu(mpath, &tbl->walk_head, walk_list) {
if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
continue;
if (IS_ERR(mpath))
break;
if (i++ == idx) if (i++ == idx)
break; break;
} }
rhashtable_walk_stop(&iter);
rhashtable_walk_exit(&iter);
if (IS_ERR(mpath) || !mpath) if (!mpath)
return NULL; return NULL;
if (mpath_expired(mpath)) { if (mpath_expired(mpath)) {
...@@ -432,6 +421,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, ...@@ -432,6 +421,7 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
tbl = sdata->u.mesh.mesh_paths; tbl = sdata->u.mesh.mesh_paths;
spin_lock_bh(&tbl->walk_lock);
do { do {
ret = rhashtable_lookup_insert_fast(&tbl->rhead, ret = rhashtable_lookup_insert_fast(&tbl->rhead,
&new_mpath->rhash, &new_mpath->rhash,
...@@ -441,20 +431,20 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata, ...@@ -441,20 +431,20 @@ struct mesh_path *mesh_path_add(struct ieee80211_sub_if_data *sdata,
mpath = rhashtable_lookup_fast(&tbl->rhead, mpath = rhashtable_lookup_fast(&tbl->rhead,
dst, dst,
mesh_rht_params); mesh_rht_params);
else if (!ret)
hlist_add_head(&new_mpath->walk_list, &tbl->walk_head);
} while (unlikely(ret == -EEXIST && !mpath)); } while (unlikely(ret == -EEXIST && !mpath));
spin_unlock_bh(&tbl->walk_lock);
if (ret && ret != -EEXIST) if (ret) {
return ERR_PTR(ret);
/* At this point either new_mpath was added, or we found a
* matching entry already in the table; in the latter case
* free the unnecessary new entry.
*/
if (ret == -EEXIST) {
kfree(new_mpath); kfree(new_mpath);
if (ret != -EEXIST)
return ERR_PTR(ret);
new_mpath = mpath; new_mpath = mpath;
} }
sdata->u.mesh.mesh_paths_generation++; sdata->u.mesh.mesh_paths_generation++;
return new_mpath; return new_mpath;
} }
...@@ -480,9 +470,17 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata, ...@@ -480,9 +470,17 @@ int mpp_path_add(struct ieee80211_sub_if_data *sdata,
memcpy(new_mpath->mpp, mpp, ETH_ALEN); memcpy(new_mpath->mpp, mpp, ETH_ALEN);
tbl = sdata->u.mesh.mpp_paths; tbl = sdata->u.mesh.mpp_paths;
spin_lock_bh(&tbl->walk_lock);
ret = rhashtable_lookup_insert_fast(&tbl->rhead, ret = rhashtable_lookup_insert_fast(&tbl->rhead,
&new_mpath->rhash, &new_mpath->rhash,
mesh_rht_params); mesh_rht_params);
if (!ret)
hlist_add_head_rcu(&new_mpath->walk_list, &tbl->walk_head);
spin_unlock_bh(&tbl->walk_lock);
if (ret)
kfree(new_mpath);
sdata->u.mesh.mpp_paths_generation++; sdata->u.mesh.mpp_paths_generation++;
return ret; return ret;
...@@ -503,20 +501,9 @@ void mesh_plink_broken(struct sta_info *sta) ...@@ -503,20 +501,9 @@ void mesh_plink_broken(struct sta_info *sta)
struct mesh_table *tbl = sdata->u.mesh.mesh_paths; struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; static const u8 bcast[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
struct mesh_path *mpath; struct mesh_path *mpath;
struct rhashtable_iter iter;
int ret;
ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
if (ret)
return;
rhashtable_walk_start(&iter); rcu_read_lock();
hlist_for_each_entry_rcu(mpath, &tbl->walk_head, walk_list) {
while ((mpath = rhashtable_walk_next(&iter))) {
if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
continue;
if (IS_ERR(mpath))
break;
if (rcu_access_pointer(mpath->next_hop) == sta && if (rcu_access_pointer(mpath->next_hop) == sta &&
mpath->flags & MESH_PATH_ACTIVE && mpath->flags & MESH_PATH_ACTIVE &&
!(mpath->flags & MESH_PATH_FIXED)) { !(mpath->flags & MESH_PATH_FIXED)) {
...@@ -530,8 +517,7 @@ void mesh_plink_broken(struct sta_info *sta) ...@@ -530,8 +517,7 @@ void mesh_plink_broken(struct sta_info *sta)
WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast); WLAN_REASON_MESH_PATH_DEST_UNREACHABLE, bcast);
} }
} }
rhashtable_walk_stop(&iter); rcu_read_unlock();
rhashtable_walk_exit(&iter);
} }
static void mesh_path_free_rcu(struct mesh_table *tbl, static void mesh_path_free_rcu(struct mesh_table *tbl,
...@@ -551,6 +537,7 @@ static void mesh_path_free_rcu(struct mesh_table *tbl, ...@@ -551,6 +537,7 @@ static void mesh_path_free_rcu(struct mesh_table *tbl,
static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath) static void __mesh_path_del(struct mesh_table *tbl, struct mesh_path *mpath)
{ {
hlist_del_rcu(&mpath->walk_list);
rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params); rhashtable_remove_fast(&tbl->rhead, &mpath->rhash, mesh_rht_params);
mesh_path_free_rcu(tbl, mpath); mesh_path_free_rcu(tbl, mpath);
} }
...@@ -571,27 +558,14 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta) ...@@ -571,27 +558,14 @@ void mesh_path_flush_by_nexthop(struct sta_info *sta)
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
struct mesh_table *tbl = sdata->u.mesh.mesh_paths; struct mesh_table *tbl = sdata->u.mesh.mesh_paths;
struct mesh_path *mpath; struct mesh_path *mpath;
struct rhashtable_iter iter; struct hlist_node *n;
int ret;
ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
if (ret)
return;
rhashtable_walk_start(&iter);
while ((mpath = rhashtable_walk_next(&iter))) {
if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
continue;
if (IS_ERR(mpath))
break;
spin_lock_bh(&tbl->walk_lock);
hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) {
if (rcu_access_pointer(mpath->next_hop) == sta) if (rcu_access_pointer(mpath->next_hop) == sta)
__mesh_path_del(tbl, mpath); __mesh_path_del(tbl, mpath);
} }
spin_unlock_bh(&tbl->walk_lock);
rhashtable_walk_stop(&iter);
rhashtable_walk_exit(&iter);
} }
static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
...@@ -599,51 +573,26 @@ static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata, ...@@ -599,51 +573,26 @@ static void mpp_flush_by_proxy(struct ieee80211_sub_if_data *sdata,
{ {
struct mesh_table *tbl = sdata->u.mesh.mpp_paths; struct mesh_table *tbl = sdata->u.mesh.mpp_paths;
struct mesh_path *mpath; struct mesh_path *mpath;
struct rhashtable_iter iter; struct hlist_node *n;
int ret;
ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
if (ret)
return;
rhashtable_walk_start(&iter);
while ((mpath = rhashtable_walk_next(&iter))) {
if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
continue;
if (IS_ERR(mpath))
break;
spin_lock_bh(&tbl->walk_lock);
hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) {
if (ether_addr_equal(mpath->mpp, proxy)) if (ether_addr_equal(mpath->mpp, proxy))
__mesh_path_del(tbl, mpath); __mesh_path_del(tbl, mpath);
} }
spin_unlock_bh(&tbl->walk_lock);
rhashtable_walk_stop(&iter);
rhashtable_walk_exit(&iter);
} }
static void table_flush_by_iface(struct mesh_table *tbl) static void table_flush_by_iface(struct mesh_table *tbl)
{ {
struct mesh_path *mpath; struct mesh_path *mpath;
struct rhashtable_iter iter; struct hlist_node *n;
int ret;
ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_ATOMIC);
if (ret)
return;
rhashtable_walk_start(&iter);
while ((mpath = rhashtable_walk_next(&iter))) { spin_lock_bh(&tbl->walk_lock);
if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN) hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) {
continue;
if (IS_ERR(mpath))
break;
__mesh_path_del(tbl, mpath); __mesh_path_del(tbl, mpath);
} }
spin_unlock_bh(&tbl->walk_lock);
rhashtable_walk_stop(&iter);
rhashtable_walk_exit(&iter);
} }
/** /**
...@@ -675,7 +624,7 @@ static int table_path_del(struct mesh_table *tbl, ...@@ -675,7 +624,7 @@ static int table_path_del(struct mesh_table *tbl,
{ {
struct mesh_path *mpath; struct mesh_path *mpath;
rcu_read_lock(); spin_lock_bh(&tbl->walk_lock);
mpath = rhashtable_lookup_fast(&tbl->rhead, addr, mesh_rht_params); mpath = rhashtable_lookup_fast(&tbl->rhead, addr, mesh_rht_params);
if (!mpath) { if (!mpath) {
rcu_read_unlock(); rcu_read_unlock();
...@@ -683,7 +632,7 @@ static int table_path_del(struct mesh_table *tbl, ...@@ -683,7 +632,7 @@ static int table_path_del(struct mesh_table *tbl,
} }
__mesh_path_del(tbl, mpath); __mesh_path_del(tbl, mpath);
rcu_read_unlock(); spin_unlock_bh(&tbl->walk_lock);
return 0; return 0;
} }
...@@ -854,28 +803,16 @@ void mesh_path_tbl_expire(struct ieee80211_sub_if_data *sdata, ...@@ -854,28 +803,16 @@ void mesh_path_tbl_expire(struct ieee80211_sub_if_data *sdata,
struct mesh_table *tbl) struct mesh_table *tbl)
{ {
struct mesh_path *mpath; struct mesh_path *mpath;
struct rhashtable_iter iter; struct hlist_node *n;
int ret;
ret = rhashtable_walk_init(&tbl->rhead, &iter, GFP_KERNEL); spin_lock_bh(&tbl->walk_lock);
if (ret) hlist_for_each_entry_safe(mpath, n, &tbl->walk_head, walk_list) {
return;
rhashtable_walk_start(&iter);
while ((mpath = rhashtable_walk_next(&iter))) {
if (IS_ERR(mpath) && PTR_ERR(mpath) == -EAGAIN)
continue;
if (IS_ERR(mpath))
break;
if ((!(mpath->flags & MESH_PATH_RESOLVING)) && if ((!(mpath->flags & MESH_PATH_RESOLVING)) &&
(!(mpath->flags & MESH_PATH_FIXED)) && (!(mpath->flags & MESH_PATH_FIXED)) &&
time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE)) time_after(jiffies, mpath->exp_time + MESH_PATH_EXPIRE))
__mesh_path_del(tbl, mpath); __mesh_path_del(tbl, mpath);
} }
spin_unlock_bh(&tbl->walk_lock);
rhashtable_walk_stop(&iter);
rhashtable_walk_exit(&iter);
} }
void mesh_path_expire(struct ieee80211_sub_if_data *sdata) void mesh_path_expire(struct ieee80211_sub_if_data *sdata)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment