Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'ethtool-allow-dumping-policies-to-user-space'

Jakub Kicinski says:

====================
ethtool: allow dumping policies to user space

This series wires up ethtool policies to ops, so they can be
dumped to user space for feature discovery.

First patch wires up GET commands, and second patch wires up SETs.

The policy tables are trimmed to save space and LoC.

Next - take care of linking up nested policies for the header
(which is the policy what we actually care about). And once header
policy is linked make sure that attribute range validation for flags
is done by policy, not a conditions in the code. New type of policy
is needed to validate masks (patch 6).

Netlink as always staying a step ahead of all the other kernel
API interfaces :)

v2:
- merge patches 1 & 2 -> 1
- add patch 3 & 5
- remove .max_attr from struct ethnl_request_ops
====================

Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

+317 -414
+19 -8
include/net/netlink.h
··· 200 200 NLA_VALIDATE_RANGE_WARN_TOO_LONG, 201 201 NLA_VALIDATE_MIN, 202 202 NLA_VALIDATE_MAX, 203 + NLA_VALIDATE_MASK, 203 204 NLA_VALIDATE_RANGE_PTR, 204 205 NLA_VALIDATE_FUNCTION, 205 206 }; ··· 318 317 u16 len; 319 318 union { 320 319 const u32 bitfield32_valid; 320 + const u32 mask; 321 321 const char *reject_message; 322 322 const struct nla_policy *nested_policy; 323 323 struct netlink_range_validation *range; ··· 364 362 #define NLA_POLICY_BITFIELD32(valid) \ 365 363 { .type = NLA_BITFIELD32, .bitfield32_valid = valid } 366 364 365 + #define __NLA_IS_UINT_TYPE(tp) \ 366 + (tp == NLA_U8 || tp == NLA_U16 || tp == NLA_U32 || tp == NLA_U64) 367 + #define __NLA_IS_SINT_TYPE(tp) \ 368 + (tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64) 369 + 367 370 #define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition)) 371 + #define NLA_ENSURE_UINT_TYPE(tp) \ 372 + (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp)) + tp) 368 373 #define NLA_ENSURE_UINT_OR_BINARY_TYPE(tp) \ 369 - (__NLA_ENSURE(tp == NLA_U8 || tp == NLA_U16 || \ 370 - tp == NLA_U32 || tp == NLA_U64 || \ 374 + (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp) || \ 371 375 tp == NLA_MSECS || \ 372 376 tp == NLA_BINARY) + tp) 373 377 #define NLA_ENSURE_SINT_TYPE(tp) \ 374 - (__NLA_ENSURE(tp == NLA_S8 || tp == NLA_S16 || \ 375 - tp == NLA_S32 || tp == NLA_S64) + tp) 378 + (__NLA_ENSURE(__NLA_IS_SINT_TYPE(tp)) + tp) 376 379 #define NLA_ENSURE_INT_OR_BINARY_TYPE(tp) \ 377 - (__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \ 378 - tp == NLA_S16 || tp == NLA_U16 || \ 379 - tp == NLA_S32 || tp == NLA_U32 || \ 380 - tp == NLA_S64 || tp == NLA_U64 || \ 380 + (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp) || \ 381 + __NLA_IS_SINT_TYPE(tp) || \ 381 382 tp == NLA_MSECS || \ 382 383 tp == NLA_BINARY) + tp) 383 384 #define NLA_ENSURE_NO_VALIDATION_PTR(tp) \ ··· 418 413 .type = NLA_ENSURE_INT_OR_BINARY_TYPE(tp), \ 419 414 .validation_type = NLA_VALIDATE_MAX, \ 420 415 .max = _max, \ 416 + } 417 + 418 + #define NLA_POLICY_MASK(tp, _mask) { \ 419 + .type = NLA_ENSURE_UINT_TYPE(tp), \ 420 + .validation_type = NLA_VALIDATE_MASK, \ 421 + .mask = _mask, \ 421 422 } 422 423 423 424 #define NLA_POLICY_VALIDATE_FN(tp, fn, ...) { \
+2
include/uapi/linux/netlink.h
··· 331 331 * the index, if limited inside the nesting (U32) 332 332 * @NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: valid mask for the 333 333 * bitfield32 type (U32) 334 + * @NL_POLICY_TYPE_ATTR_MASK: mask of valid bits for unsigned integers (U64) 334 335 * @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment 335 336 */ 336 337 enum netlink_policy_type_attr { ··· 347 346 NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE, 348 347 NL_POLICY_TYPE_ATTR_BITFIELD32_MASK, 349 348 NL_POLICY_TYPE_ATTR_PAD, 349 + NL_POLICY_TYPE_ATTR_MASK, 350 350 351 351 /* keep last */ 352 352 __NL_POLICY_TYPE_ATTR_MAX,
+36
lib/nlattr.c
··· 323 323 } 324 324 } 325 325 326 + static int nla_validate_mask(const struct nla_policy *pt, 327 + const struct nlattr *nla, 328 + struct netlink_ext_ack *extack) 329 + { 330 + u64 value; 331 + 332 + switch (pt->type) { 333 + case NLA_U8: 334 + value = nla_get_u8(nla); 335 + break; 336 + case NLA_U16: 337 + value = nla_get_u16(nla); 338 + break; 339 + case NLA_U32: 340 + value = nla_get_u32(nla); 341 + break; 342 + case NLA_U64: 343 + value = nla_get_u64(nla); 344 + break; 345 + default: 346 + return -EINVAL; 347 + } 348 + 349 + if (value & ~(u64)pt->mask) { 350 + NL_SET_ERR_MSG_ATTR(extack, nla, "reserved bit set"); 351 + return -EINVAL; 352 + } 353 + 354 + return 0; 355 + } 356 + 326 357 static int validate_nla(const struct nlattr *nla, int maxtype, 327 358 const struct nla_policy *policy, unsigned int validate, 328 359 struct netlink_ext_ack *extack, unsigned int depth) ··· 531 500 case NLA_VALIDATE_MIN: 532 501 case NLA_VALIDATE_MAX: 533 502 err = nla_validate_int_range(pt, nla, extack, validate); 503 + if (err) 504 + return err; 505 + break; 506 + case NLA_VALIDATE_MASK: 507 + err = nla_validate_mask(pt, nla, extack); 534 508 if (err) 535 509 return err; 536 510 break;
+12 -14
net/ethtool/bitset.c
··· 302 302 return -EMSGSIZE; 303 303 } 304 304 305 - static const struct nla_policy bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = { 306 - [ETHTOOL_A_BITSET_UNSPEC] = { .type = NLA_REJECT }, 305 + static const struct nla_policy bitset_policy[] = { 307 306 [ETHTOOL_A_BITSET_NOMASK] = { .type = NLA_FLAG }, 308 307 [ETHTOOL_A_BITSET_SIZE] = NLA_POLICY_MAX(NLA_U32, 309 308 ETHNL_MAX_BITSET_SIZE), ··· 311 312 [ETHTOOL_A_BITSET_MASK] = { .type = NLA_BINARY }, 312 313 }; 313 314 314 - static const struct nla_policy bit_policy[ETHTOOL_A_BITSET_BIT_MAX + 1] = { 315 - [ETHTOOL_A_BITSET_BIT_UNSPEC] = { .type = NLA_REJECT }, 315 + static const struct nla_policy bit_policy[] = { 316 316 [ETHTOOL_A_BITSET_BIT_INDEX] = { .type = NLA_U32 }, 317 317 [ETHTOOL_A_BITSET_BIT_NAME] = { .type = NLA_NUL_STRING }, 318 318 [ETHTOOL_A_BITSET_BIT_VALUE] = { .type = NLA_FLAG }, ··· 327 329 */ 328 330 int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact) 329 331 { 330 - struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1]; 332 + struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; 331 333 int ret; 332 334 333 - ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, bitset, 335 + ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, bitset, 334 336 bitset_policy, NULL); 335 337 if (ret < 0) 336 338 return ret; ··· 379 381 ethnl_string_array_t names, 380 382 struct netlink_ext_ack *extack) 381 383 { 382 - struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1]; 384 + struct nlattr *tb[ARRAY_SIZE(bit_policy)]; 383 385 int ret, idx; 384 386 385 - ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_BIT_MAX, bit_attr, 387 + ret = nla_parse_nested(tb, ARRAY_SIZE(bit_policy) - 1, bit_attr, 386 388 bit_policy, extack); 387 389 if (ret < 0) 388 390 return ret; ··· 553 555 const struct nlattr *attr, ethnl_string_array_t names, 554 556 struct netlink_ext_ack *extack, bool *mod) 555 557 { 556 - struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1]; 558 + struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; 557 559 unsigned int change_bits; 558 560 bool no_mask; 559 561 int ret; 560 562 561 563 if (!attr) 562 564 return 0; 563 - ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, attr, bitset_policy, 564 - extack); 565 + ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr, 566 + bitset_policy, extack); 565 567 if (ret < 0) 566 568 return ret; 567 569 ··· 606 608 ethnl_string_array_t names, 607 609 struct netlink_ext_ack *extack) 608 610 { 609 - struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1]; 611 + struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; 610 612 const struct nlattr *bit_attr; 611 613 bool no_mask; 612 614 int rem; ··· 614 616 615 617 if (!attr) 616 618 return 0; 617 - ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, attr, bitset_policy, 618 - extack); 619 + ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr, 620 + bitset_policy, extack); 619 621 if (ret < 0) 620 622 return ret; 621 623 no_mask = tb[ETHTOOL_A_BITSET_NOMASK];
+14 -27
net/ethtool/cabletest.c
··· 11 11 */ 12 12 #define MAX_CABLE_LENGTH_CM (150 * 100) 13 13 14 - static const struct nla_policy 15 - cable_test_act_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { 16 - [ETHTOOL_A_CABLE_TEST_UNSPEC] = { .type = NLA_REJECT }, 17 - [ETHTOOL_A_CABLE_TEST_HEADER] = { .type = NLA_NESTED }, 14 + const struct nla_policy ethnl_cable_test_act_policy[] = { 15 + [ETHTOOL_A_CABLE_TEST_HEADER] = 16 + NLA_POLICY_NESTED(ethnl_header_policy), 18 17 }; 19 18 20 19 static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd) ··· 55 56 56 57 int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) 57 58 { 58 - struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1]; 59 59 struct ethnl_req_info req_info = {}; 60 60 const struct ethtool_phy_ops *ops; 61 + struct nlattr **tb = info->attrs; 61 62 struct net_device *dev; 62 63 int ret; 63 - 64 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 65 - ETHTOOL_A_CABLE_TEST_MAX, 66 - cable_test_act_policy, info->extack); 67 - if (ret < 0) 68 - return ret; 69 64 70 65 ret = ethnl_parse_header_dev_get(&req_info, 71 66 tb[ETHTOOL_A_CABLE_TEST_HEADER], ··· 211 218 struct ethnl_req_info base; 212 219 }; 213 220 214 - static const struct nla_policy 215 - cable_test_tdr_act_cfg_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX + 1] = { 221 + static const struct nla_policy cable_test_tdr_act_cfg_policy[] = { 216 222 [ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST] = { .type = NLA_U32 }, 217 223 [ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST] = { .type = NLA_U32 }, 218 224 [ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP] = { .type = NLA_U32 }, 219 225 [ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR] = { .type = NLA_U8 }, 220 226 }; 221 227 222 - static const struct nla_policy 223 - cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1] = { 224 - [ETHTOOL_A_CABLE_TEST_TDR_UNSPEC] = { .type = NLA_REJECT }, 225 - [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = { .type = NLA_NESTED }, 228 + const struct nla_policy ethnl_cable_test_tdr_act_policy[] = { 229 + [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = 230 + NLA_POLICY_NESTED(ethnl_header_policy), 226 231 [ETHTOOL_A_CABLE_TEST_TDR_CFG] = { .type = NLA_NESTED }, 227 232 }; 228 233 ··· 229 238 struct genl_info *info, 230 239 struct phy_tdr_config *cfg) 231 240 { 232 - struct nlattr *tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX + 1]; 241 + struct nlattr *tb[ARRAY_SIZE(cable_test_tdr_act_cfg_policy)]; 233 242 int ret; 234 243 235 244 cfg->first = 100; ··· 240 249 if (!nest) 241 250 return 0; 242 251 243 - ret = nla_parse_nested(tb, ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX, nest, 244 - cable_test_tdr_act_cfg_policy, info->extack); 252 + ret = nla_parse_nested(tb, 253 + ARRAY_SIZE(cable_test_tdr_act_cfg_policy) - 1, 254 + nest, cable_test_tdr_act_cfg_policy, 255 + info->extack); 245 256 if (ret < 0) 246 257 return ret; 247 258 ··· 306 313 307 314 int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info) 308 315 { 309 - struct nlattr *tb[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1]; 310 316 struct ethnl_req_info req_info = {}; 311 317 const struct ethtool_phy_ops *ops; 318 + struct nlattr **tb = info->attrs; 312 319 struct phy_tdr_config cfg; 313 320 struct net_device *dev; 314 321 int ret; 315 - 316 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 317 - ETHTOOL_A_CABLE_TEST_TDR_MAX, 318 - cable_test_tdr_act_policy, info->extack); 319 - if (ret < 0) 320 - return ret; 321 322 322 323 ret = ethnl_parse_header_dev_get(&req_info, 323 324 tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER],
+7 -28
net/ethtool/channels.c
··· 17 17 #define CHANNELS_REPDATA(__reply_base) \ 18 18 container_of(__reply_base, struct channels_reply_data, base) 19 19 20 - static const struct nla_policy 21 - channels_get_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { 22 - [ETHTOOL_A_CHANNELS_UNSPEC] = { .type = NLA_REJECT }, 23 - [ETHTOOL_A_CHANNELS_HEADER] = { .type = NLA_NESTED }, 24 - [ETHTOOL_A_CHANNELS_RX_MAX] = { .type = NLA_REJECT }, 25 - [ETHTOOL_A_CHANNELS_TX_MAX] = { .type = NLA_REJECT }, 26 - [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .type = NLA_REJECT }, 27 - [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .type = NLA_REJECT }, 28 - [ETHTOOL_A_CHANNELS_RX_COUNT] = { .type = NLA_REJECT }, 29 - [ETHTOOL_A_CHANNELS_TX_COUNT] = { .type = NLA_REJECT }, 30 - [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .type = NLA_REJECT }, 31 - [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .type = NLA_REJECT }, 20 + const struct nla_policy ethnl_channels_get_policy[] = { 21 + [ETHTOOL_A_CHANNELS_HEADER] = 22 + NLA_POLICY_NESTED(ethnl_header_policy), 32 23 }; 33 24 34 25 static int channels_prepare_data(const struct ethnl_req_info *req_base, ··· 90 99 .request_cmd = ETHTOOL_MSG_CHANNELS_GET, 91 100 .reply_cmd = ETHTOOL_MSG_CHANNELS_GET_REPLY, 92 101 .hdr_attr = ETHTOOL_A_CHANNELS_HEADER, 93 - .max_attr = ETHTOOL_A_CHANNELS_MAX, 94 102 .req_info_size = sizeof(struct channels_req_info), 95 103 .reply_data_size = sizeof(struct channels_reply_data), 96 - .request_policy = channels_get_policy, 97 104 98 105 .prepare_data = channels_prepare_data, 99 106 .reply_size = channels_reply_size, ··· 100 111 101 112 /* CHANNELS_SET */ 102 113 103 - static const struct nla_policy 104 - channels_set_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { 105 - [ETHTOOL_A_CHANNELS_UNSPEC] = { .type = NLA_REJECT }, 106 - [ETHTOOL_A_CHANNELS_HEADER] = { .type = NLA_NESTED }, 107 - [ETHTOOL_A_CHANNELS_RX_MAX] = { .type = NLA_REJECT }, 108 - [ETHTOOL_A_CHANNELS_TX_MAX] = { .type = NLA_REJECT }, 109 - [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .type = NLA_REJECT }, 110 - [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .type = NLA_REJECT }, 114 + const struct nla_policy ethnl_channels_set_policy[] = { 115 + [ETHTOOL_A_CHANNELS_HEADER] = 116 + NLA_POLICY_NESTED(ethnl_header_policy), 111 117 [ETHTOOL_A_CHANNELS_RX_COUNT] = { .type = NLA_U32 }, 112 118 [ETHTOOL_A_CHANNELS_TX_COUNT] = { .type = NLA_U32 }, 113 119 [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .type = NLA_U32 }, ··· 111 127 112 128 int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info) 113 129 { 114 - struct nlattr *tb[ETHTOOL_A_CHANNELS_MAX + 1]; 115 130 unsigned int from_channel, old_total, i; 116 131 bool mod = false, mod_combined = false; 117 132 struct ethtool_channels channels = {}; 118 133 struct ethnl_req_info req_info = {}; 134 + struct nlattr **tb = info->attrs; 119 135 const struct nlattr *err_attr; 120 136 const struct ethtool_ops *ops; 121 137 struct net_device *dev; 122 138 u32 max_rx_in_use = 0; 123 139 int ret; 124 140 125 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 126 - ETHTOOL_A_CHANNELS_MAX, channels_set_policy, 127 - info->extack); 128 - if (ret < 0) 129 - return ret; 130 141 ret = ethnl_parse_header_dev_get(&req_info, 131 142 tb[ETHTOOL_A_CHANNELS_HEADER], 132 143 genl_info_net(info), info->extack,
+7 -38
net/ethtool/coalesce.c
··· 51 51 __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_HIGH); 52 52 __CHECK_SUPPORTED_OFFSET(COALESCE_RATE_SAMPLE_INTERVAL); 53 53 54 - static const struct nla_policy 55 - coalesce_get_policy[ETHTOOL_A_COALESCE_MAX + 1] = { 56 - [ETHTOOL_A_COALESCE_UNSPEC] = { .type = NLA_REJECT }, 57 - [ETHTOOL_A_COALESCE_HEADER] = { .type = NLA_NESTED }, 58 - [ETHTOOL_A_COALESCE_RX_USECS] = { .type = NLA_REJECT }, 59 - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .type = NLA_REJECT }, 60 - [ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .type = NLA_REJECT }, 61 - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ] = { .type = NLA_REJECT }, 62 - [ETHTOOL_A_COALESCE_TX_USECS] = { .type = NLA_REJECT }, 63 - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES] = { .type = NLA_REJECT }, 64 - [ETHTOOL_A_COALESCE_TX_USECS_IRQ] = { .type = NLA_REJECT }, 65 - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ] = { .type = NLA_REJECT }, 66 - [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS] = { .type = NLA_REJECT }, 67 - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX] = { .type = NLA_REJECT }, 68 - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX] = { .type = NLA_REJECT }, 69 - [ETHTOOL_A_COALESCE_PKT_RATE_LOW] = { .type = NLA_REJECT }, 70 - [ETHTOOL_A_COALESCE_RX_USECS_LOW] = { .type = NLA_REJECT }, 71 - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW] = { .type = NLA_REJECT }, 72 - [ETHTOOL_A_COALESCE_TX_USECS_LOW] = { .type = NLA_REJECT }, 73 - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW] = { .type = NLA_REJECT }, 74 - [ETHTOOL_A_COALESCE_PKT_RATE_HIGH] = { .type = NLA_REJECT }, 75 - [ETHTOOL_A_COALESCE_RX_USECS_HIGH] = { .type = NLA_REJECT }, 76 - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .type = NLA_REJECT }, 77 - [ETHTOOL_A_COALESCE_TX_USECS_HIGH] = { .type = NLA_REJECT }, 78 - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .type = NLA_REJECT }, 79 - [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .type = NLA_REJECT }, 54 + const struct nla_policy ethnl_coalesce_get_policy[] = { 55 + [ETHTOOL_A_COALESCE_HEADER] = 56 + NLA_POLICY_NESTED(ethnl_header_policy), 80 57 }; 81 58 82 59 static int coalesce_prepare_data(const struct ethnl_req_info *req_base, ··· 180 203 .request_cmd = ETHTOOL_MSG_COALESCE_GET, 181 204 .reply_cmd = ETHTOOL_MSG_COALESCE_GET_REPLY, 182 205 .hdr_attr = ETHTOOL_A_COALESCE_HEADER, 183 - .max_attr = ETHTOOL_A_COALESCE_MAX, 184 206 .req_info_size = sizeof(struct coalesce_req_info), 185 207 .reply_data_size = sizeof(struct coalesce_reply_data), 186 - .request_policy = coalesce_get_policy, 187 208 188 209 .prepare_data = coalesce_prepare_data, 189 210 .reply_size = coalesce_reply_size, ··· 190 215 191 216 /* COALESCE_SET */ 192 217 193 - static const struct nla_policy 194 - coalesce_set_policy[ETHTOOL_A_COALESCE_MAX + 1] = { 195 - [ETHTOOL_A_COALESCE_UNSPEC] = { .type = NLA_REJECT }, 196 - [ETHTOOL_A_COALESCE_HEADER] = { .type = NLA_NESTED }, 218 + const struct nla_policy ethnl_coalesce_set_policy[] = { 219 + [ETHTOOL_A_COALESCE_HEADER] = 220 + NLA_POLICY_NESTED(ethnl_header_policy), 197 221 [ETHTOOL_A_COALESCE_RX_USECS] = { .type = NLA_U32 }, 198 222 [ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .type = NLA_U32 }, 199 223 [ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .type = NLA_U32 }, ··· 219 245 220 246 int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info) 221 247 { 222 - struct nlattr *tb[ETHTOOL_A_COALESCE_MAX + 1]; 223 248 struct ethtool_coalesce coalesce = {}; 224 249 struct ethnl_req_info req_info = {}; 250 + struct nlattr **tb = info->attrs; 225 251 const struct ethtool_ops *ops; 226 252 struct net_device *dev; 227 253 u32 supported_params; ··· 229 255 int ret; 230 256 u16 a; 231 257 232 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 233 - ETHTOOL_A_COALESCE_MAX, coalesce_set_policy, 234 - info->extack); 235 - if (ret < 0) 236 - return ret; 237 258 ret = ethnl_parse_header_dev_get(&req_info, 238 259 tb[ETHTOOL_A_COALESCE_HEADER], 239 260 genl_info_net(info), info->extack,
+7 -17
net/ethtool/debug.c
··· 16 16 #define DEBUG_REPDATA(__reply_base) \ 17 17 container_of(__reply_base, struct debug_reply_data, base) 18 18 19 - static const struct nla_policy 20 - debug_get_policy[ETHTOOL_A_DEBUG_MAX + 1] = { 21 - [ETHTOOL_A_DEBUG_UNSPEC] = { .type = NLA_REJECT }, 22 - [ETHTOOL_A_DEBUG_HEADER] = { .type = NLA_NESTED }, 23 - [ETHTOOL_A_DEBUG_MSGMASK] = { .type = NLA_REJECT }, 19 + const struct nla_policy ethnl_debug_get_policy[] = { 20 + [ETHTOOL_A_DEBUG_HEADER] = 21 + NLA_POLICY_NESTED(ethnl_header_policy), 24 22 }; 25 23 26 24 static int debug_prepare_data(const struct ethnl_req_info *req_base, ··· 67 69 .request_cmd = ETHTOOL_MSG_DEBUG_GET, 68 70 .reply_cmd = ETHTOOL_MSG_DEBUG_GET_REPLY, 69 71 .hdr_attr = ETHTOOL_A_DEBUG_HEADER, 70 - .max_attr = ETHTOOL_A_DEBUG_MAX, 71 72 .req_info_size = sizeof(struct debug_req_info), 72 73 .reply_data_size = sizeof(struct debug_reply_data), 73 - .request_policy = debug_get_policy, 74 74 75 75 .prepare_data = debug_prepare_data, 76 76 .reply_size = debug_reply_size, ··· 77 81 78 82 /* DEBUG_SET */ 79 83 80 - static const struct nla_policy 81 - debug_set_policy[ETHTOOL_A_DEBUG_MAX + 1] = { 82 - [ETHTOOL_A_DEBUG_UNSPEC] = { .type = NLA_REJECT }, 83 - [ETHTOOL_A_DEBUG_HEADER] = { .type = NLA_NESTED }, 84 + const struct nla_policy ethnl_debug_set_policy[] = { 85 + [ETHTOOL_A_DEBUG_HEADER] = 86 + NLA_POLICY_NESTED(ethnl_header_policy), 84 87 [ETHTOOL_A_DEBUG_MSGMASK] = { .type = NLA_NESTED }, 85 88 }; 86 89 87 90 int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info) 88 91 { 89 - struct nlattr *tb[ETHTOOL_A_DEBUG_MAX + 1]; 90 92 struct ethnl_req_info req_info = {}; 93 + struct nlattr **tb = info->attrs; 91 94 struct net_device *dev; 92 95 bool mod = false; 93 96 u32 msg_mask; 94 97 int ret; 95 98 96 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 97 - ETHTOOL_A_DEBUG_MAX, debug_set_policy, 98 - info->extack); 99 - if (ret < 0) 100 - return ret; 101 99 ret = ethnl_parse_header_dev_get(&req_info, 102 100 tb[ETHTOOL_A_DEBUG_HEADER], 103 101 genl_info_net(info), info->extack,
+8 -24
net/ethtool/eee.c
··· 19 19 #define EEE_REPDATA(__reply_base) \ 20 20 container_of(__reply_base, struct eee_reply_data, base) 21 21 22 - static const struct nla_policy 23 - eee_get_policy[ETHTOOL_A_EEE_MAX + 1] = { 24 - [ETHTOOL_A_EEE_UNSPEC] = { .type = NLA_REJECT }, 25 - [ETHTOOL_A_EEE_HEADER] = { .type = NLA_NESTED }, 26 - [ETHTOOL_A_EEE_MODES_OURS] = { .type = NLA_REJECT }, 27 - [ETHTOOL_A_EEE_MODES_PEER] = { .type = NLA_REJECT }, 28 - [ETHTOOL_A_EEE_ACTIVE] = { .type = NLA_REJECT }, 29 - [ETHTOOL_A_EEE_ENABLED] = { .type = NLA_REJECT }, 30 - [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .type = NLA_REJECT }, 31 - [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .type = NLA_REJECT }, 22 + const struct nla_policy ethnl_eee_get_policy[] = { 23 + [ETHTOOL_A_EEE_HEADER] = 24 + NLA_POLICY_NESTED(ethnl_header_policy), 32 25 }; 33 26 34 27 static int eee_prepare_data(const struct ethnl_req_info *req_base, ··· 112 119 .request_cmd = ETHTOOL_MSG_EEE_GET, 113 120 .reply_cmd = ETHTOOL_MSG_EEE_GET_REPLY, 114 121 .hdr_attr = ETHTOOL_A_EEE_HEADER, 115 - .max_attr = ETHTOOL_A_EEE_MAX, 116 122 .req_info_size = sizeof(struct eee_req_info), 117 123 .reply_data_size = sizeof(struct eee_reply_data), 118 - .request_policy = eee_get_policy, 119 124 120 125 .prepare_data = eee_prepare_data, 121 126 .reply_size = eee_reply_size, ··· 122 131 123 132 /* EEE_SET */ 124 133 125 - static const struct nla_policy 126 - eee_set_policy[ETHTOOL_A_EEE_MAX + 1] = { 127 - [ETHTOOL_A_EEE_UNSPEC] = { .type = NLA_REJECT }, 128 - [ETHTOOL_A_EEE_HEADER] = { .type = NLA_NESTED }, 134 + const struct nla_policy ethnl_eee_set_policy[] = { 135 + [ETHTOOL_A_EEE_HEADER] = 136 + NLA_POLICY_NESTED(ethnl_header_policy), 129 137 [ETHTOOL_A_EEE_MODES_OURS] = { .type = NLA_NESTED }, 130 - [ETHTOOL_A_EEE_MODES_PEER] = { .type = NLA_REJECT }, 131 - [ETHTOOL_A_EEE_ACTIVE] = { .type = NLA_REJECT }, 132 138 [ETHTOOL_A_EEE_ENABLED] = { .type = NLA_U8 }, 133 139 [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .type = NLA_U8 }, 134 140 [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .type = NLA_U32 }, ··· 133 145 134 146 int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info) 135 147 { 136 - struct nlattr *tb[ETHTOOL_A_EEE_MAX + 1]; 137 - struct ethtool_eee eee = {}; 138 148 struct ethnl_req_info req_info = {}; 149 + struct nlattr **tb = info->attrs; 139 150 const struct ethtool_ops *ops; 151 + struct ethtool_eee eee = {}; 140 152 struct net_device *dev; 141 153 bool mod = false; 142 154 int ret; 143 155 144 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_EEE_MAX, 145 - eee_set_policy, info->extack); 146 - if (ret < 0) 147 - return ret; 148 156 ret = ethnl_parse_header_dev_get(&req_info, 149 157 tb[ETHTOOL_A_EEE_HEADER], 150 158 genl_info_net(info), info->extack,
+7 -23
net/ethtool/features.c
··· 20 20 #define FEATURES_REPDATA(__reply_base) \ 21 21 container_of(__reply_base, struct features_reply_data, base) 22 22 23 - static const struct nla_policy 24 - features_get_policy[ETHTOOL_A_FEATURES_MAX + 1] = { 25 - [ETHTOOL_A_FEATURES_UNSPEC] = { .type = NLA_REJECT }, 26 - [ETHTOOL_A_FEATURES_HEADER] = { .type = NLA_NESTED }, 27 - [ETHTOOL_A_FEATURES_HW] = { .type = NLA_REJECT }, 28 - [ETHTOOL_A_FEATURES_WANTED] = { .type = NLA_REJECT }, 29 - [ETHTOOL_A_FEATURES_ACTIVE] = { .type = NLA_REJECT }, 30 - [ETHTOOL_A_FEATURES_NOCHANGE] = { .type = NLA_REJECT }, 23 + const struct nla_policy ethnl_features_get_policy[] = { 24 + [ETHTOOL_A_FEATURES_HEADER] = 25 + NLA_POLICY_NESTED(ethnl_header_policy), 31 26 }; 32 27 33 28 static void ethnl_features_to_bitmap32(u32 *dest, netdev_features_t src) ··· 115 120 .request_cmd = ETHTOOL_MSG_FEATURES_GET, 116 121 .reply_cmd = ETHTOOL_MSG_FEATURES_GET_REPLY, 117 122 .hdr_attr = ETHTOOL_A_FEATURES_HEADER, 118 - .max_attr = ETHTOOL_A_FEATURES_MAX, 119 123 .req_info_size = sizeof(struct features_req_info), 120 124 .reply_data_size = sizeof(struct features_reply_data), 121 - .request_policy = features_get_policy, 122 125 123 126 .prepare_data = features_prepare_data, 124 127 .reply_size = features_reply_size, ··· 125 132 126 133 /* FEATURES_SET */ 127 134 128 - static const struct nla_policy 129 - features_set_policy[ETHTOOL_A_FEATURES_MAX + 1] = { 130 - [ETHTOOL_A_FEATURES_UNSPEC] = { .type = NLA_REJECT }, 131 - [ETHTOOL_A_FEATURES_HEADER] = { .type = NLA_NESTED }, 132 - [ETHTOOL_A_FEATURES_HW] = { .type = NLA_REJECT }, 135 + const struct nla_policy ethnl_features_set_policy[] = { 136 + [ETHTOOL_A_FEATURES_HEADER] = 137 + NLA_POLICY_NESTED(ethnl_header_policy), 133 138 [ETHTOOL_A_FEATURES_WANTED] = { .type = NLA_NESTED }, 134 - [ETHTOOL_A_FEATURES_ACTIVE] = { .type = NLA_REJECT }, 135 - [ETHTOOL_A_FEATURES_NOCHANGE] = { .type = NLA_REJECT }, 136 139 }; 137 140 138 141 static void ethnl_features_to_bitmap(unsigned long *dest, netdev_features_t val) ··· 218 229 DECLARE_BITMAP(new_wanted, NETDEV_FEATURE_COUNT); 219 230 DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT); 220 231 DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT); 221 - struct nlattr *tb[ETHTOOL_A_FEATURES_MAX + 1]; 222 232 struct ethnl_req_info req_info = {}; 233 + struct nlattr **tb = info->attrs; 223 234 struct net_device *dev; 224 235 bool mod; 225 236 int ret; 226 237 227 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 228 - ETHTOOL_A_FEATURES_MAX, features_set_policy, 229 - info->extack); 230 - if (ret < 0) 231 - return ret; 232 238 if (!tb[ETHTOOL_A_FEATURES_WANTED]) 233 239 return -EINVAL; 234 240 ret = ethnl_parse_header_dev_get(&req_info,
+7 -23
net/ethtool/linkinfo.c
··· 16 16 #define LINKINFO_REPDATA(__reply_base) \ 17 17 container_of(__reply_base, struct linkinfo_reply_data, base) 18 18 19 - static const struct nla_policy 20 - linkinfo_get_policy[ETHTOOL_A_LINKINFO_MAX + 1] = { 21 - [ETHTOOL_A_LINKINFO_UNSPEC] = { .type = NLA_REJECT }, 22 - [ETHTOOL_A_LINKINFO_HEADER] = { .type = NLA_NESTED }, 23 - [ETHTOOL_A_LINKINFO_PORT] = { .type = NLA_REJECT }, 24 - [ETHTOOL_A_LINKINFO_PHYADDR] = { .type = NLA_REJECT }, 25 - [ETHTOOL_A_LINKINFO_TP_MDIX] = { .type = NLA_REJECT }, 26 - [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .type = NLA_REJECT }, 27 - [ETHTOOL_A_LINKINFO_TRANSCEIVER] = { .type = NLA_REJECT }, 19 + const struct nla_policy ethnl_linkinfo_get_policy[] = { 20 + [ETHTOOL_A_LINKINFO_HEADER] = 21 + NLA_POLICY_NESTED(ethnl_header_policy), 28 22 }; 29 23 30 24 static int linkinfo_prepare_data(const struct ethnl_req_info *req_base, ··· 77 83 .request_cmd = ETHTOOL_MSG_LINKINFO_GET, 78 84 .reply_cmd = ETHTOOL_MSG_LINKINFO_GET_REPLY, 79 85 .hdr_attr = ETHTOOL_A_LINKINFO_HEADER, 80 - .max_attr = ETHTOOL_A_LINKINFO_MAX, 81 86 .req_info_size = sizeof(struct linkinfo_req_info), 82 87 .reply_data_size = sizeof(struct linkinfo_reply_data), 83 - .request_policy = linkinfo_get_policy, 84 88 85 89 .prepare_data = linkinfo_prepare_data, 86 90 .reply_size = linkinfo_reply_size, ··· 87 95 88 96 /* LINKINFO_SET */ 89 97 90 - static const struct nla_policy 91 - linkinfo_set_policy[ETHTOOL_A_LINKINFO_MAX + 1] = { 92 - [ETHTOOL_A_LINKINFO_UNSPEC] = { .type = NLA_REJECT }, 93 - [ETHTOOL_A_LINKINFO_HEADER] = { .type = NLA_NESTED }, 98 + const struct nla_policy ethnl_linkinfo_set_policy[] = { 99 + [ETHTOOL_A_LINKINFO_HEADER] = 100 + NLA_POLICY_NESTED(ethnl_header_policy), 94 101 [ETHTOOL_A_LINKINFO_PORT] = { .type = NLA_U8 }, 95 102 [ETHTOOL_A_LINKINFO_PHYADDR] = { .type = NLA_U8 }, 96 - [ETHTOOL_A_LINKINFO_TP_MDIX] = { .type = NLA_REJECT }, 97 103 [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .type = NLA_U8 }, 98 - [ETHTOOL_A_LINKINFO_TRANSCEIVER] = { .type = NLA_REJECT }, 99 104 }; 100 105 101 106 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info) 102 107 { 103 - struct nlattr *tb[ETHTOOL_A_LINKINFO_MAX + 1]; 104 108 struct ethtool_link_ksettings ksettings = {}; 105 109 struct ethtool_link_settings *lsettings; 106 110 struct ethnl_req_info req_info = {}; 111 + struct nlattr **tb = info->attrs; 107 112 struct net_device *dev; 108 113 bool mod = false; 109 114 int ret; 110 115 111 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 112 - ETHTOOL_A_LINKINFO_MAX, linkinfo_set_policy, 113 - info->extack); 114 - if (ret < 0) 115 - return ret; 116 116 ret = ethnl_parse_header_dev_get(&req_info, 117 117 tb[ETHTOOL_A_LINKINFO_HEADER], 118 118 genl_info_net(info), info->extack,
+7 -25
net/ethtool/linkmodes.c
··· 18 18 #define LINKMODES_REPDATA(__reply_base) \ 19 19 container_of(__reply_base, struct linkmodes_reply_data, base) 20 20 21 - static const struct nla_policy 22 - linkmodes_get_policy[ETHTOOL_A_LINKMODES_MAX + 1] = { 23 - [ETHTOOL_A_LINKMODES_UNSPEC] = { .type = NLA_REJECT }, 24 - [ETHTOOL_A_LINKMODES_HEADER] = { .type = NLA_NESTED }, 25 - [ETHTOOL_A_LINKMODES_AUTONEG] = { .type = NLA_REJECT }, 26 - [ETHTOOL_A_LINKMODES_OURS] = { .type = NLA_REJECT }, 27 - [ETHTOOL_A_LINKMODES_PEER] = { .type = NLA_REJECT }, 28 - [ETHTOOL_A_LINKMODES_SPEED] = { .type = NLA_REJECT }, 29 - [ETHTOOL_A_LINKMODES_DUPLEX] = { .type = NLA_REJECT }, 30 - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .type = NLA_REJECT }, 31 - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .type = NLA_REJECT }, 21 + const struct nla_policy ethnl_linkmodes_get_policy[] = { 22 + [ETHTOOL_A_LINKMODES_HEADER] = 23 + NLA_POLICY_NESTED(ethnl_header_policy), 32 24 }; 33 25 34 26 static int linkmodes_prepare_data(const struct ethnl_req_info *req_base, ··· 140 148 .request_cmd = ETHTOOL_MSG_LINKMODES_GET, 141 149 .reply_cmd = ETHTOOL_MSG_LINKMODES_GET_REPLY, 142 150 .hdr_attr = ETHTOOL_A_LINKMODES_HEADER, 143 - .max_attr = ETHTOOL_A_LINKMODES_MAX, 144 151 .req_info_size = sizeof(struct linkmodes_req_info), 145 152 .reply_data_size = sizeof(struct linkmodes_reply_data), 146 - .request_policy = linkmodes_get_policy, 147 153 148 154 .prepare_data = linkmodes_prepare_data, 149 155 .reply_size = linkmodes_reply_size, ··· 266 276 __DEFINE_LINK_MODE_PARAMS(100, FX, Full), 267 277 }; 268 278 269 - static const struct nla_policy 270 - linkmodes_set_policy[ETHTOOL_A_LINKMODES_MAX + 1] = { 271 - [ETHTOOL_A_LINKMODES_UNSPEC] = { .type = NLA_REJECT }, 272 - [ETHTOOL_A_LINKMODES_HEADER] = { .type = NLA_NESTED }, 279 + const struct nla_policy ethnl_linkmodes_set_policy[] = { 280 + [ETHTOOL_A_LINKMODES_HEADER] = 281 + NLA_POLICY_NESTED(ethnl_header_policy), 273 282 [ETHTOOL_A_LINKMODES_AUTONEG] = { .type = NLA_U8 }, 274 283 [ETHTOOL_A_LINKMODES_OURS] = { .type = NLA_NESTED }, 275 - [ETHTOOL_A_LINKMODES_PEER] = { .type = NLA_REJECT }, 276 284 [ETHTOOL_A_LINKMODES_SPEED] = { .type = NLA_U32 }, 277 285 [ETHTOOL_A_LINKMODES_DUPLEX] = { .type = NLA_U8 }, 278 286 [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .type = NLA_U8 }, 279 - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .type = NLA_REJECT }, 280 287 }; 281 288 282 289 /* Set advertised link modes to all supported modes matching requested speed ··· 379 392 380 393 int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info) 381 394 { 382 - struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1]; 383 395 struct ethtool_link_ksettings ksettings = {}; 384 396 struct ethnl_req_info req_info = {}; 397 + struct nlattr **tb = info->attrs; 385 398 struct net_device *dev; 386 399 bool mod = false; 387 400 int ret; 388 401 389 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 390 - ETHTOOL_A_LINKMODES_MAX, linkmodes_set_policy, 391 - info->extack); 392 - if (ret < 0) 393 - return ret; 394 402 ret = ethnl_parse_header_dev_get(&req_info, 395 403 tb[ETHTOOL_A_LINKMODES_HEADER], 396 404 genl_info_net(info), info->extack,
+3 -11
net/ethtool/linkstate.c
··· 20 20 #define LINKSTATE_REPDATA(__reply_base) \ 21 21 container_of(__reply_base, struct linkstate_reply_data, base) 22 22 23 - static const struct nla_policy 24 - linkstate_get_policy[ETHTOOL_A_LINKSTATE_MAX + 1] = { 25 - [ETHTOOL_A_LINKSTATE_UNSPEC] = { .type = NLA_REJECT }, 26 - [ETHTOOL_A_LINKSTATE_HEADER] = { .type = NLA_NESTED }, 27 - [ETHTOOL_A_LINKSTATE_LINK] = { .type = NLA_REJECT }, 28 - [ETHTOOL_A_LINKSTATE_SQI] = { .type = NLA_REJECT }, 29 - [ETHTOOL_A_LINKSTATE_SQI_MAX] = { .type = NLA_REJECT }, 30 - [ETHTOOL_A_LINKSTATE_EXT_STATE] = { .type = NLA_REJECT }, 31 - [ETHTOOL_A_LINKSTATE_EXT_SUBSTATE] = { .type = NLA_REJECT }, 23 + const struct nla_policy ethnl_linkstate_get_policy[] = { 24 + [ETHTOOL_A_LINKSTATE_HEADER] = 25 + NLA_POLICY_NESTED(ethnl_header_policy), 32 26 }; 33 27 34 28 static int linkstate_get_sqi(struct net_device *dev) ··· 173 179 .request_cmd = ETHTOOL_MSG_LINKSTATE_GET, 174 180 .reply_cmd = ETHTOOL_MSG_LINKSTATE_GET_REPLY, 175 181 .hdr_attr = ETHTOOL_A_LINKSTATE_HEADER, 176 - .max_attr = ETHTOOL_A_LINKSTATE_MAX, 177 182 .req_info_size = sizeof(struct linkstate_req_info), 178 183 .reply_data_size = sizeof(struct linkstate_reply_data), 179 - .request_policy = linkstate_get_policy, 180 184 181 185 .prepare_data = linkstate_prepare_data, 182 186 .reply_size = linkstate_reply_size,
+88 -36
net/ethtool/netlink.c
··· 9 9 static bool ethnl_ok __read_mostly; 10 10 static u32 ethnl_bcast_seq; 11 11 12 - static const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_MAX + 1] = { 13 - [ETHTOOL_A_HEADER_UNSPEC] = { .type = NLA_REJECT }, 12 + #define ETHTOOL_FLAGS_BASIC (ETHTOOL_FLAG_COMPACT_BITSETS | \ 13 + ETHTOOL_FLAG_OMIT_REPLY) 14 + #define ETHTOOL_FLAGS_STATS (ETHTOOL_FLAGS_BASIC | ETHTOOL_FLAG_STATS) 15 + 16 + const struct nla_policy ethnl_header_policy[] = { 14 17 [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 }, 15 18 [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING, 16 19 .len = ALTIFNAMSIZ - 1 }, 17 - [ETHTOOL_A_HEADER_FLAGS] = { .type = NLA_U32 }, 20 + [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32, 21 + ETHTOOL_FLAGS_BASIC), 22 + }; 23 + 24 + const struct nla_policy ethnl_header_policy_stats[] = { 25 + [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 }, 26 + [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING, 27 + .len = ALTIFNAMSIZ - 1 }, 28 + [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32, 29 + ETHTOOL_FLAGS_STATS), 18 30 }; 19 31 20 32 /** ··· 49 37 const struct nlattr *header, struct net *net, 50 38 struct netlink_ext_ack *extack, bool require_dev) 51 39 { 52 - struct nlattr *tb[ETHTOOL_A_HEADER_MAX + 1]; 40 + struct nlattr *tb[ARRAY_SIZE(ethnl_header_policy)]; 53 41 const struct nlattr *devname_attr; 54 42 struct net_device *dev = NULL; 55 43 u32 flags = 0; ··· 59 47 NL_SET_ERR_MSG(extack, "request header missing"); 60 48 return -EINVAL; 61 49 } 62 - ret = nla_parse_nested(tb, ETHTOOL_A_HEADER_MAX, header, 63 - ethnl_header_policy, extack); 50 + /* No validation here, command policy should have a nested policy set 51 + * for the header, therefore validation should have already been done. 52 + */ 53 + ret = nla_parse_nested(tb, ARRAY_SIZE(ethnl_header_policy) - 1, header, 54 + NULL, extack); 64 55 if (ret < 0) 65 56 return ret; 66 - if (tb[ETHTOOL_A_HEADER_FLAGS]) { 57 + if (tb[ETHTOOL_A_HEADER_FLAGS]) 67 58 flags = nla_get_u32(tb[ETHTOOL_A_HEADER_FLAGS]); 68 - if (flags & ~ETHTOOL_FLAG_ALL) { 69 - NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_HEADER_FLAGS], 70 - "unrecognized request flags"); 71 - nl_set_extack_cookie_u32(extack, ETHTOOL_FLAG_ALL); 72 - return -EOPNOTSUPP; 73 - } 74 - } 75 59 76 60 devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME]; 77 61 if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) { ··· 255 247 /** 256 248 * ethnl_default_parse() - Parse request message 257 249 * @req_info: pointer to structure to put data into 258 - * @nlhdr: pointer to request message header 250 + * @tb: parsed attributes 259 251 * @net: request netns 260 252 * @request_ops: struct request_ops for request type 261 253 * @extack: netlink extack for error reporting ··· 267 259 * Return: 0 on success or negative error code 268 260 */ 269 261 static int ethnl_default_parse(struct ethnl_req_info *req_info, 270 - const struct nlmsghdr *nlhdr, struct net *net, 262 + struct nlattr **tb, struct net *net, 271 263 const struct ethnl_request_ops *request_ops, 272 264 struct netlink_ext_ack *extack, bool require_dev) 273 265 { 274 - struct nlattr **tb; 275 266 int ret; 276 267 277 - tb = kmalloc_array(request_ops->max_attr + 1, sizeof(tb[0]), 278 - GFP_KERNEL); 279 - if (!tb) 280 - return -ENOMEM; 281 - 282 - ret = nlmsg_parse(nlhdr, GENL_HDRLEN, tb, request_ops->max_attr, 283 - request_ops->request_policy, extack); 284 - if (ret < 0) 285 - goto out; 286 268 ret = ethnl_parse_header_dev_get(req_info, tb[request_ops->hdr_attr], 287 269 net, extack, require_dev); 288 270 if (ret < 0) 289 - goto out; 271 + return ret; 290 272 291 273 if (request_ops->parse_request) { 292 274 ret = request_ops->parse_request(req_info, tb, extack); 293 275 if (ret < 0) 294 - goto out; 276 + return ret; 295 277 } 296 278 297 - ret = 0; 298 - out: 299 - kfree(tb); 300 - return ret; 279 + return 0; 301 280 } 302 281 303 282 /** ··· 329 334 return -ENOMEM; 330 335 } 331 336 332 - ret = ethnl_default_parse(req_info, info->nlhdr, genl_info_net(info), ops, 333 - info->extack, !ops->allow_nodev_do); 337 + ret = ethnl_default_parse(req_info, info->attrs, genl_info_net(info), 338 + ops, info->extack, !ops->allow_nodev_do); 334 339 if (ret < 0) 335 340 goto err_dev; 336 341 ethnl_init_reply_data(reply_data, ops, req_info->dev); ··· 475 480 /* generic ->start() handler for GET requests */ 476 481 static int ethnl_default_start(struct netlink_callback *cb) 477 482 { 483 + const struct genl_dumpit_info *info = genl_dumpit_info(cb); 478 484 struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb); 479 485 struct ethnl_reply_data *reply_data; 480 486 const struct ethnl_request_ops *ops; ··· 498 502 goto free_req_info; 499 503 } 500 504 501 - ret = ethnl_default_parse(req_info, cb->nlh, sock_net(cb->skb->sk), ops, 502 - cb->extack, false); 505 + ret = ethnl_default_parse(req_info, info->attrs, sock_net(cb->skb->sk), 506 + ops, cb->extack, false); 503 507 if (req_info->dev) { 504 508 /* We ignore device specification in dump requests but as the 505 509 * same parser as for non-dump (doit) requests is used, it ··· 692 696 .start = ethnl_default_start, 693 697 .dumpit = ethnl_default_dumpit, 694 698 .done = ethnl_default_done, 699 + .policy = ethnl_strset_get_policy, 700 + .maxattr = ARRAY_SIZE(ethnl_strset_get_policy) - 1, 695 701 }, 696 702 { 697 703 .cmd = ETHTOOL_MSG_LINKINFO_GET, ··· 701 703 .start = ethnl_default_start, 702 704 .dumpit = ethnl_default_dumpit, 703 705 .done = ethnl_default_done, 706 + .policy = ethnl_linkinfo_get_policy, 707 + .maxattr = ARRAY_SIZE(ethnl_linkinfo_get_policy) - 1, 704 708 }, 705 709 { 706 710 .cmd = ETHTOOL_MSG_LINKINFO_SET, 707 711 .flags = GENL_UNS_ADMIN_PERM, 708 712 .doit = ethnl_set_linkinfo, 713 + .policy = ethnl_linkinfo_set_policy, 714 + .maxattr = ARRAY_SIZE(ethnl_linkinfo_set_policy) - 1, 709 715 }, 710 716 { 711 717 .cmd = ETHTOOL_MSG_LINKMODES_GET, ··· 717 715 .start = ethnl_default_start, 718 716 .dumpit = ethnl_default_dumpit, 719 717 .done = ethnl_default_done, 718 + .policy = ethnl_linkmodes_get_policy, 719 + .maxattr = ARRAY_SIZE(ethnl_linkmodes_get_policy) - 1, 720 720 }, 721 721 { 722 722 .cmd = ETHTOOL_MSG_LINKMODES_SET, 723 723 .flags = GENL_UNS_ADMIN_PERM, 724 724 .doit = ethnl_set_linkmodes, 725 + .policy = ethnl_linkmodes_set_policy, 726 + .maxattr = ARRAY_SIZE(ethnl_linkmodes_set_policy) - 1, 725 727 }, 726 728 { 727 729 .cmd = ETHTOOL_MSG_LINKSTATE_GET, ··· 733 727 .start = ethnl_default_start, 734 728 .dumpit = ethnl_default_dumpit, 735 729 .done = ethnl_default_done, 730 + .policy = ethnl_linkstate_get_policy, 731 + .maxattr = ARRAY_SIZE(ethnl_linkstate_get_policy) - 1, 736 732 }, 737 733 { 738 734 .cmd = ETHTOOL_MSG_DEBUG_GET, ··· 742 734 .start = ethnl_default_start, 743 735 .dumpit = ethnl_default_dumpit, 744 736 .done = ethnl_default_done, 737 + .policy = ethnl_debug_get_policy, 738 + .maxattr = ARRAY_SIZE(ethnl_debug_get_policy) - 1, 745 739 }, 746 740 { 747 741 .cmd = ETHTOOL_MSG_DEBUG_SET, 748 742 .flags = GENL_UNS_ADMIN_PERM, 749 743 .doit = ethnl_set_debug, 744 + .policy = ethnl_debug_set_policy, 745 + .maxattr = ARRAY_SIZE(ethnl_debug_set_policy) - 1, 750 746 }, 751 747 { 752 748 .cmd = ETHTOOL_MSG_WOL_GET, ··· 759 747 .start = ethnl_default_start, 760 748 .dumpit = ethnl_default_dumpit, 761 749 .done = ethnl_default_done, 750 + .policy = ethnl_wol_get_policy, 751 + .maxattr = ARRAY_SIZE(ethnl_wol_get_policy) - 1, 762 752 }, 763 753 { 764 754 .cmd = ETHTOOL_MSG_WOL_SET, 765 755 .flags = GENL_UNS_ADMIN_PERM, 766 756 .doit = ethnl_set_wol, 757 + .policy = ethnl_wol_set_policy, 758 + .maxattr = ARRAY_SIZE(ethnl_wol_set_policy) - 1, 767 759 }, 768 760 { 769 761 .cmd = ETHTOOL_MSG_FEATURES_GET, ··· 775 759 .start = ethnl_default_start, 776 760 .dumpit = ethnl_default_dumpit, 777 761 .done = ethnl_default_done, 762 + .policy = ethnl_features_get_policy, 763 + .maxattr = ARRAY_SIZE(ethnl_features_get_policy) - 1, 778 764 }, 779 765 { 780 766 .cmd = ETHTOOL_MSG_FEATURES_SET, 781 767 .flags = GENL_UNS_ADMIN_PERM, 782 768 .doit = ethnl_set_features, 769 + .policy = ethnl_features_set_policy, 770 + .maxattr = ARRAY_SIZE(ethnl_features_set_policy) - 1, 783 771 }, 784 772 { 785 773 .cmd = ETHTOOL_MSG_PRIVFLAGS_GET, ··· 791 771 .start = ethnl_default_start, 792 772 .dumpit = ethnl_default_dumpit, 793 773 .done = ethnl_default_done, 774 + .policy = ethnl_privflags_get_policy, 775 + .maxattr = ARRAY_SIZE(ethnl_privflags_get_policy) - 1, 794 776 }, 795 777 { 796 778 .cmd = ETHTOOL_MSG_PRIVFLAGS_SET, 797 779 .flags = GENL_UNS_ADMIN_PERM, 798 780 .doit = ethnl_set_privflags, 781 + .policy = ethnl_privflags_set_policy, 782 + .maxattr = ARRAY_SIZE(ethnl_privflags_set_policy) - 1, 799 783 }, 800 784 { 801 785 .cmd = ETHTOOL_MSG_RINGS_GET, ··· 807 783 .start = ethnl_default_start, 808 784 .dumpit = ethnl_default_dumpit, 809 785 .done = ethnl_default_done, 786 + .policy = ethnl_rings_get_policy, 787 + .maxattr = ARRAY_SIZE(ethnl_rings_get_policy) - 1, 810 788 }, 811 789 { 812 790 .cmd = ETHTOOL_MSG_RINGS_SET, 813 791 .flags = GENL_UNS_ADMIN_PERM, 814 792 .doit = ethnl_set_rings, 793 + .policy = ethnl_rings_set_policy, 794 + .maxattr = ARRAY_SIZE(ethnl_rings_set_policy) - 1, 815 795 }, 816 796 { 817 797 .cmd = ETHTOOL_MSG_CHANNELS_GET, ··· 823 795 .start = ethnl_default_start, 824 796 .dumpit = ethnl_default_dumpit, 825 797 .done = ethnl_default_done, 798 + .policy = ethnl_channels_get_policy, 799 + .maxattr = ARRAY_SIZE(ethnl_channels_get_policy) - 1, 826 800 }, 827 801 { 828 802 .cmd = ETHTOOL_MSG_CHANNELS_SET, 829 803 .flags = GENL_UNS_ADMIN_PERM, 830 804 .doit = ethnl_set_channels, 805 + .policy = ethnl_channels_get_policy, 806 + .maxattr = ARRAY_SIZE(ethnl_channels_get_policy) - 1, 831 807 }, 832 808 { 833 809 .cmd = ETHTOOL_MSG_COALESCE_GET, ··· 839 807 .start = ethnl_default_start, 840 808 .dumpit = ethnl_default_dumpit, 841 809 .done = ethnl_default_done, 810 + .policy = ethnl_coalesce_get_policy, 811 + .maxattr = ARRAY_SIZE(ethnl_coalesce_get_policy) - 1, 842 812 }, 843 813 { 844 814 .cmd = ETHTOOL_MSG_COALESCE_SET, 845 815 .flags = GENL_UNS_ADMIN_PERM, 846 816 .doit = ethnl_set_coalesce, 817 + .policy = ethnl_coalesce_set_policy, 818 + .maxattr = ARRAY_SIZE(ethnl_coalesce_set_policy) - 1, 847 819 }, 848 820 { 849 821 .cmd = ETHTOOL_MSG_PAUSE_GET, ··· 855 819 .start = ethnl_default_start, 856 820 .dumpit = ethnl_default_dumpit, 857 821 .done = ethnl_default_done, 822 + .policy = ethnl_pause_get_policy, 823 + .maxattr = ARRAY_SIZE(ethnl_pause_get_policy) - 1, 858 824 }, 859 825 { 860 826 .cmd = ETHTOOL_MSG_PAUSE_SET, 861 827 .flags = GENL_UNS_ADMIN_PERM, 862 828 .doit = ethnl_set_pause, 829 + .policy = ethnl_pause_set_policy, 830 + .maxattr = ARRAY_SIZE(ethnl_pause_set_policy) - 1, 863 831 }, 864 832 { 865 833 .cmd = ETHTOOL_MSG_EEE_GET, ··· 871 831 .start = ethnl_default_start, 872 832 .dumpit = ethnl_default_dumpit, 873 833 .done = ethnl_default_done, 834 + .policy = ethnl_eee_get_policy, 835 + .maxattr = ARRAY_SIZE(ethnl_eee_get_policy) - 1, 874 836 }, 875 837 { 876 838 .cmd = ETHTOOL_MSG_EEE_SET, 877 839 .flags = GENL_UNS_ADMIN_PERM, 878 840 .doit = ethnl_set_eee, 841 + .policy = ethnl_eee_set_policy, 842 + .maxattr = ARRAY_SIZE(ethnl_eee_set_policy) - 1, 879 843 }, 880 844 { 881 845 .cmd = ETHTOOL_MSG_TSINFO_GET, ··· 887 843 .start = ethnl_default_start, 888 844 .dumpit = ethnl_default_dumpit, 889 845 .done = ethnl_default_done, 846 + .policy = ethnl_tsinfo_get_policy, 847 + .maxattr = ARRAY_SIZE(ethnl_tsinfo_get_policy) - 1, 890 848 }, 891 849 { 892 850 .cmd = ETHTOOL_MSG_CABLE_TEST_ACT, 893 851 .flags = GENL_UNS_ADMIN_PERM, 894 852 .doit = ethnl_act_cable_test, 853 + .policy = ethnl_cable_test_act_policy, 854 + .maxattr = ARRAY_SIZE(ethnl_cable_test_act_policy) - 1, 895 855 }, 896 856 { 897 857 .cmd = ETHTOOL_MSG_CABLE_TEST_TDR_ACT, 898 858 .flags = GENL_UNS_ADMIN_PERM, 899 859 .doit = ethnl_act_cable_test_tdr, 860 + .policy = ethnl_cable_test_tdr_act_policy, 861 + .maxattr = ARRAY_SIZE(ethnl_cable_test_tdr_act_policy) - 1, 900 862 }, 901 863 { 902 864 .cmd = ETHTOOL_MSG_TUNNEL_INFO_GET, 903 865 .doit = ethnl_tunnel_info_doit, 904 866 .start = ethnl_tunnel_info_start, 905 867 .dumpit = ethnl_tunnel_info_dumpit, 868 + .policy = ethnl_tunnel_info_get_policy, 869 + .maxattr = ARRAY_SIZE(ethnl_tunnel_info_get_policy) - 1, 906 870 }, 907 871 }; 908 872
+31 -4
net/ethtool/netlink.h
··· 266 266 * @request_cmd: command id for request (GET) 267 267 * @reply_cmd: command id for reply (GET_REPLY) 268 268 * @hdr_attr: attribute type for request header 269 - * @max_attr: maximum (top level) attribute type 270 269 * @req_info_size: size of request info 271 270 * @reply_data_size: size of reply data 272 - * @request_policy: netlink policy for message contents 273 271 * @allow_nodev_do: allow non-dump request with no device identification 274 272 * @parse_request: 275 273 * Parse request except common header (struct ethnl_req_info). Common ··· 310 312 u8 request_cmd; 311 313 u8 reply_cmd; 312 314 u16 hdr_attr; 313 - unsigned int max_attr; 314 315 unsigned int req_info_size; 315 316 unsigned int reply_data_size; 316 - const struct nla_policy *request_policy; 317 317 bool allow_nodev_do; 318 318 319 319 int (*parse_request)(struct ethnl_req_info *req_info, ··· 344 348 extern const struct ethnl_request_ops ethnl_pause_request_ops; 345 349 extern const struct ethnl_request_ops ethnl_eee_request_ops; 346 350 extern const struct ethnl_request_ops ethnl_tsinfo_request_ops; 351 + 352 + extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; 353 + extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; 354 + extern const struct nla_policy ethnl_strset_get_policy[ETHTOOL_A_STRSET_STRINGSETS + 1]; 355 + extern const struct nla_policy ethnl_linkinfo_get_policy[ETHTOOL_A_LINKINFO_HEADER + 1]; 356 + extern const struct nla_policy ethnl_linkinfo_set_policy[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL + 1]; 357 + extern const struct nla_policy ethnl_linkmodes_get_policy[ETHTOOL_A_LINKMODES_HEADER + 1]; 358 + extern const struct nla_policy ethnl_linkmodes_set_policy[ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG + 1]; 359 + extern const struct nla_policy ethnl_linkstate_get_policy[ETHTOOL_A_LINKSTATE_HEADER + 1]; 360 + extern const struct nla_policy ethnl_debug_get_policy[ETHTOOL_A_DEBUG_HEADER + 1]; 361 + extern const struct nla_policy ethnl_debug_set_policy[ETHTOOL_A_DEBUG_MSGMASK + 1]; 362 + extern const struct nla_policy ethnl_wol_get_policy[ETHTOOL_A_WOL_HEADER + 1]; 363 + extern const struct nla_policy ethnl_wol_set_policy[ETHTOOL_A_WOL_SOPASS + 1]; 364 + extern const struct nla_policy ethnl_features_get_policy[ETHTOOL_A_FEATURES_HEADER + 1]; 365 + extern const struct nla_policy ethnl_features_set_policy[ETHTOOL_A_FEATURES_WANTED + 1]; 366 + extern const struct nla_policy ethnl_privflags_get_policy[ETHTOOL_A_PRIVFLAGS_HEADER + 1]; 367 + extern const struct nla_policy ethnl_privflags_set_policy[ETHTOOL_A_PRIVFLAGS_FLAGS + 1]; 368 + extern const struct nla_policy ethnl_rings_get_policy[ETHTOOL_A_RINGS_HEADER + 1]; 369 + extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_TX + 1]; 370 + extern const struct nla_policy ethnl_channels_get_policy[ETHTOOL_A_CHANNELS_HEADER + 1]; 371 + extern const struct nla_policy ethnl_channels_set_policy[ETHTOOL_A_CHANNELS_COMBINED_COUNT + 1]; 372 + extern const struct nla_policy ethnl_coalesce_get_policy[ETHTOOL_A_COALESCE_HEADER + 1]; 373 + extern const struct nla_policy ethnl_coalesce_set_policy[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL + 1]; 374 + extern const struct nla_policy ethnl_pause_get_policy[ETHTOOL_A_PAUSE_HEADER + 1]; 375 + extern const struct nla_policy ethnl_pause_set_policy[ETHTOOL_A_PAUSE_TX + 1]; 376 + extern const struct nla_policy ethnl_eee_get_policy[ETHTOOL_A_EEE_HEADER + 1]; 377 + extern const struct nla_policy ethnl_eee_set_policy[ETHTOOL_A_EEE_TX_LPI_TIMER + 1]; 378 + extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_HEADER + 1]; 379 + extern const struct nla_policy ethnl_cable_test_act_policy[ETHTOOL_A_CABLE_TEST_HEADER + 1]; 380 + extern const struct nla_policy ethnl_cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG + 1]; 381 + extern const struct nla_policy ethnl_tunnel_info_get_policy[ETHTOOL_A_TUNNEL_INFO_HEADER + 1]; 347 382 348 383 int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); 349 384 int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info);
+7 -20
net/ethtool/pause.c
··· 16 16 #define PAUSE_REPDATA(__reply_base) \ 17 17 container_of(__reply_base, struct pause_reply_data, base) 18 18 19 - static const struct nla_policy 20 - pause_get_policy[ETHTOOL_A_PAUSE_MAX + 1] = { 21 - [ETHTOOL_A_PAUSE_UNSPEC] = { .type = NLA_REJECT }, 22 - [ETHTOOL_A_PAUSE_HEADER] = { .type = NLA_NESTED }, 23 - [ETHTOOL_A_PAUSE_AUTONEG] = { .type = NLA_REJECT }, 24 - [ETHTOOL_A_PAUSE_RX] = { .type = NLA_REJECT }, 25 - [ETHTOOL_A_PAUSE_TX] = { .type = NLA_REJECT }, 26 - [ETHTOOL_A_PAUSE_STATS] = { .type = NLA_REJECT }, 19 + const struct nla_policy ethnl_pause_get_policy[] = { 20 + [ETHTOOL_A_PAUSE_HEADER] = 21 + NLA_POLICY_NESTED(ethnl_header_policy_stats), 27 22 }; 28 23 29 24 static void ethtool_stats_init(u64 *stats, unsigned int n) ··· 125 130 .request_cmd = ETHTOOL_MSG_PAUSE_GET, 126 131 .reply_cmd = ETHTOOL_MSG_PAUSE_GET_REPLY, 127 132 .hdr_attr = ETHTOOL_A_PAUSE_HEADER, 128 - .max_attr = ETHTOOL_A_PAUSE_MAX, 129 133 .req_info_size = sizeof(struct pause_req_info), 130 134 .reply_data_size = sizeof(struct pause_reply_data), 131 - .request_policy = pause_get_policy, 132 135 133 136 .prepare_data = pause_prepare_data, 134 137 .reply_size = pause_reply_size, ··· 135 142 136 143 /* PAUSE_SET */ 137 144 138 - static const struct nla_policy 139 - pause_set_policy[ETHTOOL_A_PAUSE_MAX + 1] = { 140 - [ETHTOOL_A_PAUSE_UNSPEC] = { .type = NLA_REJECT }, 141 - [ETHTOOL_A_PAUSE_HEADER] = { .type = NLA_NESTED }, 145 + const struct nla_policy ethnl_pause_set_policy[] = { 146 + [ETHTOOL_A_PAUSE_HEADER] = 147 + NLA_POLICY_NESTED(ethnl_header_policy), 142 148 [ETHTOOL_A_PAUSE_AUTONEG] = { .type = NLA_U8 }, 143 149 [ETHTOOL_A_PAUSE_RX] = { .type = NLA_U8 }, 144 150 [ETHTOOL_A_PAUSE_TX] = { .type = NLA_U8 }, 145 - [ETHTOOL_A_PAUSE_STATS] = { .type = NLA_REJECT }, 146 151 }; 147 152 148 153 int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info) 149 154 { 150 - struct nlattr *tb[ETHTOOL_A_PAUSE_MAX + 1]; 151 155 struct ethtool_pauseparam params = {}; 152 156 struct ethnl_req_info req_info = {}; 157 + struct nlattr **tb = info->attrs; 153 158 const struct ethtool_ops *ops; 154 159 struct net_device *dev; 155 160 bool mod = false; 156 161 int ret; 157 162 158 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_PAUSE_MAX, 159 - pause_set_policy, info->extack); 160 - if (ret < 0) 161 - return ret; 162 163 ret = ethnl_parse_header_dev_get(&req_info, 163 164 tb[ETHTOOL_A_PAUSE_HEADER], 164 165 genl_info_net(info), info->extack,
+7 -17
net/ethtool/privflags.c
··· 18 18 #define PRIVFLAGS_REPDATA(__reply_base) \ 19 19 container_of(__reply_base, struct privflags_reply_data, base) 20 20 21 - static const struct nla_policy 22 - privflags_get_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = { 23 - [ETHTOOL_A_PRIVFLAGS_UNSPEC] = { .type = NLA_REJECT }, 24 - [ETHTOOL_A_PRIVFLAGS_HEADER] = { .type = NLA_NESTED }, 25 - [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .type = NLA_REJECT }, 21 + const struct nla_policy ethnl_privflags_get_policy[] = { 22 + [ETHTOOL_A_PRIVFLAGS_HEADER] = 23 + NLA_POLICY_NESTED(ethnl_header_policy), 26 24 }; 27 25 28 26 static int ethnl_get_priv_flags_info(struct net_device *dev, ··· 122 124 .request_cmd = ETHTOOL_MSG_PRIVFLAGS_GET, 123 125 .reply_cmd = ETHTOOL_MSG_PRIVFLAGS_GET_REPLY, 124 126 .hdr_attr = ETHTOOL_A_PRIVFLAGS_HEADER, 125 - .max_attr = ETHTOOL_A_PRIVFLAGS_MAX, 126 127 .req_info_size = sizeof(struct privflags_req_info), 127 128 .reply_data_size = sizeof(struct privflags_reply_data), 128 - .request_policy = privflags_get_policy, 129 129 130 130 .prepare_data = privflags_prepare_data, 131 131 .reply_size = privflags_reply_size, ··· 133 137 134 138 /* PRIVFLAGS_SET */ 135 139 136 - static const struct nla_policy 137 - privflags_set_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = { 138 - [ETHTOOL_A_PRIVFLAGS_UNSPEC] = { .type = NLA_REJECT }, 139 - [ETHTOOL_A_PRIVFLAGS_HEADER] = { .type = NLA_NESTED }, 140 + const struct nla_policy ethnl_privflags_set_policy[] = { 141 + [ETHTOOL_A_PRIVFLAGS_HEADER] = 142 + NLA_POLICY_NESTED(ethnl_header_policy), 140 143 [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .type = NLA_NESTED }, 141 144 }; 142 145 143 146 int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info) 144 147 { 145 - struct nlattr *tb[ETHTOOL_A_PRIVFLAGS_MAX + 1]; 146 148 const char (*names)[ETH_GSTRING_LEN] = NULL; 147 149 struct ethnl_req_info req_info = {}; 150 + struct nlattr **tb = info->attrs; 148 151 const struct ethtool_ops *ops; 149 152 struct net_device *dev; 150 153 unsigned int nflags; ··· 152 157 u32 flags; 153 158 int ret; 154 159 155 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 156 - ETHTOOL_A_PRIVFLAGS_MAX, privflags_set_policy, 157 - info->extack); 158 - if (ret < 0) 159 - return ret; 160 160 if (!tb[ETHTOOL_A_PRIVFLAGS_FLAGS]) 161 161 return -EINVAL; 162 162 ret = ethnl_bitset_is_compact(tb[ETHTOOL_A_PRIVFLAGS_FLAGS], &compact);
+7 -28
net/ethtool/rings.c
··· 15 15 #define RINGS_REPDATA(__reply_base) \ 16 16 container_of(__reply_base, struct rings_reply_data, base) 17 17 18 - static const struct nla_policy 19 - rings_get_policy[ETHTOOL_A_RINGS_MAX + 1] = { 20 - [ETHTOOL_A_RINGS_UNSPEC] = { .type = NLA_REJECT }, 21 - [ETHTOOL_A_RINGS_HEADER] = { .type = NLA_NESTED }, 22 - [ETHTOOL_A_RINGS_RX_MAX] = { .type = NLA_REJECT }, 23 - [ETHTOOL_A_RINGS_RX_MINI_MAX] = { .type = NLA_REJECT }, 24 - [ETHTOOL_A_RINGS_RX_JUMBO_MAX] = { .type = NLA_REJECT }, 25 - [ETHTOOL_A_RINGS_TX_MAX] = { .type = NLA_REJECT }, 26 - [ETHTOOL_A_RINGS_RX] = { .type = NLA_REJECT }, 27 - [ETHTOOL_A_RINGS_RX_MINI] = { .type = NLA_REJECT }, 28 - [ETHTOOL_A_RINGS_RX_JUMBO] = { .type = NLA_REJECT }, 29 - [ETHTOOL_A_RINGS_TX] = { .type = NLA_REJECT }, 18 + const struct nla_policy ethnl_rings_get_policy[] = { 19 + [ETHTOOL_A_RINGS_HEADER] = 20 + NLA_POLICY_NESTED(ethnl_header_policy), 30 21 }; 31 22 32 23 static int rings_prepare_data(const struct ethnl_req_info *req_base, ··· 88 97 .request_cmd = ETHTOOL_MSG_RINGS_GET, 89 98 .reply_cmd = ETHTOOL_MSG_RINGS_GET_REPLY, 90 99 .hdr_attr = ETHTOOL_A_RINGS_HEADER, 91 - .max_attr = ETHTOOL_A_RINGS_MAX, 92 100 .req_info_size = sizeof(struct rings_req_info), 93 101 .reply_data_size = sizeof(struct rings_reply_data), 94 - .request_policy = rings_get_policy, 95 102 96 103 .prepare_data = rings_prepare_data, 97 104 .reply_size = rings_reply_size, ··· 98 109 99 110 /* RINGS_SET */ 100 111 101 - static const struct nla_policy 102 - rings_set_policy[ETHTOOL_A_RINGS_MAX + 1] = { 103 - [ETHTOOL_A_RINGS_UNSPEC] = { .type = NLA_REJECT }, 104 - [ETHTOOL_A_RINGS_HEADER] = { .type = NLA_NESTED }, 105 - [ETHTOOL_A_RINGS_RX_MAX] = { .type = NLA_REJECT }, 106 - [ETHTOOL_A_RINGS_RX_MINI_MAX] = { .type = NLA_REJECT }, 107 - [ETHTOOL_A_RINGS_RX_JUMBO_MAX] = { .type = NLA_REJECT }, 108 - [ETHTOOL_A_RINGS_TX_MAX] = { .type = NLA_REJECT }, 112 + const struct nla_policy ethnl_rings_set_policy[] = { 113 + [ETHTOOL_A_RINGS_HEADER] = 114 + NLA_POLICY_NESTED(ethnl_header_policy), 109 115 [ETHTOOL_A_RINGS_RX] = { .type = NLA_U32 }, 110 116 [ETHTOOL_A_RINGS_RX_MINI] = { .type = NLA_U32 }, 111 117 [ETHTOOL_A_RINGS_RX_JUMBO] = { .type = NLA_U32 }, ··· 109 125 110 126 int ethnl_set_rings(struct sk_buff *skb, struct genl_info *info) 111 127 { 112 - struct nlattr *tb[ETHTOOL_A_RINGS_MAX + 1]; 113 128 struct ethtool_ringparam ringparam = {}; 114 129 struct ethnl_req_info req_info = {}; 130 + struct nlattr **tb = info->attrs; 115 131 const struct nlattr *err_attr; 116 132 const struct ethtool_ops *ops; 117 133 struct net_device *dev; 118 134 bool mod = false; 119 135 int ret; 120 136 121 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, 122 - ETHTOOL_A_RINGS_MAX, rings_set_policy, 123 - info->extack); 124 - if (ret < 0) 125 - return ret; 126 137 ret = ethnl_parse_header_dev_get(&req_info, 127 138 tb[ETHTOOL_A_RINGS_HEADER], 128 139 genl_info_net(info), info->extack,
+9 -16
net/ethtool/strset.c
··· 99 99 #define STRSET_REPDATA(__reply_base) \ 100 100 container_of(__reply_base, struct strset_reply_data, base) 101 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 }, 102 + const struct nla_policy ethnl_strset_get_policy[] = { 103 + [ETHTOOL_A_STRSET_HEADER] = 104 + NLA_POLICY_NESTED(ethnl_header_policy), 105 105 [ETHTOOL_A_STRSET_STRINGSETS] = { .type = NLA_NESTED }, 106 106 }; 107 107 108 - static const struct nla_policy 109 - get_stringset_policy[ETHTOOL_A_STRINGSET_MAX + 1] = { 110 - [ETHTOOL_A_STRINGSET_UNSPEC] = { .type = NLA_REJECT }, 108 + static const struct nla_policy get_stringset_policy[] = { 111 109 [ETHTOOL_A_STRINGSET_ID] = { .type = NLA_U32 }, 112 - [ETHTOOL_A_STRINGSET_COUNT] = { .type = NLA_REJECT }, 113 - [ETHTOOL_A_STRINGSET_STRINGS] = { .type = NLA_REJECT }, 114 110 }; 115 111 116 112 /** ··· 134 138 static int strset_get_id(const struct nlattr *nest, u32 *val, 135 139 struct netlink_ext_ack *extack) 136 140 { 137 - struct nlattr *tb[ETHTOOL_A_STRINGSET_MAX + 1]; 141 + struct nlattr *tb[ARRAY_SIZE(get_stringset_policy)]; 138 142 int ret; 139 143 140 - ret = nla_parse_nested(tb, ETHTOOL_A_STRINGSET_MAX, nest, 144 + ret = nla_parse_nested(tb, ARRAY_SIZE(get_stringset_policy) - 1, nest, 141 145 get_stringset_policy, extack); 142 146 if (ret < 0) 143 147 return ret; ··· 148 152 return 0; 149 153 } 150 154 151 - static const struct nla_policy 152 - strset_stringsets_policy[ETHTOOL_A_STRINGSETS_MAX + 1] = { 153 - [ETHTOOL_A_STRINGSETS_UNSPEC] = { .type = NLA_REJECT }, 155 + static const struct nla_policy strset_stringsets_policy[] = { 154 156 [ETHTOOL_A_STRINGSETS_STRINGSET] = { .type = NLA_NESTED }, 155 157 }; 156 158 ··· 163 169 164 170 if (!nest) 165 171 return 0; 166 - ret = nla_validate_nested(nest, ETHTOOL_A_STRINGSETS_MAX, 172 + ret = nla_validate_nested(nest, 173 + ARRAY_SIZE(strset_stringsets_policy) - 1, 167 174 strset_stringsets_policy, extack); 168 175 if (ret < 0) 169 176 return ret; ··· 440 445 .request_cmd = ETHTOOL_MSG_STRSET_GET, 441 446 .reply_cmd = ETHTOOL_MSG_STRSET_GET_REPLY, 442 447 .hdr_attr = ETHTOOL_A_STRSET_HEADER, 443 - .max_attr = ETHTOOL_A_STRSET_MAX, 444 448 .req_info_size = sizeof(struct strset_req_info), 445 449 .reply_data_size = sizeof(struct strset_reply_data), 446 - .request_policy = strset_get_policy, 447 450 .allow_nodev_do = true, 448 451 449 452 .parse_request = strset_parse_request,
+3 -10
net/ethtool/tsinfo.c
··· 18 18 #define TSINFO_REPDATA(__reply_base) \ 19 19 container_of(__reply_base, struct tsinfo_reply_data, base) 20 20 21 - static const struct nla_policy 22 - tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1] = { 23 - [ETHTOOL_A_TSINFO_UNSPEC] = { .type = NLA_REJECT }, 24 - [ETHTOOL_A_TSINFO_HEADER] = { .type = NLA_NESTED }, 25 - [ETHTOOL_A_TSINFO_TIMESTAMPING] = { .type = NLA_REJECT }, 26 - [ETHTOOL_A_TSINFO_TX_TYPES] = { .type = NLA_REJECT }, 27 - [ETHTOOL_A_TSINFO_RX_FILTERS] = { .type = NLA_REJECT }, 28 - [ETHTOOL_A_TSINFO_PHC_INDEX] = { .type = NLA_REJECT }, 21 + const struct nla_policy ethnl_tsinfo_get_policy[] = { 22 + [ETHTOOL_A_TSINFO_HEADER] = 23 + NLA_POLICY_NESTED(ethnl_header_policy), 29 24 }; 30 25 31 26 static int tsinfo_prepare_data(const struct ethnl_req_info *req_base, ··· 127 132 .request_cmd = ETHTOOL_MSG_TSINFO_GET, 128 133 .reply_cmd = ETHTOOL_MSG_TSINFO_GET_REPLY, 129 134 .hdr_attr = ETHTOOL_A_TSINFO_HEADER, 130 - .max_attr = ETHTOOL_A_TSINFO_MAX, 131 135 .req_info_size = sizeof(struct tsinfo_req_info), 132 136 .reply_data_size = sizeof(struct tsinfo_reply_data), 133 - .request_policy = tsinfo_get_policy, 134 137 135 138 .prepare_data = tsinfo_prepare_data, 136 139 .reply_size = tsinfo_reply_size,
+14 -28
net/ethtool/tunnels.c
··· 8 8 #include "common.h" 9 9 #include "netlink.h" 10 10 11 - static const struct nla_policy 12 - ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = { 13 - [ETHTOOL_A_TUNNEL_INFO_UNSPEC] = { .type = NLA_REJECT }, 14 - [ETHTOOL_A_TUNNEL_INFO_HEADER] = { .type = NLA_NESTED }, 11 + const struct nla_policy ethnl_tunnel_info_get_policy[] = { 12 + [ETHTOOL_A_TUNNEL_INFO_HEADER] = 13 + NLA_POLICY_NESTED(ethnl_header_policy), 15 14 }; 16 15 17 16 static_assert(ETHTOOL_UDP_TUNNEL_TYPE_VXLAN == ilog2(UDP_TUNNEL_TYPE_VXLAN)); ··· 160 161 return -EMSGSIZE; 161 162 } 162 163 163 - static int 164 - ethnl_tunnel_info_req_parse(struct ethnl_req_info *req_info, 165 - const struct nlmsghdr *nlhdr, struct net *net, 166 - struct netlink_ext_ack *extack, bool require_dev) 167 - { 168 - struct nlattr *tb[ETHTOOL_A_TUNNEL_INFO_MAX + 1]; 169 - int ret; 170 - 171 - ret = nlmsg_parse(nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_TUNNEL_INFO_MAX, 172 - ethtool_tunnel_info_policy, extack); 173 - if (ret < 0) 174 - return ret; 175 - 176 - return ethnl_parse_header_dev_get(req_info, 177 - tb[ETHTOOL_A_TUNNEL_INFO_HEADER], 178 - net, extack, require_dev); 179 - } 180 - 181 164 int ethnl_tunnel_info_doit(struct sk_buff *skb, struct genl_info *info) 182 165 { 183 166 struct ethnl_req_info req_info = {}; 167 + struct nlattr **tb = info->attrs; 184 168 struct sk_buff *rskb; 185 169 void *reply_payload; 186 170 int reply_len; 187 171 int ret; 188 172 189 - ret = ethnl_tunnel_info_req_parse(&req_info, info->nlhdr, 190 - genl_info_net(info), info->extack, 191 - true); 173 + ret = ethnl_parse_header_dev_get(&req_info, 174 + tb[ETHTOOL_A_TUNNEL_INFO_HEADER], 175 + genl_info_net(info), info->extack, 176 + true); 192 177 if (ret < 0) 193 178 return ret; 194 179 ··· 216 233 217 234 int ethnl_tunnel_info_start(struct netlink_callback *cb) 218 235 { 236 + const struct genl_dumpit_info *info = genl_dumpit_info(cb); 219 237 struct ethnl_tunnel_info_dump_ctx *ctx = (void *)cb->ctx; 238 + struct nlattr **tb = info->attrs; 220 239 int ret; 221 240 222 241 BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx)); 223 242 224 243 memset(ctx, 0, sizeof(*ctx)); 225 244 226 - ret = ethnl_tunnel_info_req_parse(&ctx->req_info, cb->nlh, 227 - sock_net(cb->skb->sk), cb->extack, 228 - false); 245 + ret = ethnl_parse_header_dev_get(&ctx->req_info, 246 + tb[ETHTOOL_A_TUNNEL_INFO_HEADER], 247 + sock_net(cb->skb->sk), cb->extack, 248 + false); 229 249 if (ctx->req_info.dev) { 230 250 dev_put(ctx->req_info.dev); 231 251 ctx->req_info.dev = NULL;
+7 -17
net/ethtool/wol.c
··· 17 17 #define WOL_REPDATA(__reply_base) \ 18 18 container_of(__reply_base, struct wol_reply_data, base) 19 19 20 - static const struct nla_policy 21 - wol_get_policy[ETHTOOL_A_WOL_MAX + 1] = { 22 - [ETHTOOL_A_WOL_UNSPEC] = { .type = NLA_REJECT }, 23 - [ETHTOOL_A_WOL_HEADER] = { .type = NLA_NESTED }, 24 - [ETHTOOL_A_WOL_MODES] = { .type = NLA_REJECT }, 25 - [ETHTOOL_A_WOL_SOPASS] = { .type = NLA_REJECT }, 20 + const struct nla_policy ethnl_wol_get_policy[] = { 21 + [ETHTOOL_A_WOL_HEADER] = 22 + NLA_POLICY_NESTED(ethnl_header_policy), 26 23 }; 27 24 28 25 static int wol_prepare_data(const struct ethnl_req_info *req_base, ··· 86 89 .request_cmd = ETHTOOL_MSG_WOL_GET, 87 90 .reply_cmd = ETHTOOL_MSG_WOL_GET_REPLY, 88 91 .hdr_attr = ETHTOOL_A_WOL_HEADER, 89 - .max_attr = ETHTOOL_A_WOL_MAX, 90 92 .req_info_size = sizeof(struct wol_req_info), 91 93 .reply_data_size = sizeof(struct wol_reply_data), 92 - .request_policy = wol_get_policy, 93 94 94 95 .prepare_data = wol_prepare_data, 95 96 .reply_size = wol_reply_size, ··· 96 101 97 102 /* WOL_SET */ 98 103 99 - static const struct nla_policy 100 - wol_set_policy[ETHTOOL_A_WOL_MAX + 1] = { 101 - [ETHTOOL_A_WOL_UNSPEC] = { .type = NLA_REJECT }, 102 - [ETHTOOL_A_WOL_HEADER] = { .type = NLA_NESTED }, 104 + const struct nla_policy ethnl_wol_set_policy[] = { 105 + [ETHTOOL_A_WOL_HEADER] = 106 + NLA_POLICY_NESTED(ethnl_header_policy), 103 107 [ETHTOOL_A_WOL_MODES] = { .type = NLA_NESTED }, 104 108 [ETHTOOL_A_WOL_SOPASS] = { .type = NLA_BINARY, 105 109 .len = SOPASS_MAX }, ··· 107 113 int ethnl_set_wol(struct sk_buff *skb, struct genl_info *info) 108 114 { 109 115 struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; 110 - struct nlattr *tb[ETHTOOL_A_WOL_MAX + 1]; 111 116 struct ethnl_req_info req_info = {}; 117 + struct nlattr **tb = info->attrs; 112 118 struct net_device *dev; 113 119 bool mod = false; 114 120 int ret; 115 121 116 - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_WOL_MAX, 117 - wol_set_policy, info->extack); 118 - if (ret < 0) 119 - return ret; 120 122 ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_WOL_HEADER], 121 123 genl_info_net(info), info->extack, 122 124 true);
+8
net/netlink/policy.c
··· 263 263 else 264 264 type = NL_ATTR_TYPE_U64; 265 265 266 + if (pt->validation_type == NLA_VALIDATE_MASK) { 267 + if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MASK, 268 + pt->mask, 269 + NL_POLICY_TYPE_ATTR_PAD)) 270 + goto nla_put_failure; 271 + break; 272 + } 273 + 266 274 nla_get_range_unsigned(pt, &range); 267 275 268 276 if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U,