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