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

~ [ 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