octeontx2-pf: Fix error return code in otx2_probe()
[linux/fpc-iii.git] / net / ethtool / privflags.c
blob77447dceb109f01d1123b482740ba81f0992fdc2
1 // SPDX-License-Identifier: GPL-2.0-only
3 #include "netlink.h"
4 #include "common.h"
5 #include "bitset.h"
7 struct privflags_req_info {
8 struct ethnl_req_info base;
9 };
11 struct privflags_reply_data {
12 struct ethnl_reply_data base;
13 const char (*priv_flag_names)[ETH_GSTRING_LEN];
14 unsigned int n_priv_flags;
15 u32 priv_flags;
18 #define PRIVFLAGS_REPDATA(__reply_base) \
19 container_of(__reply_base, struct privflags_reply_data, base)
21 static const struct nla_policy
22 privflags_get_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = {
23 [ETHTOOL_A_PRIVFLAGS_UNSPEC] = { .type = NLA_REJECT },
24 [ETHTOOL_A_PRIVFLAGS_HEADER] = { .type = NLA_NESTED },
25 [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .type = NLA_REJECT },
28 static int ethnl_get_priv_flags_info(struct net_device *dev,
29 unsigned int *count,
30 const char (**names)[ETH_GSTRING_LEN])
32 const struct ethtool_ops *ops = dev->ethtool_ops;
33 int nflags;
35 nflags = ops->get_sset_count(dev, ETH_SS_PRIV_FLAGS);
36 if (nflags < 0)
37 return nflags;
39 if (names) {
40 *names = kcalloc(nflags, ETH_GSTRING_LEN, GFP_KERNEL);
41 if (!*names)
42 return -ENOMEM;
43 ops->get_strings(dev, ETH_SS_PRIV_FLAGS, (u8 *)*names);
46 /* We can pass more than 32 private flags to userspace via netlink but
47 * we cannot get more with ethtool_ops::get_priv_flags(). Note that we
48 * must not adjust nflags before allocating the space for flag names
49 * as the buffer must be large enough for all flags.
51 if (WARN_ONCE(nflags > 32,
52 "device %s reports more than 32 private flags (%d)\n",
53 netdev_name(dev), nflags))
54 nflags = 32;
55 *count = nflags;
57 return 0;
60 static int privflags_prepare_data(const struct ethnl_req_info *req_base,
61 struct ethnl_reply_data *reply_base,
62 struct genl_info *info)
64 struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
65 struct net_device *dev = reply_base->dev;
66 const char (*names)[ETH_GSTRING_LEN];
67 const struct ethtool_ops *ops;
68 unsigned int nflags;
69 int ret;
71 ops = dev->ethtool_ops;
72 if (!ops->get_priv_flags || !ops->get_sset_count || !ops->get_strings)
73 return -EOPNOTSUPP;
74 ret = ethnl_ops_begin(dev);
75 if (ret < 0)
76 return ret;
78 ret = ethnl_get_priv_flags_info(dev, &nflags, &names);
79 if (ret < 0)
80 goto out_ops;
81 data->priv_flags = ops->get_priv_flags(dev);
82 data->priv_flag_names = names;
83 data->n_priv_flags = nflags;
85 out_ops:
86 ethnl_ops_complete(dev);
87 return ret;
90 static int privflags_reply_size(const struct ethnl_req_info *req_base,
91 const struct ethnl_reply_data *reply_base)
93 const struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
94 bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
95 const u32 all_flags = ~(u32)0 >> (32 - data->n_priv_flags);
97 return ethnl_bitset32_size(&data->priv_flags, &all_flags,
98 data->n_priv_flags,
99 data->priv_flag_names, compact);
102 static int privflags_fill_reply(struct sk_buff *skb,
103 const struct ethnl_req_info *req_base,
104 const struct ethnl_reply_data *reply_base)
106 const struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_base);
107 bool compact = req_base->flags & ETHTOOL_FLAG_COMPACT_BITSETS;
108 const u32 all_flags = ~(u32)0 >> (32 - data->n_priv_flags);
110 return ethnl_put_bitset32(skb, ETHTOOL_A_PRIVFLAGS_FLAGS,
111 &data->priv_flags, &all_flags,
112 data->n_priv_flags, data->priv_flag_names,
113 compact);
116 static void privflags_cleanup_data(struct ethnl_reply_data *reply_data)
118 struct privflags_reply_data *data = PRIVFLAGS_REPDATA(reply_data);
120 kfree(data->priv_flag_names);
123 const struct ethnl_request_ops ethnl_privflags_request_ops = {
124 .request_cmd = ETHTOOL_MSG_PRIVFLAGS_GET,
125 .reply_cmd = ETHTOOL_MSG_PRIVFLAGS_GET_REPLY,
126 .hdr_attr = ETHTOOL_A_PRIVFLAGS_HEADER,
127 .max_attr = ETHTOOL_A_PRIVFLAGS_MAX,
128 .req_info_size = sizeof(struct privflags_req_info),
129 .reply_data_size = sizeof(struct privflags_reply_data),
130 .request_policy = privflags_get_policy,
132 .prepare_data = privflags_prepare_data,
133 .reply_size = privflags_reply_size,
134 .fill_reply = privflags_fill_reply,
135 .cleanup_data = privflags_cleanup_data,
138 /* PRIVFLAGS_SET */
140 static const struct nla_policy
141 privflags_set_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = {
142 [ETHTOOL_A_PRIVFLAGS_UNSPEC] = { .type = NLA_REJECT },
143 [ETHTOOL_A_PRIVFLAGS_HEADER] = { .type = NLA_NESTED },
144 [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .type = NLA_NESTED },
147 int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info)
149 struct nlattr *tb[ETHTOOL_A_PRIVFLAGS_MAX + 1];
150 const char (*names)[ETH_GSTRING_LEN] = NULL;
151 struct ethnl_req_info req_info = {};
152 const struct ethtool_ops *ops;
153 struct net_device *dev;
154 unsigned int nflags;
155 bool mod = false;
156 bool compact;
157 u32 flags;
158 int ret;
160 ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb,
161 ETHTOOL_A_PRIVFLAGS_MAX, privflags_set_policy,
162 info->extack);
163 if (ret < 0)
164 return ret;
165 if (!tb[ETHTOOL_A_PRIVFLAGS_FLAGS])
166 return -EINVAL;
167 ret = ethnl_bitset_is_compact(tb[ETHTOOL_A_PRIVFLAGS_FLAGS], &compact);
168 if (ret < 0)
169 return ret;
170 ret = ethnl_parse_header_dev_get(&req_info,
171 tb[ETHTOOL_A_PRIVFLAGS_HEADER],
172 genl_info_net(info), info->extack,
173 true);
174 if (ret < 0)
175 return ret;
176 dev = req_info.dev;
177 ops = dev->ethtool_ops;
178 ret = -EOPNOTSUPP;
179 if (!ops->get_priv_flags || !ops->set_priv_flags ||
180 !ops->get_sset_count || !ops->get_strings)
181 goto out_dev;
183 rtnl_lock();
184 ret = ethnl_ops_begin(dev);
185 if (ret < 0)
186 goto out_rtnl;
187 ret = ethnl_get_priv_flags_info(dev, &nflags, compact ? NULL : &names);
188 if (ret < 0)
189 goto out_ops;
190 flags = ops->get_priv_flags(dev);
192 ret = ethnl_update_bitset32(&flags, nflags,
193 tb[ETHTOOL_A_PRIVFLAGS_FLAGS], names,
194 info->extack, &mod);
195 if (ret < 0 || !mod)
196 goto out_free;
197 ret = ops->set_priv_flags(dev, flags);
198 if (ret < 0)
199 goto out_free;
200 ethtool_notify(dev, ETHTOOL_MSG_PRIVFLAGS_NTF, NULL);
202 out_free:
203 kfree(names);
204 out_ops:
205 ethnl_ops_complete(dev);
206 out_rtnl:
207 rtnl_unlock();
208 out_dev:
209 dev_put(dev);
210 return ret;