summaryrefslogtreecommitdiffstats
path: root/net/dsa
diff options
context:
space:
mode:
authorVladimir Oltean <olteanv@gmail.com>2019-06-08 08:04:29 -0400
committerDavid S. Miller <davem@davemloft.net>2019-06-08 18:20:39 -0400
commitd461933638ae9fa49ad22f60a40de5b3ed414912 (patch)
treeb64fade690f6cf9244260f0640e0e02a1065eb29 /net/dsa
parent5e3f847a02aabfecea519d7b2fd48f4d6f551be6 (diff)
net: dsa: tag_8021q: Create helper function for removing VLAN header
This removes the existing implementation from tag_sja1105, which was partially incorrect (it was not changing the MAC header offset, thereby leaving it to point 4 bytes earlier than it should have). This overwrites the VLAN tag by moving the Ethernet source and destination MACs 4 bytes to the right. Then skb->data (assumed to be pointing immediately after the EtherType) is temporarily pushed to the beginning of the new Ethernet header, the new Ethernet header offset and length are recorded, then skb->data is moved back to where it was. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dsa')
-rw-r--r--net/dsa/tag_8021q.c57
-rw-r--r--net/dsa/tag_sja1105.c19
2 files changed, 46 insertions, 30 deletions
diff --git a/net/dsa/tag_8021q.c b/net/dsa/tag_8021q.c
index 65a35e976d7b..6ebbd799c4eb 100644
--- a/net/dsa/tag_8021q.c
+++ b/net/dsa/tag_8021q.c
@@ -235,31 +235,48 @@ struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
235} 235}
236EXPORT_SYMBOL_GPL(dsa_8021q_xmit); 236EXPORT_SYMBOL_GPL(dsa_8021q_xmit);
237 237
238struct sk_buff *dsa_8021q_rcv(struct sk_buff *skb, struct net_device *netdev, 238/* In the DSA packet_type handler, skb->data points in the middle of the VLAN
239 struct packet_type *pt, u16 *tpid, u16 *tci) 239 * tag, after tpid and before tci. This is because so far, ETH_HLEN
240 * (DMAC, SMAC, EtherType) bytes were pulled.
241 * There are 2 bytes of VLAN tag left in skb->data, and upper
242 * layers expect the 'real' EtherType to be consumed as well.
243 * Coincidentally, a VLAN header is also of the same size as
244 * the number of bytes that need to be pulled.
245 *
246 * skb_mac_header skb->data
247 * | |
248 * v v
249 * | | | | | | | | | | | | | | | | | | |
250 * +-----------------------+-----------------------+-------+-------+-------+
251 * | Destination MAC | Source MAC | TPID | TCI | EType |
252 * +-----------------------+-----------------------+-------+-------+-------+
253 * ^ | |
254 * |<--VLAN_HLEN-->to <---VLAN_HLEN--->
255 * from |
256 * >>>>>>> v
257 * >>>>>>> | | | | | | | | | | | | | | |
258 * >>>>>>> +-----------------------+-----------------------+-------+
259 * >>>>>>> | Destination MAC | Source MAC | EType |
260 * +-----------------------+-----------------------+-------+
261 * ^ ^
262 * (now part of | |
263 * skb->head) skb_mac_header skb->data
264 */
265struct sk_buff *dsa_8021q_remove_header(struct sk_buff *skb)
240{ 266{
241 struct vlan_ethhdr *tag; 267 u8 *from = skb_mac_header(skb);
242 268 u8 *dest = from + VLAN_HLEN;
243 if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
244 return NULL;
245 269
246 tag = vlan_eth_hdr(skb); 270 memmove(dest, from, ETH_HLEN - VLAN_HLEN);
247 *tpid = ntohs(tag->h_vlan_proto); 271 skb_pull(skb, VLAN_HLEN);
248 *tci = ntohs(tag->h_vlan_TCI); 272 skb_push(skb, ETH_HLEN);
249 273 skb_reset_mac_header(skb);
250 /* skb->data points in the middle of the VLAN tag, 274 skb_reset_mac_len(skb);
251 * after tpid and before tci. This is because so far, 275 skb_pull_rcsum(skb, ETH_HLEN);
252 * ETH_HLEN (DMAC, SMAC, EtherType) bytes were pulled.
253 * There are 2 bytes of VLAN tag left in skb->data, and upper
254 * layers expect the 'real' EtherType to be consumed as well.
255 * Coincidentally, a VLAN header is also of the same size as
256 * the number of bytes that need to be pulled.
257 */
258 skb_pull_rcsum(skb, VLAN_HLEN);
259 276
260 return skb; 277 return skb;
261} 278}
262EXPORT_SYMBOL_GPL(dsa_8021q_rcv); 279EXPORT_SYMBOL_GPL(dsa_8021q_remove_header);
263 280
264static const struct dsa_device_ops dsa_8021q_netdev_ops = { 281static const struct dsa_device_ops dsa_8021q_netdev_ops = {
265 .name = "8021q", 282 .name = "8021q",
diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c
index d43737e6c3fb..77eeea004e92 100644
--- a/net/dsa/tag_sja1105.c
+++ b/net/dsa/tag_sja1105.c
@@ -66,17 +66,14 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
66 struct net_device *netdev, 66 struct net_device *netdev,
67 struct packet_type *pt) 67 struct packet_type *pt)
68{ 68{
69 struct ethhdr *hdr = eth_hdr(skb); 69 int source_port, switch_id;
70 u64 source_port, switch_id; 70 struct vlan_ethhdr *hdr;
71 struct sk_buff *nskb;
72 u16 tpid, vid, tci; 71 u16 tpid, vid, tci;
73 bool is_tagged; 72 bool is_tagged;
74 73
75 nskb = dsa_8021q_rcv(skb, netdev, pt, &tpid, &tci); 74 hdr = vlan_eth_hdr(skb);
76 is_tagged = (nskb && tpid == ETH_P_SJA1105); 75 tpid = ntohs(hdr->h_vlan_proto);
77 76 is_tagged = (tpid == ETH_P_SJA1105);
78 skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
79 vid = tci & VLAN_VID_MASK;
80 77
81 skb->offload_fwd_mark = 1; 78 skb->offload_fwd_mark = 1;
82 79
@@ -92,8 +89,11 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
92 hdr->h_dest[4] = 0; 89 hdr->h_dest[4] = 0;
93 } else { 90 } else {
94 /* Normal traffic path. */ 91 /* Normal traffic path. */
92 tci = ntohs(hdr->h_vlan_TCI);
93 vid = tci & VLAN_VID_MASK;
95 source_port = dsa_8021q_rx_source_port(vid); 94 source_port = dsa_8021q_rx_source_port(vid);
96 switch_id = dsa_8021q_rx_switch_id(vid); 95 switch_id = dsa_8021q_rx_switch_id(vid);
96 skb->priority = (tci & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
97 } 97 }
98 98
99 skb->dev = dsa_master_find_slave(netdev, switch_id, source_port); 99 skb->dev = dsa_master_find_slave(netdev, switch_id, source_port);
@@ -106,8 +106,7 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
106 * it there, see dsa_switch_rcv: skb_push(skb, ETH_HLEN). 106 * it there, see dsa_switch_rcv: skb_push(skb, ETH_HLEN).
107 */ 107 */
108 if (is_tagged) 108 if (is_tagged)
109 memmove(skb->data - ETH_HLEN, skb->data - ETH_HLEN - VLAN_HLEN, 109 skb = dsa_8021q_remove_header(skb);
110 ETH_HLEN - VLAN_HLEN);
111 110
112 return skb; 111 return skb;
113} 112}