| // SPDX-License-Identifier: GPL-2.0 | |
| /* Copyright 2022 NXP | |
| */ | |
| #include <linux/netdevice.h> | |
| #include <net/rtnetlink.h> | |
| #include "netlink.h" | |
| #include "user.h" | |
| static const struct nla_policy dsa_policy[IFLA_DSA_MAX + 1] = { | |
| [IFLA_DSA_CONDUIT] = { .type = NLA_U32 }, | |
| }; | |
| static int dsa_changelink(struct net_device *dev, struct nlattr *tb[], | |
| struct nlattr *data[], | |
| struct netlink_ext_ack *extack) | |
| { | |
| int err; | |
| if (!data) | |
| return 0; | |
| if (data[IFLA_DSA_CONDUIT]) { | |
| u32 ifindex = nla_get_u32(data[IFLA_DSA_CONDUIT]); | |
| struct net_device *conduit; | |
| conduit = __dev_get_by_index(dev_net(dev), ifindex); | |
| if (!conduit) | |
| return -EINVAL; | |
| err = dsa_user_change_conduit(dev, conduit, extack); | |
| if (err) | |
| return err; | |
| } | |
| return 0; | |
| } | |
| static size_t dsa_get_size(const struct net_device *dev) | |
| { | |
| return nla_total_size(sizeof(u32)) + /* IFLA_DSA_CONDUIT */ | |
| 0; | |
| } | |
| static int dsa_fill_info(struct sk_buff *skb, const struct net_device *dev) | |
| { | |
| struct net_device *conduit = dsa_user_to_conduit(dev); | |
| if (nla_put_u32(skb, IFLA_DSA_CONDUIT, conduit->ifindex)) | |
| return -EMSGSIZE; | |
| return 0; | |
| } | |
| struct rtnl_link_ops dsa_link_ops __read_mostly = { | |
| .kind = "dsa", | |
| .priv_size = sizeof(struct dsa_port), | |
| .maxtype = IFLA_DSA_MAX, | |
| .policy = dsa_policy, | |
| .changelink = dsa_changelink, | |
| .get_size = dsa_get_size, | |
| .fill_info = dsa_fill_info, | |
| .netns_refund = true, | |
| }; |