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