1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright 2022 NXP |
3 | */ |
4 | #include <linux/netdevice.h> |
5 | #include <net/rtnetlink.h> |
6 | |
7 | #include "netlink.h" |
8 | #include "user.h" |
9 | |
10 | static const struct nla_policy dsa_policy[IFLA_DSA_MAX + 1] = { |
11 | [IFLA_DSA_CONDUIT] = { .type = NLA_U32 }, |
12 | }; |
13 | |
14 | static int dsa_changelink(struct net_device *dev, struct nlattr *tb[], |
15 | struct nlattr *data[], |
16 | struct netlink_ext_ack *extack) |
17 | { |
18 | int err; |
19 | |
20 | if (!data) |
21 | return 0; |
22 | |
23 | if (data[IFLA_DSA_CONDUIT]) { |
24 | u32 ifindex = nla_get_u32(nla: data[IFLA_DSA_CONDUIT]); |
25 | struct net_device *conduit; |
26 | |
27 | conduit = __dev_get_by_index(net: dev_net(dev), ifindex); |
28 | if (!conduit) |
29 | return -EINVAL; |
30 | |
31 | err = dsa_user_change_conduit(dev, conduit, extack); |
32 | if (err) |
33 | return err; |
34 | } |
35 | |
36 | return 0; |
37 | } |
38 | |
39 | static size_t dsa_get_size(const struct net_device *dev) |
40 | { |
41 | return nla_total_size(payload: sizeof(u32)) + /* IFLA_DSA_CONDUIT */ |
42 | 0; |
43 | } |
44 | |
45 | static int dsa_fill_info(struct sk_buff *skb, const struct net_device *dev) |
46 | { |
47 | struct net_device *conduit = dsa_user_to_conduit(dev); |
48 | |
49 | if (nla_put_u32(skb, attrtype: IFLA_DSA_CONDUIT, value: conduit->ifindex)) |
50 | return -EMSGSIZE; |
51 | |
52 | return 0; |
53 | } |
54 | |
55 | struct rtnl_link_ops dsa_link_ops __read_mostly = { |
56 | .kind = "dsa" , |
57 | .priv_size = sizeof(struct dsa_port), |
58 | .maxtype = IFLA_DSA_MAX, |
59 | .policy = dsa_policy, |
60 | .changelink = dsa_changelink, |
61 | .get_size = dsa_get_size, |
62 | .fill_info = dsa_fill_info, |
63 | .netns_refund = true, |
64 | }; |
65 | |