Blame view

net/dsa/tag_dsa.c 3.73 KB
dfedd3b62   Andrew Lunn   dsa: Add SPDX hea...
1
  // SPDX-License-Identifier: GPL-2.0+
cf85d08fd   Lennert Buytenhek   dsa: add support ...
2
3
  /*
   * net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging
e84665c9c   Lennert Buytenhek   dsa: add switch c...
4
   * Copyright (c) 2008-2009 Marvell Semiconductor
cf85d08fd   Lennert Buytenhek   dsa: add support ...
5
6
7
8
   */
  
  #include <linux/etherdevice.h>
  #include <linux/list.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
9
  #include <linux/slab.h>
ea5dd34be   Vivien Didelot   net: dsa: include...
10

cf85d08fd   Lennert Buytenhek   dsa: add support ...
11
12
13
  #include "dsa_priv.h"
  
  #define DSA_HLEN	4
4ed70ce9f   Florian Fainelli   net: dsa: Refacto...
14
  static struct sk_buff *dsa_xmit(struct sk_buff *skb, struct net_device *dev)
cf85d08fd   Lennert Buytenhek   dsa: add support ...
15
  {
d945097bb   Vivien Didelot   net: dsa: add sla...
16
  	struct dsa_port *dp = dsa_slave_to_port(dev);
cf85d08fd   Lennert Buytenhek   dsa: add support ...
17
  	u8 *dsa_header;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
18
19
20
21
22
23
24
  	/*
  	 * Convert the outermost 802.1q tag to a DSA tag for tagged
  	 * packets, or insert a DSA tag between the addresses and
  	 * the ethertype field for untagged packets.
  	 */
  	if (skb->protocol == htons(ETH_P_8021Q)) {
  		if (skb_cow_head(skb, 0) < 0)
fe47d5630   Vivien Didelot   net: dsa: factor ...
25
  			return NULL;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
26
27
28
29
30
  
  		/*
  		 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
  		 */
  		dsa_header = skb->data + 2 * ETH_ALEN;
d945097bb   Vivien Didelot   net: dsa: add sla...
31
32
  		dsa_header[0] = 0x60 | dp->ds->index;
  		dsa_header[1] = dp->index << 3;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
33
34
35
36
37
38
39
40
41
42
  
  		/*
  		 * Move CFI field from byte 2 to byte 1.
  		 */
  		if (dsa_header[2] & 0x10) {
  			dsa_header[1] |= 0x01;
  			dsa_header[2] &= ~0x10;
  		}
  	} else {
  		if (skb_cow_head(skb, DSA_HLEN) < 0)
fe47d5630   Vivien Didelot   net: dsa: factor ...
43
  			return NULL;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
44
45
46
47
48
49
50
51
  		skb_push(skb, DSA_HLEN);
  
  		memmove(skb->data, skb->data + DSA_HLEN, 2 * ETH_ALEN);
  
  		/*
  		 * Construct untagged FROM_CPU DSA tag.
  		 */
  		dsa_header = skb->data + 2 * ETH_ALEN;
d945097bb   Vivien Didelot   net: dsa: add sla...
52
53
  		dsa_header[0] = 0x40 | dp->ds->index;
  		dsa_header[1] = dp->index << 3;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
54
55
56
  		dsa_header[2] = 0x00;
  		dsa_header[3] = 0x00;
  	}
4ed70ce9f   Florian Fainelli   net: dsa: Refacto...
57
  	return skb;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
58
  }
a86d8becc   Florian Fainelli   net: dsa: Factor ...
59
  static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
89e49506b   Florian Westphal   dsa: remove unuse...
60
  			       struct packet_type *pt)
cf85d08fd   Lennert Buytenhek   dsa: add support ...
61
  {
cf85d08fd   Lennert Buytenhek   dsa: add support ...
62
  	u8 *dsa_header;
e84665c9c   Lennert Buytenhek   dsa: add switch c...
63
  	int source_device;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
64
  	int source_port;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
65
  	if (unlikely(!pskb_may_pull(skb, DSA_HLEN)))
547097958   Vivien Didelot   net: dsa: remove ...
66
  		return NULL;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
67
68
69
70
71
72
73
  
  	/*
  	 * The ethertype field is part of the DSA header.
  	 */
  	dsa_header = skb->data - 2;
  
  	/*
e84665c9c   Lennert Buytenhek   dsa: add switch c...
74
  	 * Check that frame type is either TO_CPU or FORWARD.
cf85d08fd   Lennert Buytenhek   dsa: add support ...
75
  	 */
e84665c9c   Lennert Buytenhek   dsa: add switch c...
76
  	if ((dsa_header[0] & 0xc0) != 0x00 && (dsa_header[0] & 0xc0) != 0xc0)
547097958   Vivien Didelot   net: dsa: remove ...
77
  		return NULL;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
78
79
  
  	/*
e84665c9c   Lennert Buytenhek   dsa: add switch c...
80
  	 * Determine source device and port.
cf85d08fd   Lennert Buytenhek   dsa: add support ...
81
  	 */
e84665c9c   Lennert Buytenhek   dsa: add switch c...
82
  	source_device = dsa_header[0] & 0x1f;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
83
  	source_port = (dsa_header[1] >> 3) & 0x1f;
e84665c9c   Lennert Buytenhek   dsa: add switch c...
84

2231c43b5   Vivien Didelot   net: dsa: rename ...
85
  	skb->dev = dsa_master_find_slave(dev, source_device, source_port);
3775b1b7f   Vivien Didelot   net: dsa: add mas...
86
  	if (!skb->dev)
547097958   Vivien Didelot   net: dsa: remove ...
87
  		return NULL;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  
  	/*
  	 * Convert the DSA header to an 802.1q header if the 'tagged'
  	 * bit in the DSA header is set.  If the 'tagged' bit is clear,
  	 * delete the DSA header entirely.
  	 */
  	if (dsa_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] = dsa_header[2] & ~0x10;
  		new_header[3] = dsa_header[3];
  
  		/*
  		 * Move CFI bit from its place in the DSA header to
  		 * its 802.1q-designated place.
  		 */
  		if (dsa_header[1] & 0x01)
  			new_header[2] |= 0x10;
  
  		/*
  		 * 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(dsa_header + 2, 2, 0));
  			skb->csum = c;
  		}
  
  		memcpy(dsa_header, new_header, DSA_HLEN);
  	} else {
  		/*
  		 * Remove DSA tag and update checksum.
  		 */
  		skb_pull_rcsum(skb, DSA_HLEN);
  		memmove(skb->data - ETH_HLEN,
  			skb->data - ETH_HLEN - DSA_HLEN,
  			2 * ETH_ALEN);
  	}
13edbdb6e   Andrew Lunn   net: dsa: {e}dsa:...
134
  	skb->offload_fwd_mark = 1;
a86d8becc   Florian Fainelli   net: dsa: Factor ...
135
  	return skb;
cf85d08fd   Lennert Buytenhek   dsa: add support ...
136
  }
57fd96783   Rundong Ge   net: dsa: Impleme...
137
138
139
140
141
142
143
  static int dsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
  				int *offset)
  {
  	*offset = 4;
  	*proto = ((__be16 *)skb->data)[1];
  	return 0;
  }
f81a43e8d   Andrew Lunn   dsa: Cleanup unne...
144
  static const struct dsa_device_ops dsa_netdev_ops = {
875138f81   Andrew Lunn   dsa: Move tagger ...
145
  	.name	= "dsa",
056eed2fb   Andrew Lunn   dsa: Add TAG prot...
146
  	.proto	= DSA_TAG_PROTO_DSA,
3e8a72d1d   Florian Fainelli   net: dsa: reduce ...
147
148
  	.xmit	= dsa_xmit,
  	.rcv	= dsa_rcv,
57fd96783   Rundong Ge   net: dsa: Impleme...
149
  	.flow_dissect   = dsa_tag_flow_dissect,
a5dd30877   Andrew Lunn   net: dsa: Add ove...
150
  	.overhead = DSA_HLEN,
cf85d08fd   Lennert Buytenhek   dsa: add support ...
151
  };
0b42f0336   Andrew Lunn   dsa: Add MODULE_A...
152

f18bba50d   Andrew Lunn   dsa: Add MODULE_L...
153
  MODULE_LICENSE("GPL");
0b42f0336   Andrew Lunn   dsa: Add MODULE_A...
154
  MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_DSA);
d3b8c0498   Andrew Lunn   dsa: Add boilerpl...
155
156
  
  module_dsa_tag_driver(dsa_netdev_ops);