Commit 166e8732 authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by Marc Kleine-Budde
Browse files

can: propagate CAN device capabilities via ml_priv



Commit 1a620a72 ("can: raw: instantly reject unsupported CAN frames")
caused a sequence of dependency and linker fixes.

Instead of accessing CAN device internal data structures which caused the
dependency problems this patch introduces capability information into the
CAN specific ml_priv data which is accessible from both sides.

With this change the CAN network layer can check the required features and
the decoupling of the driver layer and network layer is restored.

Fixes: 1a620a72 ("can: raw: instantly reject unsupported CAN frames")
Cc: Marc Kleine-Budde <mkl@pengutronix.de>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Vincent Mailhol <mailhol@kernel.org>
Signed-off-by: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20260109144135.8495-3-socketcan@hartkopp.net


Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent 4650ff58
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -375,6 +375,32 @@ void can_set_default_mtu(struct net_device *dev)
	}
}

void can_set_cap_info(struct net_device *dev)
{
	struct can_priv *priv = netdev_priv(dev);
	u32 can_cap;

	if (can_dev_in_xl_only_mode(priv)) {
		/* XL only mode => no CC/FD capability */
		can_cap = CAN_CAP_XL;
	} else {
		/* mixed mode => CC + FD/XL capability */
		can_cap = CAN_CAP_CC;

		if (priv->ctrlmode & CAN_CTRLMODE_FD)
			can_cap |= CAN_CAP_FD;

		if (priv->ctrlmode & CAN_CTRLMODE_XL)
			can_cap |= CAN_CAP_XL;
	}

	if (priv->ctrlmode & (CAN_CTRLMODE_LISTENONLY |
			      CAN_CTRLMODE_RESTRICTED))
		can_cap |= CAN_CAP_RO;

	can_set_cap(dev, can_cap);
}

/* helper to define static CAN controller features at device creation time */
int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode)
{
@@ -390,6 +416,7 @@ int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode)

	/* override MTU which was set by default in can_setup()? */
	can_set_default_mtu(dev);
	can_set_cap_info(dev);

	return 0;
}
+1 −0
Original line number Diff line number Diff line
@@ -377,6 +377,7 @@ static int can_ctrlmode_changelink(struct net_device *dev,
	}

	can_set_default_mtu(dev);
	can_set_cap_info(dev);

	return 0;
}
+15 −0
Original line number Diff line number Diff line
@@ -130,6 +130,19 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
	return NETDEV_TX_OK;
}

static void vcan_set_cap_info(struct net_device *dev)
{
	u32 can_cap = CAN_CAP_CC;

	if (dev->mtu > CAN_MTU)
		can_cap |= CAN_CAP_FD;

	if (dev->mtu >= CANXL_MIN_MTU)
		can_cap |= CAN_CAP_XL;

	can_set_cap(dev, can_cap);
}

static int vcan_change_mtu(struct net_device *dev, int new_mtu)
{
	/* Do not allow changing the MTU while running */
@@ -141,6 +154,7 @@ static int vcan_change_mtu(struct net_device *dev, int new_mtu)
		return -EINVAL;

	WRITE_ONCE(dev->mtu, new_mtu);
	vcan_set_cap_info(dev);
	return 0;
}

@@ -162,6 +176,7 @@ static void vcan_setup(struct net_device *dev)
	dev->tx_queue_len	= 0;
	dev->flags		= IFF_NOARP;
	can_set_ml_priv(dev, netdev_priv(dev));
	vcan_set_cap_info(dev);

	/* set flags according to driver capabilities */
	if (echo)
+15 −0
Original line number Diff line number Diff line
@@ -125,6 +125,19 @@ static int vxcan_get_iflink(const struct net_device *dev)
	return iflink;
}

static void vxcan_set_cap_info(struct net_device *dev)
{
	u32 can_cap = CAN_CAP_CC;

	if (dev->mtu > CAN_MTU)
		can_cap |= CAN_CAP_FD;

	if (dev->mtu >= CANXL_MIN_MTU)
		can_cap |= CAN_CAP_XL;

	can_set_cap(dev, can_cap);
}

static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
{
	/* Do not allow changing the MTU while running */
@@ -136,6 +149,7 @@ static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
		return -EINVAL;

	WRITE_ONCE(dev->mtu, new_mtu);
	vxcan_set_cap_info(dev);
	return 0;
}

@@ -167,6 +181,7 @@ static void vxcan_setup(struct net_device *dev)

	can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
	can_set_ml_priv(dev, can_ml);
	vxcan_set_cap_info(dev);
}

/* forward declaration for rtnl_create_link() */
+24 −0
Original line number Diff line number Diff line
@@ -46,6 +46,12 @@
#include <linux/list.h>
#include <linux/netdevice.h>

/* exposed CAN device capabilities for network layer */
#define CAN_CAP_CC BIT(0) /* CAN CC aka Classical CAN */
#define CAN_CAP_FD BIT(1) /* CAN FD */
#define CAN_CAP_XL BIT(2) /* CAN XL */
#define CAN_CAP_RO BIT(3) /* read-only mode (LISTEN/RESTRICTED) */

#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
#define CAN_EFF_RCV_HASH_BITS 10
#define CAN_EFF_RCV_ARRAY_SZ (1 << CAN_EFF_RCV_HASH_BITS)
@@ -64,6 +70,7 @@ struct can_ml_priv {
#ifdef CAN_J1939
	struct j1939_priv *j1939_priv;
#endif
	u32 can_cap;
};

static inline struct can_ml_priv *can_get_ml_priv(struct net_device *dev)
@@ -77,4 +84,21 @@ static inline void can_set_ml_priv(struct net_device *dev,
	netdev_set_ml_priv(dev, ml_priv, ML_PRIV_CAN);
}

static inline bool can_cap_enabled(struct net_device *dev, u32 cap)
{
	struct can_ml_priv *can_ml = can_get_ml_priv(dev);

	if (!can_ml)
		return false;

	return (can_ml->can_cap & cap);
}

static inline void can_set_cap(struct net_device *dev, u32 cap)
{
	struct can_ml_priv *can_ml = can_get_ml_priv(dev);

	can_ml->can_cap = cap;
}

#endif /* CAN_ML_H */
Loading