1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #include <linux/ethtool.h> 4 #include <linux/phy.h> 5 6 #include "common.h" 7 #include "netlink.h" 8 9 struct strset_info { 10 bool per_dev; 11 bool free_strings; 12 unsigned int count; 13 const char (*strings)[ETH_GSTRING_LEN]; 14 }; 15 16 static const struct strset_info info_template[] = { 17 [ETH_SS_TEST] = { 18 .per_dev = true, 19 }, 20 [ETH_SS_STATS] = { 21 .per_dev = true, 22 }, 23 [ETH_SS_PRIV_FLAGS] = { 24 .per_dev = true, 25 }, 26 [ETH_SS_FEATURES] = { 27 .per_dev = false, 28 .count = ARRAY_SIZE(netdev_features_strings), 29 .strings = netdev_features_strings, 30 }, 31 [ETH_SS_RSS_HASH_FUNCS] = { 32 .per_dev = false, 33 .count = ARRAY_SIZE(rss_hash_func_strings), 34 .strings = rss_hash_func_strings, 35 }, 36 [ETH_SS_TUNABLES] = { 37 .per_dev = false, 38 .count = ARRAY_SIZE(tunable_strings), 39 .strings = tunable_strings, 40 }, 41 [ETH_SS_PHY_STATS] = { 42 .per_dev = true, 43 }, 44 [ETH_SS_PHY_TUNABLES] = { 45 .per_dev = false, 46 .count = ARRAY_SIZE(phy_tunable_strings), 47 .strings = phy_tunable_strings, 48 }, 49 [ETH_SS_LINK_MODES] = { 50 .per_dev = false, 51 .count = __ETHTOOL_LINK_MODE_MASK_NBITS, 52 .strings = link_mode_names, 53 }, 54 [ETH_SS_MSG_CLASSES] = { 55 .per_dev = false, 56 .count = NETIF_MSG_CLASS_COUNT, 57 .strings = netif_msg_class_names, 58 }, 59 [ETH_SS_WOL_MODES] = { 60 .per_dev = false, 61 .count = WOL_MODE_COUNT, 62 .strings = wol_mode_names, 63 }, 64 [ETH_SS_SOF_TIMESTAMPING] = { 65 .per_dev = false, 66 .count = __SOF_TIMESTAMPING_CNT, 67 .strings = sof_timestamping_names, 68 }, 69 [ETH_SS_TS_TX_TYPES] = { 70 .per_dev = false, 71 .count = __HWTSTAMP_TX_CNT, 72 .strings = ts_tx_type_names, 73 }, 74 [ETH_SS_TS_RX_FILTERS] = { 75 .per_dev = false, 76 .count = __HWTSTAMP_FILTER_CNT, 77 .strings = ts_rx_filter_names, 78 }, 79 [ETH_SS_TS_FLAGS] = { 80 .per_dev = false, 81 .count = __HWTSTAMP_FLAG_CNT, 82 .strings = ts_flags_names, 83 }, 84 [ETH_SS_UDP_TUNNEL_TYPES] = { 85 .per_dev = false, 86 .count = __ETHTOOL_UDP_TUNNEL_TYPE_CNT, 87 .strings = udp_tunnel_type_names, 88 }, 89 [ETH_SS_STATS_STD] = { 90 .per_dev = false, 91 .count = __ETHTOOL_STATS_CNT, 92 .strings = stats_std_names, 93 }, 94 [ETH_SS_STATS_ETH_PHY] = { 95 .per_dev = false, 96 .count = __ETHTOOL_A_STATS_ETH_PHY_CNT, 97 .strings = stats_eth_phy_names, 98 }, 99 [ETH_SS_STATS_ETH_MAC] = { 100 .per_dev = false, 101 .count = __ETHTOOL_A_STATS_ETH_MAC_CNT, 102 .strings = stats_eth_mac_names, 103 }, 104 [ETH_SS_STATS_ETH_CTRL] = { 105 .per_dev = false, 106 .count = __ETHTOOL_A_STATS_ETH_CTRL_CNT, 107 .strings = stats_eth_ctrl_names, 108 }, 109 [ETH_SS_STATS_RMON] = { 110 .per_dev = false, 111 .count = __ETHTOOL_A_STATS_RMON_CNT, 112 .strings = stats_rmon_names, 113 }, 114 [ETH_SS_STATS_PHY] = { 115 .per_dev = false, 116 .count = __ETHTOOL_A_STATS_PHY_CNT, 117 .strings = stats_phy_names, 118 }, 119 }; 120 121 struct strset_req_info { 122 struct ethnl_req_info base; 123 u32 req_ids; 124 bool counts_only; 125 }; 126 127 #define STRSET_REQINFO(__req_base) \ 128 container_of(__req_base, struct strset_req_info, base) 129 130 struct strset_reply_data { 131 struct ethnl_reply_data base; 132 struct strset_info sets[ETH_SS_COUNT]; 133 }; 134 135 #define STRSET_REPDATA(__reply_base) \ 136 container_of(__reply_base, struct strset_reply_data, base) 137 138 const struct nla_policy ethnl_strset_get_policy[] = { 139 [ETHTOOL_A_STRSET_HEADER] = 140 NLA_POLICY_NESTED(ethnl_header_policy_phy), 141 [ETHTOOL_A_STRSET_STRINGSETS] = { .type = NLA_NESTED }, 142 [ETHTOOL_A_STRSET_COUNTS_ONLY] = { .type = NLA_FLAG }, 143 }; 144 145 static const struct nla_policy get_stringset_policy[] = { 146 [ETHTOOL_A_STRINGSET_ID] = { .type = NLA_U32 }, 147 }; 148 149 /** 150 * strset_include() - test if a string set should be included in reply 151 * @info: parsed client request 152 * @data: pointer to request data structure 153 * @id: id of string set to check (ETH_SS_* constants) 154 */ 155 static bool strset_include(const struct strset_req_info *info, 156 const struct strset_reply_data *data, u32 id) 157 { 158 bool per_dev; 159 160 BUILD_BUG_ON(ETH_SS_COUNT >= BITS_PER_BYTE * sizeof(info->req_ids)); 161 162 if (info->req_ids) 163 return info->req_ids & (1U << id); 164 per_dev = data->sets[id].per_dev; 165 if (!per_dev && !data->sets[id].strings) 166 return false; 167 168 return data->base.dev ? per_dev : !per_dev; 169 } 170 171 static int strset_get_id(const struct nlattr *nest, u32 *val, 172 struct netlink_ext_ack *extack) 173 { 174 struct nlattr *tb[ARRAY_SIZE(get_stringset_policy)]; 175 int ret; 176 177 ret = nla_parse_nested(tb, ARRAY_SIZE(get_stringset_policy) - 1, nest, 178 get_stringset_policy, extack); 179 if (ret < 0) 180 return ret; 181 if (NL_REQ_ATTR_CHECK(extack, nest, tb, ETHTOOL_A_STRINGSET_ID)) 182 return -EINVAL; 183 184 *val = nla_get_u32(tb[ETHTOOL_A_STRINGSET_ID]); 185 return 0; 186 } 187 188 static const struct nla_policy strset_stringsets_policy[] = { 189 [ETHTOOL_A_STRINGSETS_STRINGSET] = { .type = NLA_NESTED }, 190 }; 191 192 static int strset_parse_request(struct ethnl_req_info *req_base, 193 struct nlattr **tb, 194 struct netlink_ext_ack *extack) 195 { 196 struct strset_req_info *req_info = STRSET_REQINFO(req_base); 197 struct nlattr *nest = tb[ETHTOOL_A_STRSET_STRINGSETS]; 198 struct nlattr *attr; 199 int rem, ret; 200 201 if (!nest) 202 return 0; 203 ret = nla_validate_nested(nest, 204 ARRAY_SIZE(strset_stringsets_policy) - 1, 205 strset_stringsets_policy, extack); 206 if (ret < 0) 207 return ret; 208 209 req_info->counts_only = tb[ETHTOOL_A_STRSET_COUNTS_ONLY]; 210 nla_for_each_nested(attr, nest, rem) { 211 u32 id; 212 213 if (WARN_ONCE(nla_type(attr) != ETHTOOL_A_STRINGSETS_STRINGSET, 214 "unexpected attrtype %u in ETHTOOL_A_STRSET_STRINGSETS\n", 215 nla_type(attr))) 216 return -EINVAL; 217 218 ret = strset_get_id(attr, &id, extack); 219 if (ret < 0) 220 return ret; 221 if (id >= ETH_SS_COUNT) { 222 NL_SET_ERR_MSG_ATTR(extack, attr, 223 "unknown string set id"); 224 return -EOPNOTSUPP; 225 } 226 227 req_info->req_ids |= (1U << id); 228 } 229 230 return 0; 231 } 232 233 static void strset_cleanup_data(struct ethnl_reply_data *reply_base) 234 { 235 struct strset_reply_data *data = STRSET_REPDATA(reply_base); 236 unsigned int i; 237 238 for (i = 0; i < ETH_SS_COUNT; i++) 239 if (data->sets[i].free_strings) { 240 kfree(data->sets[i].strings); 241 data->sets[i].strings = NULL; 242 data->sets[i].free_strings = false; 243 } 244 } 245 246 static int strset_prepare_set(struct strset_info *info, struct net_device *dev, 247 struct phy_device *phydev, unsigned int id, 248 bool counts_only) 249 { 250 const struct ethtool_phy_ops *phy_ops = ethtool_phy_ops; 251 const struct ethtool_ops *ops = dev->ethtool_ops; 252 void *strings; 253 int count, ret; 254 255 if (id == ETH_SS_PHY_STATS && phydev && 256 !ops->get_ethtool_phy_stats && phy_ops && 257 phy_ops->get_sset_count) 258 ret = phy_ops->get_sset_count(phydev); 259 else if (ops->get_sset_count && ops->get_strings) 260 ret = ops->get_sset_count(dev, id); 261 else 262 ret = -EOPNOTSUPP; 263 if (ret <= 0) { 264 info->count = 0; 265 return 0; 266 } 267 268 count = ret; 269 if (!counts_only) { 270 strings = kcalloc(count, ETH_GSTRING_LEN, GFP_KERNEL); 271 if (!strings) 272 return -ENOMEM; 273 if (id == ETH_SS_PHY_STATS && phydev && 274 !ops->get_ethtool_phy_stats && phy_ops && 275 phy_ops->get_strings) 276 phy_ops->get_strings(phydev, strings); 277 else 278 ops->get_strings(dev, id, strings); 279 info->strings = strings; 280 info->free_strings = true; 281 } 282 info->count = count; 283 284 return 0; 285 } 286 287 static int strset_prepare_data(const struct ethnl_req_info *req_base, 288 struct ethnl_reply_data *reply_base, 289 const struct genl_info *info) 290 { 291 const struct strset_req_info *req_info = STRSET_REQINFO(req_base); 292 struct strset_reply_data *data = STRSET_REPDATA(reply_base); 293 struct net_device *dev = reply_base->dev; 294 struct nlattr **tb = info->attrs; 295 struct phy_device *phydev; 296 unsigned int i; 297 int ret; 298 299 BUILD_BUG_ON(ARRAY_SIZE(info_template) != ETH_SS_COUNT); 300 memcpy(&data->sets, &info_template, sizeof(data->sets)); 301 302 if (!dev) { 303 for (i = 0; i < ETH_SS_COUNT; i++) { 304 if ((req_info->req_ids & (1U << i)) && 305 data->sets[i].per_dev) { 306 GENL_SET_ERR_MSG(info, "requested per device strings without dev"); 307 return -EINVAL; 308 } 309 } 310 return 0; 311 } 312 313 phydev = ethnl_req_get_phydev(req_base, tb, ETHTOOL_A_HEADER_FLAGS, 314 info->extack); 315 316 /* phydev can be NULL, check for errors only */ 317 if (IS_ERR(phydev)) 318 return PTR_ERR(phydev); 319 320 ret = ethnl_ops_begin(dev); 321 if (ret < 0) 322 goto err_strset; 323 for (i = 0; i < ETH_SS_COUNT; i++) { 324 if (!strset_include(req_info, data, i) || 325 !data->sets[i].per_dev) 326 continue; 327 328 ret = strset_prepare_set(&data->sets[i], dev, phydev, i, 329 req_info->counts_only); 330 if (ret < 0) 331 goto err_ops; 332 } 333 ethnl_ops_complete(dev); 334 335 return 0; 336 err_ops: 337 ethnl_ops_complete(dev); 338 err_strset: 339 strset_cleanup_data(reply_base); 340 return ret; 341 } 342 343 /* calculate size of ETHTOOL_A_STRSET_STRINGSET nest for one string set */ 344 static int strset_set_size(const struct strset_info *info, bool counts_only) 345 { 346 unsigned int len = 0; 347 unsigned int i; 348 349 if (info->count == 0) 350 return 0; 351 if (counts_only) 352 return nla_total_size(2 * nla_total_size(sizeof(u32))); 353 354 for (i = 0; i < info->count; i++) { 355 const char *str = info->strings[i]; 356 357 /* ETHTOOL_A_STRING_INDEX, ETHTOOL_A_STRING_VALUE, nest */ 358 len += nla_total_size(nla_total_size(sizeof(u32)) + 359 ethnl_strz_size(str)); 360 } 361 /* ETHTOOL_A_STRINGSET_ID, ETHTOOL_A_STRINGSET_COUNT */ 362 len = 2 * nla_total_size(sizeof(u32)) + nla_total_size(len); 363 364 return nla_total_size(len); 365 } 366 367 static int strset_reply_size(const struct ethnl_req_info *req_base, 368 const struct ethnl_reply_data *reply_base) 369 { 370 const struct strset_req_info *req_info = STRSET_REQINFO(req_base); 371 const struct strset_reply_data *data = STRSET_REPDATA(reply_base); 372 unsigned int i; 373 int len = 0; 374 int ret; 375 376 len += nla_total_size(0); /* ETHTOOL_A_STRSET_STRINGSETS */ 377 378 for (i = 0; i < ETH_SS_COUNT; i++) { 379 const struct strset_info *set_info = &data->sets[i]; 380 381 if (!strset_include(req_info, data, i)) 382 continue; 383 384 ret = strset_set_size(set_info, req_info->counts_only); 385 if (ret < 0) 386 return ret; 387 len += ret; 388 } 389 390 return len; 391 } 392 393 /* fill one string into reply */ 394 static int strset_fill_string(struct sk_buff *skb, 395 const struct strset_info *set_info, u32 idx) 396 { 397 struct nlattr *string_attr; 398 const char *value; 399 400 value = set_info->strings[idx]; 401 402 string_attr = nla_nest_start(skb, ETHTOOL_A_STRINGS_STRING); 403 if (!string_attr) 404 return -EMSGSIZE; 405 if (nla_put_u32(skb, ETHTOOL_A_STRING_INDEX, idx) || 406 ethnl_put_strz(skb, ETHTOOL_A_STRING_VALUE, value)) 407 goto nla_put_failure; 408 nla_nest_end(skb, string_attr); 409 410 return 0; 411 nla_put_failure: 412 nla_nest_cancel(skb, string_attr); 413 return -EMSGSIZE; 414 } 415 416 /* fill one string set into reply */ 417 static int strset_fill_set(struct sk_buff *skb, 418 const struct strset_info *set_info, u32 id, 419 bool counts_only) 420 { 421 struct nlattr *stringset_attr; 422 struct nlattr *strings_attr; 423 unsigned int i; 424 425 if (!set_info->per_dev && !set_info->strings) 426 return -EOPNOTSUPP; 427 if (set_info->count == 0) 428 return 0; 429 stringset_attr = nla_nest_start(skb, ETHTOOL_A_STRINGSETS_STRINGSET); 430 if (!stringset_attr) 431 return -EMSGSIZE; 432 433 if (nla_put_u32(skb, ETHTOOL_A_STRINGSET_ID, id) || 434 nla_put_u32(skb, ETHTOOL_A_STRINGSET_COUNT, set_info->count)) 435 goto nla_put_failure; 436 437 if (!counts_only) { 438 strings_attr = nla_nest_start(skb, ETHTOOL_A_STRINGSET_STRINGS); 439 if (!strings_attr) 440 goto nla_put_failure; 441 for (i = 0; i < set_info->count; i++) { 442 if (strset_fill_string(skb, set_info, i) < 0) 443 goto nla_put_failure; 444 } 445 nla_nest_end(skb, strings_attr); 446 } 447 448 nla_nest_end(skb, stringset_attr); 449 return 0; 450 451 nla_put_failure: 452 nla_nest_cancel(skb, stringset_attr); 453 return -EMSGSIZE; 454 } 455 456 static int strset_fill_reply(struct sk_buff *skb, 457 const struct ethnl_req_info *req_base, 458 const struct ethnl_reply_data *reply_base) 459 { 460 const struct strset_req_info *req_info = STRSET_REQINFO(req_base); 461 const struct strset_reply_data *data = STRSET_REPDATA(reply_base); 462 struct nlattr *nest; 463 unsigned int i; 464 int ret; 465 466 nest = nla_nest_start(skb, ETHTOOL_A_STRSET_STRINGSETS); 467 if (!nest) 468 return -EMSGSIZE; 469 470 for (i = 0; i < ETH_SS_COUNT; i++) { 471 if (strset_include(req_info, data, i)) { 472 ret = strset_fill_set(skb, &data->sets[i], i, 473 req_info->counts_only); 474 if (ret < 0) 475 goto nla_put_failure; 476 } 477 } 478 479 nla_nest_end(skb, nest); 480 return 0; 481 482 nla_put_failure: 483 nla_nest_cancel(skb, nest); 484 return ret; 485 } 486 487 const struct ethnl_request_ops ethnl_strset_request_ops = { 488 .request_cmd = ETHTOOL_MSG_STRSET_GET, 489 .reply_cmd = ETHTOOL_MSG_STRSET_GET_REPLY, 490 .hdr_attr = ETHTOOL_A_STRSET_HEADER, 491 .req_info_size = sizeof(struct strset_req_info), 492 .reply_data_size = sizeof(struct strset_reply_data), 493 .allow_nodev_do = true, 494 495 .parse_request = strset_parse_request, 496 .prepare_data = strset_prepare_data, 497 .reply_size = strset_reply_size, 498 .fill_reply = strset_fill_reply, 499 .cleanup_data = strset_cleanup_data, 500 }; 501