1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Handler for Realtek 8 byte switch tags
4 *
5 * Copyright (C) 2021 Alvin Šipraga <alsi@bang-olufsen.dk>
6 *
7 * NOTE: Currently only supports protocol "4" found in the RTL8365MB, hence
8 * named tag_rtl8_4.
9 *
10 * This tag has the following format:
11 *
12 * 0 7|8 15
13 * |-----------------------------------+-----------------------------------|---
14 * | (16-bit) | ^
15 * | Realtek EtherType [0x8899] | |
16 * |-----------------------------------+-----------------------------------| 8
17 * | (8-bit) | (8-bit) |
18 * | Protocol [0x04] | REASON | b
19 * |-----------------------------------+-----------------------------------| y
20 * | (1) | (1) | (2) | (1) | (3) | (1) | (1) | (1) | (5) | t
21 * | FID_EN | X | FID | PRI_EN | PRI | KEEP | X | LEARN_DIS | X | e
22 * |-----------------------------------+-----------------------------------| s
23 * | (1) | (15-bit) | |
24 * | ALLOW | TX/RX | v
25 * |-----------------------------------+-----------------------------------|---
26 *
27 * With the following field descriptions:
28 *
29 * field | description
30 * ------------+-------------
31 * Realtek | 0x8899: indicates that this is a proprietary Realtek tag;
32 * EtherType | note that Realtek uses the same EtherType for
33 * | other incompatible tag formats (e.g. tag_rtl4_a.c)
34 * Protocol | 0x04: indicates that this tag conforms to this format
35 * X | reserved
36 * ------------+-------------
37 * REASON | reason for forwarding packet to CPU
38 * | 0: packet was forwarded or flooded to CPU
39 * | 80: packet was trapped to CPU
40 * FID_EN | 1: packet has an FID
41 * | 0: no FID
42 * FID | FID of packet (if FID_EN=1)
43 * PRI_EN | 1: force priority of packet
44 * | 0: don't force priority
45 * PRI | priority of packet (if PRI_EN=1)
46 * KEEP | preserve packet VLAN tag format
47 * LEARN_DIS | don't learn the source MAC address of the packet
48 * ALLOW | 1: treat TX/RX field as an allowance port mask, meaning the
49 * | packet may only be forwarded to ports specified in the
50 * | mask
51 * | 0: no allowance port mask, TX/RX field is the forwarding
52 * | port mask
53 * TX/RX | TX (switch->CPU): port number the packet was received on
54 * | RX (CPU->switch): forwarding port mask (if ALLOW=0)
55 * | allowance port mask (if ALLOW=1)
56 *
57 * The tag can be positioned before Ethertype, using tag "rtl8_4":
58 *
59 * +--------+--------+------------+------+-----
60 * | MAC DA | MAC SA | 8 byte tag | Type | ...
61 * +--------+--------+------------+------+-----
62 *
63 * The tag can also appear between the end of the payload and before the CRC,
64 * using tag "rtl8_4t":
65 *
66 * +--------+--------+------+-----+---------+------------+-----+
67 * | MAC DA | MAC SA | TYPE | ... | payload | 8-byte tag | CRC |
68 * +--------+--------+------+-----+---------+------------+-----+
69 *
70 * The added bytes after the payload will break most checksums, either in
71 * software or hardware. To avoid this issue, if the checksum is still pending,
72 * this tagger checksums the packet in software before adding the tag.
73 *
74 */
75
76 #include <linux/bitfield.h>
77 #include <linux/bits.h>
78 #include <linux/etherdevice.h>
79
80 #include "dsa_priv.h"
81
82 /* Protocols supported:
83 *
84 * 0x04 = RTL8365MB DSA protocol
85 */
86
87 #define RTL8_4_TAG_LEN 8
88
89 #define RTL8_4_PROTOCOL GENMASK(15, 8)
90 #define RTL8_4_PROTOCOL_RTL8365MB 0x04
91 #define RTL8_4_REASON GENMASK(7, 0)
92 #define RTL8_4_REASON_FORWARD 0
93 #define RTL8_4_REASON_TRAP 80
94
95 #define RTL8_4_LEARN_DIS BIT(5)
96
97 #define RTL8_4_TX GENMASK(3, 0)
98 #define RTL8_4_RX GENMASK(10, 0)
99
rtl8_4_write_tag(struct sk_buff * skb,struct net_device * dev,void * tag)100 static void rtl8_4_write_tag(struct sk_buff *skb, struct net_device *dev,
101 void *tag)
102 {
103 struct dsa_port *dp = dsa_slave_to_port(dev);
104 __be16 tag16[RTL8_4_TAG_LEN / 2];
105
106 /* Set Realtek EtherType */
107 tag16[0] = htons(ETH_P_REALTEK);
108
109 /* Set Protocol; zero REASON */
110 tag16[1] = htons(FIELD_PREP(RTL8_4_PROTOCOL, RTL8_4_PROTOCOL_RTL8365MB));
111
112 /* Zero FID_EN, FID, PRI_EN, PRI, KEEP; set LEARN_DIS */
113 tag16[2] = htons(FIELD_PREP(RTL8_4_LEARN_DIS, 1));
114
115 /* Zero ALLOW; set RX (CPU->switch) forwarding port mask */
116 tag16[3] = htons(FIELD_PREP(RTL8_4_RX, BIT(dp->index)));
117
118 memcpy(tag, tag16, RTL8_4_TAG_LEN);
119 }
120
rtl8_4_tag_xmit(struct sk_buff * skb,struct net_device * dev)121 static struct sk_buff *rtl8_4_tag_xmit(struct sk_buff *skb,
122 struct net_device *dev)
123 {
124 skb_push(skb, RTL8_4_TAG_LEN);
125
126 dsa_alloc_etype_header(skb, RTL8_4_TAG_LEN);
127
128 rtl8_4_write_tag(skb, dev, dsa_etype_header_pos_tx(skb));
129
130 return skb;
131 }
132
rtl8_4t_tag_xmit(struct sk_buff * skb,struct net_device * dev)133 static struct sk_buff *rtl8_4t_tag_xmit(struct sk_buff *skb,
134 struct net_device *dev)
135 {
136 /* Calculate the checksum here if not done yet as trailing tags will
137 * break either software or hardware based checksum
138 */
139 if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
140 return NULL;
141
142 rtl8_4_write_tag(skb, dev, skb_put(skb, RTL8_4_TAG_LEN));
143
144 return skb;
145 }
146
rtl8_4_read_tag(struct sk_buff * skb,struct net_device * dev,void * tag)147 static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev,
148 void *tag)
149 {
150 __be16 tag16[RTL8_4_TAG_LEN / 2];
151 u16 etype;
152 u8 reason;
153 u8 proto;
154 u8 port;
155
156 memcpy(tag16, tag, RTL8_4_TAG_LEN);
157
158 /* Parse Realtek EtherType */
159 etype = ntohs(tag16[0]);
160 if (unlikely(etype != ETH_P_REALTEK)) {
161 dev_warn_ratelimited(&dev->dev,
162 "non-realtek ethertype 0x%04x\n", etype);
163 return -EPROTO;
164 }
165
166 /* Parse Protocol */
167 proto = FIELD_GET(RTL8_4_PROTOCOL, ntohs(tag16[1]));
168 if (unlikely(proto != RTL8_4_PROTOCOL_RTL8365MB)) {
169 dev_warn_ratelimited(&dev->dev,
170 "unknown realtek protocol 0x%02x\n",
171 proto);
172 return -EPROTO;
173 }
174
175 /* Parse REASON */
176 reason = FIELD_GET(RTL8_4_REASON, ntohs(tag16[1]));
177
178 /* Parse TX (switch->CPU) */
179 port = FIELD_GET(RTL8_4_TX, ntohs(tag16[3]));
180 skb->dev = dsa_master_find_slave(dev, 0, port);
181 if (!skb->dev) {
182 dev_warn_ratelimited(&dev->dev,
183 "could not find slave for port %d\n",
184 port);
185 return -ENOENT;
186 }
187
188 if (reason != RTL8_4_REASON_TRAP)
189 dsa_default_offload_fwd_mark(skb);
190
191 return 0;
192 }
193
rtl8_4_tag_rcv(struct sk_buff * skb,struct net_device * dev)194 static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
195 struct net_device *dev)
196 {
197 if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN)))
198 return NULL;
199
200 if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb))))
201 return NULL;
202
203 /* Remove tag and recalculate checksum */
204 skb_pull_rcsum(skb, RTL8_4_TAG_LEN);
205
206 dsa_strip_etype_header(skb, RTL8_4_TAG_LEN);
207
208 return skb;
209 }
210
rtl8_4t_tag_rcv(struct sk_buff * skb,struct net_device * dev)211 static struct sk_buff *rtl8_4t_tag_rcv(struct sk_buff *skb,
212 struct net_device *dev)
213 {
214 if (skb_linearize(skb))
215 return NULL;
216
217 if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN)))
218 return NULL;
219
220 if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN))
221 return NULL;
222
223 return skb;
224 }
225
226 /* Ethertype version */
227 static const struct dsa_device_ops rtl8_4_netdev_ops = {
228 .name = "rtl8_4",
229 .proto = DSA_TAG_PROTO_RTL8_4,
230 .xmit = rtl8_4_tag_xmit,
231 .rcv = rtl8_4_tag_rcv,
232 .needed_headroom = RTL8_4_TAG_LEN,
233 };
234
235 DSA_TAG_DRIVER(rtl8_4_netdev_ops);
236
237 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4);
238
239 /* Tail version */
240 static const struct dsa_device_ops rtl8_4t_netdev_ops = {
241 .name = "rtl8_4t",
242 .proto = DSA_TAG_PROTO_RTL8_4T,
243 .xmit = rtl8_4t_tag_xmit,
244 .rcv = rtl8_4t_tag_rcv,
245 .needed_tailroom = RTL8_4_TAG_LEN,
246 };
247
248 DSA_TAG_DRIVER(rtl8_4t_netdev_ops);
249
250 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4T);
251
252 static struct dsa_tag_driver *dsa_tag_drivers[] = {
253 &DSA_TAG_DRIVER_NAME(rtl8_4_netdev_ops),
254 &DSA_TAG_DRIVER_NAME(rtl8_4t_netdev_ops),
255 };
256 module_dsa_tag_drivers(dsa_tag_drivers);
257
258 MODULE_LICENSE("GPL");
259