Commit 396138f03f4521c55ecc3a5dd75d4c56e6323244

Authored by Lennert Buytenhek
Committed by David S. Miller
1 parent 2e5f032095

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>

Showing 10 changed files with 164 additions and 0 deletions Side-by-side Diff

include/linux/if_ether.h
... ... @@ -102,6 +102,7 @@
102 102 #define ETH_P_HDLC 0x0019 /* HDLC frames */
103 103 #define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */
104 104 #define ETH_P_DSA 0x001B /* Distributed Switch Arch. */
  105 +#define ETH_P_TRAILER 0x001C /* Trailer switch tagging */
105 106 #define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */
106 107  
107 108 /*
include/linux/netdevice.h
... ... @@ -812,6 +812,16 @@
812 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 826 * netdev_priv - access network device private data
817 827 * @dev: network device
... ... @@ -31,6 +31,7 @@
31 31 };
32 32  
33 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 37 #endif
... ... @@ -18,6 +18,10 @@
18 18 bool
19 19 default n
20 20  
  21 +config NET_DSA_TAG_TRAILER
  22 + bool
  23 + default n
  24 +
21 25  
22 26 # switch drivers
23 27 config NET_DSA_MV88E6XXX
1 1 # tagging formats
2 2 obj-$(CONFIG_NET_DSA_TAG_DSA) += tag_dsa.o
3 3 obj-$(CONFIG_NET_DSA_TAG_EDSA) += tag_edsa.o
  4 +obj-$(CONFIG_NET_DSA_TAG_TRAILER) += tag_trailer.o
4 5  
5 6 # switch drivers
6 7 obj-$(CONFIG_NET_DSA_MV88E6XXX) += mv88e6xxx.o
... ... @@ -217,6 +217,13 @@
217 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 228 /* link polling *************************************************************/
222 229 static void dsa_link_poll_work(struct work_struct *ugly)
... ... @@ -109,6 +109,9 @@
109 109 /* tag_edsa.c */
110 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 116 #endif
... ... @@ -249,6 +249,11 @@
249 249 slave_dev->hard_start_xmit = edsa_xmit;
250 250 break;
251 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 257 default:
253 258 BUG();
254 259 }
net/dsa/tag_trailer.c
  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);
... ... @@ -193,6 +193,8 @@
193 193 */
194 194 if (netdev_uses_dsa_tags(dev))
195 195 return htons(ETH_P_DSA);
  196 + if (netdev_uses_trailer_tags(dev))
  197 + return htons(ETH_P_TRAILER);
196 198  
197 199 if (ntohs(eth->h_proto) >= 1536)
198 200 return eth->h_proto;