diff options
author | Lennert Buytenhek <buytenh@wantstofly.org> | 2008-10-07 09:46:07 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-10-08 20:24:16 -0400 |
commit | 396138f03f4521c55ecc3a5dd75d4c56e6323244 (patch) | |
tree | 61dc43e540c861a4b05753da56a9fe2a19bea206 | |
parent | 2e5f032095ff101274dfb03d5fd5e06d9aeb83cd (diff) |
dsa: add support for Trailer tagging format
This adds support for the Trailer switch tagging format. This is
another tagging that doesn't explicitly mark tagged packets with a
distinct ethertype, so that we need to add a similar hack in the
receive path as for the Original DSA tagging format.
Signed-off-by: Lennert Buytenhek <buytenh@marvell.com>
Tested-by: Byron Bradley <byron.bbradley@gmail.com>
Tested-by: Tim Ellis <tim.ellis@mac.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/if_ether.h | 1 | ||||
-rw-r--r-- | include/linux/netdevice.h | 10 | ||||
-rw-r--r-- | include/net/dsa.h | 1 | ||||
-rw-r--r-- | net/dsa/Kconfig | 4 | ||||
-rw-r--r-- | net/dsa/Makefile | 1 | ||||
-rw-r--r-- | net/dsa/dsa.c | 7 | ||||
-rw-r--r-- | net/dsa/dsa_priv.h | 3 | ||||
-rw-r--r-- | net/dsa/slave.c | 5 | ||||
-rw-r--r-- | net/dsa/tag_trailer.c | 130 | ||||
-rw-r--r-- | net/ethernet/eth.c | 2 |
10 files changed, 164 insertions, 0 deletions
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h index 32b9dcda68c7..a0099e98b5c4 100644 --- a/include/linux/if_ether.h +++ b/include/linux/if_ether.h | |||
@@ -102,6 +102,7 @@ | |||
102 | #define ETH_P_HDLC 0x0019 /* HDLC frames */ | 102 | #define ETH_P_HDLC 0x0019 /* HDLC frames */ |
103 | #define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */ | 103 | #define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */ |
104 | #define ETH_P_DSA 0x001B /* Distributed Switch Arch. */ | 104 | #define ETH_P_DSA 0x001B /* Distributed Switch Arch. */ |
105 | #define ETH_P_TRAILER 0x001C /* Trailer switch tagging */ | ||
105 | #define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */ | 106 | #define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */ |
106 | 107 | ||
107 | /* | 108 | /* |
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index 97f0c64c152a..d3ea3de70a8a 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h | |||
@@ -812,6 +812,16 @@ static inline bool netdev_uses_dsa_tags(struct net_device *dev) | |||
812 | return 0; | 812 | return 0; |
813 | } | 813 | } |
814 | 814 | ||
815 | static inline bool netdev_uses_trailer_tags(struct net_device *dev) | ||
816 | { | ||
817 | #ifdef CONFIG_NET_DSA_TAG_TRAILER | ||
818 | if (dev->dsa_ptr != NULL) | ||
819 | return dsa_uses_trailer_tags(dev->dsa_ptr); | ||
820 | #endif | ||
821 | |||
822 | return 0; | ||
823 | } | ||
824 | |||
815 | /** | 825 | /** |
816 | * netdev_priv - access network device private data | 826 | * netdev_priv - access network device private data |
817 | * @dev: network device | 827 | * @dev: network device |
diff --git a/include/net/dsa.h b/include/net/dsa.h index 72e509b6a12e..52e97bfca5a1 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h | |||
@@ -31,6 +31,7 @@ struct dsa_platform_data { | |||
31 | }; | 31 | }; |
32 | 32 | ||
33 | extern bool dsa_uses_dsa_tags(void *dsa_ptr); | 33 | extern bool dsa_uses_dsa_tags(void *dsa_ptr); |
34 | extern bool dsa_uses_trailer_tags(void *dsa_ptr); | ||
34 | 35 | ||
35 | 36 | ||
36 | #endif | 37 | #endif |
diff --git a/net/dsa/Kconfig b/net/dsa/Kconfig index 79bcd76d3f10..505aa14e67fc 100644 --- a/net/dsa/Kconfig +++ b/net/dsa/Kconfig | |||
@@ -18,6 +18,10 @@ config NET_DSA_TAG_EDSA | |||
18 | bool | 18 | bool |
19 | default n | 19 | default n |
20 | 20 | ||
21 | config NET_DSA_TAG_TRAILER | ||
22 | bool | ||
23 | default n | ||
24 | |||
21 | 25 | ||
22 | # switch drivers | 26 | # switch drivers |
23 | config NET_DSA_MV88E6XXX | 27 | config NET_DSA_MV88E6XXX |
diff --git a/net/dsa/Makefile b/net/dsa/Makefile index 7fb6f85a69ed..63d3c44908b0 100644 --- a/net/dsa/Makefile +++ b/net/dsa/Makefile | |||
@@ -1,6 +1,7 @@ | |||
1 | # tagging formats | 1 | # tagging formats |
2 | obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o | 2 | obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o |
3 | obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o | 3 | obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o |
4 | obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o | ||
4 | 5 | ||
5 | # switch drivers | 6 | # switch drivers |
6 | obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o | 7 | obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o |
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c index f8c549281c30..33e99462023a 100644 --- a/net/dsa/dsa.c +++ b/net/dsa/dsa.c | |||
@@ -217,6 +217,13 @@ bool dsa_uses_dsa_tags(void *dsa_ptr) | |||
217 | return !!(ds->tag_protocol == htons(ETH_P_DSA)); | 217 | return !!(ds->tag_protocol == htons(ETH_P_DSA)); |
218 | } | 218 | } |
219 | 219 | ||
220 | bool dsa_uses_trailer_tags(void *dsa_ptr) | ||
221 | { | ||
222 | struct dsa_switch *ds = dsa_ptr; | ||
223 | |||
224 | return !!(ds->tag_protocol == htons(ETH_P_TRAILER)); | ||
225 | } | ||
226 | |||
220 | 227 | ||
221 | /* link polling *************************************************************/ | 228 | /* link polling *************************************************************/ |
222 | static void dsa_link_poll_work(struct work_struct *ugly) | 229 | static void dsa_link_poll_work(struct work_struct *ugly) |
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 2f1d68c495e8..7063378a1ebf 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h | |||
@@ -109,5 +109,8 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev); | |||
109 | /* tag_edsa.c */ | 109 | /* tag_edsa.c */ |
110 | int edsa_xmit(struct sk_buff *skb, struct net_device *dev); | 110 | int edsa_xmit(struct sk_buff *skb, struct net_device *dev); |
111 | 111 | ||
112 | /* tag_trailer.c */ | ||
113 | int trailer_xmit(struct sk_buff *skb, struct net_device *dev); | ||
114 | |||
112 | 115 | ||
113 | #endif | 116 | #endif |
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 8f8868dd4302..37616884b8a9 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c | |||
@@ -249,6 +249,11 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent, | |||
249 | slave_dev->hard_start_xmit = edsa_xmit; | 249 | slave_dev->hard_start_xmit = edsa_xmit; |
250 | break; | 250 | break; |
251 | #endif | 251 | #endif |
252 | #ifdef CONFIG_NET_DSA_TAG_TRAILER | ||
253 | case htons(ETH_P_TRAILER): | ||
254 | slave_dev->hard_start_xmit = trailer_xmit; | ||
255 | break; | ||
256 | #endif | ||
252 | default: | 257 | default: |
253 | BUG(); | 258 | BUG(); |
254 | } | 259 | } |
diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c new file mode 100644 index 000000000000..d3117764b2c2 --- /dev/null +++ b/net/dsa/tag_trailer.c | |||
@@ -0,0 +1,130 @@ | |||
1 | /* | ||
2 | * net/dsa/tag_trailer.c - Trailer tag format handling | ||
3 | * Copyright (c) 2008 Marvell Semiconductor | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. | ||
9 | */ | ||
10 | |||
11 | #include <linux/etherdevice.h> | ||
12 | #include <linux/list.h> | ||
13 | #include <linux/netdevice.h> | ||
14 | #include "dsa_priv.h" | ||
15 | |||
16 | int trailer_xmit(struct sk_buff *skb, struct net_device *dev) | ||
17 | { | ||
18 | struct dsa_slave_priv *p = netdev_priv(dev); | ||
19 | struct sk_buff *nskb; | ||
20 | int padlen; | ||
21 | u8 *trailer; | ||
22 | |||
23 | dev->stats.tx_packets++; | ||
24 | dev->stats.tx_bytes += skb->len; | ||
25 | |||
26 | /* | ||
27 | * We have to make sure that the trailer ends up as the very | ||
28 | * last 4 bytes of the packet. This means that we have to pad | ||
29 | * the packet to the minimum ethernet frame size, if necessary, | ||
30 | * before adding the trailer. | ||
31 | */ | ||
32 | padlen = 0; | ||
33 | if (skb->len < 60) | ||
34 | padlen = 60 - skb->len; | ||
35 | |||
36 | nskb = alloc_skb(NET_IP_ALIGN + skb->len + padlen + 4, GFP_ATOMIC); | ||
37 | if (nskb == NULL) { | ||
38 | kfree_skb(skb); | ||
39 | return NETDEV_TX_OK; | ||
40 | } | ||
41 | skb_reserve(nskb, NET_IP_ALIGN); | ||
42 | |||
43 | skb_reset_mac_header(nskb); | ||
44 | skb_set_network_header(nskb, skb_network_header(skb) - skb->head); | ||
45 | skb_set_transport_header(nskb, skb_transport_header(skb) - skb->head); | ||
46 | skb_copy_and_csum_dev(skb, skb_put(nskb, skb->len)); | ||
47 | kfree_skb(skb); | ||
48 | |||
49 | if (padlen) { | ||
50 | u8 *pad = skb_put(nskb, padlen); | ||
51 | memset(pad, 0, padlen); | ||
52 | } | ||
53 | |||
54 | trailer = skb_put(nskb, 4); | ||
55 | trailer[0] = 0x80; | ||
56 | trailer[1] = 1 << p->port; | ||
57 | trailer[2] = 0x10; | ||
58 | trailer[3] = 0x00; | ||
59 | |||
60 | nskb->protocol = htons(ETH_P_TRAILER); | ||
61 | |||
62 | nskb->dev = p->parent->master_netdev; | ||
63 | dev_queue_xmit(nskb); | ||
64 | |||
65 | return NETDEV_TX_OK; | ||
66 | } | ||
67 | |||
68 | static int trailer_rcv(struct sk_buff *skb, struct net_device *dev, | ||
69 | struct packet_type *pt, struct net_device *orig_dev) | ||
70 | { | ||
71 | struct dsa_switch *ds = dev->dsa_ptr; | ||
72 | u8 *trailer; | ||
73 | int source_port; | ||
74 | |||
75 | if (unlikely(ds == NULL)) | ||
76 | goto out_drop; | ||
77 | |||
78 | skb = skb_unshare(skb, GFP_ATOMIC); | ||
79 | if (skb == NULL) | ||
80 | goto out; | ||
81 | |||
82 | if (skb_linearize(skb)) | ||
83 | goto out_drop; | ||
84 | |||
85 | trailer = skb_tail_pointer(skb) - 4; | ||
86 | if (trailer[0] != 0x80 || (trailer[1] & 0xf8) != 0x00 || | ||
87 | (trailer[3] & 0xef) != 0x00 || trailer[3] != 0x00) | ||
88 | goto out_drop; | ||
89 | |||
90 | source_port = trailer[1] & 7; | ||
91 | if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) | ||
92 | goto out_drop; | ||
93 | |||
94 | pskb_trim_rcsum(skb, skb->len - 4); | ||
95 | |||
96 | skb->dev = ds->ports[source_port]; | ||
97 | skb_push(skb, ETH_HLEN); | ||
98 | skb->protocol = eth_type_trans(skb, skb->dev); | ||
99 | |||
100 | skb->dev->last_rx = jiffies; | ||
101 | skb->dev->stats.rx_packets++; | ||
102 | skb->dev->stats.rx_bytes += skb->len; | ||
103 | |||
104 | netif_receive_skb(skb); | ||
105 | |||
106 | return 0; | ||
107 | |||
108 | out_drop: | ||
109 | kfree_skb(skb); | ||
110 | out: | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static struct packet_type trailer_packet_type = { | ||
115 | .type = __constant_htons(ETH_P_TRAILER), | ||
116 | .func = trailer_rcv, | ||
117 | }; | ||
118 | |||
119 | static int __init trailer_init_module(void) | ||
120 | { | ||
121 | dev_add_pack(&trailer_packet_type); | ||
122 | return 0; | ||
123 | } | ||
124 | module_init(trailer_init_module); | ||
125 | |||
126 | static void __exit trailer_cleanup_module(void) | ||
127 | { | ||
128 | dev_remove_pack(&trailer_packet_type); | ||
129 | } | ||
130 | module_exit(trailer_cleanup_module); | ||
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index dae47e7a44d8..b9d85af2dd31 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c | |||
@@ -193,6 +193,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) | |||
193 | */ | 193 | */ |
194 | if (netdev_uses_dsa_tags(dev)) | 194 | if (netdev_uses_dsa_tags(dev)) |
195 | return htons(ETH_P_DSA); | 195 | return htons(ETH_P_DSA); |
196 | if (netdev_uses_trailer_tags(dev)) | ||
197 | return htons(ETH_P_TRAILER); | ||
196 | 198 | ||
197 | if (ntohs(eth->h_proto) >= 1536) | 199 | if (ntohs(eth->h_proto) >= 1536) |
198 | return eth->h_proto; | 200 | return eth->h_proto; |