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_phy), 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 struct nlattr **tb = info->attrs; 284 struct phy_device *phydev; 285 unsigned int i; 286 int ret; 287 288 BUILD_BUG_ON(ARRAY_SIZE(info_template) != ETH_SS_COUNT); 289 memcpy(&data->sets, &info_template, sizeof(data->sets)); 290 291 if (!dev) { 292 for (i = 0; i < ETH_SS_COUNT; i++) { 293 if ((req_info->req_ids & (1U << i)) && 294 data->sets[i].per_dev) { 295 GENL_SET_ERR_MSG(info, "requested per device strings without dev"); 296 return -EINVAL; 297 } 298 } 299 return 0; 300 } 301 302 phydev = ethnl_req_get_phydev(req_base, tb[ETHTOOL_A_HEADER_FLAGS], 303 info->extack); 304 305 /* phydev can be NULL, check for errors only */ 306 if (IS_ERR(phydev)) 307 return PTR_ERR(phydev); 308 309 ret = ethnl_ops_begin(dev); 310 if (ret < 0) 311 goto err_strset; 312 for (i = 0; i < ETH_SS_COUNT; i++) { 313 if (!strset_include(req_info, data, i) || 314 !data->sets[i].per_dev) 315 continue; 316 317 ret = strset_prepare_set(&data->sets[i], dev, phydev, i, 318 req_info->counts_only); 319 if (ret < 0) 320 goto err_ops; 321 } 322 ethnl_ops_complete(dev); 323 324 return 0; 325 err_ops: 326 ethnl_ops_complete(dev); 327 err_strset: 328 strset_cleanup_data(reply_base); 329 return ret; 330 } 331 332 /* calculate size of ETHTOOL_A_STRSET_STRINGSET nest for one string set */ 333 static int strset_set_size(const struct strset_info *info, bool counts_only) 334 { 335 unsigned int len = 0; 336 unsigned int i; 337 338 if (info->count == 0) 339 return 0; 340 if (counts_only) 341 return nla_total_size(2 * nla_total_size(sizeof(u32))); 342 343 for (i = 0; i < info->count; i++) { 344 const char *str = info->strings[i]; 345 346 /* ETHTOOL_A_STRING_INDEX, ETHTOOL_A_STRING_VALUE, nest */ 347 len += nla_total_size(nla_total_size(sizeof(u32)) + 348 ethnl_strz_size(str)); 349 } 350 /* ETHTOOL_A_STRINGSET_ID, ETHTOOL_A_STRINGSET_COUNT */ 351 len = 2 * nla_total_size(sizeof(u32)) + nla_total_size(len); 352 353 return nla_total_size(len); 354 } 355 356 static int strset_reply_size(const struct ethnl_req_info *req_base, 357 const struct ethnl_reply_data *reply_base) 358 { 359 const struct strset_req_info *req_info = STRSET_REQINFO(req_base); 360 const struct strset_reply_data *data = STRSET_REPDATA(reply_base); 361 unsigned int i; 362 int len = 0; 363 int ret; 364 365 len += nla_total_size(0); /* ETHTOOL_A_STRSET_STRINGSETS */ 366 367 for (i = 0; i < ETH_SS_COUNT; i++) { 368 const struct strset_info *set_info = &data->sets[i]; 369 370 if (!strset_include(req_info, data, i)) 371 continue; 372 373 ret = strset_set_size(set_info, req_info->counts_only); 374 if (ret < 0) 375 return ret; 376 len += ret; 377 } 378 379 return len; 380 } 381 382 /* fill one string into reply */ 383 static int strset_fill_string(struct sk_buff *skb, 384 const struct strset_info *set_info, u32 idx) 385 { 386 struct nlattr *string_attr; 387 const char *value; 388 389 value = set_info->strings[idx]; 390 391 string_attr = nla_nest_start(skb, ETHTOOL_A_STRINGS_STRING); 392 if (!string_attr) 393 return -EMSGSIZE; 394 if (nla_put_u32(skb, ETHTOOL_A_STRING_INDEX, idx) || 395 ethnl_put_strz(skb, ETHTOOL_A_STRING_VALUE, value)) 396 goto nla_put_failure; 397 nla_nest_end(skb, string_attr); 398 399 return 0; 400 nla_put_failure: 401 nla_nest_cancel(skb, string_attr); 402 return -EMSGSIZE; 403 } 404 405 /* fill one string set into reply */ 406 static int strset_fill_set(struct sk_buff *skb, 407 const struct strset_info *set_info, u32 id, 408 bool counts_only) 409 { 410 struct nlattr *stringset_attr; 411 struct nlattr *strings_attr; 412 unsigned int i; 413 414 if (!set_info->per_dev && !set_info->strings) 415 return -EOPNOTSUPP; 416 if (set_info->count == 0) 417 return 0; 418 stringset_attr = nla_nest_start(skb, ETHTOOL_A_STRINGSETS_STRINGSET); 419 if (!stringset_attr) 420 return -EMSGSIZE; 421 422 if (nla_put_u32(skb, ETHTOOL_A_STRINGSET_ID, id) || 423 nla_put_u32(skb, ETHTOOL_A_STRINGSET_COUNT, set_info->count)) 424 goto nla_put_failure; 425 426 if (!counts_only) { 427 strings_attr = nla_nest_start(skb, ETHTOOL_A_STRINGSET_STRINGS); 428 if (!strings_attr) 429 goto nla_put_failure; 430 for (i = 0; i < set_info->count; i++) { 431 if (strset_fill_string(skb, set_info, i) < 0) 432 goto nla_put_failure; 433 } 434 nla_nest_end(skb, strings_attr); 435 } 436 437 nla_nest_end(skb, stringset_attr); 438 return 0; 439 440 nla_put_failure: 441 nla_nest_cancel(skb, stringset_attr); 442 return -EMSGSIZE; 443 } 444 445 static int strset_fill_reply(struct sk_buff *skb, 446 const struct ethnl_req_info *req_base, 447 const struct ethnl_reply_data *reply_base) 448 { 449 const struct strset_req_info *req_info = STRSET_REQINFO(req_base); 450 const struct strset_reply_data *data = STRSET_REPDATA(reply_base); 451 struct nlattr *nest; 452 unsigned int i; 453 int ret; 454 455 nest = nla_nest_start(skb, ETHTOOL_A_STRSET_STRINGSETS); 456 if (!nest) 457 return -EMSGSIZE; 458 459 for (i = 0; i < ETH_SS_COUNT; i++) { 460 if (strset_include(req_info, data, i)) { 461 ret = strset_fill_set(skb, &data->sets[i], i, 462 req_info->counts_only); 463 if (ret < 0) 464 goto nla_put_failure; 465 } 466 } 467 468 nla_nest_end(skb, nest); 469 return 0; 470 471 nla_put_failure: 472 nla_nest_cancel(skb, nest); 473 return ret; 474 } 475 476 const struct ethnl_request_ops ethnl_strset_request_ops = { 477 .request_cmd = ETHTOOL_MSG_STRSET_GET, 478 .reply_cmd = ETHTOOL_MSG_STRSET_GET_REPLY, 479 .hdr_attr = ETHTOOL_A_STRSET_HEADER, 480 .req_info_size = sizeof(struct strset_req_info), 481 .reply_data_size = sizeof(struct strset_reply_data), 482 .allow_nodev_do = true, 483 484 .parse_request = strset_parse_request, 485 .prepare_data = strset_prepare_data, 486 .reply_size = strset_reply_size, 487 .fill_reply = strset_fill_reply, 488 .cleanup_data = strset_cleanup_data, 489 }; 490