Pull the port information from the VLAN protocol ID field
Signed-off-by: Felix Fietkau <nbd@nbd.name>
---
net/dsa/tag_mtk.c | 26 +++++++++++++++++++++-----
1 file changed, 21 insertions(+), 5 deletions(-)
@@ -73,13 +73,18 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
if (unlikely(!pskb_may_pull(skb, MTK_HDR_LEN)))
return NULL;
- phdr = dsa_etype_header_pos_rx(skb);
- hdr = ntohs(*phdr);
+ if (skb_vlan_tag_present(skb)) {
+ hdr = ntohs(skb->vlan_proto);
+ __vlan_hwaccel_clear_tag(skb);
+ } else {
+ phdr = dsa_etype_header_pos_rx(skb);
+ hdr = ntohs(*phdr);
- /* Remove MTK tag and recalculate checksum. */
- skb_pull_rcsum(skb, MTK_HDR_LEN);
+ /* Remove MTK tag and recalculate checksum. */
+ skb_pull_rcsum(skb, MTK_HDR_LEN);
- dsa_strip_etype_header(skb, MTK_HDR_LEN);
+ dsa_strip_etype_header(skb, MTK_HDR_LEN);
+ }
/* Get source port information */
port = (hdr & MTK_HDR_RECV_SOURCE_PORT_MASK);
@@ -93,11 +98,22 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev)
return skb;
}
+static void mtk_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+ int *offset)
+{
+ if (!skb_vlan_tag_present(skb))
+ return dsa_tag_generic_flow_dissect(skb, proto, offset);
+
+ *offset = 0;
+ *proto = ((__be16 *)skb->data)[-1];
+}
+
static const struct dsa_device_ops mtk_netdev_ops = {
.name = "mtk",
.proto = DSA_TAG_PROTO_MTK,
.xmit = mtk_tag_xmit,
.rcv = mtk_tag_rcv,
+ .flow_dissect = mtk_tag_flow_dissect,
.needed_headroom = MTK_HDR_LEN,
};