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