From: Felix Fietkau <nbd@nbd.name>
To: linux-wireless@vger.kernel.org
Cc: johannes@sipsolutions.net, Ryder Lee <ryder.lee@mediatek.com>
Subject: [PATCH 7/7] mac80211: implement support for yet another mesh A-MSDU format
Date: Tue, 14 Mar 2023 10:59:56 +0100 [thread overview]
Message-ID: <20230314095956.62085-7-nbd@nbd.name> (raw)
In-Reply-To: <20230314095956.62085-1-nbd@nbd.name>
MT7996 hardware supports mesh A-MSDU subframes in hardware, but uses a
big-endian length field
Signed-off-by: Felix Fietkau <nbd@nbd.name>
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
include/net/cfg80211.h | 11 +++++++----
net/mac80211/rx.c | 22 ++++++++++++++++------
net/mac80211/sta_info.h | 5 ++++-
net/wireless/util.c | 36 +++++++++++++++++++++++-------------
4 files changed, 50 insertions(+), 24 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 7cebba1c4135..86cb048dc924 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -6274,10 +6274,13 @@ static inline int ieee80211_data_to_8023(struct sk_buff *skb, const u8 *addr,
* mesh control field.
*
* @skb: The input A-MSDU frame without any headers.
- * @mesh_hdr: use standard compliant mesh A-MSDU subframe header
+ * @mesh_hdr: the type of mesh header to test
+ * 0: non-mesh A-MSDU length field
+ * 1: big-endian mesh A-MSDU length field
+ * 2: little-endian mesh A-MSDU length field
* Returns: true if subframe header lengths are valid for the @mesh_hdr mode
*/
-bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr);
+bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr);
/**
* ieee80211_amsdu_to_8023s - decode an IEEE 802.11n A-MSDU frame
@@ -6294,13 +6297,13 @@ bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr);
* @extra_headroom: The hardware extra headroom for SKBs in the @list.
* @check_da: DA to check in the inner ethernet header, or NULL
* @check_sa: SA to check in the inner ethernet header, or NULL
- * @mesh_control: A-MSDU subframe header includes the mesh control field
+ * @mesh_control: see mesh_hdr in ieee80211_is_valid_amsdu
*/
void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype,
const unsigned int extra_headroom,
const u8 *check_da, const u8 *check_sa,
- bool mesh_control);
+ u8 mesh_control);
/**
* ieee80211_get_8023_tunnel_proto - get RFC1042 or bridge tunnel encap protocol
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 2a883d956260..3635d036375a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2983,13 +2983,23 @@ __ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx, u8 data_offset)
return RX_DROP_UNUSABLE;
if (rx->sta && rx->sta->amsdu_mesh_control < 0) {
- bool valid_std = ieee80211_is_valid_amsdu(skb, true);
- bool valid_nonstd = ieee80211_is_valid_amsdu(skb, false);
+ s8 valid = -1;
+ int i;
+
+ for (i = 0; i <= 2; i++) {
+ if (!ieee80211_is_valid_amsdu(skb, i))
+ continue;
+
+ if (valid >= 0) {
+ /* ambiguous */
+ valid = -1;
+ break;
+ }
+
+ valid = i;
+ }
- if (valid_std && !valid_nonstd)
- rx->sta->amsdu_mesh_control = 1;
- else if (valid_nonstd && !valid_std)
- rx->sta->amsdu_mesh_control = 0;
+ rx->sta->amsdu_mesh_control = valid;
}
ieee80211_amsdu_to_8023s(skb, &frame_list, dev->dev_addr,
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index e8e482a82d77..f354d470e174 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -623,7 +623,10 @@ struct link_sta_info {
* @cparams: CoDel parameters for this station.
* @reserved_tid: reserved TID (if any, otherwise IEEE80211_TID_UNRESERVED)
* @amsdu_mesh_control: track the mesh A-MSDU format used by the peer
- * (-1: not yet known, 0: non-standard [without mesh header], 1: standard)
+ * (-1: not yet known,
+ * 0: non-mesh A-MSDU length field
+ * 1: big-endian mesh A-MSDU length field
+ * 2: little-endian mesh A-MSDU length field)
* @fast_tx: TX fastpath information
* @fast_rx: RX fastpath information
* @tdls_chandef: a TDLS peer can have a wider chandef that is compatible to
diff --git a/net/wireless/util.c b/net/wireless/util.c
index d1a89e82ead0..3bc0c3072e78 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -776,7 +776,24 @@ __ieee80211_amsdu_copy(struct sk_buff *skb, unsigned int hlen,
return frame;
}
-bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr)
+static u16
+ieee80211_amsdu_subframe_length(void *field, u8 mesh_flags, u8 hdr_type)
+{
+ __le16 *field_le = field;
+ __be16 *field_be = field;
+ u16 len;
+
+ if (hdr_type >= 2)
+ len = le16_to_cpu(*field_le);
+ else
+ len = be16_to_cpu(*field_be);
+ if (hdr_type)
+ len += __ieee80211_get_mesh_hdrlen(mesh_flags);
+
+ return len;
+}
+
+bool ieee80211_is_valid_amsdu(struct sk_buff *skb, u8 mesh_hdr)
{
int offset = 0, remaining, subframe_len, padding;
@@ -790,12 +807,8 @@ bool ieee80211_is_valid_amsdu(struct sk_buff *skb, bool mesh_hdr)
if (skb_copy_bits(skb, offset + 2 * ETH_ALEN, &hdr, sizeof(hdr)) < 0)
return false;
- if (mesh_hdr)
- len = le16_to_cpu(*(__le16 *)&hdr.len) +
- __ieee80211_get_mesh_hdrlen(hdr.mesh_flags);
- else
- len = ntohs(hdr.len);
-
+ len = ieee80211_amsdu_subframe_length(&hdr.len, hdr.mesh_flags,
+ mesh_hdr);
subframe_len = sizeof(struct ethhdr) + len;
padding = (4 - subframe_len) & 0x3;
remaining = skb->len - offset;
@@ -812,7 +825,7 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
const u8 *addr, enum nl80211_iftype iftype,
const unsigned int extra_headroom,
const u8 *check_da, const u8 *check_sa,
- bool mesh_control)
+ u8 mesh_control)
{
unsigned int hlen = ALIGN(extra_headroom, 4);
struct sk_buff *frame = NULL;
@@ -837,11 +850,8 @@ void ieee80211_amsdu_to_8023s(struct sk_buff *skb, struct sk_buff_head *list,
skb_copy_bits(skb, offset, &hdr, copy_len);
if (iftype == NL80211_IFTYPE_MESH_POINT)
mesh_len = __ieee80211_get_mesh_hdrlen(hdr.flags);
- if (mesh_control)
- len = le16_to_cpu(*(__le16 *)&hdr.eth.h_proto) + mesh_len;
- else
- len = ntohs(hdr.eth.h_proto);
-
+ len = ieee80211_amsdu_subframe_length(&hdr.eth.h_proto, hdr.flags,
+ mesh_control);
subframe_len = sizeof(struct ethhdr) + len;
padding = (4 - subframe_len) & 0x3;
--
2.39.0
next prev parent reply other threads:[~2023-03-14 10:00 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-03-14 9:59 [PATCH 1/7] wifi: mac80211: fix qos on mesh interfaces Felix Fietkau
2023-03-14 9:59 ` [PATCH 2/7] wifi: mac80211: fix race in mesh sequence number assignment Felix Fietkau
2023-03-14 9:59 ` [PATCH 3/7] wifi: mac80211: fix mesh path discovery based on unicast packets Felix Fietkau
2023-03-14 9:59 ` [PATCH 4/7] wifi: mac80211: mesh fast xmit support Felix Fietkau
2023-03-14 9:59 ` [PATCH 5/7] wifi: mac80211: use mesh header cache to speed up mesh forwarding Felix Fietkau
2023-03-14 9:59 ` [PATCH 6/7] wifi: mac80211: add mesh fast-rx support Felix Fietkau
2023-03-14 9:59 ` Felix Fietkau [this message]
2023-03-15 13:04 ` [PATCH 7/7] mac80211: implement support for yet another mesh A-MSDU format kernel test robot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230314095956.62085-7-nbd@nbd.name \
--to=nbd@nbd.name \
--cc=johannes@sipsolutions.net \
--cc=linux-wireless@vger.kernel.org \
--cc=ryder.lee@mediatek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.