aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/dsa/sja1105/sja1105_main.c37
1 files changed, 29 insertions, 8 deletions
diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c
index 05ba65042b5f..6be9fed50ed5 100644
--- a/drivers/net/dsa/sja1105/sja1105_main.c
+++ b/drivers/net/dsa/sja1105/sja1105_main.c
@@ -120,12 +120,21 @@ static int sja1105_commit_pvid(struct dsa_switch *ds, int port)
if (rc)
return rc;
- vlan = priv->static_config.tables[BLK_IDX_VLAN_LOOKUP].entries;
+ /* Only force dropping of untagged packets when the port is under a
+ * VLAN-aware bridge. When the tag_8021q pvid is used, we are
+ * deliberately removing the RX VLAN from the port's VMEMB_PORT list,
+ * to prevent DSA tag spoofing from the link partner. Untagged packets
+ * are the only ones that should be received with tag_8021q, so
+ * definitely don't drop them.
+ */
+ if (pvid == priv->bridge_pvid[port]) {
+ vlan = priv->static_config.tables[BLK_IDX_VLAN_LOOKUP].entries;
- match = sja1105_is_vlan_configured(priv, pvid);
+ match = sja1105_is_vlan_configured(priv, pvid);
- if (match < 0 || !(vlan[match].vmemb_port & BIT(port)))
- drop_untagged = true;
+ if (match < 0 || !(vlan[match].vmemb_port & BIT(port)))
+ drop_untagged = true;
+ }
return sja1105_drop_untagged(ds, port, drop_untagged);
}
@@ -2343,7 +2352,7 @@ int sja1105_vlan_filtering(struct dsa_switch *ds, int port, bool enabled,
}
static int sja1105_vlan_add(struct sja1105_private *priv, int port, u16 vid,
- u16 flags)
+ u16 flags, bool allowed_ingress)
{
struct sja1105_vlan_lookup_entry *vlan;
struct sja1105_table *table;
@@ -2365,7 +2374,12 @@ static int sja1105_vlan_add(struct sja1105_private *priv, int port, u16 vid,
vlan[match].type_entry = SJA1110_VLAN_D_TAG;
vlan[match].vlanid = vid;
vlan[match].vlan_bc |= BIT(port);
- vlan[match].vmemb_port |= BIT(port);
+
+ if (allowed_ingress)
+ vlan[match].vmemb_port |= BIT(port);
+ else
+ vlan[match].vmemb_port &= ~BIT(port);
+
if (flags & BRIDGE_VLAN_INFO_UNTAGGED)
vlan[match].tag_port &= ~BIT(port);
else
@@ -2437,7 +2451,7 @@ static int sja1105_bridge_vlan_add(struct dsa_switch *ds, int port,
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
flags = 0;
- rc = sja1105_vlan_add(priv, port, vlan->vid, flags);
+ rc = sja1105_vlan_add(priv, port, vlan->vid, flags, true);
if (rc)
return rc;
@@ -2467,9 +2481,16 @@ static int sja1105_dsa_8021q_vlan_add(struct dsa_switch *ds, int port, u16 vid,
u16 flags)
{
struct sja1105_private *priv = ds->priv;
+ bool allowed_ingress = true;
int rc;
- rc = sja1105_vlan_add(priv, port, vid, flags);
+ /* Prevent attackers from trying to inject a DSA tag from
+ * the outside world.
+ */
+ if (dsa_is_user_port(ds, port))
+ allowed_ingress = false;
+
+ rc = sja1105_vlan_add(priv, port, vid, flags, allowed_ingress);
if (rc)
return rc;