Skip to content

Commit

Permalink
wifi: mac80211: split mesh fast tx cache into local/proxied/forwarded
Browse files Browse the repository at this point in the history
[ Upstream commit 8c75cdc ]

Depending on the origin of the packets (and their SA), 802.11 + mesh headers
could be filled in differently. In order to properly deal with that, add a
new field to the lookup key, indicating the type (local, proxied or
forwarded). This can fix spurious packet drop issues that depend on the order
in which nodes/hosts communicate with each other.

Fixes: d5edb9a ("wifi: mac80211: mesh fast xmit support")
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Link: https://msgid.link/20240415121811.13391-1-nbd@nbd.name
[use sizeof_field() for key_len]
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
  • Loading branch information
nbd168 authored and gregkh committed May 2, 2024
1 parent 1ba4d2a commit 154be74
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 16 deletions.
8 changes: 7 additions & 1 deletion net/mac80211/mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -765,6 +765,9 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 ctrl_flags)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_mesh_fast_tx_key key = {
.type = MESH_FAST_TX_TYPE_LOCAL
};
struct ieee80211_mesh_fast_tx *entry;
struct ieee80211s_hdr *meshhdr;
u8 sa[ETH_ALEN] __aligned(2);
Expand Down Expand Up @@ -800,7 +803,10 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
return false;
}

entry = mesh_fast_tx_get(sdata, skb->data);
ether_addr_copy(key.addr, skb->data);
if (!ether_addr_equal(skb->data + ETH_ALEN, sdata->vif.addr))
key.type = MESH_FAST_TX_TYPE_PROXIED;
entry = mesh_fast_tx_get(sdata, &key);
if (!entry)
return false;

Expand Down
36 changes: 33 additions & 3 deletions net/mac80211/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,39 @@ struct mesh_path {
#define MESH_FAST_TX_CACHE_THRESHOLD_SIZE 384
#define MESH_FAST_TX_CACHE_TIMEOUT 8000 /* msecs */

/**
* enum ieee80211_mesh_fast_tx_type - cached mesh fast tx entry type
*
* @MESH_FAST_TX_TYPE_LOCAL: tx from the local vif address as SA
* @MESH_FAST_TX_TYPE_PROXIED: local tx with a different SA (e.g. bridged)
* @MESH_FAST_TX_TYPE_FORWARDED: forwarded from a different mesh point
* @NUM_MESH_FAST_TX_TYPE: number of entry types
*/
enum ieee80211_mesh_fast_tx_type {
MESH_FAST_TX_TYPE_LOCAL,
MESH_FAST_TX_TYPE_PROXIED,
MESH_FAST_TX_TYPE_FORWARDED,

/* must be last */
NUM_MESH_FAST_TX_TYPE
};


/**
* struct ieee80211_mesh_fast_tx_key - cached mesh fast tx entry key
*
* @addr: The Ethernet DA for this entry
* @type: cache entry type
*/
struct ieee80211_mesh_fast_tx_key {
u8 addr[ETH_ALEN] __aligned(2);
u16 type;
};

/**
* struct ieee80211_mesh_fast_tx - cached mesh fast tx entry
* @rhash: rhashtable pointer
* @addr_key: The Ethernet DA which is the key for this entry
* @key: the lookup key for this cache entry
* @fast_tx: base fast_tx data
* @hdr: cached mesh and rfc1042 headers
* @hdrlen: length of mesh + rfc1042
Expand All @@ -147,7 +176,7 @@ struct mesh_path {
*/
struct ieee80211_mesh_fast_tx {
struct rhash_head rhash;
u8 addr_key[ETH_ALEN] __aligned(2);
struct ieee80211_mesh_fast_tx_key key;

struct ieee80211_fast_tx fast_tx;
u8 hdr[sizeof(struct ieee80211s_hdr) + sizeof(rfc1042_header)];
Expand Down Expand Up @@ -333,7 +362,8 @@ void mesh_path_tx_root_frame(struct ieee80211_sub_if_data *sdata);

bool mesh_action_is_path_sel(struct ieee80211_mgmt *mgmt);
struct ieee80211_mesh_fast_tx *
mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr);
mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mesh_fast_tx_key *key);
bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 ctrl_flags);
void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
Expand Down
31 changes: 22 additions & 9 deletions net/mac80211/mesh_pathtbl.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ static const struct rhashtable_params mesh_rht_params = {
static const struct rhashtable_params fast_tx_rht_params = {
.nelem_hint = 10,
.automatic_shrinking = true,
.key_len = ETH_ALEN,
.key_offset = offsetof(struct ieee80211_mesh_fast_tx, addr_key),
.key_len = sizeof_field(struct ieee80211_mesh_fast_tx, key),
.key_offset = offsetof(struct ieee80211_mesh_fast_tx, key),
.head_offset = offsetof(struct ieee80211_mesh_fast_tx, rhash),
.hashfn = mesh_table_hash,
};
Expand Down Expand Up @@ -426,20 +426,21 @@ static void mesh_fast_tx_entry_free(struct mesh_tx_cache *cache,
}

struct ieee80211_mesh_fast_tx *
mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata, const u8 *addr)
mesh_fast_tx_get(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mesh_fast_tx_key *key)
{
struct ieee80211_mesh_fast_tx *entry;
struct mesh_tx_cache *cache;

cache = &sdata->u.mesh.tx_cache;
entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
if (!entry)
return NULL;

if (!(entry->mpath->flags & MESH_PATH_ACTIVE) ||
mpath_expired(entry->mpath)) {
spin_lock_bh(&cache->walk_lock);
entry = rhashtable_lookup(&cache->rht, addr, fast_tx_rht_params);
entry = rhashtable_lookup(&cache->rht, key, fast_tx_rht_params);
if (entry)
mesh_fast_tx_entry_free(cache, entry);
spin_unlock_bh(&cache->walk_lock);
Expand Down Expand Up @@ -484,18 +485,24 @@ void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
if (!sta)
return;

build.key.type = MESH_FAST_TX_TYPE_LOCAL;
if ((meshhdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6) {
/* This is required to keep the mppath alive */
mppath = mpp_path_lookup(sdata, meshhdr->eaddr1);
if (!mppath)
return;
build.mppath = mppath;
if (!ether_addr_equal(meshhdr->eaddr2, sdata->vif.addr))
build.key.type = MESH_FAST_TX_TYPE_PROXIED;
} else if (ieee80211_has_a4(hdr->frame_control)) {
mppath = mpath;
} else {
return;
}

if (!ether_addr_equal(hdr->addr4, sdata->vif.addr))
build.key.type = MESH_FAST_TX_TYPE_FORWARDED;

/* rate limit, in case fast xmit can't be enabled */
if (mppath->fast_tx_check == jiffies)
return;
Expand Down Expand Up @@ -542,7 +549,7 @@ void mesh_fast_tx_cache(struct ieee80211_sub_if_data *sdata,
}
}

memcpy(build.addr_key, mppath->dst, ETH_ALEN);
memcpy(build.key.addr, mppath->dst, ETH_ALEN);
build.timestamp = jiffies;
build.fast_tx.band = info->band;
build.fast_tx.da_offs = offsetof(struct ieee80211_hdr, addr3);
Expand Down Expand Up @@ -641,12 +648,18 @@ void mesh_fast_tx_flush_addr(struct ieee80211_sub_if_data *sdata,
const u8 *addr)
{
struct mesh_tx_cache *cache = &sdata->u.mesh.tx_cache;
struct ieee80211_mesh_fast_tx_key key = {};
struct ieee80211_mesh_fast_tx *entry;
int i;

ether_addr_copy(key.addr, addr);
spin_lock_bh(&cache->walk_lock);
entry = rhashtable_lookup_fast(&cache->rht, addr, fast_tx_rht_params);
if (entry)
mesh_fast_tx_entry_free(cache, entry);
for (i = 0; i < NUM_MESH_FAST_TX_TYPE; i++) {
key.type = i;
entry = rhashtable_lookup_fast(&cache->rht, &key, fast_tx_rht_params);
if (entry)
mesh_fast_tx_entry_free(cache, entry);
}
spin_unlock_bh(&cache->walk_lock);
}

Expand Down
13 changes: 10 additions & 3 deletions net/mac80211/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -2726,7 +2726,10 @@ ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, int hdrlen)
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct ieee80211_mesh_fast_tx *entry = NULL;
struct ieee80211_mesh_fast_tx_key key = {
.type = MESH_FAST_TX_TYPE_FORWARDED
};
struct ieee80211_mesh_fast_tx *entry;
struct ieee80211s_hdr *mesh_hdr;
struct tid_ampdu_tx *tid_tx;
struct sta_info *sta;
Expand All @@ -2735,9 +2738,13 @@ ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,

mesh_hdr = (struct ieee80211s_hdr *)(skb->data + sizeof(eth));
if ((mesh_hdr->flags & MESH_FLAGS_AE) == MESH_FLAGS_AE_A5_A6)
entry = mesh_fast_tx_get(sdata, mesh_hdr->eaddr1);
ether_addr_copy(key.addr, mesh_hdr->eaddr1);
else if (!(mesh_hdr->flags & MESH_FLAGS_AE))
entry = mesh_fast_tx_get(sdata, skb->data);
ether_addr_copy(key.addr, skb->data);
else
return false;

entry = mesh_fast_tx_get(sdata, &key);
if (!entry)
return false;

Expand Down

0 comments on commit 154be74

Please sign in to comment.