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 "tag.h" 81 82 /* Protocols supported: 83 * 84 * 0x04 = RTL8365MB DSA protocol 85 */ 86 87 #define RTL8_4_NAME "rtl8_4" 88 #define RTL8_4T_NAME "rtl8_4t" 89 90 #define RTL8_4_TAG_LEN 8 91 92 #define RTL8_4_PROTOCOL GENMASK(15, 8) 93 #define RTL8_4_PROTOCOL_RTL8365MB 0x04 94 #define RTL8_4_REASON GENMASK(7, 0) 95 #define RTL8_4_REASON_FORWARD 0 96 #define RTL8_4_REASON_TRAP 80 97 98 #define RTL8_4_LEARN_DIS BIT(5) 99 100 #define RTL8_4_TX GENMASK(3, 0) 101 #define RTL8_4_RX GENMASK(10, 0) 102 103 static void rtl8_4_write_tag(struct sk_buff *skb, struct net_device *dev, 104 void *tag) 105 { 106 struct dsa_port *dp = dsa_slave_to_port(dev); 107 __be16 tag16[RTL8_4_TAG_LEN / 2]; 108 109 /* Set Realtek EtherType */ 110 tag16[0] = htons(ETH_P_REALTEK); 111 112 /* Set Protocol; zero REASON */ 113 tag16[1] = htons(FIELD_PREP(RTL8_4_PROTOCOL, RTL8_4_PROTOCOL_RTL8365MB)); 114 115 /* Zero FID_EN, FID, PRI_EN, PRI, KEEP; set LEARN_DIS */ 116 tag16[2] = htons(FIELD_PREP(RTL8_4_LEARN_DIS, 1)); 117 118 /* Zero ALLOW; set RX (CPU->switch) forwarding port mask */ 119 tag16[3] = htons(FIELD_PREP(RTL8_4_RX, BIT(dp->index))); 120 121 memcpy(tag, tag16, RTL8_4_TAG_LEN); 122 } 123 124 static struct sk_buff *rtl8_4_tag_xmit(struct sk_buff *skb, 125 struct net_device *dev) 126 { 127 skb_push(skb, RTL8_4_TAG_LEN); 128 129 dsa_alloc_etype_header(skb, RTL8_4_TAG_LEN); 130 131 rtl8_4_write_tag(skb, dev, dsa_etype_header_pos_tx(skb)); 132 133 return skb; 134 } 135 136 static struct sk_buff *rtl8_4t_tag_xmit(struct sk_buff *skb, 137 struct net_device *dev) 138 { 139 /* Calculate the checksum here if not done yet as trailing tags will 140 * break either software or hardware based checksum 141 */ 142 if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb)) 143 return NULL; 144 145 rtl8_4_write_tag(skb, dev, skb_put(skb, RTL8_4_TAG_LEN)); 146 147 return skb; 148 } 149 150 static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev, 151 void *tag) 152 { 153 __be16 tag16[RTL8_4_TAG_LEN / 2]; 154 u16 etype; 155 u8 reason; 156 u8 proto; 157 u8 port; 158 159 memcpy(tag16, tag, RTL8_4_TAG_LEN); 160 161 /* Parse Realtek EtherType */ 162 etype = ntohs(tag16[0]); 163 if (unlikely(etype != ETH_P_REALTEK)) { 164 dev_warn_ratelimited(&dev->dev, 165 "non-realtek ethertype 0x%04x\n", etype); 166 return -EPROTO; 167 } 168 169 /* Parse Protocol */ 170 proto = FIELD_GET(RTL8_4_PROTOCOL, ntohs(tag16[1])); 171 if (unlikely(proto != RTL8_4_PROTOCOL_RTL8365MB)) { 172 dev_warn_ratelimited(&dev->dev, 173 "unknown realtek protocol 0x%02x\n", 174 proto); 175 return -EPROTO; 176 } 177 178 /* Parse REASON */ 179 reason = FIELD_GET(RTL8_4_REASON, ntohs(tag16[1])); 180 181 /* Parse TX (switch->CPU) */ 182 port = FIELD_GET(RTL8_4_TX, ntohs(tag16[3])); 183 skb->dev = dsa_master_find_slave(dev, 0, port); 184 if (!skb->dev) { 185 dev_warn_ratelimited(&dev->dev, 186 "could not find slave for port %d\n", 187 port); 188 return -ENOENT; 189 } 190 191 if (reason != RTL8_4_REASON_TRAP) 192 dsa_default_offload_fwd_mark(skb); 193 194 return 0; 195 } 196 197 static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb, 198 struct net_device *dev) 199 { 200 if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN))) 201 return NULL; 202 203 if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb)))) 204 return NULL; 205 206 /* Remove tag and recalculate checksum */ 207 skb_pull_rcsum(skb, RTL8_4_TAG_LEN); 208 209 dsa_strip_etype_header(skb, RTL8_4_TAG_LEN); 210 211 return skb; 212 } 213 214 static struct sk_buff *rtl8_4t_tag_rcv(struct sk_buff *skb, 215 struct net_device *dev) 216 { 217 if (skb_linearize(skb)) 218 return NULL; 219 220 if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN))) 221 return NULL; 222 223 if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN)) 224 return NULL; 225 226 return skb; 227 } 228 229 /* Ethertype version */ 230 static const struct dsa_device_ops rtl8_4_netdev_ops = { 231 .name = "rtl8_4", 232 .proto = DSA_TAG_PROTO_RTL8_4, 233 .xmit = rtl8_4_tag_xmit, 234 .rcv = rtl8_4_tag_rcv, 235 .needed_headroom = RTL8_4_TAG_LEN, 236 }; 237 238 DSA_TAG_DRIVER(rtl8_4_netdev_ops); 239 240 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4, RTL8_4_NAME); 241 242 /* Tail version */ 243 static const struct dsa_device_ops rtl8_4t_netdev_ops = { 244 .name = "rtl8_4t", 245 .proto = DSA_TAG_PROTO_RTL8_4T, 246 .xmit = rtl8_4t_tag_xmit, 247 .rcv = rtl8_4t_tag_rcv, 248 .needed_tailroom = RTL8_4_TAG_LEN, 249 }; 250 251 DSA_TAG_DRIVER(rtl8_4t_netdev_ops); 252 253 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4T, RTL8_4T_NAME); 254 255 static struct dsa_tag_driver *dsa_tag_drivers[] = { 256 &DSA_TAG_DRIVER_NAME(rtl8_4_netdev_ops), 257 &DSA_TAG_DRIVER_NAME(rtl8_4t_netdev_ops), 258 }; 259 module_dsa_tag_drivers(dsa_tag_drivers); 260 261 MODULE_LICENSE("GPL"); 262