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