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