Blame view
net/dsa/tag_edsa.c
5.3 KB
91da11f87 net: Distributed ... |
1 2 |
/* * net/dsa/tag_edsa.c - Ethertype DSA tagging |
e84665c9c dsa: add switch c... |
3 |
* Copyright (c) 2008-2009 Marvell Semiconductor |
91da11f87 net: Distributed ... |
4 5 6 7 8 9 10 11 12 13 |
* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ #include <linux/etherdevice.h> #include <linux/list.h> #include <linux/netdevice.h> |
5a0e3ad6a include cleanup: ... |
14 |
#include <linux/slab.h> |
91da11f87 net: Distributed ... |
15 16 17 18 |
#include "dsa_priv.h" #define DSA_HLEN 4 #define EDSA_HLEN 8 |
6fef4c0c8 netdev: convert p... |
19 |
netdev_tx_t edsa_xmit(struct sk_buff *skb, struct net_device *dev) |
91da11f87 net: Distributed ... |
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
{ struct dsa_slave_priv *p = netdev_priv(dev); u8 *edsa_header; dev->stats.tx_packets++; dev->stats.tx_bytes += skb->len; /* * Convert the outermost 802.1q tag to a DSA tag and prepend * a DSA ethertype field is the packet is tagged, or insert * a DSA ethertype plus DSA tag between the addresses and the * current ethertype field if the packet is untagged. */ if (skb->protocol == htons(ETH_P_8021Q)) { if (skb_cow_head(skb, DSA_HLEN) < 0) goto out_free; skb_push(skb, DSA_HLEN); memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN); /* * Construct tagged FROM_CPU DSA tag from 802.1q tag. */ edsa_header = skb->data + 2 * ETH_ALEN; edsa_header[0] = (ETH_P_EDSA >> 8) & 0xff; edsa_header[1] = ETH_P_EDSA & 0xff; edsa_header[2] = 0x00; edsa_header[3] = 0x00; |
e84665c9c dsa: add switch c... |
48 |
edsa_header[4] = 0x60 | p->parent->index; |
91da11f87 net: Distributed ... |
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
edsa_header[5] = p->port << 3; /* * Move CFI field from byte 6 to byte 5. */ if (edsa_header[6] & 0x10) { edsa_header[5] |= 0x01; edsa_header[6] &= ~0x10; } } else { if (skb_cow_head(skb, EDSA_HLEN) < 0) goto out_free; skb_push(skb, EDSA_HLEN); memmove(skb->data, skb->data + EDSA_HLEN, 2 * ETH_ALEN); /* * Construct untagged FROM_CPU DSA tag. */ edsa_header = skb->data + 2 * ETH_ALEN; edsa_header[0] = (ETH_P_EDSA >> 8) & 0xff; edsa_header[1] = ETH_P_EDSA & 0xff; edsa_header[2] = 0x00; edsa_header[3] = 0x00; |
e84665c9c dsa: add switch c... |
73 |
edsa_header[4] = 0x40 | p->parent->index; |
91da11f87 net: Distributed ... |
74 75 76 77 78 79 |
edsa_header[5] = p->port << 3; edsa_header[6] = 0x00; edsa_header[7] = 0x00; } skb->protocol = htons(ETH_P_EDSA); |
e84665c9c dsa: add switch c... |
80 |
skb->dev = p->parent->dst->master_netdev; |
91da11f87 net: Distributed ... |
81 82 83 84 85 86 87 88 89 90 91 92 |
dev_queue_xmit(skb); return NETDEV_TX_OK; out_free: kfree_skb(skb); return NETDEV_TX_OK; } static int edsa_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev) { |
e84665c9c dsa: add switch c... |
93 94 |
struct dsa_switch_tree *dst = dev->dsa_ptr; struct dsa_switch *ds; |
91da11f87 net: Distributed ... |
95 |
u8 *edsa_header; |
e84665c9c dsa: add switch c... |
96 |
int source_device; |
91da11f87 net: Distributed ... |
97 |
int source_port; |
e84665c9c dsa: add switch c... |
98 |
if (unlikely(dst == NULL)) |
91da11f87 net: Distributed ... |
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
goto out_drop; skb = skb_unshare(skb, GFP_ATOMIC); if (skb == NULL) goto out; if (unlikely(!pskb_may_pull(skb, EDSA_HLEN))) goto out_drop; /* * Skip the two null bytes after the ethertype. */ edsa_header = skb->data + 2; /* |
e84665c9c dsa: add switch c... |
114 |
* Check that frame type is either TO_CPU or FORWARD. |
91da11f87 net: Distributed ... |
115 |
*/ |
e84665c9c dsa: add switch c... |
116 |
if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0) |
91da11f87 net: Distributed ... |
117 118 119 |
goto out_drop; /* |
e84665c9c dsa: add switch c... |
120 |
* Determine source device and port. |
91da11f87 net: Distributed ... |
121 |
*/ |
e84665c9c dsa: add switch c... |
122 |
source_device = edsa_header[0] & 0x1f; |
91da11f87 net: Distributed ... |
123 |
source_port = (edsa_header[1] >> 3) & 0x1f; |
e84665c9c dsa: add switch c... |
124 125 126 127 128 129 130 131 |
/* * Check that the source device exists and that the source * port is a registered DSA port. */ if (source_device >= dst->pd->nr_chips) goto out_drop; ds = dst->ds[source_device]; |
91da11f87 net: Distributed ... |
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL) goto out_drop; /* * If the 'tagged' bit is set, convert the DSA tag to a 802.1q * tag and delete the ethertype part. If the 'tagged' bit is * clear, delete the ethertype and the DSA tag parts. */ if (edsa_header[0] & 0x20) { u8 new_header[4]; /* * Insert 802.1q ethertype and copy the VLAN-related * fields, but clear the bit that will hold CFI (since * DSA uses that bit location for another purpose). */ new_header[0] = (ETH_P_8021Q >> 8) & 0xff; new_header[1] = ETH_P_8021Q & 0xff; new_header[2] = edsa_header[2] & ~0x10; new_header[3] = edsa_header[3]; /* * Move CFI bit from its place in the DSA header to * its 802.1q-designated place. */ if (edsa_header[1] & 0x01) new_header[2] |= 0x10; skb_pull_rcsum(skb, DSA_HLEN); /* * Update packet checksum if skb is CHECKSUM_COMPLETE. */ if (skb->ip_summed == CHECKSUM_COMPLETE) { __wsum c = skb->csum; c = csum_add(c, csum_partial(new_header + 2, 2, 0)); c = csum_sub(c, csum_partial(edsa_header + 2, 2, 0)); skb->csum = c; } memcpy(edsa_header, new_header, DSA_HLEN); memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - DSA_HLEN, 2 * ETH_ALEN); } else { /* * Remove DSA tag and update checksum. */ skb_pull_rcsum(skb, EDSA_HLEN); memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - EDSA_HLEN, 2 * ETH_ALEN); } skb->dev = ds->ports[source_port]; skb_push(skb, ETH_HLEN); |
14ee6742b dsa: fix skb->pkt... |
189 |
skb->pkt_type = PACKET_HOST; |
91da11f87 net: Distributed ... |
190 |
skb->protocol = eth_type_trans(skb, skb->dev); |
91da11f87 net: Distributed ... |
191 192 193 194 195 196 197 198 199 200 201 202 |
skb->dev->stats.rx_packets++; skb->dev->stats.rx_bytes += skb->len; netif_receive_skb(skb); return 0; out_drop: kfree_skb(skb); out: return 0; } |
7546dd97d net: convert usag... |
203 |
static struct packet_type edsa_packet_type __read_mostly = { |
09640e636 net: replace uses... |
204 |
.type = cpu_to_be16(ETH_P_EDSA), |
91da11f87 net: Distributed ... |
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
.func = edsa_rcv, }; static int __init edsa_init_module(void) { dev_add_pack(&edsa_packet_type); return 0; } module_init(edsa_init_module); static void __exit edsa_cleanup_module(void) { dev_remove_pack(&edsa_packet_type); } module_exit(edsa_cleanup_module); |