Skip to content

Commit efd7fe6

Browse files
Linus Walleijdavem330
authored andcommitted
net: dsa: tag_rtl4_a: Implement Realtek 4 byte A tag
This implements the known parts of the Realtek 4 byte tag protocol version 0xA, as found in the RTL8366RB DSA switch. It is designated as protocol version 0xA as a different Realtek 4 byte tag format with protocol version 0x9 is known to exist in the Realtek RTL8306 chips. The tag and switch chip lacks public documentation, so the tag format has been reverse-engineered from packet dumps. As only ingress traffic has been available for analysis an egress tag has not been possible to develop (even using educated guesses about bit fields) so this is as far as it gets. It is not known if the switch even supports egress tagging. Excessive attempts to figure out the egress tag format was made. When nothing else worked, I just tried all bit combinations with 0xannp where a is protocol and p is port. I looped through all values several times trying to get a response from ping, without any positive result. Using just these ingress tags however, the switch functionality is vastly improved and the packets find their way into the destination port without any tricky VLAN configuration. On the D-Link DIR-685 the LAN ports now come up and respond to ping without any command line configuration so this is a real improvement for users. Egress packets need to be restricted to the proper target ports using VLAN, which the RTL8366RB DSA switch driver already sets up. Cc: DENG Qingfang <[email protected]> Cc: Mauri Sandberg <[email protected]> Reviewed-by: Andrew Lunn <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: Linus Walleij <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 12fdafb commit efd7fe6

File tree

4 files changed

+140
-0
lines changed

4 files changed

+140
-0
lines changed

include/net/dsa.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct phylink_link_state;
4444
#define DSA_TAG_PROTO_KSZ8795_VALUE 14
4545
#define DSA_TAG_PROTO_OCELOT_VALUE 15
4646
#define DSA_TAG_PROTO_AR9331_VALUE 16
47+
#define DSA_TAG_PROTO_RTL4_A_VALUE 17
4748

4849
enum dsa_tag_protocol {
4950
DSA_TAG_PROTO_NONE = DSA_TAG_PROTO_NONE_VALUE,
@@ -63,6 +64,7 @@ enum dsa_tag_protocol {
6364
DSA_TAG_PROTO_KSZ8795 = DSA_TAG_PROTO_KSZ8795_VALUE,
6465
DSA_TAG_PROTO_OCELOT = DSA_TAG_PROTO_OCELOT_VALUE,
6566
DSA_TAG_PROTO_AR9331 = DSA_TAG_PROTO_AR9331_VALUE,
67+
DSA_TAG_PROTO_RTL4_A = DSA_TAG_PROTO_RTL4_A_VALUE,
6668
};
6769

6870
struct packet_type;

net/dsa/Kconfig

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ config NET_DSA_TAG_KSZ
8686
Say Y if you want to enable support for tagging frames for the
8787
Microchip 8795/9477/9893 families of switches.
8888

89+
config NET_DSA_TAG_RTL4_A
90+
tristate "Tag driver for Realtek 4 byte protocol A tags"
91+
help
92+
Say Y or M if you want to enable support for tagging frames for the
93+
Realtek switches with 4 byte protocol A tags, sich as found in
94+
the Realtek RTL8366RB.
95+
8996
config NET_DSA_TAG_OCELOT
9097
tristate "Tag driver for Ocelot family of switches"
9198
select PACKING

net/dsa/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
1111
obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
1212
obj-$(CONFIG_NET_DSA_TAG_GSWIP) += tag_gswip.o
1313
obj-$(CONFIG_NET_DSA_TAG_KSZ) += tag_ksz.o
14+
obj-$(CONFIG_NET_DSA_TAG_RTL4_A) += tag_rtl4_a.o
1415
obj-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o
1516
obj-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
1617
obj-$(CONFIG_NET_DSA_TAG_OCELOT) += tag_ocelot.o

net/dsa/tag_rtl4_a.c

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Handler for Realtek 4 byte DSA switch tags
4+
* Currently only supports protocol "A" found in RTL8366RB
5+
* Copyright (c) 2020 Linus Walleij <[email protected]>
6+
*
7+
* This "proprietary tag" header looks like so:
8+
*
9+
* -------------------------------------------------
10+
* | MAC DA | MAC SA | 0x8899 | 2 bytes tag | Type |
11+
* -------------------------------------------------
12+
*
13+
* The 2 bytes tag form a 16 bit big endian word. The exact
14+
* meaning has been guessed from packet dumps from ingress
15+
* frames, as no working egress traffic has been available
16+
* we do not know the format of the egress tags or if they
17+
* are even supported.
18+
*/
19+
20+
#include <linux/etherdevice.h>
21+
#include <linux/bits.h>
22+
23+
#include "dsa_priv.h"
24+
25+
#define RTL4_A_HDR_LEN 4
26+
#define RTL4_A_ETHERTYPE 0x8899
27+
#define RTL4_A_PROTOCOL_SHIFT 12
28+
/*
29+
* 0x1 = Realtek Remote Control protocol (RRCP)
30+
* 0x2/0x3 seems to be used for loopback testing
31+
* 0x9 = RTL8306 DSA protocol
32+
* 0xa = RTL8366RB DSA protocol
33+
*/
34+
#define RTL4_A_PROTOCOL_RTL8366RB 0xa
35+
36+
static struct sk_buff *rtl4a_tag_xmit(struct sk_buff *skb,
37+
struct net_device *dev)
38+
{
39+
/*
40+
* Just let it pass thru, we don't know if it is possible
41+
* to tag a frame with the 0x8899 ethertype and direct it
42+
* to a specific port, all attempts at reverse-engineering have
43+
* ended up with the frames getting dropped.
44+
*
45+
* The VLAN set-up needs to restrict the frames to the right port.
46+
*
47+
* If you have documentation on the tagging format for RTL8366RB
48+
* (tag type A) then please contribute.
49+
*/
50+
return skb;
51+
}
52+
53+
static struct sk_buff *rtl4a_tag_rcv(struct sk_buff *skb,
54+
struct net_device *dev,
55+
struct packet_type *pt)
56+
{
57+
u16 protport;
58+
__be16 *p;
59+
u16 etype;
60+
u8 *tag;
61+
u8 prot;
62+
u8 port;
63+
64+
if (unlikely(!pskb_may_pull(skb, RTL4_A_HDR_LEN)))
65+
return NULL;
66+
67+
/* The RTL4 header has its own custom Ethertype 0x8899 and that
68+
* starts right at the beginning of the packet, after the src
69+
* ethernet addr. Apparantly skb->data always points 2 bytes in,
70+
* behind the Ethertype.
71+
*/
72+
tag = skb->data - 2;
73+
p = (__be16 *)tag;
74+
etype = ntohs(*p);
75+
if (etype != RTL4_A_ETHERTYPE) {
76+
/* Not custom, just pass through */
77+
netdev_dbg(dev, "non-realtek ethertype 0x%04x\n", etype);
78+
return skb;
79+
}
80+
p = (__be16 *)(tag + 2);
81+
protport = ntohs(*p);
82+
/* The 4 upper bits are the protocol */
83+
prot = (protport >> RTL4_A_PROTOCOL_SHIFT) & 0x0f;
84+
if (prot != RTL4_A_PROTOCOL_RTL8366RB) {
85+
netdev_err(dev, "unknown realtek protocol 0x%01x\n", prot);
86+
return NULL;
87+
}
88+
port = protport & 0xff;
89+
90+
skb->dev = dsa_master_find_slave(dev, 0, port);
91+
if (!skb->dev) {
92+
netdev_dbg(dev, "could not find slave for port %d\n", port);
93+
return NULL;
94+
}
95+
96+
/* Remove RTL4 tag and recalculate checksum */
97+
skb_pull_rcsum(skb, RTL4_A_HDR_LEN);
98+
99+
/* Move ethernet DA and SA in front of the data */
100+
memmove(skb->data - ETH_HLEN,
101+
skb->data - ETH_HLEN - RTL4_A_HDR_LEN,
102+
2 * ETH_ALEN);
103+
104+
skb->offload_fwd_mark = 1;
105+
106+
return skb;
107+
}
108+
109+
static int rtl4a_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
110+
int *offset)
111+
{
112+
*offset = RTL4_A_HDR_LEN;
113+
/* Skip past the tag and fetch the encapsulated Ethertype */
114+
*proto = ((__be16 *)skb->data)[1];
115+
116+
return 0;
117+
}
118+
119+
static const struct dsa_device_ops rtl4a_netdev_ops = {
120+
.name = "rtl4a",
121+
.proto = DSA_TAG_PROTO_RTL4_A,
122+
.xmit = rtl4a_tag_xmit,
123+
.rcv = rtl4a_tag_rcv,
124+
.flow_dissect = rtl4a_tag_flow_dissect,
125+
.overhead = RTL4_A_HDR_LEN,
126+
};
127+
module_dsa_tag_driver(rtl4a_netdev_ops);
128+
129+
MODULE_LICENSE("GPL");
130+
MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL4_A);

0 commit comments

Comments
 (0)