[PATCH net-next v2] net: mscc: ocelot: validate netdev belongs to switch in .netdev_to_port()
From: David Yang
Date: Sat Jun 06 2026 - 08:53:16 EST
The .netdev_to_port() currently takes only a net_device and returns the
port index, without verifying the netdev actually belongs to the switch
being operated on. This can cause flower rule parsing to silently
resolve to a wrong port on the local hardware.
Update both implementations felix_netdev_to_port() and
ocelot_netdev_to_port() to validate ownership. Also update the callers
in ocelot_flower.c to pass through the ocelot context.
Signed-off-by: David Yang <mmyangfl@xxxxxxxxx>
---
v1: https://lore.kernel.org/r/20260603024234.66603-1-mmyangfl@xxxxxxxxx
- also fix ocelot_netdev_to_port()
drivers/net/dsa/ocelot/felix.c | 6 ++++--
drivers/net/dsa/ocelot/felix.h | 2 +-
drivers/net/ethernet/mscc/ocelot.h | 2 +-
drivers/net/ethernet/mscc/ocelot_flower.c | 4 ++--
drivers/net/ethernet/mscc/ocelot_net.c | 4 +++-
include/soc/mscc/ocelot.h | 2 +-
6 files changed, 12 insertions(+), 8 deletions(-)
diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c
index 4272ea6e9ca8..84a95007825f 100644
--- a/drivers/net/dsa/ocelot/felix.c
+++ b/drivers/net/dsa/ocelot/felix.c
@@ -2446,12 +2446,14 @@ struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port)
}
EXPORT_SYMBOL_GPL(felix_port_to_netdev);
-int felix_netdev_to_port(struct net_device *dev)
+int felix_netdev_to_port(struct ocelot *ocelot, struct net_device *dev)
{
+ struct felix *felix = ocelot_to_felix(ocelot);
+ struct dsa_switch *ds = felix->ds;
struct dsa_port *dp;
dp = dsa_port_from_netdev(dev);
- if (IS_ERR(dp))
+ if (IS_ERR(dp) || dp->ds != ds)
return -EINVAL;
return dp->index;
diff --git a/drivers/net/dsa/ocelot/felix.h b/drivers/net/dsa/ocelot/felix.h
index a657b190c5d7..19addcfd62be 100644
--- a/drivers/net/dsa/ocelot/felix.h
+++ b/drivers/net/dsa/ocelot/felix.h
@@ -104,6 +104,6 @@ int felix_register_switch(struct device *dev, resource_size_t switch_base,
enum dsa_tag_protocol init_tag_proto,
const struct felix_info *info);
struct net_device *felix_port_to_netdev(struct ocelot *ocelot, int port);
-int felix_netdev_to_port(struct net_device *dev);
+int felix_netdev_to_port(struct ocelot *ocelot, struct net_device *dev);
#endif
diff --git a/drivers/net/ethernet/mscc/ocelot.h b/drivers/net/ethernet/mscc/ocelot.h
index e50be508c166..42d2c456f712 100644
--- a/drivers/net/ethernet/mscc/ocelot.h
+++ b/drivers/net/ethernet/mscc/ocelot.h
@@ -92,7 +92,7 @@ int ocelot_mact_learn(struct ocelot *ocelot, int port,
int ocelot_mact_forget(struct ocelot *ocelot,
const unsigned char mac[ETH_ALEN], unsigned int vid);
struct net_device *ocelot_port_to_netdev(struct ocelot *ocelot, int port);
-int ocelot_netdev_to_port(struct net_device *dev);
+int ocelot_netdev_to_port(struct ocelot *ocelot, struct net_device *dev);
int ocelot_probe_port(struct ocelot *ocelot, int port, struct regmap *target,
struct device_node *portnp);
diff --git a/drivers/net/ethernet/mscc/ocelot_flower.c b/drivers/net/ethernet/mscc/ocelot_flower.c
index 844292eb7422..c5983c56a544 100644
--- a/drivers/net/ethernet/mscc/ocelot_flower.c
+++ b/drivers/net/ethernet/mscc/ocelot_flower.c
@@ -233,8 +233,8 @@ ocelot_flower_parse_egress_port(struct ocelot *ocelot, struct flow_cls_offload *
const struct flow_action_entry *a, bool mirror,
struct netlink_ext_ack *extack)
{
+ int egress_port = ocelot->ops->netdev_to_port(ocelot, a->dev);
const char *act_string = mirror ? "mirror" : "redirect";
- int egress_port = ocelot->ops->netdev_to_port(a->dev);
enum flow_action_id offloadable_act_id;
offloadable_act_id = mirror ? FLOW_ACTION_MIRRED : FLOW_ACTION_REDIRECT;
@@ -580,7 +580,7 @@ static int ocelot_flower_parse_indev(struct ocelot *ocelot, int port,
return -ENOENT;
}
- ingress_port = ocelot->ops->netdev_to_port(indev);
+ ingress_port = ocelot->ops->netdev_to_port(ocelot, indev);
if (ingress_port < 0) {
NL_SET_ERR_MSG_MOD(extack,
"Can only offload an ocelot ingress port");
diff --git a/drivers/net/ethernet/mscc/ocelot_net.c b/drivers/net/ethernet/mscc/ocelot_net.c
index 1b8269320464..4d45e136f08f 100644
--- a/drivers/net/ethernet/mscc/ocelot_net.c
+++ b/drivers/net/ethernet/mscc/ocelot_net.c
@@ -984,7 +984,7 @@ static bool ocelot_netdevice_dev_check(const struct net_device *dev)
return dev->netdev_ops == &ocelot_port_netdev_ops;
}
-int ocelot_netdev_to_port(struct net_device *dev)
+int ocelot_netdev_to_port(struct ocelot *ocelot, struct net_device *dev)
{
struct ocelot_port_private *priv;
@@ -992,6 +992,8 @@ int ocelot_netdev_to_port(struct net_device *dev)
return -EINVAL;
priv = netdev_priv(dev);
+ if (priv->port.ocelot != ocelot)
+ return -EINVAL;
return priv->port.index;
}
diff --git a/include/soc/mscc/ocelot.h b/include/soc/mscc/ocelot.h
index 48d6deb3efd7..05a8191b148e 100644
--- a/include/soc/mscc/ocelot.h
+++ b/include/soc/mscc/ocelot.h
@@ -650,7 +650,7 @@ struct device_node;
struct ocelot_ops {
struct net_device *(*port_to_netdev)(struct ocelot *ocelot, int port);
- int (*netdev_to_port)(struct net_device *dev);
+ int (*netdev_to_port)(struct ocelot *ocelot, struct net_device *dev);
int (*reset)(struct ocelot *ocelot);
u16 (*wm_enc)(u16 value);
u16 (*wm_dec)(u16 value);
--
2.53.0