Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

can: add dummy_can driver

During the development of CAN XL, we found the need of creating a
dummy CAN XL driver in order to test the new netlink interface. While
this code was initially intended to be some throwaway, it received
some positive feedback.

Add the dummy_can driver. This driver acts similarly to the vcan
interface in the sense that it will echo back any packet it receives.
The difference is that it exposes a set on bittiming parameters as a
real device would and thus must be configured as if it was a real
physical interface.

The driver comes with a debug mode. If debug message are enabled (for
example by enabling CONFIG_CAN_DEBUG_DEVICES), it will print in the
kernel log all the bittiming values, similar to what a:

ip --details link show can0

would do.

This driver is mostly intended for debugging and testing, but some
developers also may want to look at it as a simple reference
implementation.

Signed-off-by: Vincent Mailhol <mailhol@kernel.org>
Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net>
Link: https://patch.msgid.link/20251126-canxl-v8-15-e7e3eb74f889@pengutronix.de
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>

authored by

Vincent Mailhol and committed by
Marc Kleine-Budde
816cf430 f5de373a

+303
+17
drivers/net/can/Kconfig
··· 124 124 125 125 If this driver is built as a module, it will be called can327. 126 126 127 + config CAN_DUMMY 128 + tristate "Dummy CAN" 129 + help 130 + A dummy CAN module supporting Classical CAN, CAN FD and CAN XL. It 131 + exposes bittiming values which can be configured through the netlink 132 + interface. 133 + 134 + The module will simply echo any frame sent to it. If debug messages 135 + are activated, it prints all the CAN bittiming information in the 136 + kernel log. Aside from that it does nothing. 137 + 138 + This is convenient for testing the CAN netlink interface. Most of the 139 + users will never need this. If unsure, say NO. 140 + 141 + To compile this driver as a module, choose M here: the module will be 142 + called dummy-can. 143 + 127 144 config CAN_FLEXCAN 128 145 tristate "Support for Freescale FLEXCAN based chips" 129 146 depends on OF || COLDFIRE || COMPILE_TEST
+1
drivers/net/can/Makefile
··· 21 21 obj-$(CONFIG_CAN_CC770) += cc770/ 22 22 obj-$(CONFIG_CAN_C_CAN) += c_can/ 23 23 obj-$(CONFIG_CAN_CTUCANFD) += ctucanfd/ 24 + obj-$(CONFIG_CAN_DUMMY) += dummy_can.o 24 25 obj-$(CONFIG_CAN_FLEXCAN) += flexcan/ 25 26 obj-$(CONFIG_CAN_GRCAN) += grcan.o 26 27 obj-$(CONFIG_CAN_IFI_CANFD) += ifi_canfd/
+285
drivers/net/can/dummy_can.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* Copyright (c) 2025 Vincent Mailhol <mailhol@kernel.org> */ 4 + 5 + #include <linux/array_size.h> 6 + #include <linux/errno.h> 7 + #include <linux/init.h> 8 + #include <linux/kernel.h> 9 + #include <linux/module.h> 10 + #include <linux/netdevice.h> 11 + #include <linux/units.h> 12 + #include <linux/string_choices.h> 13 + 14 + #include <linux/can.h> 15 + #include <linux/can/bittiming.h> 16 + #include <linux/can/dev.h> 17 + #include <linux/can/skb.h> 18 + 19 + struct dummy_can { 20 + struct can_priv can; 21 + struct net_device *dev; 22 + }; 23 + 24 + static struct dummy_can *dummy_can; 25 + 26 + static const struct can_bittiming_const dummy_can_bittiming_const = { 27 + .name = "dummy_can CC", 28 + .tseg1_min = 2, 29 + .tseg1_max = 256, 30 + .tseg2_min = 2, 31 + .tseg2_max = 128, 32 + .sjw_max = 128, 33 + .brp_min = 1, 34 + .brp_max = 512, 35 + .brp_inc = 1 36 + }; 37 + 38 + static const struct can_bittiming_const dummy_can_fd_databittiming_const = { 39 + .name = "dummy_can FD", 40 + .tseg1_min = 2, 41 + .tseg1_max = 256, 42 + .tseg2_min = 2, 43 + .tseg2_max = 128, 44 + .sjw_max = 128, 45 + .brp_min = 1, 46 + .brp_max = 512, 47 + .brp_inc = 1 48 + }; 49 + 50 + static const struct can_tdc_const dummy_can_fd_tdc_const = { 51 + .tdcv_min = 0, 52 + .tdcv_max = 0, /* Manual mode not supported. */ 53 + .tdco_min = 0, 54 + .tdco_max = 127, 55 + .tdcf_min = 0, 56 + .tdcf_max = 127 57 + }; 58 + 59 + static const struct can_bittiming_const dummy_can_xl_databittiming_const = { 60 + .name = "dummy_can XL", 61 + .tseg1_min = 2, 62 + .tseg1_max = 256, 63 + .tseg2_min = 2, 64 + .tseg2_max = 128, 65 + .sjw_max = 128, 66 + .brp_min = 1, 67 + .brp_max = 512, 68 + .brp_inc = 1 69 + }; 70 + 71 + static const struct can_tdc_const dummy_can_xl_tdc_const = { 72 + .tdcv_min = 0, 73 + .tdcv_max = 0, /* Manual mode not supported. */ 74 + .tdco_min = 0, 75 + .tdco_max = 127, 76 + .tdcf_min = 0, 77 + .tdcf_max = 127 78 + }; 79 + 80 + static const struct can_pwm_const dummy_can_pwm_const = { 81 + .pwms_min = 1, 82 + .pwms_max = 8, 83 + .pwml_min = 2, 84 + .pwml_max = 24, 85 + .pwmo_min = 0, 86 + .pwmo_max = 16, 87 + }; 88 + 89 + static void dummy_can_print_bittiming(struct net_device *dev, 90 + struct can_bittiming *bt) 91 + { 92 + netdev_dbg(dev, "\tbitrate: %u\n", bt->bitrate); 93 + netdev_dbg(dev, "\tsample_point: %u\n", bt->sample_point); 94 + netdev_dbg(dev, "\ttq: %u\n", bt->tq); 95 + netdev_dbg(dev, "\tprop_seg: %u\n", bt->prop_seg); 96 + netdev_dbg(dev, "\tphase_seg1: %u\n", bt->phase_seg1); 97 + netdev_dbg(dev, "\tphase_seg2: %u\n", bt->phase_seg2); 98 + netdev_dbg(dev, "\tsjw: %u\n", bt->sjw); 99 + netdev_dbg(dev, "\tbrp: %u\n", bt->brp); 100 + } 101 + 102 + static void dummy_can_print_tdc(struct net_device *dev, struct can_tdc *tdc) 103 + { 104 + netdev_dbg(dev, "\t\ttdcv: %u\n", tdc->tdcv); 105 + netdev_dbg(dev, "\t\ttdco: %u\n", tdc->tdco); 106 + netdev_dbg(dev, "\t\ttdcf: %u\n", tdc->tdcf); 107 + } 108 + 109 + static void dummy_can_print_pwm(struct net_device *dev, struct can_pwm *pwm, 110 + struct can_bittiming *dbt) 111 + { 112 + netdev_dbg(dev, "\t\tpwms: %u\n", pwm->pwms); 113 + netdev_dbg(dev, "\t\tpwml: %u\n", pwm->pwml); 114 + netdev_dbg(dev, "\t\tpwmo: %u\n", pwm->pwmo); 115 + } 116 + 117 + static void dummy_can_print_ctrlmode(struct net_device *dev) 118 + { 119 + struct dummy_can *priv = netdev_priv(dev); 120 + struct can_priv *can_priv = &priv->can; 121 + unsigned long supported = can_priv->ctrlmode_supported; 122 + u32 enabled = can_priv->ctrlmode; 123 + 124 + netdev_dbg(dev, "Control modes:\n"); 125 + netdev_dbg(dev, "\tsupported: 0x%08x\n", (u32)supported); 126 + netdev_dbg(dev, "\tenabled: 0x%08x\n", enabled); 127 + 128 + if (supported) { 129 + int idx; 130 + 131 + netdev_dbg(dev, "\tlist:"); 132 + for_each_set_bit(idx, &supported, BITS_PER_TYPE(u32)) 133 + netdev_dbg(dev, "\t\t%s: %s\n", 134 + can_get_ctrlmode_str(BIT(idx)), 135 + enabled & BIT(idx) ? "on" : "off"); 136 + } 137 + } 138 + 139 + static void dummy_can_print_bittiming_info(struct net_device *dev) 140 + { 141 + struct dummy_can *priv = netdev_priv(dev); 142 + struct can_priv *can_priv = &priv->can; 143 + 144 + netdev_dbg(dev, "Clock frequency: %u\n", can_priv->clock.freq); 145 + netdev_dbg(dev, "Maximum bitrate: %u\n", can_priv->bitrate_max); 146 + netdev_dbg(dev, "MTU: %u\n", dev->mtu); 147 + netdev_dbg(dev, "\n"); 148 + 149 + dummy_can_print_ctrlmode(dev); 150 + netdev_dbg(dev, "\n"); 151 + 152 + netdev_dbg(dev, "Classical CAN nominal bittiming:\n"); 153 + dummy_can_print_bittiming(dev, &can_priv->bittiming); 154 + netdev_dbg(dev, "\n"); 155 + 156 + if (can_priv->ctrlmode & CAN_CTRLMODE_FD) { 157 + netdev_dbg(dev, "CAN FD databittiming:\n"); 158 + dummy_can_print_bittiming(dev, &can_priv->fd.data_bittiming); 159 + if (can_fd_tdc_is_enabled(can_priv)) { 160 + netdev_dbg(dev, "\tCAN FD TDC:\n"); 161 + dummy_can_print_tdc(dev, &can_priv->fd.tdc); 162 + } 163 + } 164 + netdev_dbg(dev, "\n"); 165 + 166 + if (can_priv->ctrlmode & CAN_CTRLMODE_XL) { 167 + netdev_dbg(dev, "CAN XL databittiming:\n"); 168 + dummy_can_print_bittiming(dev, &can_priv->xl.data_bittiming); 169 + if (can_xl_tdc_is_enabled(can_priv)) { 170 + netdev_dbg(dev, "\tCAN XL TDC:\n"); 171 + dummy_can_print_tdc(dev, &can_priv->xl.tdc); 172 + } 173 + if (can_priv->ctrlmode & CAN_CTRLMODE_XL_TMS) { 174 + netdev_dbg(dev, "\tCAN XL PWM:\n"); 175 + dummy_can_print_pwm(dev, &can_priv->xl.pwm, 176 + &can_priv->xl.data_bittiming); 177 + } 178 + } 179 + netdev_dbg(dev, "\n"); 180 + } 181 + 182 + static int dummy_can_netdev_open(struct net_device *dev) 183 + { 184 + int ret; 185 + struct can_priv *priv = netdev_priv(dev); 186 + 187 + dummy_can_print_bittiming_info(dev); 188 + netdev_dbg(dev, "error-signalling is %s\n", 189 + str_enabled_disabled(!can_dev_in_xl_only_mode(priv))); 190 + 191 + ret = open_candev(dev); 192 + if (ret) 193 + return ret; 194 + netif_start_queue(dev); 195 + netdev_dbg(dev, "dummy-can is up\n"); 196 + 197 + return 0; 198 + } 199 + 200 + static int dummy_can_netdev_close(struct net_device *dev) 201 + { 202 + netif_stop_queue(dev); 203 + close_candev(dev); 204 + netdev_dbg(dev, "dummy-can is down\n"); 205 + 206 + return 0; 207 + } 208 + 209 + static netdev_tx_t dummy_can_start_xmit(struct sk_buff *skb, 210 + struct net_device *dev) 211 + { 212 + if (can_dev_dropped_skb(dev, skb)) 213 + return NETDEV_TX_OK; 214 + 215 + can_put_echo_skb(skb, dev, 0, 0); 216 + dev->stats.tx_packets++; 217 + dev->stats.tx_bytes += can_get_echo_skb(dev, 0, NULL); 218 + 219 + return NETDEV_TX_OK; 220 + } 221 + 222 + static const struct net_device_ops dummy_can_netdev_ops = { 223 + .ndo_open = dummy_can_netdev_open, 224 + .ndo_stop = dummy_can_netdev_close, 225 + .ndo_start_xmit = dummy_can_start_xmit, 226 + }; 227 + 228 + static const struct ethtool_ops dummy_can_ethtool_ops = { 229 + .get_ts_info = ethtool_op_get_ts_info, 230 + }; 231 + 232 + static int __init dummy_can_init(void) 233 + { 234 + struct net_device *dev; 235 + struct dummy_can *priv; 236 + int ret; 237 + 238 + dev = alloc_candev(sizeof(*priv), 1); 239 + if (!dev) 240 + return -ENOMEM; 241 + 242 + dev->netdev_ops = &dummy_can_netdev_ops; 243 + dev->ethtool_ops = &dummy_can_ethtool_ops; 244 + priv = netdev_priv(dev); 245 + priv->can.bittiming_const = &dummy_can_bittiming_const; 246 + priv->can.bitrate_max = 20 * MEGA /* BPS */; 247 + priv->can.clock.freq = 160 * MEGA /* Hz */; 248 + priv->can.fd.data_bittiming_const = &dummy_can_fd_databittiming_const; 249 + priv->can.fd.tdc_const = &dummy_can_fd_tdc_const; 250 + priv->can.xl.data_bittiming_const = &dummy_can_xl_databittiming_const; 251 + priv->can.xl.tdc_const = &dummy_can_xl_tdc_const; 252 + priv->can.xl.pwm_const = &dummy_can_pwm_const; 253 + priv->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY | 254 + CAN_CTRLMODE_FD | CAN_CTRLMODE_TDC_AUTO | 255 + CAN_CTRLMODE_RESTRICTED | CAN_CTRLMODE_XL | 256 + CAN_CTRLMODE_XL_TDC_AUTO | CAN_CTRLMODE_XL_TMS; 257 + priv->dev = dev; 258 + 259 + ret = register_candev(priv->dev); 260 + if (ret) { 261 + free_candev(priv->dev); 262 + return ret; 263 + } 264 + 265 + dummy_can = priv; 266 + netdev_dbg(dev, "dummy-can ready\n"); 267 + 268 + return 0; 269 + } 270 + 271 + static void __exit dummy_can_exit(void) 272 + { 273 + struct net_device *dev = dummy_can->dev; 274 + 275 + netdev_dbg(dev, "dummy-can bye bye\n"); 276 + unregister_candev(dev); 277 + free_candev(dev); 278 + } 279 + 280 + module_init(dummy_can_init); 281 + module_exit(dummy_can_exit); 282 + 283 + MODULE_DESCRIPTION("A dummy CAN driver, mainly to test the netlink interface"); 284 + MODULE_LICENSE("GPL"); 285 + MODULE_AUTHOR("Vincent Mailhol <mailhol@kernel.org>");