Skip to content

Commit 166e873

Browse files
hartkoppmarckleinebudde
authored andcommitted
can: propagate CAN device capabilities via ml_priv
Commit 1a620a7 ("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: 1a620a7 ("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: Oliver Hartkopp <socketcan@hartkopp.net> Link: https://patch.msgid.link/20260109144135.8495-3-socketcan@hartkopp.net Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
1 parent 4650ff5 commit 166e873

6 files changed

Lines changed: 83 additions & 0 deletions

File tree

drivers/net/can/dev/dev.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,32 @@ void can_set_default_mtu(struct net_device *dev)
375375
}
376376
}
377377

378+
void can_set_cap_info(struct net_device *dev)
379+
{
380+
struct can_priv *priv = netdev_priv(dev);
381+
u32 can_cap;
382+
383+
if (can_dev_in_xl_only_mode(priv)) {
384+
/* XL only mode => no CC/FD capability */
385+
can_cap = CAN_CAP_XL;
386+
} else {
387+
/* mixed mode => CC + FD/XL capability */
388+
can_cap = CAN_CAP_CC;
389+
390+
if (priv->ctrlmode & CAN_CTRLMODE_FD)
391+
can_cap |= CAN_CAP_FD;
392+
393+
if (priv->ctrlmode & CAN_CTRLMODE_XL)
394+
can_cap |= CAN_CAP_XL;
395+
}
396+
397+
if (priv->ctrlmode & (CAN_CTRLMODE_LISTENONLY |
398+
CAN_CTRLMODE_RESTRICTED))
399+
can_cap |= CAN_CAP_RO;
400+
401+
can_set_cap(dev, can_cap);
402+
}
403+
378404
/* helper to define static CAN controller features at device creation time */
379405
int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode)
380406
{
@@ -390,6 +416,7 @@ int can_set_static_ctrlmode(struct net_device *dev, u32 static_mode)
390416

391417
/* override MTU which was set by default in can_setup()? */
392418
can_set_default_mtu(dev);
419+
can_set_cap_info(dev);
393420

394421
return 0;
395422
}

drivers/net/can/dev/netlink.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ static int can_ctrlmode_changelink(struct net_device *dev,
377377
}
378378

379379
can_set_default_mtu(dev);
380+
can_set_cap_info(dev);
380381

381382
return 0;
382383
}

drivers/net/can/vcan.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,19 @@ static netdev_tx_t vcan_tx(struct sk_buff *skb, struct net_device *dev)
130130
return NETDEV_TX_OK;
131131
}
132132

133+
static void vcan_set_cap_info(struct net_device *dev)
134+
{
135+
u32 can_cap = CAN_CAP_CC;
136+
137+
if (dev->mtu > CAN_MTU)
138+
can_cap |= CAN_CAP_FD;
139+
140+
if (dev->mtu >= CANXL_MIN_MTU)
141+
can_cap |= CAN_CAP_XL;
142+
143+
can_set_cap(dev, can_cap);
144+
}
145+
133146
static int vcan_change_mtu(struct net_device *dev, int new_mtu)
134147
{
135148
/* Do not allow changing the MTU while running */
@@ -141,6 +154,7 @@ static int vcan_change_mtu(struct net_device *dev, int new_mtu)
141154
return -EINVAL;
142155

143156
WRITE_ONCE(dev->mtu, new_mtu);
157+
vcan_set_cap_info(dev);
144158
return 0;
145159
}
146160

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

166181
/* set flags according to driver capabilities */
167182
if (echo)

drivers/net/can/vxcan.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,19 @@ static int vxcan_get_iflink(const struct net_device *dev)
125125
return iflink;
126126
}
127127

128+
static void vxcan_set_cap_info(struct net_device *dev)
129+
{
130+
u32 can_cap = CAN_CAP_CC;
131+
132+
if (dev->mtu > CAN_MTU)
133+
can_cap |= CAN_CAP_FD;
134+
135+
if (dev->mtu >= CANXL_MIN_MTU)
136+
can_cap |= CAN_CAP_XL;
137+
138+
can_set_cap(dev, can_cap);
139+
}
140+
128141
static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
129142
{
130143
/* Do not allow changing the MTU while running */
@@ -136,6 +149,7 @@ static int vxcan_change_mtu(struct net_device *dev, int new_mtu)
136149
return -EINVAL;
137150

138151
WRITE_ONCE(dev->mtu, new_mtu);
152+
vxcan_set_cap_info(dev);
139153
return 0;
140154
}
141155

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

168182
can_ml = netdev_priv(dev) + ALIGN(sizeof(struct vxcan_priv), NETDEV_ALIGN);
169183
can_set_ml_priv(dev, can_ml);
184+
vxcan_set_cap_info(dev);
170185
}
171186

172187
/* forward declaration for rtnl_create_link() */

include/linux/can/can-ml.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
#include <linux/list.h>
4747
#include <linux/netdevice.h>
4848

49+
/* exposed CAN device capabilities for network layer */
50+
#define CAN_CAP_CC BIT(0) /* CAN CC aka Classical CAN */
51+
#define CAN_CAP_FD BIT(1) /* CAN FD */
52+
#define CAN_CAP_XL BIT(2) /* CAN XL */
53+
#define CAN_CAP_RO BIT(3) /* read-only mode (LISTEN/RESTRICTED) */
54+
4955
#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
5056
#define CAN_EFF_RCV_HASH_BITS 10
5157
#define CAN_EFF_RCV_ARRAY_SZ (1 << CAN_EFF_RCV_HASH_BITS)
@@ -64,6 +70,7 @@ struct can_ml_priv {
6470
#ifdef CAN_J1939
6571
struct j1939_priv *j1939_priv;
6672
#endif
73+
u32 can_cap;
6774
};
6875

6976
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,
7784
netdev_set_ml_priv(dev, ml_priv, ML_PRIV_CAN);
7885
}
7986

87+
static inline bool can_cap_enabled(struct net_device *dev, u32 cap)
88+
{
89+
struct can_ml_priv *can_ml = can_get_ml_priv(dev);
90+
91+
if (!can_ml)
92+
return false;
93+
94+
return (can_ml->can_cap & cap);
95+
}
96+
97+
static inline void can_set_cap(struct net_device *dev, u32 cap)
98+
{
99+
struct can_ml_priv *can_ml = can_get_ml_priv(dev);
100+
101+
can_ml->can_cap = cap;
102+
}
103+
80104
#endif /* CAN_ML_H */

include/linux/can/dev.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct can_priv *safe_candev_priv(struct net_device *dev);
116116
int open_candev(struct net_device *dev);
117117
void close_candev(struct net_device *dev);
118118
void can_set_default_mtu(struct net_device *dev);
119+
void can_set_cap_info(struct net_device *dev);
119120
int __must_check can_set_static_ctrlmode(struct net_device *dev,
120121
u32 static_mode);
121122
int can_hwtstamp_get(struct net_device *netdev,

0 commit comments

Comments
 (0)