mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	can: dev: move netlink related code into seperate file
This patch moves the netlink related code of the CAN device infrastructure into a separate file. Reviewed-by: Vincent Mailhol <mailhol.vincent@wanadoo.fr> Link: https://lore.kernel.org/r/20210111141930.693847-7-mkl@pengutronix.de Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
This commit is contained in:
		
							parent
							
								
									18f2dbfd22
								
							
						
					
					
						commit
						0a042c6ec9
					
				
					 4 changed files with 389 additions and 367 deletions
				
			
		| 
						 | 
					@ -4,6 +4,7 @@ obj-$(CONFIG_CAN_DEV)		+= can-dev.o
 | 
				
			||||||
can-dev-y			+= bittiming.o
 | 
					can-dev-y			+= bittiming.o
 | 
				
			||||||
can-dev-y			+= dev.o
 | 
					can-dev-y			+= dev.o
 | 
				
			||||||
can-dev-y			+= length.o
 | 
					can-dev-y			+= length.o
 | 
				
			||||||
 | 
					can-dev-y			+= netlink.o
 | 
				
			||||||
can-dev-y			+= rx-offload.o
 | 
					can-dev-y			+= rx-offload.o
 | 
				
			||||||
can-dev-y                       += skb.o
 | 
					can-dev-y                       += skb.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,10 +14,8 @@
 | 
				
			||||||
#include <linux/can/can-ml.h>
 | 
					#include <linux/can/can-ml.h>
 | 
				
			||||||
#include <linux/can/dev.h>
 | 
					#include <linux/can/dev.h>
 | 
				
			||||||
#include <linux/can/skb.h>
 | 
					#include <linux/can/skb.h>
 | 
				
			||||||
#include <linux/can/netlink.h>
 | 
					 | 
				
			||||||
#include <linux/can/led.h>
 | 
					#include <linux/can/led.h>
 | 
				
			||||||
#include <linux/of.h>
 | 
					#include <linux/of.h>
 | 
				
			||||||
#include <net/rtnetlink.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MOD_DESC "CAN device driver interface"
 | 
					#define MOD_DESC "CAN device driver interface"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -223,7 +221,7 @@ void can_bus_off(struct net_device *dev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(can_bus_off);
 | 
					EXPORT_SYMBOL_GPL(can_bus_off);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void can_setup(struct net_device *dev)
 | 
					void can_setup(struct net_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	dev->type = ARPHRD_CAN;
 | 
						dev->type = ARPHRD_CAN;
 | 
				
			||||||
	dev->mtu = CAN_MTU;
 | 
						dev->mtu = CAN_MTU;
 | 
				
			||||||
| 
						 | 
					@ -399,368 +397,6 @@ void close_candev(struct net_device *dev)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(close_candev);
 | 
					EXPORT_SYMBOL_GPL(close_candev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* CAN netlink interface */
 | 
					 | 
				
			||||||
static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
 | 
					 | 
				
			||||||
	[IFLA_CAN_STATE]	= { .type = NLA_U32 },
 | 
					 | 
				
			||||||
	[IFLA_CAN_CTRLMODE]	= { .len = sizeof(struct can_ctrlmode) },
 | 
					 | 
				
			||||||
	[IFLA_CAN_RESTART_MS]	= { .type = NLA_U32 },
 | 
					 | 
				
			||||||
	[IFLA_CAN_RESTART]	= { .type = NLA_U32 },
 | 
					 | 
				
			||||||
	[IFLA_CAN_BITTIMING]	= { .len = sizeof(struct can_bittiming) },
 | 
					 | 
				
			||||||
	[IFLA_CAN_BITTIMING_CONST]
 | 
					 | 
				
			||||||
				= { .len = sizeof(struct can_bittiming_const) },
 | 
					 | 
				
			||||||
	[IFLA_CAN_CLOCK]	= { .len = sizeof(struct can_clock) },
 | 
					 | 
				
			||||||
	[IFLA_CAN_BERR_COUNTER]	= { .len = sizeof(struct can_berr_counter) },
 | 
					 | 
				
			||||||
	[IFLA_CAN_DATA_BITTIMING]
 | 
					 | 
				
			||||||
				= { .len = sizeof(struct can_bittiming) },
 | 
					 | 
				
			||||||
	[IFLA_CAN_DATA_BITTIMING_CONST]
 | 
					 | 
				
			||||||
				= { .len = sizeof(struct can_bittiming_const) },
 | 
					 | 
				
			||||||
	[IFLA_CAN_TERMINATION]	= { .type = NLA_U16 },
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int can_validate(struct nlattr *tb[], struct nlattr *data[],
 | 
					 | 
				
			||||||
			struct netlink_ext_ack *extack)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	bool is_can_fd = false;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* Make sure that valid CAN FD configurations always consist of
 | 
					 | 
				
			||||||
	 * - nominal/arbitration bittiming
 | 
					 | 
				
			||||||
	 * - data bittiming
 | 
					 | 
				
			||||||
	 * - control mode with CAN_CTRLMODE_FD set
 | 
					 | 
				
			||||||
	 */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!data)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (data[IFLA_CAN_CTRLMODE]) {
 | 
					 | 
				
			||||||
		struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (is_can_fd) {
 | 
					 | 
				
			||||||
		if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
 | 
					 | 
				
			||||||
			return -EOPNOTSUPP;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (data[IFLA_CAN_DATA_BITTIMING]) {
 | 
					 | 
				
			||||||
		if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
 | 
					 | 
				
			||||||
			return -EOPNOTSUPP;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int can_changelink(struct net_device *dev, struct nlattr *tb[],
 | 
					 | 
				
			||||||
			  struct nlattr *data[],
 | 
					 | 
				
			||||||
			  struct netlink_ext_ack *extack)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct can_priv *priv = netdev_priv(dev);
 | 
					 | 
				
			||||||
	int err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* We need synchronization with dev->stop() */
 | 
					 | 
				
			||||||
	ASSERT_RTNL();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (data[IFLA_CAN_BITTIMING]) {
 | 
					 | 
				
			||||||
		struct can_bittiming bt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Do not allow changing bittiming while running */
 | 
					 | 
				
			||||||
		if (dev->flags & IFF_UP)
 | 
					 | 
				
			||||||
			return -EBUSY;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Calculate bittiming parameters based on
 | 
					 | 
				
			||||||
		 * bittiming_const if set, otherwise pass bitrate
 | 
					 | 
				
			||||||
		 * directly via do_set_bitrate(). Bail out if neither
 | 
					 | 
				
			||||||
		 * is given.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (!priv->bittiming_const && !priv->do_set_bittiming)
 | 
					 | 
				
			||||||
			return -EOPNOTSUPP;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
 | 
					 | 
				
			||||||
		err = can_get_bittiming(dev, &bt,
 | 
					 | 
				
			||||||
					priv->bittiming_const,
 | 
					 | 
				
			||||||
					priv->bitrate_const,
 | 
					 | 
				
			||||||
					priv->bitrate_const_cnt);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
 | 
					 | 
				
			||||||
			netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
 | 
					 | 
				
			||||||
				   priv->bitrate_max);
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		memcpy(&priv->bittiming, &bt, sizeof(bt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (priv->do_set_bittiming) {
 | 
					 | 
				
			||||||
			/* Finally, set the bit-timing registers */
 | 
					 | 
				
			||||||
			err = priv->do_set_bittiming(dev);
 | 
					 | 
				
			||||||
			if (err)
 | 
					 | 
				
			||||||
				return err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (data[IFLA_CAN_CTRLMODE]) {
 | 
					 | 
				
			||||||
		struct can_ctrlmode *cm;
 | 
					 | 
				
			||||||
		u32 ctrlstatic;
 | 
					 | 
				
			||||||
		u32 maskedflags;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Do not allow changing controller mode while running */
 | 
					 | 
				
			||||||
		if (dev->flags & IFF_UP)
 | 
					 | 
				
			||||||
			return -EBUSY;
 | 
					 | 
				
			||||||
		cm = nla_data(data[IFLA_CAN_CTRLMODE]);
 | 
					 | 
				
			||||||
		ctrlstatic = priv->ctrlmode_static;
 | 
					 | 
				
			||||||
		maskedflags = cm->flags & cm->mask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* check whether provided bits are allowed to be passed */
 | 
					 | 
				
			||||||
		if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic))
 | 
					 | 
				
			||||||
			return -EOPNOTSUPP;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* do not check for static fd-non-iso if 'fd' is disabled */
 | 
					 | 
				
			||||||
		if (!(maskedflags & CAN_CTRLMODE_FD))
 | 
					 | 
				
			||||||
			ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* make sure static options are provided by configuration */
 | 
					 | 
				
			||||||
		if ((maskedflags & ctrlstatic) != ctrlstatic)
 | 
					 | 
				
			||||||
			return -EOPNOTSUPP;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* clear bits to be modified and copy the flag values */
 | 
					 | 
				
			||||||
		priv->ctrlmode &= ~cm->mask;
 | 
					 | 
				
			||||||
		priv->ctrlmode |= maskedflags;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* CAN_CTRLMODE_FD can only be set when driver supports FD */
 | 
					 | 
				
			||||||
		if (priv->ctrlmode & CAN_CTRLMODE_FD)
 | 
					 | 
				
			||||||
			dev->mtu = CANFD_MTU;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			dev->mtu = CAN_MTU;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (data[IFLA_CAN_RESTART_MS]) {
 | 
					 | 
				
			||||||
		/* Do not allow changing restart delay while running */
 | 
					 | 
				
			||||||
		if (dev->flags & IFF_UP)
 | 
					 | 
				
			||||||
			return -EBUSY;
 | 
					 | 
				
			||||||
		priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (data[IFLA_CAN_RESTART]) {
 | 
					 | 
				
			||||||
		/* Do not allow a restart while not running */
 | 
					 | 
				
			||||||
		if (!(dev->flags & IFF_UP))
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		err = can_restart_now(dev);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (data[IFLA_CAN_DATA_BITTIMING]) {
 | 
					 | 
				
			||||||
		struct can_bittiming dbt;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Do not allow changing bittiming while running */
 | 
					 | 
				
			||||||
		if (dev->flags & IFF_UP)
 | 
					 | 
				
			||||||
			return -EBUSY;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Calculate bittiming parameters based on
 | 
					 | 
				
			||||||
		 * data_bittiming_const if set, otherwise pass bitrate
 | 
					 | 
				
			||||||
		 * directly via do_set_bitrate(). Bail out if neither
 | 
					 | 
				
			||||||
		 * is given.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
 | 
					 | 
				
			||||||
			return -EOPNOTSUPP;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
 | 
					 | 
				
			||||||
		       sizeof(dbt));
 | 
					 | 
				
			||||||
		err = can_get_bittiming(dev, &dbt,
 | 
					 | 
				
			||||||
					priv->data_bittiming_const,
 | 
					 | 
				
			||||||
					priv->data_bitrate_const,
 | 
					 | 
				
			||||||
					priv->data_bitrate_const_cnt);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
 | 
					 | 
				
			||||||
			netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
 | 
					 | 
				
			||||||
				   priv->bitrate_max);
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (priv->do_set_data_bittiming) {
 | 
					 | 
				
			||||||
			/* Finally, set the bit-timing registers */
 | 
					 | 
				
			||||||
			err = priv->do_set_data_bittiming(dev);
 | 
					 | 
				
			||||||
			if (err)
 | 
					 | 
				
			||||||
				return err;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (data[IFLA_CAN_TERMINATION]) {
 | 
					 | 
				
			||||||
		const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);
 | 
					 | 
				
			||||||
		const unsigned int num_term = priv->termination_const_cnt;
 | 
					 | 
				
			||||||
		unsigned int i;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!priv->do_set_termination)
 | 
					 | 
				
			||||||
			return -EOPNOTSUPP;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* check whether given value is supported by the interface */
 | 
					 | 
				
			||||||
		for (i = 0; i < num_term; i++) {
 | 
					 | 
				
			||||||
			if (termval == priv->termination_const[i])
 | 
					 | 
				
			||||||
				break;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		if (i >= num_term)
 | 
					 | 
				
			||||||
			return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		/* Finally, set the termination value */
 | 
					 | 
				
			||||||
		err = priv->do_set_termination(dev, termval);
 | 
					 | 
				
			||||||
		if (err)
 | 
					 | 
				
			||||||
			return err;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		priv->termination = termval;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static size_t can_get_size(const struct net_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct can_priv *priv = netdev_priv(dev);
 | 
					 | 
				
			||||||
	size_t size = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (priv->bittiming.bitrate)				/* IFLA_CAN_BITTIMING */
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(struct can_bittiming));
 | 
					 | 
				
			||||||
	if (priv->bittiming_const)				/* IFLA_CAN_BITTIMING_CONST */
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(struct can_bittiming_const));
 | 
					 | 
				
			||||||
	size += nla_total_size(sizeof(struct can_clock));	/* IFLA_CAN_CLOCK */
 | 
					 | 
				
			||||||
	size += nla_total_size(sizeof(u32));			/* IFLA_CAN_STATE */
 | 
					 | 
				
			||||||
	size += nla_total_size(sizeof(struct can_ctrlmode));	/* IFLA_CAN_CTRLMODE */
 | 
					 | 
				
			||||||
	size += nla_total_size(sizeof(u32));			/* IFLA_CAN_RESTART_MS */
 | 
					 | 
				
			||||||
	if (priv->do_get_berr_counter)				/* IFLA_CAN_BERR_COUNTER */
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(struct can_berr_counter));
 | 
					 | 
				
			||||||
	if (priv->data_bittiming.bitrate)			/* IFLA_CAN_DATA_BITTIMING */
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(struct can_bittiming));
 | 
					 | 
				
			||||||
	if (priv->data_bittiming_const)				/* IFLA_CAN_DATA_BITTIMING_CONST */
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(struct can_bittiming_const));
 | 
					 | 
				
			||||||
	if (priv->termination_const) {
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(priv->termination));		/* IFLA_CAN_TERMINATION */
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(*priv->termination_const) *	/* IFLA_CAN_TERMINATION_CONST */
 | 
					 | 
				
			||||||
				       priv->termination_const_cnt);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (priv->bitrate_const)				/* IFLA_CAN_BITRATE_CONST */
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(*priv->bitrate_const) *
 | 
					 | 
				
			||||||
				       priv->bitrate_const_cnt);
 | 
					 | 
				
			||||||
	if (priv->data_bitrate_const)				/* IFLA_CAN_DATA_BITRATE_CONST */
 | 
					 | 
				
			||||||
		size += nla_total_size(sizeof(*priv->data_bitrate_const) *
 | 
					 | 
				
			||||||
				       priv->data_bitrate_const_cnt);
 | 
					 | 
				
			||||||
	size += sizeof(priv->bitrate_max);			/* IFLA_CAN_BITRATE_MAX */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return size;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct can_priv *priv = netdev_priv(dev);
 | 
					 | 
				
			||||||
	struct can_ctrlmode cm = {.flags = priv->ctrlmode};
 | 
					 | 
				
			||||||
	struct can_berr_counter bec;
 | 
					 | 
				
			||||||
	enum can_state state = priv->state;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (priv->do_get_state)
 | 
					 | 
				
			||||||
		priv->do_get_state(dev, &state);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((priv->bittiming.bitrate &&
 | 
					 | 
				
			||||||
	     nla_put(skb, IFLA_CAN_BITTIMING,
 | 
					 | 
				
			||||||
		     sizeof(priv->bittiming), &priv->bittiming)) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    (priv->bittiming_const &&
 | 
					 | 
				
			||||||
	     nla_put(skb, IFLA_CAN_BITTIMING_CONST,
 | 
					 | 
				
			||||||
		     sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) ||
 | 
					 | 
				
			||||||
	    nla_put_u32(skb, IFLA_CAN_STATE, state) ||
 | 
					 | 
				
			||||||
	    nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
 | 
					 | 
				
			||||||
	    nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    (priv->do_get_berr_counter &&
 | 
					 | 
				
			||||||
	     !priv->do_get_berr_counter(dev, &bec) &&
 | 
					 | 
				
			||||||
	     nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    (priv->data_bittiming.bitrate &&
 | 
					 | 
				
			||||||
	     nla_put(skb, IFLA_CAN_DATA_BITTIMING,
 | 
					 | 
				
			||||||
		     sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    (priv->data_bittiming_const &&
 | 
					 | 
				
			||||||
	     nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
 | 
					 | 
				
			||||||
		     sizeof(*priv->data_bittiming_const),
 | 
					 | 
				
			||||||
		     priv->data_bittiming_const)) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    (priv->termination_const &&
 | 
					 | 
				
			||||||
	     (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) ||
 | 
					 | 
				
			||||||
	      nla_put(skb, IFLA_CAN_TERMINATION_CONST,
 | 
					 | 
				
			||||||
		      sizeof(*priv->termination_const) *
 | 
					 | 
				
			||||||
		      priv->termination_const_cnt,
 | 
					 | 
				
			||||||
		      priv->termination_const))) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    (priv->bitrate_const &&
 | 
					 | 
				
			||||||
	     nla_put(skb, IFLA_CAN_BITRATE_CONST,
 | 
					 | 
				
			||||||
		     sizeof(*priv->bitrate_const) *
 | 
					 | 
				
			||||||
		     priv->bitrate_const_cnt,
 | 
					 | 
				
			||||||
		     priv->bitrate_const)) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    (priv->data_bitrate_const &&
 | 
					 | 
				
			||||||
	     nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
 | 
					 | 
				
			||||||
		     sizeof(*priv->data_bitrate_const) *
 | 
					 | 
				
			||||||
		     priv->data_bitrate_const_cnt,
 | 
					 | 
				
			||||||
		     priv->data_bitrate_const)) ||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	    (nla_put(skb, IFLA_CAN_BITRATE_MAX,
 | 
					 | 
				
			||||||
		     sizeof(priv->bitrate_max),
 | 
					 | 
				
			||||||
		     &priv->bitrate_max))
 | 
					 | 
				
			||||||
	    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		return -EMSGSIZE;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static size_t can_get_xstats_size(const struct net_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return sizeof(struct can_device_stats);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct can_priv *priv = netdev_priv(dev);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (nla_put(skb, IFLA_INFO_XSTATS,
 | 
					 | 
				
			||||||
		    sizeof(priv->can_stats), &priv->can_stats))
 | 
					 | 
				
			||||||
		goto nla_put_failure;
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
nla_put_failure:
 | 
					 | 
				
			||||||
	return -EMSGSIZE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int can_newlink(struct net *src_net, struct net_device *dev,
 | 
					 | 
				
			||||||
		       struct nlattr *tb[], struct nlattr *data[],
 | 
					 | 
				
			||||||
		       struct netlink_ext_ack *extack)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return -EOPNOTSUPP;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void can_dellink(struct net_device *dev, struct list_head *head)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct rtnl_link_ops can_link_ops __read_mostly = {
 | 
					 | 
				
			||||||
	.kind		= "can",
 | 
					 | 
				
			||||||
	.maxtype	= IFLA_CAN_MAX,
 | 
					 | 
				
			||||||
	.policy		= can_policy,
 | 
					 | 
				
			||||||
	.setup		= can_setup,
 | 
					 | 
				
			||||||
	.validate	= can_validate,
 | 
					 | 
				
			||||||
	.newlink	= can_newlink,
 | 
					 | 
				
			||||||
	.changelink	= can_changelink,
 | 
					 | 
				
			||||||
	.dellink	= can_dellink,
 | 
					 | 
				
			||||||
	.get_size	= can_get_size,
 | 
					 | 
				
			||||||
	.fill_info	= can_fill_info,
 | 
					 | 
				
			||||||
	.get_xstats_size = can_get_xstats_size,
 | 
					 | 
				
			||||||
	.fill_xstats	= can_fill_xstats,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/* Register the CAN network device */
 | 
					/* Register the CAN network device */
 | 
				
			||||||
int register_candev(struct net_device *dev)
 | 
					int register_candev(struct net_device *dev)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -812,7 +448,7 @@ static __init int can_dev_init(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	can_led_notifier_init();
 | 
						can_led_notifier_init();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	err = rtnl_link_register(&can_link_ops);
 | 
						err = can_netlink_register();
 | 
				
			||||||
	if (!err)
 | 
						if (!err)
 | 
				
			||||||
		pr_info(MOD_DESC "\n");
 | 
							pr_info(MOD_DESC "\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -822,7 +458,7 @@ module_init(can_dev_init);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static __exit void can_dev_exit(void)
 | 
					static __exit void can_dev_exit(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	rtnl_link_unregister(&can_link_ops);
 | 
						can_netlink_unregister();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	can_led_notifier_exit();
 | 
						can_led_notifier_exit();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										379
									
								
								drivers/net/can/dev/netlink.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								drivers/net/can/dev/netlink.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,379 @@
 | 
				
			||||||
 | 
					// SPDX-License-Identifier: GPL-2.0-only
 | 
				
			||||||
 | 
					/* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
 | 
				
			||||||
 | 
					 * Copyright (C) 2006 Andrey Volkov, Varma Electronics
 | 
				
			||||||
 | 
					 * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/can/dev.h>
 | 
				
			||||||
 | 
					#include <net/rtnetlink.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
 | 
				
			||||||
 | 
						[IFLA_CAN_STATE]	= { .type = NLA_U32 },
 | 
				
			||||||
 | 
						[IFLA_CAN_CTRLMODE]	= { .len = sizeof(struct can_ctrlmode) },
 | 
				
			||||||
 | 
						[IFLA_CAN_RESTART_MS]	= { .type = NLA_U32 },
 | 
				
			||||||
 | 
						[IFLA_CAN_RESTART]	= { .type = NLA_U32 },
 | 
				
			||||||
 | 
						[IFLA_CAN_BITTIMING]	= { .len = sizeof(struct can_bittiming) },
 | 
				
			||||||
 | 
						[IFLA_CAN_BITTIMING_CONST]
 | 
				
			||||||
 | 
									= { .len = sizeof(struct can_bittiming_const) },
 | 
				
			||||||
 | 
						[IFLA_CAN_CLOCK]	= { .len = sizeof(struct can_clock) },
 | 
				
			||||||
 | 
						[IFLA_CAN_BERR_COUNTER]	= { .len = sizeof(struct can_berr_counter) },
 | 
				
			||||||
 | 
						[IFLA_CAN_DATA_BITTIMING]
 | 
				
			||||||
 | 
									= { .len = sizeof(struct can_bittiming) },
 | 
				
			||||||
 | 
						[IFLA_CAN_DATA_BITTIMING_CONST]
 | 
				
			||||||
 | 
									= { .len = sizeof(struct can_bittiming_const) },
 | 
				
			||||||
 | 
						[IFLA_CAN_TERMINATION]	= { .type = NLA_U16 },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int can_validate(struct nlattr *tb[], struct nlattr *data[],
 | 
				
			||||||
 | 
								struct netlink_ext_ack *extack)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						bool is_can_fd = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Make sure that valid CAN FD configurations always consist of
 | 
				
			||||||
 | 
						 * - nominal/arbitration bittiming
 | 
				
			||||||
 | 
						 * - data bittiming
 | 
				
			||||||
 | 
						 * - control mode with CAN_CTRLMODE_FD set
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!data)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data[IFLA_CAN_CTRLMODE]) {
 | 
				
			||||||
 | 
							struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (is_can_fd) {
 | 
				
			||||||
 | 
							if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
 | 
				
			||||||
 | 
								return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data[IFLA_CAN_DATA_BITTIMING]) {
 | 
				
			||||||
 | 
							if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
 | 
				
			||||||
 | 
								return -EOPNOTSUPP;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int can_changelink(struct net_device *dev, struct nlattr *tb[],
 | 
				
			||||||
 | 
								  struct nlattr *data[],
 | 
				
			||||||
 | 
								  struct netlink_ext_ack *extack)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct can_priv *priv = netdev_priv(dev);
 | 
				
			||||||
 | 
						int err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* We need synchronization with dev->stop() */
 | 
				
			||||||
 | 
						ASSERT_RTNL();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data[IFLA_CAN_BITTIMING]) {
 | 
				
			||||||
 | 
							struct can_bittiming bt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Do not allow changing bittiming while running */
 | 
				
			||||||
 | 
							if (dev->flags & IFF_UP)
 | 
				
			||||||
 | 
								return -EBUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Calculate bittiming parameters based on
 | 
				
			||||||
 | 
							 * bittiming_const if set, otherwise pass bitrate
 | 
				
			||||||
 | 
							 * directly via do_set_bitrate(). Bail out if neither
 | 
				
			||||||
 | 
							 * is given.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (!priv->bittiming_const && !priv->do_set_bittiming)
 | 
				
			||||||
 | 
								return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
 | 
				
			||||||
 | 
							err = can_get_bittiming(dev, &bt,
 | 
				
			||||||
 | 
										priv->bittiming_const,
 | 
				
			||||||
 | 
										priv->bitrate_const,
 | 
				
			||||||
 | 
										priv->bitrate_const_cnt);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
 | 
				
			||||||
 | 
								netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
 | 
				
			||||||
 | 
									   priv->bitrate_max);
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(&priv->bittiming, &bt, sizeof(bt));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (priv->do_set_bittiming) {
 | 
				
			||||||
 | 
								/* Finally, set the bit-timing registers */
 | 
				
			||||||
 | 
								err = priv->do_set_bittiming(dev);
 | 
				
			||||||
 | 
								if (err)
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data[IFLA_CAN_CTRLMODE]) {
 | 
				
			||||||
 | 
							struct can_ctrlmode *cm;
 | 
				
			||||||
 | 
							u32 ctrlstatic;
 | 
				
			||||||
 | 
							u32 maskedflags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Do not allow changing controller mode while running */
 | 
				
			||||||
 | 
							if (dev->flags & IFF_UP)
 | 
				
			||||||
 | 
								return -EBUSY;
 | 
				
			||||||
 | 
							cm = nla_data(data[IFLA_CAN_CTRLMODE]);
 | 
				
			||||||
 | 
							ctrlstatic = priv->ctrlmode_static;
 | 
				
			||||||
 | 
							maskedflags = cm->flags & cm->mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* check whether provided bits are allowed to be passed */
 | 
				
			||||||
 | 
							if (cm->mask & ~(priv->ctrlmode_supported | ctrlstatic))
 | 
				
			||||||
 | 
								return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* do not check for static fd-non-iso if 'fd' is disabled */
 | 
				
			||||||
 | 
							if (!(maskedflags & CAN_CTRLMODE_FD))
 | 
				
			||||||
 | 
								ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* make sure static options are provided by configuration */
 | 
				
			||||||
 | 
							if ((maskedflags & ctrlstatic) != ctrlstatic)
 | 
				
			||||||
 | 
								return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* clear bits to be modified and copy the flag values */
 | 
				
			||||||
 | 
							priv->ctrlmode &= ~cm->mask;
 | 
				
			||||||
 | 
							priv->ctrlmode |= maskedflags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* CAN_CTRLMODE_FD can only be set when driver supports FD */
 | 
				
			||||||
 | 
							if (priv->ctrlmode & CAN_CTRLMODE_FD)
 | 
				
			||||||
 | 
								dev->mtu = CANFD_MTU;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								dev->mtu = CAN_MTU;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data[IFLA_CAN_RESTART_MS]) {
 | 
				
			||||||
 | 
							/* Do not allow changing restart delay while running */
 | 
				
			||||||
 | 
							if (dev->flags & IFF_UP)
 | 
				
			||||||
 | 
								return -EBUSY;
 | 
				
			||||||
 | 
							priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data[IFLA_CAN_RESTART]) {
 | 
				
			||||||
 | 
							/* Do not allow a restart while not running */
 | 
				
			||||||
 | 
							if (!(dev->flags & IFF_UP))
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							err = can_restart_now(dev);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data[IFLA_CAN_DATA_BITTIMING]) {
 | 
				
			||||||
 | 
							struct can_bittiming dbt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Do not allow changing bittiming while running */
 | 
				
			||||||
 | 
							if (dev->flags & IFF_UP)
 | 
				
			||||||
 | 
								return -EBUSY;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Calculate bittiming parameters based on
 | 
				
			||||||
 | 
							 * data_bittiming_const if set, otherwise pass bitrate
 | 
				
			||||||
 | 
							 * directly via do_set_bitrate(). Bail out if neither
 | 
				
			||||||
 | 
							 * is given.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
 | 
				
			||||||
 | 
								return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
 | 
				
			||||||
 | 
							       sizeof(dbt));
 | 
				
			||||||
 | 
							err = can_get_bittiming(dev, &dbt,
 | 
				
			||||||
 | 
										priv->data_bittiming_const,
 | 
				
			||||||
 | 
										priv->data_bitrate_const,
 | 
				
			||||||
 | 
										priv->data_bitrate_const_cnt);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
 | 
				
			||||||
 | 
								netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
 | 
				
			||||||
 | 
									   priv->bitrate_max);
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (priv->do_set_data_bittiming) {
 | 
				
			||||||
 | 
								/* Finally, set the bit-timing registers */
 | 
				
			||||||
 | 
								err = priv->do_set_data_bittiming(dev);
 | 
				
			||||||
 | 
								if (err)
 | 
				
			||||||
 | 
									return err;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data[IFLA_CAN_TERMINATION]) {
 | 
				
			||||||
 | 
							const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);
 | 
				
			||||||
 | 
							const unsigned int num_term = priv->termination_const_cnt;
 | 
				
			||||||
 | 
							unsigned int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (!priv->do_set_termination)
 | 
				
			||||||
 | 
								return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* check whether given value is supported by the interface */
 | 
				
			||||||
 | 
							for (i = 0; i < num_term; i++) {
 | 
				
			||||||
 | 
								if (termval == priv->termination_const[i])
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if (i >= num_term)
 | 
				
			||||||
 | 
								return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Finally, set the termination value */
 | 
				
			||||||
 | 
							err = priv->do_set_termination(dev, termval);
 | 
				
			||||||
 | 
							if (err)
 | 
				
			||||||
 | 
								return err;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							priv->termination = termval;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t can_get_size(const struct net_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct can_priv *priv = netdev_priv(dev);
 | 
				
			||||||
 | 
						size_t size = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (priv->bittiming.bitrate)				/* IFLA_CAN_BITTIMING */
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(struct can_bittiming));
 | 
				
			||||||
 | 
						if (priv->bittiming_const)				/* IFLA_CAN_BITTIMING_CONST */
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(struct can_bittiming_const));
 | 
				
			||||||
 | 
						size += nla_total_size(sizeof(struct can_clock));	/* IFLA_CAN_CLOCK */
 | 
				
			||||||
 | 
						size += nla_total_size(sizeof(u32));			/* IFLA_CAN_STATE */
 | 
				
			||||||
 | 
						size += nla_total_size(sizeof(struct can_ctrlmode));	/* IFLA_CAN_CTRLMODE */
 | 
				
			||||||
 | 
						size += nla_total_size(sizeof(u32));			/* IFLA_CAN_RESTART_MS */
 | 
				
			||||||
 | 
						if (priv->do_get_berr_counter)				/* IFLA_CAN_BERR_COUNTER */
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(struct can_berr_counter));
 | 
				
			||||||
 | 
						if (priv->data_bittiming.bitrate)			/* IFLA_CAN_DATA_BITTIMING */
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(struct can_bittiming));
 | 
				
			||||||
 | 
						if (priv->data_bittiming_const)				/* IFLA_CAN_DATA_BITTIMING_CONST */
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(struct can_bittiming_const));
 | 
				
			||||||
 | 
						if (priv->termination_const) {
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(priv->termination));		/* IFLA_CAN_TERMINATION */
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(*priv->termination_const) *	/* IFLA_CAN_TERMINATION_CONST */
 | 
				
			||||||
 | 
									       priv->termination_const_cnt);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (priv->bitrate_const)				/* IFLA_CAN_BITRATE_CONST */
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(*priv->bitrate_const) *
 | 
				
			||||||
 | 
									       priv->bitrate_const_cnt);
 | 
				
			||||||
 | 
						if (priv->data_bitrate_const)				/* IFLA_CAN_DATA_BITRATE_CONST */
 | 
				
			||||||
 | 
							size += nla_total_size(sizeof(*priv->data_bitrate_const) *
 | 
				
			||||||
 | 
									       priv->data_bitrate_const_cnt);
 | 
				
			||||||
 | 
						size += sizeof(priv->bitrate_max);			/* IFLA_CAN_BITRATE_MAX */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return size;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct can_priv *priv = netdev_priv(dev);
 | 
				
			||||||
 | 
						struct can_ctrlmode cm = {.flags = priv->ctrlmode};
 | 
				
			||||||
 | 
						struct can_berr_counter bec;
 | 
				
			||||||
 | 
						enum can_state state = priv->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (priv->do_get_state)
 | 
				
			||||||
 | 
							priv->do_get_state(dev, &state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((priv->bittiming.bitrate &&
 | 
				
			||||||
 | 
						     nla_put(skb, IFLA_CAN_BITTIMING,
 | 
				
			||||||
 | 
							     sizeof(priv->bittiming), &priv->bittiming)) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    (priv->bittiming_const &&
 | 
				
			||||||
 | 
						     nla_put(skb, IFLA_CAN_BITTIMING_CONST,
 | 
				
			||||||
 | 
							     sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) ||
 | 
				
			||||||
 | 
						    nla_put_u32(skb, IFLA_CAN_STATE, state) ||
 | 
				
			||||||
 | 
						    nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
 | 
				
			||||||
 | 
						    nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    (priv->do_get_berr_counter &&
 | 
				
			||||||
 | 
						     !priv->do_get_berr_counter(dev, &bec) &&
 | 
				
			||||||
 | 
						     nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    (priv->data_bittiming.bitrate &&
 | 
				
			||||||
 | 
						     nla_put(skb, IFLA_CAN_DATA_BITTIMING,
 | 
				
			||||||
 | 
							     sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    (priv->data_bittiming_const &&
 | 
				
			||||||
 | 
						     nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
 | 
				
			||||||
 | 
							     sizeof(*priv->data_bittiming_const),
 | 
				
			||||||
 | 
							     priv->data_bittiming_const)) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    (priv->termination_const &&
 | 
				
			||||||
 | 
						     (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) ||
 | 
				
			||||||
 | 
						      nla_put(skb, IFLA_CAN_TERMINATION_CONST,
 | 
				
			||||||
 | 
							      sizeof(*priv->termination_const) *
 | 
				
			||||||
 | 
							      priv->termination_const_cnt,
 | 
				
			||||||
 | 
							      priv->termination_const))) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    (priv->bitrate_const &&
 | 
				
			||||||
 | 
						     nla_put(skb, IFLA_CAN_BITRATE_CONST,
 | 
				
			||||||
 | 
							     sizeof(*priv->bitrate_const) *
 | 
				
			||||||
 | 
							     priv->bitrate_const_cnt,
 | 
				
			||||||
 | 
							     priv->bitrate_const)) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    (priv->data_bitrate_const &&
 | 
				
			||||||
 | 
						     nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
 | 
				
			||||||
 | 
							     sizeof(*priv->data_bitrate_const) *
 | 
				
			||||||
 | 
							     priv->data_bitrate_const_cnt,
 | 
				
			||||||
 | 
							     priv->data_bitrate_const)) ||
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    (nla_put(skb, IFLA_CAN_BITRATE_MAX,
 | 
				
			||||||
 | 
							     sizeof(priv->bitrate_max),
 | 
				
			||||||
 | 
							     &priv->bitrate_max))
 | 
				
			||||||
 | 
						    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							return -EMSGSIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static size_t can_get_xstats_size(const struct net_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return sizeof(struct can_device_stats);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct can_priv *priv = netdev_priv(dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (nla_put(skb, IFLA_INFO_XSTATS,
 | 
				
			||||||
 | 
							    sizeof(priv->can_stats), &priv->can_stats))
 | 
				
			||||||
 | 
							goto nla_put_failure;
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					nla_put_failure:
 | 
				
			||||||
 | 
						return -EMSGSIZE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int can_newlink(struct net *src_net, struct net_device *dev,
 | 
				
			||||||
 | 
							       struct nlattr *tb[], struct nlattr *data[],
 | 
				
			||||||
 | 
							       struct netlink_ext_ack *extack)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return -EOPNOTSUPP;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void can_dellink(struct net_device *dev, struct list_head *head)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct rtnl_link_ops can_link_ops __read_mostly = {
 | 
				
			||||||
 | 
						.kind		= "can",
 | 
				
			||||||
 | 
						.maxtype	= IFLA_CAN_MAX,
 | 
				
			||||||
 | 
						.policy		= can_policy,
 | 
				
			||||||
 | 
						.setup		= can_setup,
 | 
				
			||||||
 | 
						.validate	= can_validate,
 | 
				
			||||||
 | 
						.newlink	= can_newlink,
 | 
				
			||||||
 | 
						.changelink	= can_changelink,
 | 
				
			||||||
 | 
						.dellink	= can_dellink,
 | 
				
			||||||
 | 
						.get_size	= can_get_size,
 | 
				
			||||||
 | 
						.fill_info	= can_fill_info,
 | 
				
			||||||
 | 
						.get_xstats_size = can_get_xstats_size,
 | 
				
			||||||
 | 
						.fill_xstats	= can_fill_xstats,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int can_netlink_register(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return rtnl_link_register(&can_link_ops);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void can_netlink_unregister(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						rtnl_link_unregister(&can_link_ops);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -100,6 +100,8 @@ static inline void can_set_static_ctrlmode(struct net_device *dev,
 | 
				
			||||||
		dev->mtu = CANFD_MTU;
 | 
							dev->mtu = CANFD_MTU;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void can_setup(struct net_device *dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
 | 
					struct net_device *alloc_candev_mqs(int sizeof_priv, unsigned int echo_skb_max,
 | 
				
			||||||
				    unsigned int txqs, unsigned int rxqs);
 | 
									    unsigned int txqs, unsigned int rxqs);
 | 
				
			||||||
#define alloc_candev(sizeof_priv, echo_skb_max) \
 | 
					#define alloc_candev(sizeof_priv, echo_skb_max) \
 | 
				
			||||||
| 
						 | 
					@ -130,4 +132,8 @@ void of_can_transceiver(struct net_device *dev);
 | 
				
			||||||
static inline void of_can_transceiver(struct net_device *dev) { }
 | 
					static inline void of_can_transceiver(struct net_device *dev) { }
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern struct rtnl_link_ops can_link_ops;
 | 
				
			||||||
 | 
					int can_netlink_register(void);
 | 
				
			||||||
 | 
					void can_netlink_unregister(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* !_CAN_DEV_H */
 | 
					#endif /* !_CAN_DEV_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue