Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Handler for Realtek 8 byte switch tags
0004  *
0005  * Copyright (C) 2021 Alvin Šipraga <alsi@bang-olufsen.dk>
0006  *
0007  * NOTE: Currently only supports protocol "4" found in the RTL8365MB, hence
0008  * named tag_rtl8_4.
0009  *
0010  * This tag has the following format:
0011  *
0012  *  0                                  7|8                                 15
0013  *  |-----------------------------------+-----------------------------------|---
0014  *  |                               (16-bit)                                | ^
0015  *  |                       Realtek EtherType [0x8899]                      | |
0016  *  |-----------------------------------+-----------------------------------| 8
0017  *  |              (8-bit)              |              (8-bit)              |
0018  *  |          Protocol [0x04]          |              REASON               | b
0019  *  |-----------------------------------+-----------------------------------| y
0020  *  |   (1)  | (1) | (2) |   (1)  | (3) | (1)  | (1) |    (1)    |   (5)    | t
0021  *  | FID_EN |  X  | FID | PRI_EN | PRI | KEEP |  X  | LEARN_DIS |    X     | e
0022  *  |-----------------------------------+-----------------------------------| s
0023  *  |   (1)  |                       (15-bit)                               | |
0024  *  |  ALLOW |                        TX/RX                                 | v
0025  *  |-----------------------------------+-----------------------------------|---
0026  *
0027  * With the following field descriptions:
0028  *
0029  *    field      | description
0030  *   ------------+-------------
0031  *    Realtek    | 0x8899: indicates that this is a proprietary Realtek tag;
0032  *     EtherType |         note that Realtek uses the same EtherType for
0033  *               |         other incompatible tag formats (e.g. tag_rtl4_a.c)
0034  *    Protocol   | 0x04: indicates that this tag conforms to this format
0035  *    X          | reserved
0036  *   ------------+-------------
0037  *    REASON     | reason for forwarding packet to CPU
0038  *               | 0: packet was forwarded or flooded to CPU
0039  *               | 80: packet was trapped to CPU
0040  *    FID_EN     | 1: packet has an FID
0041  *               | 0: no FID
0042  *    FID        | FID of packet (if FID_EN=1)
0043  *    PRI_EN     | 1: force priority of packet
0044  *               | 0: don't force priority
0045  *    PRI        | priority of packet (if PRI_EN=1)
0046  *    KEEP       | preserve packet VLAN tag format
0047  *    LEARN_DIS  | don't learn the source MAC address of the packet
0048  *    ALLOW      | 1: treat TX/RX field as an allowance port mask, meaning the
0049  *               |    packet may only be forwarded to ports specified in the
0050  *               |    mask
0051  *               | 0: no allowance port mask, TX/RX field is the forwarding
0052  *               |    port mask
0053  *    TX/RX      | TX (switch->CPU): port number the packet was received on
0054  *               | RX (CPU->switch): forwarding port mask (if ALLOW=0)
0055  *               |                   allowance port mask (if ALLOW=1)
0056  *
0057  * The tag can be positioned before Ethertype, using tag "rtl8_4":
0058  *
0059  *  +--------+--------+------------+------+-----
0060  *  | MAC DA | MAC SA | 8 byte tag | Type | ...
0061  *  +--------+--------+------------+------+-----
0062  *
0063  * The tag can also appear between the end of the payload and before the CRC,
0064  * using tag "rtl8_4t":
0065  *
0066  * +--------+--------+------+-----+---------+------------+-----+
0067  * | MAC DA | MAC SA | TYPE | ... | payload | 8-byte tag | CRC |
0068  * +--------+--------+------+-----+---------+------------+-----+
0069  *
0070  * The added bytes after the payload will break most checksums, either in
0071  * software or hardware. To avoid this issue, if the checksum is still pending,
0072  * this tagger checksums the packet in software before adding the tag.
0073  *
0074  */
0075 
0076 #include <linux/bitfield.h>
0077 #include <linux/bits.h>
0078 #include <linux/etherdevice.h>
0079 
0080 #include "dsa_priv.h"
0081 
0082 /* Protocols supported:
0083  *
0084  * 0x04 = RTL8365MB DSA protocol
0085  */
0086 
0087 #define RTL8_4_TAG_LEN          8
0088 
0089 #define RTL8_4_PROTOCOL         GENMASK(15, 8)
0090 #define   RTL8_4_PROTOCOL_RTL8365MB 0x04
0091 #define RTL8_4_REASON           GENMASK(7, 0)
0092 #define   RTL8_4_REASON_FORWARD     0
0093 #define   RTL8_4_REASON_TRAP        80
0094 
0095 #define RTL8_4_LEARN_DIS        BIT(5)
0096 
0097 #define RTL8_4_TX           GENMASK(3, 0)
0098 #define RTL8_4_RX           GENMASK(10, 0)
0099 
0100 static void rtl8_4_write_tag(struct sk_buff *skb, struct net_device *dev,
0101                  void *tag)
0102 {
0103     struct dsa_port *dp = dsa_slave_to_port(dev);
0104     __be16 tag16[RTL8_4_TAG_LEN / 2];
0105 
0106     /* Set Realtek EtherType */
0107     tag16[0] = htons(ETH_P_REALTEK);
0108 
0109     /* Set Protocol; zero REASON */
0110     tag16[1] = htons(FIELD_PREP(RTL8_4_PROTOCOL, RTL8_4_PROTOCOL_RTL8365MB));
0111 
0112     /* Zero FID_EN, FID, PRI_EN, PRI, KEEP; set LEARN_DIS */
0113     tag16[2] = htons(FIELD_PREP(RTL8_4_LEARN_DIS, 1));
0114 
0115     /* Zero ALLOW; set RX (CPU->switch) forwarding port mask */
0116     tag16[3] = htons(FIELD_PREP(RTL8_4_RX, BIT(dp->index)));
0117 
0118     memcpy(tag, tag16, RTL8_4_TAG_LEN);
0119 }
0120 
0121 static struct sk_buff *rtl8_4_tag_xmit(struct sk_buff *skb,
0122                        struct net_device *dev)
0123 {
0124     skb_push(skb, RTL8_4_TAG_LEN);
0125 
0126     dsa_alloc_etype_header(skb, RTL8_4_TAG_LEN);
0127 
0128     rtl8_4_write_tag(skb, dev, dsa_etype_header_pos_tx(skb));
0129 
0130     return skb;
0131 }
0132 
0133 static struct sk_buff *rtl8_4t_tag_xmit(struct sk_buff *skb,
0134                     struct net_device *dev)
0135 {
0136     /* Calculate the checksum here if not done yet as trailing tags will
0137      * break either software or hardware based checksum
0138      */
0139     if (skb->ip_summed == CHECKSUM_PARTIAL && skb_checksum_help(skb))
0140         return NULL;
0141 
0142     rtl8_4_write_tag(skb, dev, skb_put(skb, RTL8_4_TAG_LEN));
0143 
0144     return skb;
0145 }
0146 
0147 static int rtl8_4_read_tag(struct sk_buff *skb, struct net_device *dev,
0148                void *tag)
0149 {
0150     __be16 tag16[RTL8_4_TAG_LEN / 2];
0151     u16 etype;
0152     u8 reason;
0153     u8 proto;
0154     u8 port;
0155 
0156     memcpy(tag16, tag, RTL8_4_TAG_LEN);
0157 
0158     /* Parse Realtek EtherType */
0159     etype = ntohs(tag16[0]);
0160     if (unlikely(etype != ETH_P_REALTEK)) {
0161         dev_warn_ratelimited(&dev->dev,
0162                      "non-realtek ethertype 0x%04x\n", etype);
0163         return -EPROTO;
0164     }
0165 
0166     /* Parse Protocol */
0167     proto = FIELD_GET(RTL8_4_PROTOCOL, ntohs(tag16[1]));
0168     if (unlikely(proto != RTL8_4_PROTOCOL_RTL8365MB)) {
0169         dev_warn_ratelimited(&dev->dev,
0170                      "unknown realtek protocol 0x%02x\n",
0171                      proto);
0172         return -EPROTO;
0173     }
0174 
0175     /* Parse REASON */
0176     reason = FIELD_GET(RTL8_4_REASON, ntohs(tag16[1]));
0177 
0178     /* Parse TX (switch->CPU) */
0179     port = FIELD_GET(RTL8_4_TX, ntohs(tag16[3]));
0180     skb->dev = dsa_master_find_slave(dev, 0, port);
0181     if (!skb->dev) {
0182         dev_warn_ratelimited(&dev->dev,
0183                      "could not find slave for port %d\n",
0184                      port);
0185         return -ENOENT;
0186     }
0187 
0188     if (reason != RTL8_4_REASON_TRAP)
0189         dsa_default_offload_fwd_mark(skb);
0190 
0191     return 0;
0192 }
0193 
0194 static struct sk_buff *rtl8_4_tag_rcv(struct sk_buff *skb,
0195                       struct net_device *dev)
0196 {
0197     if (unlikely(!pskb_may_pull(skb, RTL8_4_TAG_LEN)))
0198         return NULL;
0199 
0200     if (unlikely(rtl8_4_read_tag(skb, dev, dsa_etype_header_pos_rx(skb))))
0201         return NULL;
0202 
0203     /* Remove tag and recalculate checksum */
0204     skb_pull_rcsum(skb, RTL8_4_TAG_LEN);
0205 
0206     dsa_strip_etype_header(skb, RTL8_4_TAG_LEN);
0207 
0208     return skb;
0209 }
0210 
0211 static struct sk_buff *rtl8_4t_tag_rcv(struct sk_buff *skb,
0212                        struct net_device *dev)
0213 {
0214     if (skb_linearize(skb))
0215         return NULL;
0216 
0217     if (unlikely(rtl8_4_read_tag(skb, dev, skb_tail_pointer(skb) - RTL8_4_TAG_LEN)))
0218         return NULL;
0219 
0220     if (pskb_trim_rcsum(skb, skb->len - RTL8_4_TAG_LEN))
0221         return NULL;
0222 
0223     return skb;
0224 }
0225 
0226 /* Ethertype version */
0227 static const struct dsa_device_ops rtl8_4_netdev_ops = {
0228     .name = "rtl8_4",
0229     .proto = DSA_TAG_PROTO_RTL8_4,
0230     .xmit = rtl8_4_tag_xmit,
0231     .rcv = rtl8_4_tag_rcv,
0232     .needed_headroom = RTL8_4_TAG_LEN,
0233 };
0234 
0235 DSA_TAG_DRIVER(rtl8_4_netdev_ops);
0236 
0237 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4);
0238 
0239 /* Tail version */
0240 static const struct dsa_device_ops rtl8_4t_netdev_ops = {
0241     .name = "rtl8_4t",
0242     .proto = DSA_TAG_PROTO_RTL8_4T,
0243     .xmit = rtl8_4t_tag_xmit,
0244     .rcv = rtl8_4t_tag_rcv,
0245     .needed_tailroom = RTL8_4_TAG_LEN,
0246 };
0247 
0248 DSA_TAG_DRIVER(rtl8_4t_netdev_ops);
0249 
0250 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_RTL8_4T);
0251 
0252 static struct dsa_tag_driver *dsa_tag_drivers[] = {
0253     &DSA_TAG_DRIVER_NAME(rtl8_4_netdev_ops),
0254     &DSA_TAG_DRIVER_NAME(rtl8_4t_netdev_ops),
0255 };
0256 module_dsa_tag_drivers(dsa_tag_drivers);
0257 
0258 MODULE_LICENSE("GPL");