Skip to content

Commit e8fe177

Browse files
jbeptxdavem330
authored andcommitted
net: dsa: add support for the SMSC-LAN9303 tagging format
To define the outgoing port and to discover the incoming port a regular VLAN tag is used by the LAN9303. But its VID meaning is 'special'. This tag handler/filter depends on some hardware features which must be enabled in the device to provide and make use of this special VLAN tag to control the destination and the source of an ethernet packet. Signed-off-by: Juergen Borleis <[email protected]> Reviewed-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 8dc7d11 commit e8fe177

File tree

6 files changed

+153
-0
lines changed

6 files changed

+153
-0
lines changed

include/net/dsa.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ enum dsa_tag_protocol {
3333
DSA_TAG_PROTO_BRCM,
3434
DSA_TAG_PROTO_QCA,
3535
DSA_TAG_PROTO_MTK,
36+
DSA_TAG_PROTO_LAN9303,
3637
DSA_TAG_LAST, /* MUST BE LAST */
3738
};
3839

net/dsa/Kconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,8 @@ config NET_DSA_TAG_QCA
3333

3434
config NET_DSA_TAG_MTK
3535
bool
36+
37+
config NET_DSA_TAG_LAN9303
38+
bool
39+
3640
endif

net/dsa/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ dsa_core-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
99
dsa_core-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
1010
dsa_core-$(CONFIG_NET_DSA_TAG_QCA) += tag_qca.o
1111
dsa_core-$(CONFIG_NET_DSA_TAG_MTK) += tag_mtk.o
12+
dsa_core-$(CONFIG_NET_DSA_TAG_LAN9303) += tag_lan9303.o

net/dsa/dsa.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ const struct dsa_device_ops *dsa_device_ops[DSA_TAG_LAST] = {
5757
#endif
5858
#ifdef CONFIG_NET_DSA_TAG_MTK
5959
[DSA_TAG_PROTO_MTK] = &mtk_netdev_ops,
60+
#endif
61+
#ifdef CONFIG_NET_DSA_TAG_LAN9303
62+
[DSA_TAG_PROTO_LAN9303] = &lan9303_netdev_ops,
6063
#endif
6164
[DSA_TAG_PROTO_NONE] = &none_ops,
6265
};

net/dsa/dsa_priv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,7 @@ extern const struct dsa_device_ops qca_netdev_ops;
9393
/* tag_mtk.c */
9494
extern const struct dsa_device_ops mtk_netdev_ops;
9595

96+
/* tag_lan9303.c */
97+
extern const struct dsa_device_ops lan9303_netdev_ops;
98+
9699
#endif

net/dsa/tag_lan9303.c

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
/*
2+
* Copyright (C) 2017 Pengutronix, Juergen Borleis <[email protected]>
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/etherdevice.h>
15+
#include <linux/list.h>
16+
#include <linux/slab.h>
17+
#include <net/dsa.h>
18+
#include "dsa_priv.h"
19+
20+
/* To define the outgoing port and to discover the incoming port a regular
21+
* VLAN tag is used by the LAN9303. But its VID meaning is 'special':
22+
*
23+
* Dest MAC Src MAC TAG Type
24+
* ...| 1 2 3 4 5 6 | 1 2 3 4 5 6 | 1 2 3 4 | 1 2 |...
25+
* |<------->|
26+
* TAG:
27+
* |<------------->|
28+
* | 1 2 | 3 4 |
29+
* TPID VID
30+
* 0x8100
31+
*
32+
* VID bit 3 indicates a request for an ALR lookup.
33+
*
34+
* If VID bit 3 is zero, then bits 0 and 1 specify the destination port
35+
* (0, 1, 2) or broadcast (3) or the source port (1, 2).
36+
*
37+
* VID bit 4 is used to specify if the STP port state should be overridden.
38+
* Required when no forwarding between the external ports should happen.
39+
*/
40+
41+
#define LAN9303_TAG_LEN 4
42+
#define LAN9303_MAX_PORTS 3
43+
44+
static struct sk_buff *lan9303_xmit(struct sk_buff *skb, struct net_device *dev)
45+
{
46+
struct dsa_slave_priv *p = netdev_priv(dev);
47+
u16 *lan9303_tag;
48+
49+
/* insert a special VLAN tag between the MAC addresses
50+
* and the current ethertype field.
51+
*/
52+
if (skb_cow_head(skb, LAN9303_TAG_LEN) < 0) {
53+
dev_dbg(&dev->dev,
54+
"Cannot make room for the special tag. Dropping packet\n");
55+
goto out_free;
56+
}
57+
58+
/* provide 'LAN9303_TAG_LEN' bytes additional space */
59+
skb_push(skb, LAN9303_TAG_LEN);
60+
61+
/* make room between MACs and Ether-Type */
62+
memmove(skb->data, skb->data + LAN9303_TAG_LEN, 2 * ETH_ALEN);
63+
64+
lan9303_tag = (u16 *)(skb->data + 2 * ETH_ALEN);
65+
lan9303_tag[0] = htons(ETH_P_8021Q);
66+
lan9303_tag[1] = htons(p->dp->index | BIT(4));
67+
68+
return skb;
69+
out_free:
70+
kfree_skb(skb);
71+
return NULL;
72+
}
73+
74+
static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
75+
struct packet_type *pt, struct net_device *orig_dev)
76+
{
77+
u16 *lan9303_tag;
78+
struct dsa_switch_tree *dst = dev->dsa_ptr;
79+
struct dsa_switch *ds;
80+
unsigned int source_port;
81+
82+
if (unlikely(!dst)) {
83+
dev_warn_ratelimited(&dev->dev, "Dropping packet, due to missing switch tree device\n");
84+
return NULL;
85+
}
86+
87+
ds = dst->ds[0];
88+
89+
if (unlikely(!ds)) {
90+
dev_warn_ratelimited(&dev->dev, "Dropping packet, due to missing DSA switch device\n");
91+
return NULL;
92+
}
93+
94+
if (unlikely(!pskb_may_pull(skb, LAN9303_TAG_LEN))) {
95+
dev_warn_ratelimited(&dev->dev,
96+
"Dropping packet, cannot pull\n");
97+
return NULL;
98+
}
99+
100+
/* '->data' points into the middle of our special VLAN tag information:
101+
*
102+
* ~ MAC src | 0x81 | 0x00 | 0xyy | 0xzz | ether type
103+
* ^
104+
* ->data
105+
*/
106+
lan9303_tag = (u16 *)(skb->data - 2);
107+
108+
if (lan9303_tag[0] != htons(ETH_P_8021Q)) {
109+
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid VLAN marker\n");
110+
return NULL;
111+
}
112+
113+
source_port = ntohs(lan9303_tag[1]) & 0x3;
114+
115+
if (source_port >= LAN9303_MAX_PORTS) {
116+
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid source port\n");
117+
return NULL;
118+
}
119+
120+
if (!ds->ports[source_port].netdev) {
121+
dev_warn_ratelimited(&dev->dev, "Dropping packet due to invalid netdev or device\n");
122+
return NULL;
123+
}
124+
125+
/* remove the special VLAN tag between the MAC addresses
126+
* and the current ethertype field.
127+
*/
128+
skb_pull_rcsum(skb, 2 + 2);
129+
memmove(skb->data - ETH_HLEN, skb->data - (ETH_HLEN + LAN9303_TAG_LEN),
130+
2 * ETH_ALEN);
131+
132+
/* forward the packet to the dedicated interface */
133+
skb->dev = ds->ports[source_port].netdev;
134+
135+
return skb;
136+
}
137+
138+
const struct dsa_device_ops lan9303_netdev_ops = {
139+
.xmit = lan9303_xmit,
140+
.rcv = lan9303_rcv,
141+
};

0 commit comments

Comments
 (0)