root/net/dsa/netlink.c
// 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,
};