kernel: Move an upstreamed patch under backports
[openwrt/openwrt.git] / target / linux / generic / backport-5.4 / 757-v5.8-net-dsa-tag_rtl4_a-Implement-Realtek-4-byte-A-tag.patch
1 From 078ced30af696b52a450a016a16eb47499d68117 Mon Sep 17 00:00:00 2001
2 From: Linus Walleij <linus.walleij@linaro.org>
3 Date: Wed, 8 Jul 2020 14:25:36 +0200
4 Subject: [PATCH 2/5] net: dsa: tag_rtl4_a: Implement Realtek 4 byte A tag
5
6 This implements the known parts of the Realtek 4 byte
7 tag protocol version 0xA, as found in the RTL8366RB
8 DSA switch.
9
10 It is designated as protocol version 0xA as a
11 different Realtek 4 byte tag format with protocol
12 version 0x9 is known to exist in the Realtek RTL8306
13 chips.
14
15 The tag and switch chip lacks public documentation, so
16 the tag format has been reverse-engineered from
17 packet dumps. As only ingress traffic has been available
18 for analysis an egress tag has not been possible to
19 develop (even using educated guesses about bit fields)
20 so this is as far as it gets. It is not known if the
21 switch even supports egress tagging.
22
23 Excessive attempts to figure out the egress tag format
24 was made. When nothing else worked, I just tried all bit
25 combinations with 0xannp where a is protocol and p is
26 port. I looped through all values several times trying
27 to get a response from ping, without any positive
28 result.
29
30 Using just these ingress tags however, the switch
31 functionality is vastly improved and the packets find
32 their way into the destination port without any
33 tricky VLAN configuration. On the D-Link DIR-685 the
34 LAN ports now come up and respond to ping without
35 any command line configuration so this is a real
36 improvement for users.
37
38 Egress packets need to be restricted to the proper
39 target ports using VLAN, which the RTL8366RB DSA
40 switch driver already sets up.
41
42 Cc: DENG Qingfang <dqfext@gmail.com>
43 Cc: Mauri Sandberg <sandberg@mailfence.com>
44 Reviewed-by: Andrew Lunn <andrew@lunn.ch>
45 Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
46 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
47 Signed-off-by: David S. Miller <davem@davemloft.net>
48 ---
49 include/net/dsa.h | 2 +
50 net/dsa/Kconfig | 7 +++
51 net/dsa/Makefile | 1 +
52 net/dsa/tag_rtl4_a.c | 130 +++++++++++++++++++++++++++++++++++++++++++
53 4 files changed, 140 insertions(+)
54 create mode 100644 net/dsa/tag_rtl4_a.c
55
56 --- a/include/net/dsa.h
57 +++ b/include/net/dsa.h
58 @@ -42,6 +42,7 @@ struct phylink_link_state;
59 #define DSA_TAG_PROTO_8021Q_VALUE 12
60 #define DSA_TAG_PROTO_SJA1105_VALUE 13
61 #define DSA_TAG_PROTO_KSZ8795_VALUE 14
62 +#define DSA_TAG_PROTO_RTL4_A_VALUE 17
63
64 enum dsa_tag_protocol {
65 DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
66 @@ -59,6 +60,7 @@ enum dsa_tag_protocol {
67 DSA_TAG_PROTO_8021Q = DSA_TAG_PROTO_8021Q_VALUE,
68 DSA_TAG_PROTO_SJA1105 = DSA_TAG_PROTO_SJA1105_VALUE,
69 DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE,
70 + DSA_TAG_PROTO_RTL4_A = DSA_TAG_PROTO_RTL4_A_VALUE,
71 };
72
73 struct packet_type;
74 --- a/net/dsa/Kconfig
75 +++ b/net/dsa/Kconfig
76 @@ -80,6 +80,13 @@ config NET_DSA_TAG_KSZ
77 Say Y if you want to enable support for tagging frames for the
78 Microchip 8795/9477/9893 families of switches.
79
80 +config NET_DSA_TAG_RTL4_A
81 + tristate "Tag driver for Realtek 4 byte protocol A tags"
82 + help
83 + Say Y or M if you want to enable support for tagging frames for the
84 + Realtek switches with 4 byte protocol A tags, sich as found in
85 + the Realtek RTL8366RB.
86 +
87 config NET_DSA_TAG_QCA
88 tristate "Tag driver for Qualcomm Atheros QCA8K switches"
89 help
90 --- a/net/dsa/Makefile
91 +++ b/net/dsa/Makefile
92 @@ -10,6 +10,7 @@ obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa
93 obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
94 obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
95 obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
96 +obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o
97 obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
98 obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
99 obj-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
100 --- /dev/null
101 +++ b/net/dsa/tag_rtl4_a.c
102 @@ -0,0 +1,130 @@
103 +// SPDX-License-Identifier: GPL-2.0
104 +/*
105 + * Handler for Realtek 4 byte DSA switch tags
106 + * Currently only supports protocol "A" found in RTL8366RB
107 + * Copyright (c) 2020 Linus Walleij <linus.walleij@linaro.org>
108 + *
109 + * This "proprietary tag" header looks like so:
110 + *
111 + * -------------------------------------------------
112 + * | MAC DA | MAC SA | 0x8899 | 2 bytes tag | Type |
113 + * -------------------------------------------------
114 + *
115 + * The 2 bytes tag form a 16 bit big endian word. The exact
116 + * meaning has been guessed from packet dumps from ingress
117 + * frames, as no working egress traffic has been available
118 + * we do not know the format of the egress tags or if they
119 + * are even supported.
120 + */
121 +
122 +#include <linux/etherdevice.h>
123 +#include <linux/bits.h>
124 +
125 +#include "dsa_priv.h"
126 +
127 +#define RTL4_A_HDR_LEN 4
128 +#define RTL4_A_ETHERTYPE 0x8899
129 +#define RTL4_A_PROTOCOL_SHIFT 12
130 +/*
131 + * 0x1 = Realtek Remote Control protocol (RRCP)
132 + * 0x2/0x3 seems to be used for loopback testing
133 + * 0x9 = RTL8306 DSA protocol
134 + * 0xa = RTL8366RB DSA protocol
135 + */
136 +#define RTL4_A_PROTOCOL_RTL8366RB 0xa
137 +
138 +static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
139 + struct net_device *dev)
140 +{
141 + /*
142 + * Just let it pass thru, we don't know if it is possible
143 + * to tag a frame with the 0x8899 ethertype and direct it
144 + * to a specific port, all attempts at reverse-engineering have
145 + * ended up with the frames getting dropped.
146 + *
147 + * The VLAN set-up needs to restrict the frames to the right port.
148 + *
149 + * If you have documentation on the tagging format for RTL8366RB
150 + * (tag type A) then please contribute.
151 + */
152 + return skb;
153 +}
154 +
155 +static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
156 + struct net_device *dev,
157 + struct packet_type *pt)
158 +{
159 + u16 protport;
160 + __be16 *p;
161 + u16 etype;
162 + u8 *tag;
163 + u8 prot;
164 + u8 port;
165 +
166 + if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN)))
167 + return NULL;
168 +
169 + /* The RTL4 header has its own custom Ethertype 0x8899 and that
170 + * starts right at the beginning of the packet, after the src
171 + * ethernet addr. Apparantly skb->data always points 2 bytes in,
172 + * behind the Ethertype.
173 + */
174 + tag = skb->data - 2;
175 + p = (__be16 *)tag;
176 + etype = ntohs(*p);
177 + if (etype != RTL4_A_ETHERTYPE) {
178 + /* Not custom, just pass through */
179 + netdev_dbg(dev, "non-realtek ethertype 0x%04x\n", etype);
180 + return skb;
181 + }
182 + p = (__be16 *)(tag + 2);
183 + protport = ntohs(*p);
184 + /* The 4 upper bits are the protocol */
185 + prot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f;
186 + if (prot != RTL4_A_PROTOCOL_RTL8366RB) {
187 + netdev_err(dev, "unknown realtek protocol 0x%01x\n", prot);
188 + return NULL;
189 + }
190 + port = protport & 0xff;
191 +
192 + skb->dev = dsa_master_find_slave(dev, 0, port);
193 + if (!skb->dev) {
194 + netdev_dbg(dev, "could not find slave for port %d\n", port);
195 + return NULL;
196 + }
197 +
198 + /* Remove RTL4 tag and recalculate checksum */
199 + skb_pull_rcsum(skb, RTL4_A_HDR_LEN);
200 +
201 + /* Move ethernet DA and SA in front of the data */
202 + memmove(skb->data - ETH_HLEN,
203 + skb->data - ETH_HLEN - RTL4_A_HDR_LEN,
204 + 2 * ETH_ALEN);
205 +
206 + skb->offload_fwd_mark = 1;
207 +
208 + return skb;
209 +}
210 +
211 +static int rtl4a_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
212 + int *offset)
213 +{
214 + *offset = RTL4_A_HDR_LEN;
215 + /* Skip past the tag and fetch the encapsulated Ethertype */
216 + *proto = ((__be16 *)skb->data)[1];
217 +
218 + return 0;
219 +}
220 +
221 +static const struct dsa_device_ops rtl4a_netdev_ops = {
222 + .name = "rtl4a",
223 + .proto = DSA_TAG_PROTO_RTL4_A,
224 + .xmit = rtl4a_tag_xmit,
225 + .rcv = rtl4a_tag_rcv,
226 + .flow_dissect = rtl4a_tag_flow_dissect,
227 + .overhead = RTL4_A_HDR_LEN,
228 +};
229 +module_dsa_tag_driver(rtl4a_netdev_ops);
230 +
231 +MODULE_LICENSE("GPL");
232 +MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL4_A);