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