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@gmail.com>
Link: https://patch.msgid.link/20260606125247.305167-1-mmyangfl@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
}
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;
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
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);
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;
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");
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;
return -EINVAL;
priv = netdev_priv(dev);
+ if (priv->port.ocelot != ocelot)
+ return -EINVAL;
return priv->port.index;
}
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);