~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/dsa/tag_lan9303.c

Version: ~ [ linux-5.12-rc5 ] ~ [ linux-5.11.11 ] ~ [ linux-5.10.27 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.109 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.184 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.228 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.264 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.264 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0
  2 /*
  3  * Copyright (C) 2017 Pengutronix, Juergen Borleis <jbe@pengutronix.de>
  4  */
  5 #include <linux/dsa/lan9303.h>
  6 #include <linux/etherdevice.h>
  7 #include <linux/list.h>
  8 #include <linux/slab.h>
  9 
 10 #include "dsa_priv.h"
 11 
 12 /* To define the outgoing port and to discover the incoming port a regular
 13  * VLAN tag is used by the LAN9303. But its VID meaning is 'special':
 14  *
 15  *       Dest MAC       Src MAC        TAG    Type
 16  * ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 | 1 2 |...
 17  *                                |<------->|
 18  * TAG:
 19  *    |<------------->|
 20  *    |  1  2 | 3  4  |
 21  *      TPID    VID
 22  *     0x8100
 23  *
 24  * VID bit 3 indicates a request for an ALR lookup.
 25  *
 26  * If VID bit 3 is zero, then bits 0 and 1 specify the destination port
 27  * (0, 1, 2) or broadcast (3) or the source port (1, 2).
 28  *
 29  * VID bit 4 is used to specify if the STP port state should be overridden.
 30  * Required when no forwarding between the external ports should happen.
 31  */
 32 
 33 #define LAN9303_TAG_LEN 4
 34 # define LAN9303_TAG_TX_USE_ALR BIT(3)
 35 # define LAN9303_TAG_TX_STP_OVERRIDE BIT(4)
 36 # define LAN9303_TAG_RX_IGMP BIT(3)
 37 # define LAN9303_TAG_RX_STP BIT(4)
 38 # define LAN9303_TAG_RX_TRAPPED_TO_CPU (LAN9303_TAG_RX_IGMP | \
 39                                         LAN9303_TAG_RX_STP)
 40 
 41 /* Decide whether to transmit using ALR lookup, or transmit directly to
 42  * port using tag. ALR learning is performed only when using ALR lookup.
 43  * If the two external ports are bridged and the frame is unicast,
 44  * then use ALR lookup to allow ALR learning on CPU port.
 45  * Otherwise transmit directly to port with STP state override.
 46  * See also: lan9303_separate_ports() and lan9303.pdf 6.4.10.1
 47  */
 48 static int lan9303_xmit_use_arl(struct dsa_port *dp, u8 *dest_addr)
 49 {
 50         struct lan9303 *chip = dp->ds->priv;
 51 
 52         return chip->is_bridged && !is_multicast_ether_addr(dest_addr);
 53 }
 54 
 55 static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)
 56 {
 57         struct dsa_port *dp = dsa_slave_to_port(dev);
 58         u16 *lan9303_tag;
 59 
 60         /* insert a special VLAN tag between the MAC addresses
 61          * and the current ethertype field.
 62          */
 63         if (skb_cow_head(skb, LAN9303_TAG_LEN) < 0) {
 64                 dev_dbg(&dev->dev,
 65                         "Cannot make room for the special tag. Dropping packet\n");
 66                 return NULL;
 67         }
 68 
 69         /* provide 'LAN9303_TAG_LEN' bytes additional space */
 70         skb_push(skb, LAN9303_TAG_LEN);
 71 
 72         /* make room between MACs and Ether-Type */
 73         memmove(skb->data, skb->data + LAN9303_TAG_LEN, 2 * ETH_ALEN);
 74 
 75         lan9303_tag = (u16 *)(skb->data + 2 * ETH_ALEN);
 76         lan9303_tag[0] = htons(ETH_P_8021Q);
 77         lan9303_tag[1] = lan9303_xmit_use_arl(dp, skb->data) ?
 78                                 LAN9303_TAG_TX_USE_ALR :
 79                                 dp->index | LAN9303_TAG_TX_STP_OVERRIDE;
 80         lan9303_tag[1] = htons(lan9303_tag[1]);
 81 
 82         return skb;
 83 }
 84 
 85 static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
 86                                    struct packet_type *pt)
 87 {
 88         u16 *lan9303_tag;
 89         u16 lan9303_tag1;
 90         unsigned int source_port;
 91 
 92         if (unlikely(!pskb_may_pull(skb, LAN9303_TAG_LEN))) {
 93                 dev_warn_ratelimited(&dev->dev,
 94                                      "Dropping packet, cannot pull\n");
 95                 return NULL;
 96         }
 97 
 98         /* '->data' points into the middle of our special VLAN tag information:
 99          *
100          * ~ MAC src   | 0x81 | 0x00 | 0xyy | 0xzz | ether type
101          *                           ^
102          *                        ->data
103          */
104         lan9303_tag = (u16 *)(skb->data - 2);
105 
106         if (lan9303_tag[0] != htons(ETH_P_8021Q)) {
107                 dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid VLAN marker\n");
108                 return NULL;
109         }
110 
111         lan9303_tag1 = ntohs(lan9303_tag[1]);
112         source_port = lan9303_tag1 & 0x3;
113 
114         skb->dev = dsa_master_find_slave(dev, 0, source_port);
115         if (!skb->dev) {
116                 dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n");
117                 return NULL;
118         }
119 
120         /* remove the special VLAN tag between the MAC addresses
121          * and the current ethertype field.
122          */
123         skb_pull_rcsum(skb, 2 + 2);
124         memmove(skb->data - ETH_HLEN, skb->data - (ETH_HLEN + LAN9303_TAG_LEN),
125                 2 * ETH_ALEN);
126         skb->offload_fwd_mark = !(lan9303_tag1 & LAN9303_TAG_RX_TRAPPED_TO_CPU);
127 
128         return skb;
129 }
130 
131 static const struct dsa_device_ops lan9303_netdev_ops = {
132         .name = "lan9303",
133         .proto  = DSA_TAG_PROTO_LAN9303,
134         .xmit = lan9303_xmit,
135         .rcv = lan9303_rcv,
136         .overhead = LAN9303_TAG_LEN,
137 };
138 
139 MODULE_LICENSE("GPL");
140 MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_LAN9303);
141 
142 module_dsa_tag_driver(lan9303_netdev_ops);
143 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp