0001
0002
0003 #include <linux/ethtool.h>
0004 #include <linux/phy.h>
0005 #include "netlink.h"
0006 #include "common.h"
0007
0008 struct strset_info {
0009 bool per_dev;
0010 bool free_strings;
0011 unsigned int count;
0012 const char (*strings)[ETH_GSTRING_LEN];
0013 };
0014
0015 static const struct strset_info info_template[] = {
0016 [ETH_SS_TEST] = {
0017 .per_dev = true,
0018 },
0019 [ETH_SS_STATS] = {
0020 .per_dev = true,
0021 },
0022 [ETH_SS_PRIV_FLAGS] = {
0023 .per_dev = true,
0024 },
0025 [ETH_SS_FEATURES] = {
0026 .per_dev = false,
0027 .count = ARRAY_SIZE(netdev_features_strings),
0028 .strings = netdev_features_strings,
0029 },
0030 [ETH_SS_RSS_HASH_FUNCS] = {
0031 .per_dev = false,
0032 .count = ARRAY_SIZE(rss_hash_func_strings),
0033 .strings = rss_hash_func_strings,
0034 },
0035 [ETH_SS_TUNABLES] = {
0036 .per_dev = false,
0037 .count = ARRAY_SIZE(tunable_strings),
0038 .strings = tunable_strings,
0039 },
0040 [ETH_SS_PHY_STATS] = {
0041 .per_dev = true,
0042 },
0043 [ETH_SS_PHY_TUNABLES] = {
0044 .per_dev = false,
0045 .count = ARRAY_SIZE(phy_tunable_strings),
0046 .strings = phy_tunable_strings,
0047 },
0048 [ETH_SS_LINK_MODES] = {
0049 .per_dev = false,
0050 .count = __ETHTOOL_LINK_MODE_MASK_NBITS,
0051 .strings = link_mode_names,
0052 },
0053 [ETH_SS_MSG_CLASSES] = {
0054 .per_dev = false,
0055 .count = NETIF_MSG_CLASS_COUNT,
0056 .strings = netif_msg_class_names,
0057 },
0058 [ETH_SS_WOL_MODES] = {
0059 .per_dev = false,
0060 .count = WOL_MODE_COUNT,
0061 .strings = wol_mode_names,
0062 },
0063 [ETH_SS_SOF_TIMESTAMPING] = {
0064 .per_dev = false,
0065 .count = __SOF_TIMESTAMPING_CNT,
0066 .strings = sof_timestamping_names,
0067 },
0068 [ETH_SS_TS_TX_TYPES] = {
0069 .per_dev = false,
0070 .count = __HWTSTAMP_TX_CNT,
0071 .strings = ts_tx_type_names,
0072 },
0073 [ETH_SS_TS_RX_FILTERS] = {
0074 .per_dev = false,
0075 .count = __HWTSTAMP_FILTER_CNT,
0076 .strings = ts_rx_filter_names,
0077 },
0078 [ETH_SS_UDP_TUNNEL_TYPES] = {
0079 .per_dev = false,
0080 .count = __ETHTOOL_UDP_TUNNEL_TYPE_CNT,
0081 .strings = udp_tunnel_type_names,
0082 },
0083 [ETH_SS_STATS_STD] = {
0084 .per_dev = false,
0085 .count = __ETHTOOL_STATS_CNT,
0086 .strings = stats_std_names,
0087 },
0088 [ETH_SS_STATS_ETH_PHY] = {
0089 .per_dev = false,
0090 .count = __ETHTOOL_A_STATS_ETH_PHY_CNT,
0091 .strings = stats_eth_phy_names,
0092 },
0093 [ETH_SS_STATS_ETH_MAC] = {
0094 .per_dev = false,
0095 .count = __ETHTOOL_A_STATS_ETH_MAC_CNT,
0096 .strings = stats_eth_mac_names,
0097 },
0098 [ETH_SS_STATS_ETH_CTRL] = {
0099 .per_dev = false,
0100 .count = __ETHTOOL_A_STATS_ETH_CTRL_CNT,
0101 .strings = stats_eth_ctrl_names,
0102 },
0103 [ETH_SS_STATS_RMON] = {
0104 .per_dev = false,
0105 .count = __ETHTOOL_A_STATS_RMON_CNT,
0106 .strings = stats_rmon_names,
0107 },
0108 };
0109
0110 struct strset_req_info {
0111 struct ethnl_req_info base;
0112 u32 req_ids;
0113 bool counts_only;
0114 };
0115
0116 #define STRSET_REQINFO(__req_base) \
0117 container_of(__req_base, struct strset_req_info, base)
0118
0119 struct strset_reply_data {
0120 struct ethnl_reply_data base;
0121 struct strset_info sets[ETH_SS_COUNT];
0122 };
0123
0124 #define STRSET_REPDATA(__reply_base) \
0125 container_of(__reply_base, struct strset_reply_data, base)
0126
0127 const struct nla_policy ethnl_strset_get_policy[] = {
0128 [ETHTOOL_A_STRSET_HEADER] =
0129 NLA_POLICY_NESTED(ethnl_header_policy),
0130 [ETHTOOL_A_STRSET_STRINGSETS] = { .type = NLA_NESTED },
0131 [ETHTOOL_A_STRSET_COUNTS_ONLY] = { .type = NLA_FLAG },
0132 };
0133
0134 static const struct nla_policy get_stringset_policy[] = {
0135 [ETHTOOL_A_STRINGSET_ID] = { .type = NLA_U32 },
0136 };
0137
0138
0139
0140
0141
0142
0143
0144 static bool strset_include(const struct strset_req_info *info,
0145 const struct strset_reply_data *data, u32 id)
0146 {
0147 bool per_dev;
0148
0149 BUILD_BUG_ON(ETH_SS_COUNT >= BITS_PER_BYTE * sizeof(info->req_ids));
0150
0151 if (info->req_ids)
0152 return info->req_ids & (1U << id);
0153 per_dev = data->sets[id].per_dev;
0154 if (!per_dev && !data->sets[id].strings)
0155 return false;
0156
0157 return data->base.dev ? per_dev : !per_dev;
0158 }
0159
0160 static int strset_get_id(const struct nlattr *nest, u32 *val,
0161 struct netlink_ext_ack *extack)
0162 {
0163 struct nlattr *tb[ARRAY_SIZE(get_stringset_policy)];
0164 int ret;
0165
0166 ret = nla_parse_nested(tb, ARRAY_SIZE(get_stringset_policy) - 1, nest,
0167 get_stringset_policy, extack);
0168 if (ret < 0)
0169 return ret;
0170 if (!tb[ETHTOOL_A_STRINGSET_ID])
0171 return -EINVAL;
0172
0173 *val = nla_get_u32(tb[ETHTOOL_A_STRINGSET_ID]);
0174 return 0;
0175 }
0176
0177 static const struct nla_policy strset_stringsets_policy[] = {
0178 [ETHTOOL_A_STRINGSETS_STRINGSET] = { .type = NLA_NESTED },
0179 };
0180
0181 static int strset_parse_request(struct ethnl_req_info *req_base,
0182 struct nlattr **tb,
0183 struct netlink_ext_ack *extack)
0184 {
0185 struct strset_req_info *req_info = STRSET_REQINFO(req_base);
0186 struct nlattr *nest = tb[ETHTOOL_A_STRSET_STRINGSETS];
0187 struct nlattr *attr;
0188 int rem, ret;
0189
0190 if (!nest)
0191 return 0;
0192 ret = nla_validate_nested(nest,
0193 ARRAY_SIZE(strset_stringsets_policy) - 1,
0194 strset_stringsets_policy, extack);
0195 if (ret < 0)
0196 return ret;
0197
0198 req_info->counts_only = tb[ETHTOOL_A_STRSET_COUNTS_ONLY];
0199 nla_for_each_nested(attr, nest, rem) {
0200 u32 id;
0201
0202 if (WARN_ONCE(nla_type(attr) != ETHTOOL_A_STRINGSETS_STRINGSET,
0203 "unexpected attrtype %u in ETHTOOL_A_STRSET_STRINGSETS\n",
0204 nla_type(attr)))
0205 return -EINVAL;
0206
0207 ret = strset_get_id(attr, &id, extack);
0208 if (ret < 0)
0209 return ret;
0210 if (id >= ETH_SS_COUNT) {
0211 NL_SET_ERR_MSG_ATTR(extack, attr,
0212 "unknown string set id");
0213 return -EOPNOTSUPP;
0214 }
0215
0216 req_info->req_ids |= (1U << id);
0217 }
0218
0219 return 0;
0220 }
0221
0222 static void strset_cleanup_data(struct ethnl_reply_data *reply_base)
0223 {
0224 struct strset_reply_data *data = STRSET_REPDATA(reply_base);
0225 unsigned int i;
0226
0227 for (i = 0; i < ETH_SS_COUNT; i++)
0228 if (data->sets[i].free_strings) {
0229 kfree(data->sets[i].strings);
0230 data->sets[i].strings = NULL;
0231 data->sets[i].free_strings = false;
0232 }
0233 }
0234
0235 static int strset_prepare_set(struct strset_info *info, struct net_device *dev,
0236 unsigned int id, bool counts_only)
0237 {
0238 const struct ethtool_phy_ops *phy_ops = ethtool_phy_ops;
0239 const struct ethtool_ops *ops = dev->ethtool_ops;
0240 void *strings;
0241 int count, ret;
0242
0243 if (id == ETH_SS_PHY_STATS && dev->phydev &&
0244 !ops->get_ethtool_phy_stats && phy_ops &&
0245 phy_ops->get_sset_count)
0246 ret = phy_ops->get_sset_count(dev->phydev);
0247 else if (ops->get_sset_count && ops->get_strings)
0248 ret = ops->get_sset_count(dev, id);
0249 else
0250 ret = -EOPNOTSUPP;
0251 if (ret <= 0) {
0252 info->count = 0;
0253 return 0;
0254 }
0255
0256 count = ret;
0257 if (!counts_only) {
0258 strings = kcalloc(count, ETH_GSTRING_LEN, GFP_KERNEL);
0259 if (!strings)
0260 return -ENOMEM;
0261 if (id == ETH_SS_PHY_STATS && dev->phydev &&
0262 !ops->get_ethtool_phy_stats && phy_ops &&
0263 phy_ops->get_strings)
0264 phy_ops->get_strings(dev->phydev, strings);
0265 else
0266 ops->get_strings(dev, id, strings);
0267 info->strings = strings;
0268 info->free_strings = true;
0269 }
0270 info->count = count;
0271
0272 return 0;
0273 }
0274
0275 static int strset_prepare_data(const struct ethnl_req_info *req_base,
0276 struct ethnl_reply_data *reply_base,
0277 struct genl_info *info)
0278 {
0279 const struct strset_req_info *req_info = STRSET_REQINFO(req_base);
0280 struct strset_reply_data *data = STRSET_REPDATA(reply_base);
0281 struct net_device *dev = reply_base->dev;
0282 unsigned int i;
0283 int ret;
0284
0285 BUILD_BUG_ON(ARRAY_SIZE(info_template) != ETH_SS_COUNT);
0286 memcpy(&data->sets, &info_template, sizeof(data->sets));
0287
0288 if (!dev) {
0289 for (i = 0; i < ETH_SS_COUNT; i++) {
0290 if ((req_info->req_ids & (1U << i)) &&
0291 data->sets[i].per_dev) {
0292 if (info)
0293 GENL_SET_ERR_MSG(info, "requested per device strings without dev");
0294 return -EINVAL;
0295 }
0296 }
0297 return 0;
0298 }
0299
0300 ret = ethnl_ops_begin(dev);
0301 if (ret < 0)
0302 goto err_strset;
0303 for (i = 0; i < ETH_SS_COUNT; i++) {
0304 if (!strset_include(req_info, data, i) ||
0305 !data->sets[i].per_dev)
0306 continue;
0307
0308 ret = strset_prepare_set(&data->sets[i], dev, i,
0309 req_info->counts_only);
0310 if (ret < 0)
0311 goto err_ops;
0312 }
0313 ethnl_ops_complete(dev);
0314
0315 return 0;
0316 err_ops:
0317 ethnl_ops_complete(dev);
0318 err_strset:
0319 strset_cleanup_data(reply_base);
0320 return ret;
0321 }
0322
0323
0324 static int strset_set_size(const struct strset_info *info, bool counts_only)
0325 {
0326 unsigned int len = 0;
0327 unsigned int i;
0328
0329 if (info->count == 0)
0330 return 0;
0331 if (counts_only)
0332 return nla_total_size(2 * nla_total_size(sizeof(u32)));
0333
0334 for (i = 0; i < info->count; i++) {
0335 const char *str = info->strings[i];
0336
0337
0338 len += nla_total_size(nla_total_size(sizeof(u32)) +
0339 ethnl_strz_size(str));
0340 }
0341
0342 len = 2 * nla_total_size(sizeof(u32)) + nla_total_size(len);
0343
0344 return nla_total_size(len);
0345 }
0346
0347 static int strset_reply_size(const struct ethnl_req_info *req_base,
0348 const struct ethnl_reply_data *reply_base)
0349 {
0350 const struct strset_req_info *req_info = STRSET_REQINFO(req_base);
0351 const struct strset_reply_data *data = STRSET_REPDATA(reply_base);
0352 unsigned int i;
0353 int len = 0;
0354 int ret;
0355
0356 len += nla_total_size(0);
0357
0358 for (i = 0; i < ETH_SS_COUNT; i++) {
0359 const struct strset_info *set_info = &data->sets[i];
0360
0361 if (!strset_include(req_info, data, i))
0362 continue;
0363
0364 ret = strset_set_size(set_info, req_info->counts_only);
0365 if (ret < 0)
0366 return ret;
0367 len += ret;
0368 }
0369
0370 return len;
0371 }
0372
0373
0374 static int strset_fill_string(struct sk_buff *skb,
0375 const struct strset_info *set_info, u32 idx)
0376 {
0377 struct nlattr *string_attr;
0378 const char *value;
0379
0380 value = set_info->strings[idx];
0381
0382 string_attr = nla_nest_start(skb, ETHTOOL_A_STRINGS_STRING);
0383 if (!string_attr)
0384 return -EMSGSIZE;
0385 if (nla_put_u32(skb, ETHTOOL_A_STRING_INDEX, idx) ||
0386 ethnl_put_strz(skb, ETHTOOL_A_STRING_VALUE, value))
0387 goto nla_put_failure;
0388 nla_nest_end(skb, string_attr);
0389
0390 return 0;
0391 nla_put_failure:
0392 nla_nest_cancel(skb, string_attr);
0393 return -EMSGSIZE;
0394 }
0395
0396
0397 static int strset_fill_set(struct sk_buff *skb,
0398 const struct strset_info *set_info, u32 id,
0399 bool counts_only)
0400 {
0401 struct nlattr *stringset_attr;
0402 struct nlattr *strings_attr;
0403 unsigned int i;
0404
0405 if (!set_info->per_dev && !set_info->strings)
0406 return -EOPNOTSUPP;
0407 if (set_info->count == 0)
0408 return 0;
0409 stringset_attr = nla_nest_start(skb, ETHTOOL_A_STRINGSETS_STRINGSET);
0410 if (!stringset_attr)
0411 return -EMSGSIZE;
0412
0413 if (nla_put_u32(skb, ETHTOOL_A_STRINGSET_ID, id) ||
0414 nla_put_u32(skb, ETHTOOL_A_STRINGSET_COUNT, set_info->count))
0415 goto nla_put_failure;
0416
0417 if (!counts_only) {
0418 strings_attr = nla_nest_start(skb, ETHTOOL_A_STRINGSET_STRINGS);
0419 if (!strings_attr)
0420 goto nla_put_failure;
0421 for (i = 0; i < set_info->count; i++) {
0422 if (strset_fill_string(skb, set_info, i) < 0)
0423 goto nla_put_failure;
0424 }
0425 nla_nest_end(skb, strings_attr);
0426 }
0427
0428 nla_nest_end(skb, stringset_attr);
0429 return 0;
0430
0431 nla_put_failure:
0432 nla_nest_cancel(skb, stringset_attr);
0433 return -EMSGSIZE;
0434 }
0435
0436 static int strset_fill_reply(struct sk_buff *skb,
0437 const struct ethnl_req_info *req_base,
0438 const struct ethnl_reply_data *reply_base)
0439 {
0440 const struct strset_req_info *req_info = STRSET_REQINFO(req_base);
0441 const struct strset_reply_data *data = STRSET_REPDATA(reply_base);
0442 struct nlattr *nest;
0443 unsigned int i;
0444 int ret;
0445
0446 nest = nla_nest_start(skb, ETHTOOL_A_STRSET_STRINGSETS);
0447 if (!nest)
0448 return -EMSGSIZE;
0449
0450 for (i = 0; i < ETH_SS_COUNT; i++) {
0451 if (strset_include(req_info, data, i)) {
0452 ret = strset_fill_set(skb, &data->sets[i], i,
0453 req_info->counts_only);
0454 if (ret < 0)
0455 goto nla_put_failure;
0456 }
0457 }
0458
0459 nla_nest_end(skb, nest);
0460 return 0;
0461
0462 nla_put_failure:
0463 nla_nest_cancel(skb, nest);
0464 return ret;
0465 }
0466
0467 const struct ethnl_request_ops ethnl_strset_request_ops = {
0468 .request_cmd = ETHTOOL_MSG_STRSET_GET,
0469 .reply_cmd = ETHTOOL_MSG_STRSET_GET_REPLY,
0470 .hdr_attr = ETHTOOL_A_STRSET_HEADER,
0471 .req_info_size = sizeof(struct strset_req_info),
0472 .reply_data_size = sizeof(struct strset_reply_data),
0473 .allow_nodev_do = true,
0474
0475 .parse_request = strset_parse_request,
0476 .prepare_data = strset_prepare_data,
0477 .reply_size = strset_reply_size,
0478 .fill_reply = strset_fill_reply,
0479 .cleanup_data = strset_cleanup_data,
0480 };