^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) #include "netlink.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include "common.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include "bitset.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) struct privflags_req_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) struct ethnl_req_info base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) struct privflags_reply_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) struct ethnl_reply_data base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) const char (*priv_flag_names)[ETH_GSTRING_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) unsigned int n_priv_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) u32 priv_flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define PRIVFLAGS_REPDATA(__reply_base) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) container_of(__reply_base, struct privflags_reply_data, base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) const struct nla_policy ethnl_privflags_get_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) [ETHTOOL_A_PRIVFLAGS_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) static int ethnl_get_priv_flags_info(struct net_device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) unsigned int *count,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) const char (**names)[ETH_GSTRING_LEN])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) const struct ethtool_ops *ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int nflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) nflags = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) if (nflags < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) return nflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) if (names) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) *names = kcalloc(nflags, ETH_GSTRING_LEN, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) if (!*names)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) ops->get_strings(dev, ETH_SS_PRIV_FLAGS, (u8 *)*names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) /* We can pass more than 32 private flags to userspace via netlink but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * we cannot get more with ethtool_ops::get_priv_flags(). Note that we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * must not adjust nflags before allocating the space for flag names
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * as the buffer must be large enough for all flags.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (WARN_ONCE(nflags > 32,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) "device %s reports more than 32 private flags (%d)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) netdev_name(dev), nflags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) nflags = 32;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) *count = nflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) static int privflags_prepare_data(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) struct ethnl_reply_data *reply_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) struct net_device *dev = reply_base->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) const char (*names)[ETH_GSTRING_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) const struct ethtool_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) unsigned int nflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) if (!ops->get_priv_flags || !ops->get_sset_count || !ops->get_strings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) ret = ethnl_get_priv_flags_info(dev, &nflags, &names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) data->priv_flags = ops->get_priv_flags(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) data->priv_flag_names = names;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) data->n_priv_flags = nflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) out_ops:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) static int privflags_reply_size(const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) const struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) const u32 all_flags = ~(u32)0 >> (32 - data->n_priv_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) return ethnl_bitset32_size(&data->priv_flags, &all_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) data->n_priv_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) data->priv_flag_names, compact);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static int privflags_fill_reply(struct sk_buff *skb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) const struct ethnl_req_info *req_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) const struct ethnl_reply_data *reply_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) const struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) const u32 all_flags = ~(u32)0 >> (32 - data->n_priv_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return ethnl_put_bitset32(skb, ETHTOOL_A_PRIVFLAGS_FLAGS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) &data->priv_flags, &all_flags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) data->n_priv_flags, data->priv_flag_names,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) compact);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void privflags_cleanup_data(struct ethnl_reply_data *reply_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) kfree(data->priv_flag_names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) const struct ethnl_request_ops ethnl_privflags_request_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .request_cmd = ETHTOOL_MSG_PRIVFLAGS_GET,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .reply_cmd = ETHTOOL_MSG_PRIVFLAGS_GET_REPLY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .hdr_attr = ETHTOOL_A_PRIVFLAGS_HEADER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .req_info_size = sizeof(struct privflags_req_info),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .reply_data_size = sizeof(struct privflags_reply_data),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) .prepare_data = privflags_prepare_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) .reply_size = privflags_reply_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) .fill_reply = privflags_fill_reply,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) .cleanup_data = privflags_cleanup_data,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) /* PRIVFLAGS_SET */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) const struct nla_policy ethnl_privflags_set_policy[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) [ETHTOOL_A_PRIVFLAGS_HEADER] =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) NLA_POLICY_NESTED(ethnl_header_policy),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .type = NLA_NESTED },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) const char (*names)[ETH_GSTRING_LEN] = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) struct ethnl_req_info req_info = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) struct nlattr **tb = info->attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) const struct ethtool_ops *ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) struct net_device *dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) unsigned int nflags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) bool mod = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) bool compact;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) u32 flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (!tb[ETHTOOL_A_PRIVFLAGS_FLAGS])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) ret = ethnl_bitset_is_compact(tb[ETHTOOL_A_PRIVFLAGS_FLAGS], &compact);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) ret = ethnl_parse_header_dev_get(&req_info,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) tb[ETHTOOL_A_PRIVFLAGS_HEADER],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) genl_info_net(info), info->extack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) dev = req_info.dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) ops = dev->ethtool_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ret = -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!ops->get_priv_flags || !ops->set_priv_flags ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) !ops->get_sset_count || !ops->get_strings)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) goto out_dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) rtnl_lock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) ret = ethnl_ops_begin(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) goto out_rtnl;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) ret = ethnl_get_priv_flags_info(dev, &nflags, compact ? NULL : &names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) goto out_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) flags = ops->get_priv_flags(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) ret = ethnl_update_bitset32(&flags, nflags,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) tb[ETHTOOL_A_PRIVFLAGS_FLAGS], names,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) info->extack, &mod);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (ret < 0 || !mod)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) ret = ops->set_priv_flags(dev, flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) goto out_free;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) ethtool_notify(dev, ETHTOOL_MSG_PRIVFLAGS_NTF, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) out_free:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) kfree(names);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) out_ops:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) ethnl_ops_complete(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) out_rtnl:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) rtnl_unlock();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) out_dev:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) dev_put(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }