xref: /openbmc/linux/drivers/net/can/dev/netlink.c (revision fac59652993f075d57860769c99045b3ca18780d)
10a042c6eSMarc Kleine-Budde // SPDX-License-Identifier: GPL-2.0-only
20a042c6eSMarc Kleine-Budde /* Copyright (C) 2005 Marc Kleine-Budde, Pengutronix
30a042c6eSMarc Kleine-Budde  * Copyright (C) 2006 Andrey Volkov, Varma Electronics
40a042c6eSMarc Kleine-Budde  * Copyright (C) 2008-2009 Wolfgang Grandegger <wg@grandegger.com>
5d99755f7SVincent Mailhol  * Copyright (C) 2021 Vincent Mailhol <mailhol.vincent@wanadoo.fr>
60a042c6eSMarc Kleine-Budde  */
70a042c6eSMarc Kleine-Budde 
80a042c6eSMarc Kleine-Budde #include <linux/can/dev.h>
90a042c6eSMarc Kleine-Budde #include <net/rtnetlink.h>
100a042c6eSMarc Kleine-Budde 
110a042c6eSMarc Kleine-Budde static const struct nla_policy can_policy[IFLA_CAN_MAX + 1] = {
120a042c6eSMarc Kleine-Budde 	[IFLA_CAN_STATE] = { .type = NLA_U32 },
130a042c6eSMarc Kleine-Budde 	[IFLA_CAN_CTRLMODE] = { .len = sizeof(struct can_ctrlmode) },
140a042c6eSMarc Kleine-Budde 	[IFLA_CAN_RESTART_MS] = { .type = NLA_U32 },
150a042c6eSMarc Kleine-Budde 	[IFLA_CAN_RESTART] = { .type = NLA_U32 },
160a042c6eSMarc Kleine-Budde 	[IFLA_CAN_BITTIMING] = { .len = sizeof(struct can_bittiming) },
17cfd98c83SVincent Mailhol 	[IFLA_CAN_BITTIMING_CONST] = { .len = sizeof(struct can_bittiming_const) },
180a042c6eSMarc Kleine-Budde 	[IFLA_CAN_CLOCK] = { .len = sizeof(struct can_clock) },
190a042c6eSMarc Kleine-Budde 	[IFLA_CAN_BERR_COUNTER] = { .len = sizeof(struct can_berr_counter) },
20cfd98c83SVincent Mailhol 	[IFLA_CAN_DATA_BITTIMING] = { .len = sizeof(struct can_bittiming) },
21cfd98c83SVincent Mailhol 	[IFLA_CAN_DATA_BITTIMING_CONST]	= { .len = sizeof(struct can_bittiming_const) },
220a042c6eSMarc Kleine-Budde 	[IFLA_CAN_TERMINATION] = { .type = NLA_U16 },
23d99755f7SVincent Mailhol 	[IFLA_CAN_TDC] = { .type = NLA_NESTED },
24383f0993SVincent Mailhol 	[IFLA_CAN_CTRLMODE_EXT] = { .type = NLA_NESTED },
25d99755f7SVincent Mailhol };
26d99755f7SVincent Mailhol 
27d99755f7SVincent Mailhol static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = {
28d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCV_MIN] = { .type = NLA_U32 },
29d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCV_MAX] = { .type = NLA_U32 },
30d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCO_MIN] = { .type = NLA_U32 },
31d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCO_MAX] = { .type = NLA_U32 },
32d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCF_MIN] = { .type = NLA_U32 },
33d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCF_MAX] = { .type = NLA_U32 },
34d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCV] = { .type = NLA_U32 },
35d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCO] = { .type = NLA_U32 },
36d99755f7SVincent Mailhol 	[IFLA_CAN_TDC_TDCF] = { .type = NLA_U32 },
370a042c6eSMarc Kleine-Budde };
380a042c6eSMarc Kleine-Budde 
can_validate_bittiming(const struct can_bittiming * bt,struct netlink_ext_ack * extack)3973335cfaSMarc Kleine-Budde static int can_validate_bittiming(const struct can_bittiming *bt,
4073335cfaSMarc Kleine-Budde 				  struct netlink_ext_ack *extack)
4173335cfaSMarc Kleine-Budde {
4273335cfaSMarc Kleine-Budde 	/* sample point is in one-tenth of a percent */
4373335cfaSMarc Kleine-Budde 	if (bt->sample_point >= 1000) {
4473335cfaSMarc Kleine-Budde 		NL_SET_ERR_MSG(extack, "sample point must be between 0 and 100%");
4573335cfaSMarc Kleine-Budde 
4673335cfaSMarc Kleine-Budde 		return -EINVAL;
4773335cfaSMarc Kleine-Budde 	}
4873335cfaSMarc Kleine-Budde 
4973335cfaSMarc Kleine-Budde 	return 0;
5073335cfaSMarc Kleine-Budde }
5173335cfaSMarc Kleine-Budde 
can_validate(struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)520a042c6eSMarc Kleine-Budde static int can_validate(struct nlattr *tb[], struct nlattr *data[],
530a042c6eSMarc Kleine-Budde 			struct netlink_ext_ack *extack)
540a042c6eSMarc Kleine-Budde {
550a042c6eSMarc Kleine-Budde 	bool is_can_fd = false;
5673335cfaSMarc Kleine-Budde 	int err;
570a042c6eSMarc Kleine-Budde 
580a042c6eSMarc Kleine-Budde 	/* Make sure that valid CAN FD configurations always consist of
590a042c6eSMarc Kleine-Budde 	 * - nominal/arbitration bittiming
600a042c6eSMarc Kleine-Budde 	 * - data bittiming
610a042c6eSMarc Kleine-Budde 	 * - control mode with CAN_CTRLMODE_FD set
62d99755f7SVincent Mailhol 	 * - TDC parameters are coherent (details below)
630a042c6eSMarc Kleine-Budde 	 */
640a042c6eSMarc Kleine-Budde 
650a042c6eSMarc Kleine-Budde 	if (!data)
660a042c6eSMarc Kleine-Budde 		return 0;
670a042c6eSMarc Kleine-Budde 
680a042c6eSMarc Kleine-Budde 	if (data[IFLA_CAN_CTRLMODE]) {
690a042c6eSMarc Kleine-Budde 		struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
70d99755f7SVincent Mailhol 		u32 tdc_flags = cm->flags & CAN_CTRLMODE_TDC_MASK;
710a042c6eSMarc Kleine-Budde 
720a042c6eSMarc Kleine-Budde 		is_can_fd = cm->flags & cm->mask & CAN_CTRLMODE_FD;
73d99755f7SVincent Mailhol 
74d99755f7SVincent Mailhol 		/* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually exclusive */
75d99755f7SVincent Mailhol 		if (tdc_flags == CAN_CTRLMODE_TDC_MASK)
76d99755f7SVincent Mailhol 			return -EOPNOTSUPP;
77d99755f7SVincent Mailhol 		/* If one of the CAN_CTRLMODE_TDC_* flag is set then
78d99755f7SVincent Mailhol 		 * TDC must be set and vice-versa
79d99755f7SVincent Mailhol 		 */
80d99755f7SVincent Mailhol 		if (!!tdc_flags != !!data[IFLA_CAN_TDC])
81d99755f7SVincent Mailhol 			return -EOPNOTSUPP;
82d99755f7SVincent Mailhol 		/* If providing TDC parameters, at least TDCO is
83d99755f7SVincent Mailhol 		 * needed. TDCV is needed if and only if
84d99755f7SVincent Mailhol 		 * CAN_CTRLMODE_TDC_MANUAL is set
85d99755f7SVincent Mailhol 		 */
86d99755f7SVincent Mailhol 		if (data[IFLA_CAN_TDC]) {
87d99755f7SVincent Mailhol 			struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1];
88d99755f7SVincent Mailhol 
89d99755f7SVincent Mailhol 			err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX,
90d99755f7SVincent Mailhol 					       data[IFLA_CAN_TDC],
91d99755f7SVincent Mailhol 					       can_tdc_policy, extack);
92d99755f7SVincent Mailhol 			if (err)
93d99755f7SVincent Mailhol 				return err;
94d99755f7SVincent Mailhol 
95d99755f7SVincent Mailhol 			if (tb_tdc[IFLA_CAN_TDC_TDCV]) {
96d99755f7SVincent Mailhol 				if (tdc_flags & CAN_CTRLMODE_TDC_AUTO)
97d99755f7SVincent Mailhol 					return -EOPNOTSUPP;
98d99755f7SVincent Mailhol 			} else {
99d99755f7SVincent Mailhol 				if (tdc_flags & CAN_CTRLMODE_TDC_MANUAL)
100d99755f7SVincent Mailhol 					return -EOPNOTSUPP;
101d99755f7SVincent Mailhol 			}
102d99755f7SVincent Mailhol 
103d99755f7SVincent Mailhol 			if (!tb_tdc[IFLA_CAN_TDC_TDCO])
104d99755f7SVincent Mailhol 				return -EOPNOTSUPP;
105d99755f7SVincent Mailhol 		}
1060a042c6eSMarc Kleine-Budde 	}
1070a042c6eSMarc Kleine-Budde 
108*b4f8240bSStefan Mätje 	if (data[IFLA_CAN_BITTIMING]) {
109*b4f8240bSStefan Mätje 		struct can_bittiming bt;
110*b4f8240bSStefan Mätje 
111*b4f8240bSStefan Mätje 		memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
112*b4f8240bSStefan Mätje 		err = can_validate_bittiming(&bt, extack);
113*b4f8240bSStefan Mätje 		if (err)
114*b4f8240bSStefan Mätje 			return err;
115*b4f8240bSStefan Mätje 	}
116*b4f8240bSStefan Mätje 
1170a042c6eSMarc Kleine-Budde 	if (is_can_fd) {
1180a042c6eSMarc Kleine-Budde 		if (!data[IFLA_CAN_BITTIMING] || !data[IFLA_CAN_DATA_BITTIMING])
1190a042c6eSMarc Kleine-Budde 			return -EOPNOTSUPP;
1200a042c6eSMarc Kleine-Budde 	}
1210a042c6eSMarc Kleine-Budde 
122d99755f7SVincent Mailhol 	if (data[IFLA_CAN_DATA_BITTIMING] || data[IFLA_CAN_TDC]) {
1236b6bd199SVincent Mailhol 		if (!is_can_fd)
1240a042c6eSMarc Kleine-Budde 			return -EOPNOTSUPP;
1250a042c6eSMarc Kleine-Budde 	}
1260a042c6eSMarc Kleine-Budde 
12773335cfaSMarc Kleine-Budde 	if (data[IFLA_CAN_DATA_BITTIMING]) {
12873335cfaSMarc Kleine-Budde 		struct can_bittiming bt;
12973335cfaSMarc Kleine-Budde 
13073335cfaSMarc Kleine-Budde 		memcpy(&bt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), sizeof(bt));
13173335cfaSMarc Kleine-Budde 		err = can_validate_bittiming(&bt, extack);
13273335cfaSMarc Kleine-Budde 		if (err)
13373335cfaSMarc Kleine-Budde 			return err;
13473335cfaSMarc Kleine-Budde 	}
13573335cfaSMarc Kleine-Budde 
1360a042c6eSMarc Kleine-Budde 	return 0;
1370a042c6eSMarc Kleine-Budde }
1380a042c6eSMarc Kleine-Budde 
can_tdc_changelink(struct can_priv * priv,const struct nlattr * nla,struct netlink_ext_ack * extack)139d99755f7SVincent Mailhol static int can_tdc_changelink(struct can_priv *priv, const struct nlattr *nla,
140d99755f7SVincent Mailhol 			      struct netlink_ext_ack *extack)
141d99755f7SVincent Mailhol {
142d99755f7SVincent Mailhol 	struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1];
143d99755f7SVincent Mailhol 	struct can_tdc tdc = { 0 };
144d99755f7SVincent Mailhol 	const struct can_tdc_const *tdc_const = priv->tdc_const;
145d99755f7SVincent Mailhol 	int err;
146d99755f7SVincent Mailhol 
147d99755f7SVincent Mailhol 	if (!tdc_const || !can_tdc_is_enabled(priv))
148d99755f7SVincent Mailhol 		return -EOPNOTSUPP;
149d99755f7SVincent Mailhol 
150d99755f7SVincent Mailhol 	err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX, nla,
151d99755f7SVincent Mailhol 			       can_tdc_policy, extack);
152d99755f7SVincent Mailhol 	if (err)
153d99755f7SVincent Mailhol 		return err;
154d99755f7SVincent Mailhol 
155d99755f7SVincent Mailhol 	if (tb_tdc[IFLA_CAN_TDC_TDCV]) {
156d99755f7SVincent Mailhol 		u32 tdcv = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCV]);
157d99755f7SVincent Mailhol 
158d99755f7SVincent Mailhol 		if (tdcv < tdc_const->tdcv_min || tdcv > tdc_const->tdcv_max)
159d99755f7SVincent Mailhol 			return -EINVAL;
160d99755f7SVincent Mailhol 
161d99755f7SVincent Mailhol 		tdc.tdcv = tdcv;
162d99755f7SVincent Mailhol 	}
163d99755f7SVincent Mailhol 
164d99755f7SVincent Mailhol 	if (tb_tdc[IFLA_CAN_TDC_TDCO]) {
165d99755f7SVincent Mailhol 		u32 tdco = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCO]);
166d99755f7SVincent Mailhol 
167d99755f7SVincent Mailhol 		if (tdco < tdc_const->tdco_min || tdco > tdc_const->tdco_max)
168d99755f7SVincent Mailhol 			return -EINVAL;
169d99755f7SVincent Mailhol 
170d99755f7SVincent Mailhol 		tdc.tdco = tdco;
171d99755f7SVincent Mailhol 	}
172d99755f7SVincent Mailhol 
173d99755f7SVincent Mailhol 	if (tb_tdc[IFLA_CAN_TDC_TDCF]) {
174d99755f7SVincent Mailhol 		u32 tdcf = nla_get_u32(tb_tdc[IFLA_CAN_TDC_TDCF]);
175d99755f7SVincent Mailhol 
176d99755f7SVincent Mailhol 		if (tdcf < tdc_const->tdcf_min || tdcf > tdc_const->tdcf_max)
177d99755f7SVincent Mailhol 			return -EINVAL;
178d99755f7SVincent Mailhol 
179d99755f7SVincent Mailhol 		tdc.tdcf = tdcf;
180d99755f7SVincent Mailhol 	}
181d99755f7SVincent Mailhol 
182d99755f7SVincent Mailhol 	priv->tdc = tdc;
183d99755f7SVincent Mailhol 
184d99755f7SVincent Mailhol 	return 0;
185d99755f7SVincent Mailhol }
186d99755f7SVincent Mailhol 
can_changelink(struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)1870a042c6eSMarc Kleine-Budde static int can_changelink(struct net_device *dev, struct nlattr *tb[],
1880a042c6eSMarc Kleine-Budde 			  struct nlattr *data[],
1890a042c6eSMarc Kleine-Budde 			  struct netlink_ext_ack *extack)
1900a042c6eSMarc Kleine-Budde {
1910a042c6eSMarc Kleine-Budde 	struct can_priv *priv = netdev_priv(dev);
192d99755f7SVincent Mailhol 	u32 tdc_mask = 0;
1930a042c6eSMarc Kleine-Budde 	int err;
1940a042c6eSMarc Kleine-Budde 
1950a042c6eSMarc Kleine-Budde 	/* We need synchronization with dev->stop() */
1960a042c6eSMarc Kleine-Budde 	ASSERT_RTNL();
1970a042c6eSMarc Kleine-Budde 
1980a042c6eSMarc Kleine-Budde 	if (data[IFLA_CAN_CTRLMODE]) {
1990a042c6eSMarc Kleine-Budde 		struct can_ctrlmode *cm;
2000a042c6eSMarc Kleine-Budde 		u32 ctrlstatic;
2010a042c6eSMarc Kleine-Budde 		u32 maskedflags;
2020a042c6eSMarc Kleine-Budde 
2030a042c6eSMarc Kleine-Budde 		/* Do not allow changing controller mode while running */
2040a042c6eSMarc Kleine-Budde 		if (dev->flags & IFF_UP)
2050a042c6eSMarc Kleine-Budde 			return -EBUSY;
2060a042c6eSMarc Kleine-Budde 		cm = nla_data(data[IFLA_CAN_CTRLMODE]);
207c9e1d8edSVincent Mailhol 		ctrlstatic = can_get_static_ctrlmode(priv);
2080a042c6eSMarc Kleine-Budde 		maskedflags = cm->flags & cm->mask;
2090a042c6eSMarc Kleine-Budde 
2100a042c6eSMarc Kleine-Budde 		/* check whether provided bits are allowed to be passed */
211e43aaa0fSVincent Mailhol 		if (maskedflags & ~(priv->ctrlmode_supported | ctrlstatic))
2120a042c6eSMarc Kleine-Budde 			return -EOPNOTSUPP;
2130a042c6eSMarc Kleine-Budde 
2140a042c6eSMarc Kleine-Budde 		/* do not check for static fd-non-iso if 'fd' is disabled */
2150a042c6eSMarc Kleine-Budde 		if (!(maskedflags & CAN_CTRLMODE_FD))
2160a042c6eSMarc Kleine-Budde 			ctrlstatic &= ~CAN_CTRLMODE_FD_NON_ISO;
2170a042c6eSMarc Kleine-Budde 
2180a042c6eSMarc Kleine-Budde 		/* make sure static options are provided by configuration */
2190a042c6eSMarc Kleine-Budde 		if ((maskedflags & ctrlstatic) != ctrlstatic)
2200a042c6eSMarc Kleine-Budde 			return -EOPNOTSUPP;
2210a042c6eSMarc Kleine-Budde 
2220a042c6eSMarc Kleine-Budde 		/* clear bits to be modified and copy the flag values */
2230a042c6eSMarc Kleine-Budde 		priv->ctrlmode &= ~cm->mask;
2240a042c6eSMarc Kleine-Budde 		priv->ctrlmode |= maskedflags;
2250a042c6eSMarc Kleine-Budde 
2260a042c6eSMarc Kleine-Budde 		/* CAN_CTRLMODE_FD can only be set when driver supports FD */
227e3b0a4a4SVincent Mailhol 		if (priv->ctrlmode & CAN_CTRLMODE_FD) {
2280a042c6eSMarc Kleine-Budde 			dev->mtu = CANFD_MTU;
229e3b0a4a4SVincent Mailhol 		} else {
2300a042c6eSMarc Kleine-Budde 			dev->mtu = CAN_MTU;
231e3b0a4a4SVincent Mailhol 			memset(&priv->data_bittiming, 0,
232e3b0a4a4SVincent Mailhol 			       sizeof(priv->data_bittiming));
233d99755f7SVincent Mailhol 			priv->ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
234d99755f7SVincent Mailhol 			memset(&priv->tdc, 0, sizeof(priv->tdc));
235e3b0a4a4SVincent Mailhol 		}
236d99755f7SVincent Mailhol 
237d99755f7SVincent Mailhol 		tdc_mask = cm->mask & CAN_CTRLMODE_TDC_MASK;
238d99755f7SVincent Mailhol 		/* CAN_CTRLMODE_TDC_{AUTO,MANUAL} are mutually
239d99755f7SVincent Mailhol 		 * exclusive: make sure to turn the other one off
240d99755f7SVincent Mailhol 		 */
241d99755f7SVincent Mailhol 		if (tdc_mask)
242d99755f7SVincent Mailhol 			priv->ctrlmode &= cm->flags | ~CAN_CTRLMODE_TDC_MASK;
2430a042c6eSMarc Kleine-Budde 	}
2440a042c6eSMarc Kleine-Budde 
245*b4f8240bSStefan Mätje 	if (data[IFLA_CAN_BITTIMING]) {
246*b4f8240bSStefan Mätje 		struct can_bittiming bt;
247*b4f8240bSStefan Mätje 
248*b4f8240bSStefan Mätje 		/* Do not allow changing bittiming while running */
249*b4f8240bSStefan Mätje 		if (dev->flags & IFF_UP)
250*b4f8240bSStefan Mätje 			return -EBUSY;
251*b4f8240bSStefan Mätje 
252*b4f8240bSStefan Mätje 		/* Calculate bittiming parameters based on
253*b4f8240bSStefan Mätje 		 * bittiming_const if set, otherwise pass bitrate
254*b4f8240bSStefan Mätje 		 * directly via do_set_bitrate(). Bail out if neither
255*b4f8240bSStefan Mätje 		 * is given.
256*b4f8240bSStefan Mätje 		 */
257*b4f8240bSStefan Mätje 		if (!priv->bittiming_const && !priv->do_set_bittiming &&
258*b4f8240bSStefan Mätje 		    !priv->bitrate_const)
259*b4f8240bSStefan Mätje 			return -EOPNOTSUPP;
260*b4f8240bSStefan Mätje 
261*b4f8240bSStefan Mätje 		memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
262*b4f8240bSStefan Mätje 		err = can_get_bittiming(dev, &bt,
263*b4f8240bSStefan Mätje 					priv->bittiming_const,
264*b4f8240bSStefan Mätje 					priv->bitrate_const,
265*b4f8240bSStefan Mätje 					priv->bitrate_const_cnt,
266*b4f8240bSStefan Mätje 					extack);
267*b4f8240bSStefan Mätje 		if (err)
268*b4f8240bSStefan Mätje 			return err;
269*b4f8240bSStefan Mätje 
270*b4f8240bSStefan Mätje 		if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
271*b4f8240bSStefan Mätje 			NL_SET_ERR_MSG_FMT(extack,
272*b4f8240bSStefan Mätje 					   "arbitration bitrate %u bps surpasses transceiver capabilities of %u bps",
273*b4f8240bSStefan Mätje 					   bt.bitrate, priv->bitrate_max);
274*b4f8240bSStefan Mätje 			return -EINVAL;
275*b4f8240bSStefan Mätje 		}
276*b4f8240bSStefan Mätje 
277*b4f8240bSStefan Mätje 		memcpy(&priv->bittiming, &bt, sizeof(bt));
278*b4f8240bSStefan Mätje 
279*b4f8240bSStefan Mätje 		if (priv->do_set_bittiming) {
280*b4f8240bSStefan Mätje 			/* Finally, set the bit-timing registers */
281*b4f8240bSStefan Mätje 			err = priv->do_set_bittiming(dev);
282*b4f8240bSStefan Mätje 			if (err)
283*b4f8240bSStefan Mätje 				return err;
284*b4f8240bSStefan Mätje 		}
285*b4f8240bSStefan Mätje 	}
286*b4f8240bSStefan Mätje 
2870a042c6eSMarc Kleine-Budde 	if (data[IFLA_CAN_RESTART_MS]) {
2880a042c6eSMarc Kleine-Budde 		/* Do not allow changing restart delay while running */
2890a042c6eSMarc Kleine-Budde 		if (dev->flags & IFF_UP)
2900a042c6eSMarc Kleine-Budde 			return -EBUSY;
2910a042c6eSMarc Kleine-Budde 		priv->restart_ms = nla_get_u32(data[IFLA_CAN_RESTART_MS]);
2920a042c6eSMarc Kleine-Budde 	}
2930a042c6eSMarc Kleine-Budde 
2940a042c6eSMarc Kleine-Budde 	if (data[IFLA_CAN_RESTART]) {
2950a042c6eSMarc Kleine-Budde 		/* Do not allow a restart while not running */
2960a042c6eSMarc Kleine-Budde 		if (!(dev->flags & IFF_UP))
2970a042c6eSMarc Kleine-Budde 			return -EINVAL;
2980a042c6eSMarc Kleine-Budde 		err = can_restart_now(dev);
2990a042c6eSMarc Kleine-Budde 		if (err)
3000a042c6eSMarc Kleine-Budde 			return err;
3010a042c6eSMarc Kleine-Budde 	}
3020a042c6eSMarc Kleine-Budde 
3030a042c6eSMarc Kleine-Budde 	if (data[IFLA_CAN_DATA_BITTIMING]) {
3040a042c6eSMarc Kleine-Budde 		struct can_bittiming dbt;
3050a042c6eSMarc Kleine-Budde 
3060a042c6eSMarc Kleine-Budde 		/* Do not allow changing bittiming while running */
3070a042c6eSMarc Kleine-Budde 		if (dev->flags & IFF_UP)
3080a042c6eSMarc Kleine-Budde 			return -EBUSY;
3090a042c6eSMarc Kleine-Budde 
3100a042c6eSMarc Kleine-Budde 		/* Calculate bittiming parameters based on
3110a042c6eSMarc Kleine-Budde 		 * data_bittiming_const if set, otherwise pass bitrate
3120a042c6eSMarc Kleine-Budde 		 * directly via do_set_bitrate(). Bail out if neither
3130a042c6eSMarc Kleine-Budde 		 * is given.
3140a042c6eSMarc Kleine-Budde 		 */
315ec30c109SMarc Kleine-Budde 		if (!priv->data_bittiming_const && !priv->do_set_data_bittiming &&
316ec30c109SMarc Kleine-Budde 		    !priv->data_bitrate_const)
3170a042c6eSMarc Kleine-Budde 			return -EOPNOTSUPP;
3180a042c6eSMarc Kleine-Budde 
3190a042c6eSMarc Kleine-Budde 		memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
3200a042c6eSMarc Kleine-Budde 		       sizeof(dbt));
3210a042c6eSMarc Kleine-Budde 		err = can_get_bittiming(dev, &dbt,
3220a042c6eSMarc Kleine-Budde 					priv->data_bittiming_const,
3230a042c6eSMarc Kleine-Budde 					priv->data_bitrate_const,
324286c0e09SMarc Kleine-Budde 					priv->data_bitrate_const_cnt,
325286c0e09SMarc Kleine-Budde 					extack);
3260a042c6eSMarc Kleine-Budde 		if (err)
3270a042c6eSMarc Kleine-Budde 			return err;
3280a042c6eSMarc Kleine-Budde 
3290a042c6eSMarc Kleine-Budde 		if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
3301494d27fSMarc Kleine-Budde 			NL_SET_ERR_MSG_FMT(extack,
3311494d27fSMarc Kleine-Budde 					   "CANFD data bitrate %u bps surpasses transceiver capabilities of %u bps",
3321494d27fSMarc Kleine-Budde 					   dbt.bitrate, priv->bitrate_max);
3330a042c6eSMarc Kleine-Budde 			return -EINVAL;
3340a042c6eSMarc Kleine-Budde 		}
3350a042c6eSMarc Kleine-Budde 
336d99755f7SVincent Mailhol 		memset(&priv->tdc, 0, sizeof(priv->tdc));
337d99755f7SVincent Mailhol 		if (data[IFLA_CAN_TDC]) {
338d99755f7SVincent Mailhol 			/* TDC parameters are provided: use them */
339d99755f7SVincent Mailhol 			err = can_tdc_changelink(priv, data[IFLA_CAN_TDC],
340d99755f7SVincent Mailhol 						 extack);
341d99755f7SVincent Mailhol 			if (err) {
342d99755f7SVincent Mailhol 				priv->ctrlmode &= ~CAN_CTRLMODE_TDC_MASK;
343d99755f7SVincent Mailhol 				return err;
344d99755f7SVincent Mailhol 			}
345d99755f7SVincent Mailhol 		} else if (!tdc_mask) {
346d99755f7SVincent Mailhol 			/* Neither of TDC parameters nor TDC flags are
347d99755f7SVincent Mailhol 			 * provided: do calculation
348d99755f7SVincent Mailhol 			 */
3496019c773SMaxime Jayat 			can_calc_tdco(&priv->tdc, priv->tdc_const, &dbt,
350da45a1e4SVincent Mailhol 				      &priv->ctrlmode, priv->ctrlmode_supported);
351d99755f7SVincent Mailhol 		} /* else: both CAN_CTRLMODE_TDC_{AUTO,MANUAL} are explicitly
352d99755f7SVincent Mailhol 		   * turned off. TDC is disabled: do nothing
353d99755f7SVincent Mailhol 		   */
354d99755f7SVincent Mailhol 
355d99755f7SVincent Mailhol 		memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
356c25cc799SVincent Mailhol 
3570a042c6eSMarc Kleine-Budde 		if (priv->do_set_data_bittiming) {
3580a042c6eSMarc Kleine-Budde 			/* Finally, set the bit-timing registers */
3590a042c6eSMarc Kleine-Budde 			err = priv->do_set_data_bittiming(dev);
3600a042c6eSMarc Kleine-Budde 			if (err)
3610a042c6eSMarc Kleine-Budde 				return err;
3620a042c6eSMarc Kleine-Budde 		}
3630a042c6eSMarc Kleine-Budde 	}
3640a042c6eSMarc Kleine-Budde 
3650a042c6eSMarc Kleine-Budde 	if (data[IFLA_CAN_TERMINATION]) {
3660a042c6eSMarc Kleine-Budde 		const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);
3670a042c6eSMarc Kleine-Budde 		const unsigned int num_term = priv->termination_const_cnt;
3680a042c6eSMarc Kleine-Budde 		unsigned int i;
3690a042c6eSMarc Kleine-Budde 
3700a042c6eSMarc Kleine-Budde 		if (!priv->do_set_termination)
3710a042c6eSMarc Kleine-Budde 			return -EOPNOTSUPP;
3720a042c6eSMarc Kleine-Budde 
3730a042c6eSMarc Kleine-Budde 		/* check whether given value is supported by the interface */
3740a042c6eSMarc Kleine-Budde 		for (i = 0; i < num_term; i++) {
3750a042c6eSMarc Kleine-Budde 			if (termval == priv->termination_const[i])
3760a042c6eSMarc Kleine-Budde 				break;
3770a042c6eSMarc Kleine-Budde 		}
3780a042c6eSMarc Kleine-Budde 		if (i >= num_term)
3790a042c6eSMarc Kleine-Budde 			return -EINVAL;
3800a042c6eSMarc Kleine-Budde 
3810a042c6eSMarc Kleine-Budde 		/* Finally, set the termination value */
3820a042c6eSMarc Kleine-Budde 		err = priv->do_set_termination(dev, termval);
3830a042c6eSMarc Kleine-Budde 		if (err)
3840a042c6eSMarc Kleine-Budde 			return err;
3850a042c6eSMarc Kleine-Budde 
3860a042c6eSMarc Kleine-Budde 		priv->termination = termval;
3870a042c6eSMarc Kleine-Budde 	}
3880a042c6eSMarc Kleine-Budde 
3890a042c6eSMarc Kleine-Budde 	return 0;
3900a042c6eSMarc Kleine-Budde }
3910a042c6eSMarc Kleine-Budde 
can_tdc_get_size(const struct net_device * dev)392d99755f7SVincent Mailhol static size_t can_tdc_get_size(const struct net_device *dev)
393d99755f7SVincent Mailhol {
394d99755f7SVincent Mailhol 	struct can_priv *priv = netdev_priv(dev);
395d99755f7SVincent Mailhol 	size_t size;
396d99755f7SVincent Mailhol 
397d99755f7SVincent Mailhol 	if (!priv->tdc_const)
398d99755f7SVincent Mailhol 		return 0;
399d99755f7SVincent Mailhol 
400d99755f7SVincent Mailhol 	size = nla_total_size(0);			/* nest IFLA_CAN_TDC */
401d99755f7SVincent Mailhol 	if (priv->ctrlmode_supported & CAN_CTRLMODE_TDC_MANUAL) {
402d99755f7SVincent Mailhol 		size += nla_total_size(sizeof(u32));	/* IFLA_CAN_TDCV_MIN */
403d99755f7SVincent Mailhol 		size += nla_total_size(sizeof(u32));	/* IFLA_CAN_TDCV_MAX */
404d99755f7SVincent Mailhol 	}
405d99755f7SVincent Mailhol 	size += nla_total_size(sizeof(u32));		/* IFLA_CAN_TDCO_MIN */
406d99755f7SVincent Mailhol 	size += nla_total_size(sizeof(u32));		/* IFLA_CAN_TDCO_MAX */
407d99755f7SVincent Mailhol 	if (priv->tdc_const->tdcf_max) {
408d99755f7SVincent Mailhol 		size += nla_total_size(sizeof(u32));	/* IFLA_CAN_TDCF_MIN */
409d99755f7SVincent Mailhol 		size += nla_total_size(sizeof(u32));	/* IFLA_CAN_TDCF_MAX */
410d99755f7SVincent Mailhol 	}
411d99755f7SVincent Mailhol 
412d99755f7SVincent Mailhol 	if (can_tdc_is_enabled(priv)) {
413e8060f08SVincent Mailhol 		if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL ||
414e8060f08SVincent Mailhol 		    priv->do_get_auto_tdcv)
415d99755f7SVincent Mailhol 			size += nla_total_size(sizeof(u32));	/* IFLA_CAN_TDCV */
416d99755f7SVincent Mailhol 		size += nla_total_size(sizeof(u32));		/* IFLA_CAN_TDCO */
417d99755f7SVincent Mailhol 		if (priv->tdc_const->tdcf_max)
418d99755f7SVincent Mailhol 			size += nla_total_size(sizeof(u32));	/* IFLA_CAN_TDCF */
419d99755f7SVincent Mailhol 	}
420d99755f7SVincent Mailhol 
421d99755f7SVincent Mailhol 	return size;
422d99755f7SVincent Mailhol }
423d99755f7SVincent Mailhol 
can_ctrlmode_ext_get_size(void)424383f0993SVincent Mailhol static size_t can_ctrlmode_ext_get_size(void)
425383f0993SVincent Mailhol {
426383f0993SVincent Mailhol 	return nla_total_size(0) +		/* nest IFLA_CAN_CTRLMODE_EXT */
427383f0993SVincent Mailhol 		nla_total_size(sizeof(u32));	/* IFLA_CAN_CTRLMODE_SUPPORTED */
428383f0993SVincent Mailhol }
429383f0993SVincent Mailhol 
can_get_size(const struct net_device * dev)4300a042c6eSMarc Kleine-Budde static size_t can_get_size(const struct net_device *dev)
4310a042c6eSMarc Kleine-Budde {
4320a042c6eSMarc Kleine-Budde 	struct can_priv *priv = netdev_priv(dev);
4330a042c6eSMarc Kleine-Budde 	size_t size = 0;
4340a042c6eSMarc Kleine-Budde 
4350a042c6eSMarc Kleine-Budde 	if (priv->bittiming.bitrate)				/* IFLA_CAN_BITTIMING */
4360a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(struct can_bittiming));
4370a042c6eSMarc Kleine-Budde 	if (priv->bittiming_const)				/* IFLA_CAN_BITTIMING_CONST */
4380a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(struct can_bittiming_const));
4390a042c6eSMarc Kleine-Budde 	size += nla_total_size(sizeof(struct can_clock));	/* IFLA_CAN_CLOCK */
4400a042c6eSMarc Kleine-Budde 	size += nla_total_size(sizeof(u32));			/* IFLA_CAN_STATE */
4410a042c6eSMarc Kleine-Budde 	size += nla_total_size(sizeof(struct can_ctrlmode));	/* IFLA_CAN_CTRLMODE */
4420a042c6eSMarc Kleine-Budde 	size += nla_total_size(sizeof(u32));			/* IFLA_CAN_RESTART_MS */
4430a042c6eSMarc Kleine-Budde 	if (priv->do_get_berr_counter)				/* IFLA_CAN_BERR_COUNTER */
4440a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(struct can_berr_counter));
4450a042c6eSMarc Kleine-Budde 	if (priv->data_bittiming.bitrate)			/* IFLA_CAN_DATA_BITTIMING */
4460a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(struct can_bittiming));
4470a042c6eSMarc Kleine-Budde 	if (priv->data_bittiming_const)				/* IFLA_CAN_DATA_BITTIMING_CONST */
4480a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(struct can_bittiming_const));
4490a042c6eSMarc Kleine-Budde 	if (priv->termination_const) {
4500a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(priv->termination));		/* IFLA_CAN_TERMINATION */
4510a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(*priv->termination_const) *	/* IFLA_CAN_TERMINATION_CONST */
4520a042c6eSMarc Kleine-Budde 				       priv->termination_const_cnt);
4530a042c6eSMarc Kleine-Budde 	}
4540a042c6eSMarc Kleine-Budde 	if (priv->bitrate_const)				/* IFLA_CAN_BITRATE_CONST */
4550a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(*priv->bitrate_const) *
4560a042c6eSMarc Kleine-Budde 				       priv->bitrate_const_cnt);
4570a042c6eSMarc Kleine-Budde 	if (priv->data_bitrate_const)				/* IFLA_CAN_DATA_BITRATE_CONST */
4580a042c6eSMarc Kleine-Budde 		size += nla_total_size(sizeof(*priv->data_bitrate_const) *
4590a042c6eSMarc Kleine-Budde 				       priv->data_bitrate_const_cnt);
4600a042c6eSMarc Kleine-Budde 	size += sizeof(priv->bitrate_max);			/* IFLA_CAN_BITRATE_MAX */
461d99755f7SVincent Mailhol 	size += can_tdc_get_size(dev);				/* IFLA_CAN_TDC */
462383f0993SVincent Mailhol 	size += can_ctrlmode_ext_get_size();			/* IFLA_CAN_CTRLMODE_EXT */
4630a042c6eSMarc Kleine-Budde 
4640a042c6eSMarc Kleine-Budde 	return size;
4650a042c6eSMarc Kleine-Budde }
4660a042c6eSMarc Kleine-Budde 
can_tdc_fill_info(struct sk_buff * skb,const struct net_device * dev)467d99755f7SVincent Mailhol static int can_tdc_fill_info(struct sk_buff *skb, const struct net_device *dev)
468d99755f7SVincent Mailhol {
469d99755f7SVincent Mailhol 	struct nlattr *nest;
470d99755f7SVincent Mailhol 	struct can_priv *priv = netdev_priv(dev);
471d99755f7SVincent Mailhol 	struct can_tdc *tdc = &priv->tdc;
472d99755f7SVincent Mailhol 	const struct can_tdc_const *tdc_const = priv->tdc_const;
473d99755f7SVincent Mailhol 
474d99755f7SVincent Mailhol 	if (!tdc_const)
475d99755f7SVincent Mailhol 		return 0;
476d99755f7SVincent Mailhol 
477d99755f7SVincent Mailhol 	nest = nla_nest_start(skb, IFLA_CAN_TDC);
478d99755f7SVincent Mailhol 	if (!nest)
479d99755f7SVincent Mailhol 		return -EMSGSIZE;
480d99755f7SVincent Mailhol 
481d99755f7SVincent Mailhol 	if (priv->ctrlmode_supported & CAN_CTRLMODE_TDC_MANUAL &&
482d99755f7SVincent Mailhol 	    (nla_put_u32(skb, IFLA_CAN_TDC_TDCV_MIN, tdc_const->tdcv_min) ||
483d99755f7SVincent Mailhol 	     nla_put_u32(skb, IFLA_CAN_TDC_TDCV_MAX, tdc_const->tdcv_max)))
484d99755f7SVincent Mailhol 		goto err_cancel;
485d99755f7SVincent Mailhol 	if (nla_put_u32(skb, IFLA_CAN_TDC_TDCO_MIN, tdc_const->tdco_min) ||
486d99755f7SVincent Mailhol 	    nla_put_u32(skb, IFLA_CAN_TDC_TDCO_MAX, tdc_const->tdco_max))
487d99755f7SVincent Mailhol 		goto err_cancel;
488d99755f7SVincent Mailhol 	if (tdc_const->tdcf_max &&
489d99755f7SVincent Mailhol 	    (nla_put_u32(skb, IFLA_CAN_TDC_TDCF_MIN, tdc_const->tdcf_min) ||
490d99755f7SVincent Mailhol 	     nla_put_u32(skb, IFLA_CAN_TDC_TDCF_MAX, tdc_const->tdcf_max)))
491d99755f7SVincent Mailhol 		goto err_cancel;
492d99755f7SVincent Mailhol 
493d99755f7SVincent Mailhol 	if (can_tdc_is_enabled(priv)) {
494e8060f08SVincent Mailhol 		u32 tdcv;
495e8060f08SVincent Mailhol 		int err = -EINVAL;
496e8060f08SVincent Mailhol 
497e8060f08SVincent Mailhol 		if (priv->ctrlmode & CAN_CTRLMODE_TDC_MANUAL) {
498e8060f08SVincent Mailhol 			tdcv = tdc->tdcv;
499e8060f08SVincent Mailhol 			err = 0;
500e8060f08SVincent Mailhol 		} else if (priv->do_get_auto_tdcv) {
501e8060f08SVincent Mailhol 			err = priv->do_get_auto_tdcv(dev, &tdcv);
502e8060f08SVincent Mailhol 		}
503e8060f08SVincent Mailhol 		if (!err && nla_put_u32(skb, IFLA_CAN_TDC_TDCV, tdcv))
504d99755f7SVincent Mailhol 			goto err_cancel;
505d99755f7SVincent Mailhol 		if (nla_put_u32(skb, IFLA_CAN_TDC_TDCO, tdc->tdco))
506d99755f7SVincent Mailhol 			goto err_cancel;
507d99755f7SVincent Mailhol 		if (tdc_const->tdcf_max &&
508d99755f7SVincent Mailhol 		    nla_put_u32(skb, IFLA_CAN_TDC_TDCF, tdc->tdcf))
509d99755f7SVincent Mailhol 			goto err_cancel;
510d99755f7SVincent Mailhol 	}
511d99755f7SVincent Mailhol 
512d99755f7SVincent Mailhol 	nla_nest_end(skb, nest);
513d99755f7SVincent Mailhol 	return 0;
514d99755f7SVincent Mailhol 
515d99755f7SVincent Mailhol err_cancel:
516d99755f7SVincent Mailhol 	nla_nest_cancel(skb, nest);
517d99755f7SVincent Mailhol 	return -EMSGSIZE;
518d99755f7SVincent Mailhol }
519d99755f7SVincent Mailhol 
can_ctrlmode_ext_fill_info(struct sk_buff * skb,const struct can_priv * priv)520383f0993SVincent Mailhol static int can_ctrlmode_ext_fill_info(struct sk_buff *skb,
521383f0993SVincent Mailhol 				      const struct can_priv *priv)
522383f0993SVincent Mailhol {
523383f0993SVincent Mailhol 	struct nlattr *nest;
524383f0993SVincent Mailhol 
525383f0993SVincent Mailhol 	nest = nla_nest_start(skb, IFLA_CAN_CTRLMODE_EXT);
526383f0993SVincent Mailhol 	if (!nest)
527383f0993SVincent Mailhol 		return -EMSGSIZE;
528383f0993SVincent Mailhol 
529383f0993SVincent Mailhol 	if (nla_put_u32(skb, IFLA_CAN_CTRLMODE_SUPPORTED,
530383f0993SVincent Mailhol 			priv->ctrlmode_supported)) {
531383f0993SVincent Mailhol 		nla_nest_cancel(skb, nest);
532383f0993SVincent Mailhol 		return -EMSGSIZE;
533383f0993SVincent Mailhol 	}
534383f0993SVincent Mailhol 
535383f0993SVincent Mailhol 	nla_nest_end(skb, nest);
536383f0993SVincent Mailhol 	return 0;
537383f0993SVincent Mailhol }
538383f0993SVincent Mailhol 
can_fill_info(struct sk_buff * skb,const struct net_device * dev)5390a042c6eSMarc Kleine-Budde static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
5400a042c6eSMarc Kleine-Budde {
5410a042c6eSMarc Kleine-Budde 	struct can_priv *priv = netdev_priv(dev);
5420a042c6eSMarc Kleine-Budde 	struct can_ctrlmode cm = {.flags = priv->ctrlmode};
543c358f952SJakub Kicinski 	struct can_berr_counter bec = { };
5440a042c6eSMarc Kleine-Budde 	enum can_state state = priv->state;
5450a042c6eSMarc Kleine-Budde 
5460a042c6eSMarc Kleine-Budde 	if (priv->do_get_state)
5470a042c6eSMarc Kleine-Budde 		priv->do_get_state(dev, &state);
5480a042c6eSMarc Kleine-Budde 
549036bff28SDario Binacchi 	if ((priv->bittiming.bitrate != CAN_BITRATE_UNSET &&
550036bff28SDario Binacchi 	     priv->bittiming.bitrate != CAN_BITRATE_UNKNOWN &&
5510a042c6eSMarc Kleine-Budde 	     nla_put(skb, IFLA_CAN_BITTIMING,
5520a042c6eSMarc Kleine-Budde 		     sizeof(priv->bittiming), &priv->bittiming)) ||
5530a042c6eSMarc Kleine-Budde 
5540a042c6eSMarc Kleine-Budde 	    (priv->bittiming_const &&
5550a042c6eSMarc Kleine-Budde 	     nla_put(skb, IFLA_CAN_BITTIMING_CONST,
5560a042c6eSMarc Kleine-Budde 		     sizeof(*priv->bittiming_const), priv->bittiming_const)) ||
5570a042c6eSMarc Kleine-Budde 
5580a042c6eSMarc Kleine-Budde 	    nla_put(skb, IFLA_CAN_CLOCK, sizeof(priv->clock), &priv->clock) ||
5590a042c6eSMarc Kleine-Budde 	    nla_put_u32(skb, IFLA_CAN_STATE, state) ||
5600a042c6eSMarc Kleine-Budde 	    nla_put(skb, IFLA_CAN_CTRLMODE, sizeof(cm), &cm) ||
5610a042c6eSMarc Kleine-Budde 	    nla_put_u32(skb, IFLA_CAN_RESTART_MS, priv->restart_ms) ||
5620a042c6eSMarc Kleine-Budde 
5630a042c6eSMarc Kleine-Budde 	    (priv->do_get_berr_counter &&
5640a042c6eSMarc Kleine-Budde 	     !priv->do_get_berr_counter(dev, &bec) &&
5650a042c6eSMarc Kleine-Budde 	     nla_put(skb, IFLA_CAN_BERR_COUNTER, sizeof(bec), &bec)) ||
5660a042c6eSMarc Kleine-Budde 
5670a042c6eSMarc Kleine-Budde 	    (priv->data_bittiming.bitrate &&
5680a042c6eSMarc Kleine-Budde 	     nla_put(skb, IFLA_CAN_DATA_BITTIMING,
5690a042c6eSMarc Kleine-Budde 		     sizeof(priv->data_bittiming), &priv->data_bittiming)) ||
5700a042c6eSMarc Kleine-Budde 
5710a042c6eSMarc Kleine-Budde 	    (priv->data_bittiming_const &&
5720a042c6eSMarc Kleine-Budde 	     nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
5730a042c6eSMarc Kleine-Budde 		     sizeof(*priv->data_bittiming_const),
5740a042c6eSMarc Kleine-Budde 		     priv->data_bittiming_const)) ||
5750a042c6eSMarc Kleine-Budde 
5760a042c6eSMarc Kleine-Budde 	    (priv->termination_const &&
5770a042c6eSMarc Kleine-Budde 	     (nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) ||
5780a042c6eSMarc Kleine-Budde 	      nla_put(skb, IFLA_CAN_TERMINATION_CONST,
5790a042c6eSMarc Kleine-Budde 		      sizeof(*priv->termination_const) *
5800a042c6eSMarc Kleine-Budde 		      priv->termination_const_cnt,
5810a042c6eSMarc Kleine-Budde 		      priv->termination_const))) ||
5820a042c6eSMarc Kleine-Budde 
5830a042c6eSMarc Kleine-Budde 	    (priv->bitrate_const &&
5840a042c6eSMarc Kleine-Budde 	     nla_put(skb, IFLA_CAN_BITRATE_CONST,
5850a042c6eSMarc Kleine-Budde 		     sizeof(*priv->bitrate_const) *
5860a042c6eSMarc Kleine-Budde 		     priv->bitrate_const_cnt,
5870a042c6eSMarc Kleine-Budde 		     priv->bitrate_const)) ||
5880a042c6eSMarc Kleine-Budde 
5890a042c6eSMarc Kleine-Budde 	    (priv->data_bitrate_const &&
5900a042c6eSMarc Kleine-Budde 	     nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
5910a042c6eSMarc Kleine-Budde 		     sizeof(*priv->data_bitrate_const) *
5920a042c6eSMarc Kleine-Budde 		     priv->data_bitrate_const_cnt,
5930a042c6eSMarc Kleine-Budde 		     priv->data_bitrate_const)) ||
5940a042c6eSMarc Kleine-Budde 
5950a042c6eSMarc Kleine-Budde 	    (nla_put(skb, IFLA_CAN_BITRATE_MAX,
5960a042c6eSMarc Kleine-Budde 		     sizeof(priv->bitrate_max),
597d99755f7SVincent Mailhol 		     &priv->bitrate_max)) ||
598d99755f7SVincent Mailhol 
599383f0993SVincent Mailhol 	    can_tdc_fill_info(skb, dev) ||
600383f0993SVincent Mailhol 
601383f0993SVincent Mailhol 	    can_ctrlmode_ext_fill_info(skb, priv)
6020a042c6eSMarc Kleine-Budde 	    )
6030a042c6eSMarc Kleine-Budde 
6040a042c6eSMarc Kleine-Budde 		return -EMSGSIZE;
6050a042c6eSMarc Kleine-Budde 
6060a042c6eSMarc Kleine-Budde 	return 0;
6070a042c6eSMarc Kleine-Budde }
6080a042c6eSMarc Kleine-Budde 
can_get_xstats_size(const struct net_device * dev)6090a042c6eSMarc Kleine-Budde static size_t can_get_xstats_size(const struct net_device *dev)
6100a042c6eSMarc Kleine-Budde {
6110a042c6eSMarc Kleine-Budde 	return sizeof(struct can_device_stats);
6120a042c6eSMarc Kleine-Budde }
6130a042c6eSMarc Kleine-Budde 
can_fill_xstats(struct sk_buff * skb,const struct net_device * dev)6140a042c6eSMarc Kleine-Budde static int can_fill_xstats(struct sk_buff *skb, const struct net_device *dev)
6150a042c6eSMarc Kleine-Budde {
6160a042c6eSMarc Kleine-Budde 	struct can_priv *priv = netdev_priv(dev);
6170a042c6eSMarc Kleine-Budde 
6180a042c6eSMarc Kleine-Budde 	if (nla_put(skb, IFLA_INFO_XSTATS,
6190a042c6eSMarc Kleine-Budde 		    sizeof(priv->can_stats), &priv->can_stats))
6200a042c6eSMarc Kleine-Budde 		goto nla_put_failure;
6210a042c6eSMarc Kleine-Budde 	return 0;
6220a042c6eSMarc Kleine-Budde 
6230a042c6eSMarc Kleine-Budde nla_put_failure:
6240a042c6eSMarc Kleine-Budde 	return -EMSGSIZE;
6250a042c6eSMarc Kleine-Budde }
6260a042c6eSMarc Kleine-Budde 
can_newlink(struct net * src_net,struct net_device * dev,struct nlattr * tb[],struct nlattr * data[],struct netlink_ext_ack * extack)6270a042c6eSMarc Kleine-Budde static int can_newlink(struct net *src_net, struct net_device *dev,
6280a042c6eSMarc Kleine-Budde 		       struct nlattr *tb[], struct nlattr *data[],
6290a042c6eSMarc Kleine-Budde 		       struct netlink_ext_ack *extack)
6300a042c6eSMarc Kleine-Budde {
6310a042c6eSMarc Kleine-Budde 	return -EOPNOTSUPP;
6320a042c6eSMarc Kleine-Budde }
6330a042c6eSMarc Kleine-Budde 
can_dellink(struct net_device * dev,struct list_head * head)6340a042c6eSMarc Kleine-Budde static void can_dellink(struct net_device *dev, struct list_head *head)
6350a042c6eSMarc Kleine-Budde {
6360a042c6eSMarc Kleine-Budde }
6370a042c6eSMarc Kleine-Budde 
6380a042c6eSMarc Kleine-Budde struct rtnl_link_ops can_link_ops __read_mostly = {
6390a042c6eSMarc Kleine-Budde 	.kind		= "can",
6403a5ca857SMartin Willi 	.netns_refund	= true,
6410a042c6eSMarc Kleine-Budde 	.maxtype	= IFLA_CAN_MAX,
6420a042c6eSMarc Kleine-Budde 	.policy		= can_policy,
6430a042c6eSMarc Kleine-Budde 	.setup		= can_setup,
6440a042c6eSMarc Kleine-Budde 	.validate	= can_validate,
6450a042c6eSMarc Kleine-Budde 	.newlink	= can_newlink,
6460a042c6eSMarc Kleine-Budde 	.changelink	= can_changelink,
6470a042c6eSMarc Kleine-Budde 	.dellink	= can_dellink,
6480a042c6eSMarc Kleine-Budde 	.get_size	= can_get_size,
6490a042c6eSMarc Kleine-Budde 	.fill_info	= can_fill_info,
6500a042c6eSMarc Kleine-Budde 	.get_xstats_size = can_get_xstats_size,
6510a042c6eSMarc Kleine-Budde 	.fill_xstats	= can_fill_xstats,
6520a042c6eSMarc Kleine-Budde };
6530a042c6eSMarc Kleine-Budde 
can_netlink_register(void)6540a042c6eSMarc Kleine-Budde int can_netlink_register(void)
6550a042c6eSMarc Kleine-Budde {
6560a042c6eSMarc Kleine-Budde 	return rtnl_link_register(&can_link_ops);
6570a042c6eSMarc Kleine-Budde }
6580a042c6eSMarc Kleine-Budde 
can_netlink_unregister(void)6590a042c6eSMarc Kleine-Budde void can_netlink_unregister(void)
6600a042c6eSMarc Kleine-Budde {
6610a042c6eSMarc Kleine-Budde 	rtnl_link_unregister(&can_link_ops);
6620a042c6eSMarc Kleine-Budde }
663