lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 11 May 2020 23:20:46 +0300
From:   Vladimir Oltean <olteanv@...il.com>
To:     andrew@...n.ch, f.fainelli@...il.com, vivien.didelot@...il.com
Cc:     davem@...emloft.net, kuba@...nel.org, netdev@...r.kernel.org
Subject: [PATCH net-next 4/4] net: dsa: implement and use a generic procedure for the flow dissector

From: Vladimir Oltean <vladimir.oltean@....com>

For all DSA formats that don't use tail tags, it looks like behind the
obscure number crunching they're all doing the same thing: locating the
real EtherType behind the DSA tag. Nonetheless, this is not immediately
obvious, so create a generic helper for those DSA taggers that put the
header before the EtherType.

Another assumption for the generic function is that the DSA tags are of
equal length on RX and on TX. Prior to the previous patch, this was not
true for ocelot and for gswip. The problem was resolved for ocelot, but
for gswip it still remains, so that hasn't been converted.

Signed-off-by: Vladimir Oltean <vladimir.oltean@....com>
---
 net/dsa/dsa_priv.h    | 22 ++++++++++++++++++++++
 net/dsa/tag_ar9331.c  |  9 +++++++++
 net/dsa/tag_brcm.c    |  5 +++--
 net/dsa/tag_dsa.c     |  4 ++--
 net/dsa/tag_edsa.c    |  4 ++--
 net/dsa/tag_lan9303.c |  9 +++++++++
 net/dsa/tag_mtk.c     |  3 +--
 net/dsa/tag_ocelot.c  |  9 +++++++++
 net/dsa/tag_qca.c     |  3 +--
 net/dsa/tag_sja1105.c | 13 +++++++++++++
 10 files changed, 71 insertions(+), 10 deletions(-)

diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index a1a0ae242012..cad276ff28d1 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -195,6 +195,28 @@ dsa_slave_to_master(const struct net_device *dev)
 	return dp->cpu_dp->master;
 }
 
+/* All DSA tags that push the EtherType to the right (basically all except tail
+ * tags, which don't break dissection) can be treated the same from the
+ * perspective of the flow dissector.
+ *
+ * We need to return:
+ *  - offset: the (B - A) difference between:
+ *    A. the position of the real EtherType and
+ *    B. the current skb->data (aka ETH_HLEN bytes into the frame, aka 2 bytes
+ *       after the normal EtherType was supposed to be)
+ *    The offset in bytes is exactly equal to the tagger overhead (and half of
+ *    that, in __be16 shorts).
+ *
+ *  - proto: the value of the real EtherType.
+ */
+static inline void dsa_tag_generic_flow_dissect(const struct sk_buff *skb,
+						__be16 *proto, int *offset,
+						int tag_len)
+{
+	*offset = tag_len;
+	*proto = ((__be16 *)skb->data)[(tag_len / 2) - 1];
+}
+
 /* switch.c */
 int dsa_switch_register_notifier(struct dsa_switch *ds);
 void dsa_switch_unregister_notifier(struct dsa_switch *ds);
diff --git a/net/dsa/tag_ar9331.c b/net/dsa/tag_ar9331.c
index 55b00694cdba..9aaae107483b 100644
--- a/net/dsa/tag_ar9331.c
+++ b/net/dsa/tag_ar9331.c
@@ -83,12 +83,21 @@ static struct sk_buff *ar9331_tag_rcv(struct sk_buff *skb,
 	return skb;
 }
 
+static int ar9331_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+			       int *offset)
+{
+	dsa_tag_generic_flow_dissect(skb, proto, offset, AR9331_HDR_LEN);
+
+	return 0;
+}
+
 static const struct dsa_device_ops ar9331_netdev_ops = {
 	.name	= "ar9331",
 	.proto	= DSA_TAG_PROTO_AR9331,
 	.xmit	= ar9331_tag_xmit,
 	.rcv	= ar9331_tag_rcv,
 	.overhead = AR9331_HDR_LEN,
+	.flow_dissect = ar9331_flow_dissect,
 };
 
 MODULE_LICENSE("GPL v2");
diff --git a/net/dsa/tag_brcm.c b/net/dsa/tag_brcm.c
index cc8512b5f9e2..9c6c30649d13 100644
--- a/net/dsa/tag_brcm.c
+++ b/net/dsa/tag_brcm.c
@@ -160,9 +160,10 @@ static int brcm_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
 	 * skb->data points 2 bytes before the actual Ethernet type field and
 	 * we have an offset of 4bytes between where skb->data and where the
 	 * payload starts.
+	 * So we can use the generic helper in both cases.
 	 */
-	*offset = BRCM_TAG_LEN;
-	*proto = ((__be16 *)skb->data)[1];
+	dsa_tag_generic_flow_dissect(skb, proto, offset, BRCM_TAG_LEN);
+
 	return 0;
 }
 #endif
diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c
index 7ddec9794477..09479ab9a325 100644
--- a/net/dsa/tag_dsa.c
+++ b/net/dsa/tag_dsa.c
@@ -145,8 +145,8 @@ static struct sk_buff *dsa_rcv(struct sk_buff *skb, struct net_device *dev,
 static int dsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
 				int *offset)
 {
-	*offset = 4;
-	*proto = ((__be16 *)skb->data)[1];
+	dsa_tag_generic_flow_dissect(skb, proto, offset, DSA_HLEN);
+
 	return 0;
 }
 
diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c
index e8eaa804ccb9..af16910a06c0 100644
--- a/net/dsa/tag_edsa.c
+++ b/net/dsa/tag_edsa.c
@@ -164,8 +164,8 @@ static struct sk_buff *edsa_rcv(struct sk_buff *skb, struct net_device *dev,
 static int edsa_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
 				 int *offset)
 {
-	*offset = 8;
-	*proto = ((__be16 *)skb->data)[3];
+	dsa_tag_generic_flow_dissect(skb, proto, offset, EDSA_HLEN);
+
 	return 0;
 }
 
diff --git a/net/dsa/tag_lan9303.c b/net/dsa/tag_lan9303.c
index eb0e7a32e53d..2ec1c9092bb2 100644
--- a/net/dsa/tag_lan9303.c
+++ b/net/dsa/tag_lan9303.c
@@ -128,12 +128,21 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
 	return skb;
 }
 
+static int lan9303_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+				int *offset)
+{
+	dsa_tag_generic_flow_dissect(skb, proto, offset, LAN9303_TAG_LEN);
+
+	return 0;
+}
+
 static const struct dsa_device_ops lan9303_netdev_ops = {
 	.name = "lan9303",
 	.proto	= DSA_TAG_PROTO_LAN9303,
 	.xmit = lan9303_xmit,
 	.rcv = lan9303_rcv,
 	.overhead = LAN9303_TAG_LEN,
+	.flow_dissect = lan9303_flow_dissect,
 };
 
 MODULE_LICENSE("GPL");
diff --git a/net/dsa/tag_mtk.c b/net/dsa/tag_mtk.c
index b5705cba8318..e6cf8f68dffc 100644
--- a/net/dsa/tag_mtk.c
+++ b/net/dsa/tag_mtk.c
@@ -92,8 +92,7 @@ static struct sk_buff *mtk_tag_rcv(struct sk_buff *skb, struct net_device *dev,
 static int mtk_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
 				int *offset)
 {
-	*offset = 4;
-	*proto = ((__be16 *)skb->data)[1];
+	dsa_tag_generic_flow_dissect(skb, proto, offset, MTK_HDR_LEN);
 
 	return 0;
 }
diff --git a/net/dsa/tag_ocelot.c b/net/dsa/tag_ocelot.c
index 778a7f34f8ec..5a2de13b108f 100644
--- a/net/dsa/tag_ocelot.c
+++ b/net/dsa/tag_ocelot.c
@@ -238,12 +238,21 @@ static struct sk_buff *ocelot_rcv(struct sk_buff *skb,
 	return skb;
 }
 
+static int ocelot_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+			       int *offset)
+{
+	dsa_tag_generic_flow_dissect(skb, proto, offset, OCELOT_TOTAL_TAG_LEN);
+
+	return 0;
+}
+
 static struct dsa_device_ops ocelot_netdev_ops = {
 	.name			= "ocelot",
 	.proto			= DSA_TAG_PROTO_OCELOT,
 	.xmit			= ocelot_xmit,
 	.rcv			= ocelot_rcv,
 	.overhead		= OCELOT_TOTAL_TAG_LEN,
+	.flow_dissect		= ocelot_flow_dissect,
 };
 
 MODULE_LICENSE("GPL v2");
diff --git a/net/dsa/tag_qca.c b/net/dsa/tag_qca.c
index 70db7c909f74..43a5a4eebf16 100644
--- a/net/dsa/tag_qca.c
+++ b/net/dsa/tag_qca.c
@@ -90,8 +90,7 @@ static struct sk_buff *qca_tag_rcv(struct sk_buff *skb, struct net_device *dev,
 static int qca_tag_flow_dissect(const struct sk_buff *skb, __be16 *proto,
                                 int *offset)
 {
-	*offset = QCA_HDR_LEN;
-	*proto = ((__be16 *)skb->data)[0];
+	dsa_tag_generic_flow_dissect(skb, proto, offset, QCA_HDR_LEN);
 
 	return 0;
 }
diff --git a/net/dsa/tag_sja1105.c b/net/dsa/tag_sja1105.c
index d553bf36bd41..55cc51a71b13 100644
--- a/net/dsa/tag_sja1105.c
+++ b/net/dsa/tag_sja1105.c
@@ -304,6 +304,18 @@ static struct sk_buff *sja1105_rcv(struct sk_buff *skb,
 					      is_meta);
 }
 
+static int sja1105_flow_dissect(const struct sk_buff *skb, __be16 *proto,
+				int *offset)
+{
+	/* No tag added for management frames, all ok */
+	if (unlikely(sja1105_is_link_local(skb)))
+		return 0;
+
+	dsa_tag_generic_flow_dissect(skb, proto, offset, VLAN_HLEN);
+
+	return 0;
+}
+
 static struct dsa_device_ops sja1105_netdev_ops = {
 	.name = "sja1105",
 	.proto = DSA_TAG_PROTO_SJA1105,
@@ -311,6 +323,7 @@ static struct dsa_device_ops sja1105_netdev_ops = {
 	.rcv = sja1105_rcv,
 	.filter = sja1105_filter,
 	.overhead = VLAN_HLEN,
+	.flow_dissect = sja1105_flow_dissect,
 };
 
 MODULE_LICENSE("GPL v2");
-- 
2.17.1

Powered by blists - more mailing lists