| 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 | |