diff options
-rw-r--r-- | include/net/netlink.h | 27 | ||||
-rw-r--r-- | include/uapi/linux/netlink.h | 2 | ||||
-rw-r--r-- | lib/nlattr.c | 36 | ||||
-rw-r--r-- | net/ethtool/bitset.c | 26 | ||||
-rw-r--r-- | net/ethtool/cabletest.c | 41 | ||||
-rw-r--r-- | net/ethtool/channels.c | 35 | ||||
-rw-r--r-- | net/ethtool/coalesce.c | 45 | ||||
-rw-r--r-- | net/ethtool/debug.c | 24 | ||||
-rw-r--r-- | net/ethtool/eee.c | 32 | ||||
-rw-r--r-- | net/ethtool/features.c | 30 | ||||
-rw-r--r-- | net/ethtool/linkinfo.c | 30 | ||||
-rw-r--r-- | net/ethtool/linkmodes.c | 32 | ||||
-rw-r--r-- | net/ethtool/linkstate.c | 14 | ||||
-rw-r--r-- | net/ethtool/netlink.c | 124 | ||||
-rw-r--r-- | net/ethtool/netlink.h | 35 | ||||
-rw-r--r-- | net/ethtool/pause.c | 27 | ||||
-rw-r--r-- | net/ethtool/privflags.c | 24 | ||||
-rw-r--r-- | net/ethtool/rings.c | 35 | ||||
-rw-r--r-- | net/ethtool/strset.c | 25 | ||||
-rw-r--r-- | net/ethtool/tsinfo.c | 13 | ||||
-rw-r--r-- | net/ethtool/tunnels.c | 42 | ||||
-rw-r--r-- | net/ethtool/wol.c | 24 | ||||
-rw-r--r-- | net/netlink/policy.c | 8 |
23 files changed, 317 insertions, 414 deletions
diff --git a/include/net/netlink.h b/include/net/netlink.h index 5a5ff97cc596..2b9e41075f19 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -200,6 +200,7 @@ enum nla_policy_validation { NLA_VALIDATE_RANGE_WARN_TOO_LONG, NLA_VALIDATE_MIN, NLA_VALIDATE_MAX, + NLA_VALIDATE_MASK, NLA_VALIDATE_RANGE_PTR, NLA_VALIDATE_FUNCTION, }; @@ -317,6 +318,7 @@ struct nla_policy { u16 len; union { const u32 bitfield32_valid; + const u32 mask; const char *reject_message; const struct nla_policy *nested_policy; struct netlink_range_validation *range; @@ -362,20 +364,23 @@ struct nla_policy { #define NLA_POLICY_BITFIELD32(valid) \ { .type = NLA_BITFIELD32, .bitfield32_valid = valid } +#define __NLA_IS_UINT_TYPE(tp) \ + (tp == NLA_U8 || tp == NLA_U16 || tp == NLA_U32 || tp == NLA_U64) +#define __NLA_IS_SINT_TYPE(tp) \ + (tp == NLA_S8 || tp == NLA_S16 || tp == NLA_S32 || tp == NLA_S64) + #define __NLA_ENSURE(condition) BUILD_BUG_ON_ZERO(!(condition)) +#define NLA_ENSURE_UINT_TYPE(tp) \ + (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp)) + tp) #define NLA_ENSURE_UINT_OR_BINARY_TYPE(tp) \ - (__NLA_ENSURE(tp == NLA_U8 || tp == NLA_U16 || \ - tp == NLA_U32 || tp == NLA_U64 || \ + (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp) || \ tp == NLA_MSECS || \ tp == NLA_BINARY) + tp) #define NLA_ENSURE_SINT_TYPE(tp) \ - (__NLA_ENSURE(tp == NLA_S8 || tp == NLA_S16 || \ - tp == NLA_S32 || tp == NLA_S64) + tp) + (__NLA_ENSURE(__NLA_IS_SINT_TYPE(tp)) + tp) #define NLA_ENSURE_INT_OR_BINARY_TYPE(tp) \ - (__NLA_ENSURE(tp == NLA_S8 || tp == NLA_U8 || \ - tp == NLA_S16 || tp == NLA_U16 || \ - tp == NLA_S32 || tp == NLA_U32 || \ - tp == NLA_S64 || tp == NLA_U64 || \ + (__NLA_ENSURE(__NLA_IS_UINT_TYPE(tp) || \ + __NLA_IS_SINT_TYPE(tp) || \ tp == NLA_MSECS || \ tp == NLA_BINARY) + tp) #define NLA_ENSURE_NO_VALIDATION_PTR(tp) \ @@ -415,6 +420,12 @@ struct nla_policy { .max = _max, \ } +#define NLA_POLICY_MASK(tp, _mask) { \ + .type = NLA_ENSURE_UINT_TYPE(tp), \ + .validation_type = NLA_VALIDATE_MASK, \ + .mask = _mask, \ +} + #define NLA_POLICY_VALIDATE_FN(tp, fn, ...) { \ .type = NLA_ENSURE_NO_VALIDATION_PTR(tp), \ .validation_type = NLA_VALIDATE_FUNCTION, \ diff --git a/include/uapi/linux/netlink.h b/include/uapi/linux/netlink.h index eac8a6a648ea..d02e472ba54c 100644 --- a/include/uapi/linux/netlink.h +++ b/include/uapi/linux/netlink.h @@ -331,6 +331,7 @@ enum netlink_attribute_type { * the index, if limited inside the nesting (U32) * @NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: valid mask for the * bitfield32 type (U32) + * @NL_POLICY_TYPE_ATTR_MASK: mask of valid bits for unsigned integers (U64) * @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment */ enum netlink_policy_type_attr { @@ -346,6 +347,7 @@ enum netlink_policy_type_attr { NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK, NL_POLICY_TYPE_ATTR_PAD, + NL_POLICY_TYPE_ATTR_MASK, /* keep last */ __NL_POLICY_TYPE_ATTR_MAX, diff --git a/lib/nlattr.c b/lib/nlattr.c index 80ff9fe83696..9c99f5daa4d2 100644 --- a/lib/nlattr.c +++ b/lib/nlattr.c @@ -323,6 +323,37 @@ static int nla_validate_int_range(const struct nla_policy *pt, } } +static int nla_validate_mask(const struct nla_policy *pt, + const struct nlattr *nla, + struct netlink_ext_ack *extack) +{ + u64 value; + + switch (pt->type) { + case NLA_U8: + value = nla_get_u8(nla); + break; + case NLA_U16: + value = nla_get_u16(nla); + break; + case NLA_U32: + value = nla_get_u32(nla); + break; + case NLA_U64: + value = nla_get_u64(nla); + break; + default: + return -EINVAL; + } + + if (value & ~(u64)pt->mask) { + NL_SET_ERR_MSG_ATTR(extack, nla, "reserved bit set"); + return -EINVAL; + } + + return 0; +} + static int validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *policy, unsigned int validate, struct netlink_ext_ack *extack, unsigned int depth) @@ -503,6 +534,11 @@ static int validate_nla(const struct nlattr *nla, int maxtype, if (err) return err; break; + case NLA_VALIDATE_MASK: + err = nla_validate_mask(pt, nla, extack); + if (err) + return err; + break; case NLA_VALIDATE_FUNCTION: if (pt->validate) { err = pt->validate(nla, extack); diff --git a/net/ethtool/bitset.c b/net/ethtool/bitset.c index dae7402eaca3..1fb3603d92ad 100644 --- a/net/ethtool/bitset.c +++ b/net/ethtool/bitset.c @@ -302,8 +302,7 @@ nla_put_failure: return -EMSGSIZE; } -static const struct nla_policy bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = { - [ETHTOOL_A_BITSET_UNSPEC] = { .type = NLA_REJECT }, +static const struct nla_policy bitset_policy[] = { [ETHTOOL_A_BITSET_NOMASK] = { .type = NLA_FLAG }, [ETHTOOL_A_BITSET_SIZE] = NLA_POLICY_MAX(NLA_U32, ETHNL_MAX_BITSET_SIZE), @@ -312,8 +311,7 @@ static const struct nla_policy bitset_policy[ETHTOOL_A_BITSET_MAX + 1] = { [ETHTOOL_A_BITSET_MASK] = { .type = NLA_BINARY }, }; -static const struct nla_policy bit_policy[ETHTOOL_A_BITSET_BIT_MAX + 1] = { - [ETHTOOL_A_BITSET_BIT_UNSPEC] = { .type = NLA_REJECT }, +static const struct nla_policy bit_policy[] = { [ETHTOOL_A_BITSET_BIT_INDEX] = { .type = NLA_U32 }, [ETHTOOL_A_BITSET_BIT_NAME] = { .type = NLA_NUL_STRING }, [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] = { */ int ethnl_bitset_is_compact(const struct nlattr *bitset, bool *compact) { - struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1]; + struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; int ret; - ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, bitset, + ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, bitset, bitset_policy, NULL); if (ret < 0) return ret; @@ -381,10 +379,10 @@ static int ethnl_parse_bit(unsigned int *index, bool *val, unsigned int nbits, ethnl_string_array_t names, struct netlink_ext_ack *extack) { - struct nlattr *tb[ETHTOOL_A_BITSET_BIT_MAX + 1]; + struct nlattr *tb[ARRAY_SIZE(bit_policy)]; int ret, idx; - ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_BIT_MAX, bit_attr, + ret = nla_parse_nested(tb, ARRAY_SIZE(bit_policy) - 1, bit_attr, bit_policy, extack); if (ret < 0) return ret; @@ -555,15 +553,15 @@ int ethnl_update_bitset32(u32 *bitmap, unsigned int nbits, const struct nlattr *attr, ethnl_string_array_t names, struct netlink_ext_ack *extack, bool *mod) { - struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1]; + struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; unsigned int change_bits; bool no_mask; int ret; if (!attr) return 0; - ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, attr, bitset_policy, - extack); + ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr, + bitset_policy, extack); if (ret < 0) return ret; @@ -608,7 +606,7 @@ int ethnl_parse_bitset(unsigned long *val, unsigned long *mask, ethnl_string_array_t names, struct netlink_ext_ack *extack) { - struct nlattr *tb[ETHTOOL_A_BITSET_MAX + 1]; + struct nlattr *tb[ARRAY_SIZE(bitset_policy)]; const struct nlattr *bit_attr; bool no_mask; int rem; @@ -616,8 +614,8 @@ int ethnl_parse_bitset(unsigned long *val, unsigned long *mask, if (!attr) return 0; - ret = nla_parse_nested(tb, ETHTOOL_A_BITSET_MAX, attr, bitset_policy, - extack); + ret = nla_parse_nested(tb, ARRAY_SIZE(bitset_policy) - 1, attr, + bitset_policy, extack); if (ret < 0) return ret; no_mask = tb[ETHTOOL_A_BITSET_NOMASK]; diff --git a/net/ethtool/cabletest.c b/net/ethtool/cabletest.c index 888f6e101f34..63560bbb7d1f 100644 --- a/net/ethtool/cabletest.c +++ b/net/ethtool/cabletest.c @@ -11,10 +11,9 @@ */ #define MAX_CABLE_LENGTH_CM (150 * 100) -static const struct nla_policy -cable_test_act_policy[ETHTOOL_A_CABLE_TEST_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_CABLE_TEST_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_cable_test_act_policy[] = { + [ETHTOOL_A_CABLE_TEST_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; static int ethnl_cable_test_started(struct phy_device *phydev, u8 cmd) @@ -56,18 +55,12 @@ out: int ethnl_act_cable_test(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_CABLE_TEST_MAX + 1]; struct ethnl_req_info req_info = {}; const struct ethtool_phy_ops *ops; + struct nlattr **tb = info->attrs; struct net_device *dev; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_CABLE_TEST_MAX, - cable_test_act_policy, info->extack); - if (ret < 0) - return ret; - ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_CABLE_TEST_HEADER], genl_info_net(info), info->extack, @@ -218,18 +211,16 @@ struct cable_test_tdr_req_info { struct ethnl_req_info base; }; -static const struct nla_policy -cable_test_tdr_act_cfg_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX + 1] = { +static const struct nla_policy cable_test_tdr_act_cfg_policy[] = { [ETHTOOL_A_CABLE_TEST_TDR_CFG_FIRST] = { .type = NLA_U32 }, [ETHTOOL_A_CABLE_TEST_TDR_CFG_LAST] = { .type = NLA_U32 }, [ETHTOOL_A_CABLE_TEST_TDR_CFG_STEP] = { .type = NLA_U32 }, [ETHTOOL_A_CABLE_TEST_TDR_CFG_PAIR] = { .type = NLA_U8 }, }; -static const struct nla_policy -cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1] = { - [ETHTOOL_A_CABLE_TEST_TDR_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_cable_test_tdr_act_policy[] = { + [ETHTOOL_A_CABLE_TEST_TDR_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_CABLE_TEST_TDR_CFG] = { .type = NLA_NESTED }, }; @@ -238,7 +229,7 @@ static int ethnl_act_cable_test_tdr_cfg(const struct nlattr *nest, struct genl_info *info, struct phy_tdr_config *cfg) { - struct nlattr *tb[ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX + 1]; + struct nlattr *tb[ARRAY_SIZE(cable_test_tdr_act_cfg_policy)]; int ret; cfg->first = 100; @@ -249,8 +240,10 @@ static int ethnl_act_cable_test_tdr_cfg(const struct nlattr *nest, if (!nest) return 0; - ret = nla_parse_nested(tb, ETHTOOL_A_CABLE_TEST_TDR_CFG_MAX, nest, - cable_test_tdr_act_cfg_policy, info->extack); + ret = nla_parse_nested(tb, + ARRAY_SIZE(cable_test_tdr_act_cfg_policy) - 1, + nest, cable_test_tdr_act_cfg_policy, + info->extack); if (ret < 0) return ret; @@ -313,19 +306,13 @@ static int ethnl_act_cable_test_tdr_cfg(const struct nlattr *nest, int ethnl_act_cable_test_tdr(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_CABLE_TEST_TDR_MAX + 1]; struct ethnl_req_info req_info = {}; const struct ethtool_phy_ops *ops; + struct nlattr **tb = info->attrs; struct phy_tdr_config cfg; struct net_device *dev; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_CABLE_TEST_TDR_MAX, - cable_test_tdr_act_policy, info->extack); - if (ret < 0) - return ret; - ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_CABLE_TEST_TDR_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/channels.c b/net/ethtool/channels.c index 9ecda09ecb11..5635604cb9ba 100644 --- a/net/ethtool/channels.c +++ b/net/ethtool/channels.c @@ -17,18 +17,9 @@ struct channels_reply_data { #define CHANNELS_REPDATA(__reply_base) \ container_of(__reply_base, struct channels_reply_data, base) -static const struct nla_policy -channels_get_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { - [ETHTOOL_A_CHANNELS_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_CHANNELS_RX_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_TX_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_RX_COUNT] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_TX_COUNT] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_COMBINED_COUNT] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_channels_get_policy[] = { + [ETHTOOL_A_CHANNELS_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_CHANNELS_GET, .reply_cmd = ETHTOOL_MSG_CHANNELS_GET_REPLY, .hdr_attr = ETHTOOL_A_CHANNELS_HEADER, - .max_attr = ETHTOOL_A_CHANNELS_MAX, .req_info_size = sizeof(struct channels_req_info), .reply_data_size = sizeof(struct channels_reply_data), - .request_policy = channels_get_policy, .prepare_data = channels_prepare_data, .reply_size = channels_reply_size, @@ -111,14 +100,9 @@ const struct ethnl_request_ops ethnl_channels_request_ops = { /* CHANNELS_SET */ -static const struct nla_policy -channels_set_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { - [ETHTOOL_A_CHANNELS_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_CHANNELS_RX_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_TX_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_OTHER_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_CHANNELS_COMBINED_MAX] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_channels_set_policy[] = { + [ETHTOOL_A_CHANNELS_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_CHANNELS_RX_COUNT] = { .type = NLA_U32 }, [ETHTOOL_A_CHANNELS_TX_COUNT] = { .type = NLA_U32 }, [ETHTOOL_A_CHANNELS_OTHER_COUNT] = { .type = NLA_U32 }, @@ -127,22 +111,17 @@ channels_set_policy[ETHTOOL_A_CHANNELS_MAX + 1] = { int ethnl_set_channels(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_CHANNELS_MAX + 1]; unsigned int from_channel, old_total, i; bool mod = false, mod_combined = false; struct ethtool_channels channels = {}; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; const struct nlattr *err_attr; const struct ethtool_ops *ops; struct net_device *dev; u32 max_rx_in_use = 0; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_CHANNELS_MAX, channels_set_policy, - info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_CHANNELS_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/coalesce.c b/net/ethtool/coalesce.c index 6afd99042d67..1d6bc132aa4d 100644 --- a/net/ethtool/coalesce.c +++ b/net/ethtool/coalesce.c @@ -51,32 +51,9 @@ __CHECK_SUPPORTED_OFFSET(COALESCE_TX_USECS_HIGH); __CHECK_SUPPORTED_OFFSET(COALESCE_TX_MAX_FRAMES_HIGH); __CHECK_SUPPORTED_OFFSET(COALESCE_RATE_SAMPLE_INTERVAL); -static const struct nla_policy -coalesce_get_policy[ETHTOOL_A_COALESCE_MAX + 1] = { - [ETHTOOL_A_COALESCE_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_COALESCE_RX_USECS] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_IRQ] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_TX_USECS] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_TX_USECS_IRQ] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_IRQ] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_STATS_BLOCK_USECS] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_RX] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_USE_ADAPTIVE_TX] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_PKT_RATE_LOW] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_RX_USECS_LOW] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_LOW] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_TX_USECS_LOW] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_LOW] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_PKT_RATE_HIGH] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_RX_USECS_HIGH] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_RX_MAX_FRAMES_HIGH] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_TX_USECS_HIGH] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_TX_MAX_FRAMES_HIGH] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_coalesce_get_policy[] = { + [ETHTOOL_A_COALESCE_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_COALESCE_GET, .reply_cmd = ETHTOOL_MSG_COALESCE_GET_REPLY, .hdr_attr = ETHTOOL_A_COALESCE_HEADER, - .max_attr = ETHTOOL_A_COALESCE_MAX, .req_info_size = sizeof(struct coalesce_req_info), .reply_data_size = sizeof(struct coalesce_reply_data), - .request_policy = coalesce_get_policy, .prepare_data = coalesce_prepare_data, .reply_size = coalesce_reply_size, @@ -215,10 +190,9 @@ const struct ethnl_request_ops ethnl_coalesce_request_ops = { /* COALESCE_SET */ -static const struct nla_policy -coalesce_set_policy[ETHTOOL_A_COALESCE_MAX + 1] = { - [ETHTOOL_A_COALESCE_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_COALESCE_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_coalesce_set_policy[] = { + [ETHTOOL_A_COALESCE_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_COALESCE_RX_USECS] = { .type = NLA_U32 }, [ETHTOOL_A_COALESCE_RX_MAX_FRAMES] = { .type = NLA_U32 }, [ETHTOOL_A_COALESCE_RX_USECS_IRQ] = { .type = NLA_U32 }, @@ -245,9 +219,9 @@ coalesce_set_policy[ETHTOOL_A_COALESCE_MAX + 1] = { int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_COALESCE_MAX + 1]; struct ethtool_coalesce coalesce = {}; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; const struct ethtool_ops *ops; struct net_device *dev; u32 supported_params; @@ -255,11 +229,6 @@ int ethnl_set_coalesce(struct sk_buff *skb, struct genl_info *info) int ret; u16 a; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_COALESCE_MAX, coalesce_set_policy, - info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_COALESCE_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/debug.c b/net/ethtool/debug.c index 1bd026a29f3f..f99912d7957e 100644 --- a/net/ethtool/debug.c +++ b/net/ethtool/debug.c @@ -16,11 +16,9 @@ struct debug_reply_data { #define DEBUG_REPDATA(__reply_base) \ container_of(__reply_base, struct debug_reply_data, base) -static const struct nla_policy -debug_get_policy[ETHTOOL_A_DEBUG_MAX + 1] = { - [ETHTOOL_A_DEBUG_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_DEBUG_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_DEBUG_MSGMASK] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_debug_get_policy[] = { + [ETHTOOL_A_DEBUG_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_DEBUG_GET, .reply_cmd = ETHTOOL_MSG_DEBUG_GET_REPLY, .hdr_attr = ETHTOOL_A_DEBUG_HEADER, - .max_attr = ETHTOOL_A_DEBUG_MAX, .req_info_size = sizeof(struct debug_req_info), .reply_data_size = sizeof(struct debug_reply_data), - .request_policy = debug_get_policy, .prepare_data = debug_prepare_data, .reply_size = debug_reply_size, @@ -81,27 +77,21 @@ const struct ethnl_request_ops ethnl_debug_request_ops = { /* DEBUG_SET */ -static const struct nla_policy -debug_set_policy[ETHTOOL_A_DEBUG_MAX + 1] = { - [ETHTOOL_A_DEBUG_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_DEBUG_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_debug_set_policy[] = { + [ETHTOOL_A_DEBUG_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_DEBUG_MSGMASK] = { .type = NLA_NESTED }, }; int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_DEBUG_MAX + 1]; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; struct net_device *dev; bool mod = false; u32 msg_mask; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_DEBUG_MAX, debug_set_policy, - info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_DEBUG_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/eee.c b/net/ethtool/eee.c index 94aa19cff22f..901b7de941ab 100644 --- a/net/ethtool/eee.c +++ b/net/ethtool/eee.c @@ -19,16 +19,9 @@ struct eee_reply_data { #define EEE_REPDATA(__reply_base) \ container_of(__reply_base, struct eee_reply_data, base) -static const struct nla_policy -eee_get_policy[ETHTOOL_A_EEE_MAX + 1] = { - [ETHTOOL_A_EEE_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_EEE_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_EEE_MODES_OURS] = { .type = NLA_REJECT }, - [ETHTOOL_A_EEE_MODES_PEER] = { .type = NLA_REJECT }, - [ETHTOOL_A_EEE_ACTIVE] = { .type = NLA_REJECT }, - [ETHTOOL_A_EEE_ENABLED] = { .type = NLA_REJECT }, - [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .type = NLA_REJECT }, - [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_eee_get_policy[] = { + [ETHTOOL_A_EEE_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_EEE_GET, .reply_cmd = ETHTOOL_MSG_EEE_GET_REPLY, .hdr_attr = ETHTOOL_A_EEE_HEADER, - .max_attr = ETHTOOL_A_EEE_MAX, .req_info_size = sizeof(struct eee_req_info), .reply_data_size = sizeof(struct eee_reply_data), - .request_policy = eee_get_policy, .prepare_data = eee_prepare_data, .reply_size = eee_reply_size, @@ -131,13 +122,10 @@ const struct ethnl_request_ops ethnl_eee_request_ops = { /* EEE_SET */ -static const struct nla_policy -eee_set_policy[ETHTOOL_A_EEE_MAX + 1] = { - [ETHTOOL_A_EEE_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_EEE_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_eee_set_policy[] = { + [ETHTOOL_A_EEE_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_EEE_MODES_OURS] = { .type = NLA_NESTED }, - [ETHTOOL_A_EEE_MODES_PEER] = { .type = NLA_REJECT }, - [ETHTOOL_A_EEE_ACTIVE] = { .type = NLA_REJECT }, [ETHTOOL_A_EEE_ENABLED] = { .type = NLA_U8 }, [ETHTOOL_A_EEE_TX_LPI_ENABLED] = { .type = NLA_U8 }, [ETHTOOL_A_EEE_TX_LPI_TIMER] = { .type = NLA_U32 }, @@ -145,18 +133,14 @@ eee_set_policy[ETHTOOL_A_EEE_MAX + 1] = { int ethnl_set_eee(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_EEE_MAX + 1]; - struct ethtool_eee eee = {}; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; const struct ethtool_ops *ops; + struct ethtool_eee eee = {}; struct net_device *dev; bool mod = false; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_EEE_MAX, - eee_set_policy, info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_EEE_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/features.c b/net/ethtool/features.c index 495635f152ba..8ee4cdbd6b82 100644 --- a/net/ethtool/features.c +++ b/net/ethtool/features.c @@ -20,14 +20,9 @@ struct features_reply_data { #define FEATURES_REPDATA(__reply_base) \ container_of(__reply_base, struct features_reply_data, base) -static const struct nla_policy -features_get_policy[ETHTOOL_A_FEATURES_MAX + 1] = { - [ETHTOOL_A_FEATURES_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_FEATURES_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_FEATURES_HW] = { .type = NLA_REJECT }, - [ETHTOOL_A_FEATURES_WANTED] = { .type = NLA_REJECT }, - [ETHTOOL_A_FEATURES_ACTIVE] = { .type = NLA_REJECT }, - [ETHTOOL_A_FEATURES_NOCHANGE] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_features_get_policy[] = { + [ETHTOOL_A_FEATURES_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_FEATURES_GET, .reply_cmd = ETHTOOL_MSG_FEATURES_GET_REPLY, .hdr_attr = ETHTOOL_A_FEATURES_HEADER, - .max_attr = ETHTOOL_A_FEATURES_MAX, .req_info_size = sizeof(struct features_req_info), .reply_data_size = sizeof(struct features_reply_data), - .request_policy = features_get_policy, .prepare_data = features_prepare_data, .reply_size = features_reply_size, @@ -132,14 +125,10 @@ const struct ethnl_request_ops ethnl_features_request_ops = { /* FEATURES_SET */ -static const struct nla_policy -features_set_policy[ETHTOOL_A_FEATURES_MAX + 1] = { - [ETHTOOL_A_FEATURES_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_FEATURES_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_FEATURES_HW] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_features_set_policy[] = { + [ETHTOOL_A_FEATURES_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_FEATURES_WANTED] = { .type = NLA_NESTED }, - [ETHTOOL_A_FEATURES_ACTIVE] = { .type = NLA_REJECT }, - [ETHTOOL_A_FEATURES_NOCHANGE] = { .type = NLA_REJECT }, }; 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) DECLARE_BITMAP(new_wanted, NETDEV_FEATURE_COUNT); DECLARE_BITMAP(req_wanted, NETDEV_FEATURE_COUNT); DECLARE_BITMAP(req_mask, NETDEV_FEATURE_COUNT); - struct nlattr *tb[ETHTOOL_A_FEATURES_MAX + 1]; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; struct net_device *dev; bool mod; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_FEATURES_MAX, features_set_policy, - info->extack); - if (ret < 0) - return ret; if (!tb[ETHTOOL_A_FEATURES_WANTED]) return -EINVAL; ret = ethnl_parse_header_dev_get(&req_info, diff --git a/net/ethtool/linkinfo.c b/net/ethtool/linkinfo.c index 5eaf173eaaca..b91839870efc 100644 --- a/net/ethtool/linkinfo.c +++ b/net/ethtool/linkinfo.c @@ -16,15 +16,9 @@ struct linkinfo_reply_data { #define LINKINFO_REPDATA(__reply_base) \ container_of(__reply_base, struct linkinfo_reply_data, base) -static const struct nla_policy -linkinfo_get_policy[ETHTOOL_A_LINKINFO_MAX + 1] = { - [ETHTOOL_A_LINKINFO_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKINFO_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_LINKINFO_PORT] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKINFO_PHYADDR] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKINFO_TP_MDIX] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKINFO_TRANSCEIVER] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_linkinfo_get_policy[] = { + [ETHTOOL_A_LINKINFO_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_LINKINFO_GET, .reply_cmd = ETHTOOL_MSG_LINKINFO_GET_REPLY, .hdr_attr = ETHTOOL_A_LINKINFO_HEADER, - .max_attr = ETHTOOL_A_LINKINFO_MAX, .req_info_size = sizeof(struct linkinfo_req_info), .reply_data_size = sizeof(struct linkinfo_reply_data), - .request_policy = linkinfo_get_policy, .prepare_data = linkinfo_prepare_data, .reply_size = linkinfo_reply_size, @@ -95,32 +87,24 @@ const struct ethnl_request_ops ethnl_linkinfo_request_ops = { /* LINKINFO_SET */ -static const struct nla_policy -linkinfo_set_policy[ETHTOOL_A_LINKINFO_MAX + 1] = { - [ETHTOOL_A_LINKINFO_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKINFO_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_linkinfo_set_policy[] = { + [ETHTOOL_A_LINKINFO_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_LINKINFO_PORT] = { .type = NLA_U8 }, [ETHTOOL_A_LINKINFO_PHYADDR] = { .type = NLA_U8 }, - [ETHTOOL_A_LINKINFO_TP_MDIX] = { .type = NLA_REJECT }, [ETHTOOL_A_LINKINFO_TP_MDIX_CTRL] = { .type = NLA_U8 }, - [ETHTOOL_A_LINKINFO_TRANSCEIVER] = { .type = NLA_REJECT }, }; int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_LINKINFO_MAX + 1]; struct ethtool_link_ksettings ksettings = {}; struct ethtool_link_settings *lsettings; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; struct net_device *dev; bool mod = false; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_LINKINFO_MAX, linkinfo_set_policy, - info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_LINKINFO_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/linkmodes.c b/net/ethtool/linkmodes.c index 29dcd675b65a..c5bcb9abc8b9 100644 --- a/net/ethtool/linkmodes.c +++ b/net/ethtool/linkmodes.c @@ -18,17 +18,9 @@ struct linkmodes_reply_data { #define LINKMODES_REPDATA(__reply_base) \ container_of(__reply_base, struct linkmodes_reply_data, base) -static const struct nla_policy -linkmodes_get_policy[ETHTOOL_A_LINKMODES_MAX + 1] = { - [ETHTOOL_A_LINKMODES_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKMODES_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_LINKMODES_AUTONEG] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKMODES_OURS] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKMODES_PEER] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKMODES_SPEED] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKMODES_DUPLEX] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_linkmodes_get_policy[] = { + [ETHTOOL_A_LINKMODES_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_LINKMODES_GET, .reply_cmd = ETHTOOL_MSG_LINKMODES_GET_REPLY, .hdr_attr = ETHTOOL_A_LINKMODES_HEADER, - .max_attr = ETHTOOL_A_LINKMODES_MAX, .req_info_size = sizeof(struct linkmodes_req_info), .reply_data_size = sizeof(struct linkmodes_reply_data), - .request_policy = linkmodes_get_policy, .prepare_data = linkmodes_prepare_data, .reply_size = linkmodes_reply_size, @@ -276,17 +266,14 @@ static const struct link_mode_info link_mode_params[] = { __DEFINE_LINK_MODE_PARAMS(100, FX, Full), }; -static const struct nla_policy -linkmodes_set_policy[ETHTOOL_A_LINKMODES_MAX + 1] = { - [ETHTOOL_A_LINKMODES_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKMODES_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_linkmodes_set_policy[] = { + [ETHTOOL_A_LINKMODES_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_LINKMODES_AUTONEG] = { .type = NLA_U8 }, [ETHTOOL_A_LINKMODES_OURS] = { .type = NLA_NESTED }, - [ETHTOOL_A_LINKMODES_PEER] = { .type = NLA_REJECT }, [ETHTOOL_A_LINKMODES_SPEED] = { .type = NLA_U32 }, [ETHTOOL_A_LINKMODES_DUPLEX] = { .type = NLA_U8 }, [ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG] = { .type = NLA_U8 }, - [ETHTOOL_A_LINKMODES_MASTER_SLAVE_STATE] = { .type = NLA_REJECT }, }; /* 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, int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_LINKMODES_MAX + 1]; struct ethtool_link_ksettings ksettings = {}; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; struct net_device *dev; bool mod = false; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_LINKMODES_MAX, linkmodes_set_policy, - info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_LINKMODES_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/linkstate.c b/net/ethtool/linkstate.c index 4834091ec24c..fb676f349455 100644 --- a/net/ethtool/linkstate.c +++ b/net/ethtool/linkstate.c @@ -20,15 +20,9 @@ struct linkstate_reply_data { #define LINKSTATE_REPDATA(__reply_base) \ container_of(__reply_base, struct linkstate_reply_data, base) -static const struct nla_policy -linkstate_get_policy[ETHTOOL_A_LINKSTATE_MAX + 1] = { - [ETHTOOL_A_LINKSTATE_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKSTATE_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_LINKSTATE_LINK] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKSTATE_SQI] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKSTATE_SQI_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKSTATE_EXT_STATE] = { .type = NLA_REJECT }, - [ETHTOOL_A_LINKSTATE_EXT_SUBSTATE] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_linkstate_get_policy[] = { + [ETHTOOL_A_LINKSTATE_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; static int linkstate_get_sqi(struct net_device *dev) @@ -179,10 +173,8 @@ const struct ethnl_request_ops ethnl_linkstate_request_ops = { .request_cmd = ETHTOOL_MSG_LINKSTATE_GET, .reply_cmd = ETHTOOL_MSG_LINKSTATE_GET_REPLY, .hdr_attr = ETHTOOL_A_LINKSTATE_HEADER, - .max_attr = ETHTOOL_A_LINKSTATE_MAX, .req_info_size = sizeof(struct linkstate_req_info), .reply_data_size = sizeof(struct linkstate_reply_data), - .request_policy = linkstate_get_policy, .prepare_data = linkstate_prepare_data, .reply_size = linkstate_reply_size, diff --git a/net/ethtool/netlink.c b/net/ethtool/netlink.c index 0c3f54baec4e..8a85a4e6be9b 100644 --- a/net/ethtool/netlink.c +++ b/net/ethtool/netlink.c @@ -9,12 +9,24 @@ static struct genl_family ethtool_genl_family; static bool ethnl_ok __read_mostly; static u32 ethnl_bcast_seq; -static const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_MAX + 1] = { - [ETHTOOL_A_HEADER_UNSPEC] = { .type = NLA_REJECT }, +#define ETHTOOL_FLAGS_BASIC (ETHTOOL_FLAG_COMPACT_BITSETS | \ + ETHTOOL_FLAG_OMIT_REPLY) +#define ETHTOOL_FLAGS_STATS (ETHTOOL_FLAGS_BASIC | ETHTOOL_FLAG_STATS) + +const struct nla_policy ethnl_header_policy[] = { [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 }, [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING, .len = ALTIFNAMSIZ - 1 }, - [ETHTOOL_A_HEADER_FLAGS] = { .type = NLA_U32 }, + [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32, + ETHTOOL_FLAGS_BASIC), +}; + +const struct nla_policy ethnl_header_policy_stats[] = { + [ETHTOOL_A_HEADER_DEV_INDEX] = { .type = NLA_U32 }, + [ETHTOOL_A_HEADER_DEV_NAME] = { .type = NLA_NUL_STRING, + .len = ALTIFNAMSIZ - 1 }, + [ETHTOOL_A_HEADER_FLAGS] = NLA_POLICY_MASK(NLA_U32, + ETHTOOL_FLAGS_STATS), }; /** @@ -37,7 +49,7 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, const struct nlattr *header, struct net *net, struct netlink_ext_ack *extack, bool require_dev) { - struct nlattr *tb[ETHTOOL_A_HEADER_MAX + 1]; + struct nlattr *tb[ARRAY_SIZE(ethnl_header_policy)]; const struct nlattr *devname_attr; struct net_device *dev = NULL; u32 flags = 0; @@ -47,19 +59,15 @@ int ethnl_parse_header_dev_get(struct ethnl_req_info *req_info, NL_SET_ERR_MSG(extack, "request header missing"); return -EINVAL; } - ret = nla_parse_nested(tb, ETHTOOL_A_HEADER_MAX, header, - ethnl_header_policy, extack); + /* No validation here, command policy should have a nested policy set + * for the header, therefore validation should have already been done. + */ + ret = nla_parse_nested(tb, ARRAY_SIZE(ethnl_header_policy) - 1, header, + NULL, extack); if (ret < 0) return ret; - if (tb[ETHTOOL_A_HEADER_FLAGS]) { + if (tb[ETHTOOL_A_HEADER_FLAGS]) flags = nla_get_u32(tb[ETHTOOL_A_HEADER_FLAGS]); - if (flags & ~ETHTOOL_FLAG_ALL) { - NL_SET_ERR_MSG_ATTR(extack, tb[ETHTOOL_A_HEADER_FLAGS], - "unrecognized request flags"); - nl_set_extack_cookie_u32(extack, ETHTOOL_FLAG_ALL); - return -EOPNOTSUPP; - } - } devname_attr = tb[ETHTOOL_A_HEADER_DEV_NAME]; if (tb[ETHTOOL_A_HEADER_DEV_INDEX]) { @@ -247,7 +255,7 @@ static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) /** * ethnl_default_parse() - Parse request message * @req_info: pointer to structure to put data into - * @nlhdr: pointer to request message header + * @tb: parsed attributes * @net: request netns * @request_ops: struct request_ops for request type * @extack: netlink extack for error reporting @@ -259,37 +267,24 @@ static struct ethnl_dump_ctx *ethnl_dump_context(struct netlink_callback *cb) * Return: 0 on success or negative error code */ static int ethnl_default_parse(struct ethnl_req_info *req_info, - const struct nlmsghdr *nlhdr, struct net *net, + struct nlattr **tb, struct net *net, const struct ethnl_request_ops *request_ops, struct netlink_ext_ack *extack, bool require_dev) { - struct nlattr **tb; int ret; - tb = kmalloc_array(request_ops->max_attr + 1, sizeof(tb[0]), - GFP_KERNEL); - if (!tb) - return -ENOMEM; - - ret = nlmsg_parse(nlhdr, GENL_HDRLEN, tb, request_ops->max_attr, - request_ops->request_policy, extack); - if (ret < 0) - goto out; ret = ethnl_parse_header_dev_get(req_info, tb[request_ops->hdr_attr], net, extack, require_dev); if (ret < 0) - goto out; + return ret; if (request_ops->parse_request) { ret = request_ops->parse_request(req_info, tb, extack); if (ret < 0) - goto out; + return ret; } - ret = 0; -out: - kfree(tb); - return ret; + return 0; } /** @@ -334,8 +329,8 @@ static int ethnl_default_doit(struct sk_buff *skb, struct genl_info *info) return -ENOMEM; } - ret = ethnl_default_parse(req_info, info->nlhdr, genl_info_net(info), ops, - info->extack, !ops->allow_nodev_do); + ret = ethnl_default_parse(req_info, info->attrs, genl_info_net(info), + ops, info->extack, !ops->allow_nodev_do); if (ret < 0) goto err_dev; ethnl_init_reply_data(reply_data, ops, req_info->dev); @@ -480,6 +475,7 @@ out: /* generic ->start() handler for GET requests */ static int ethnl_default_start(struct netlink_callback *cb) { + const struct genl_dumpit_info *info = genl_dumpit_info(cb); struct ethnl_dump_ctx *ctx = ethnl_dump_context(cb); struct ethnl_reply_data *reply_data; const struct ethnl_request_ops *ops; @@ -502,8 +498,8 @@ static int ethnl_default_start(struct netlink_callback *cb) goto free_req_info; } - ret = ethnl_default_parse(req_info, cb->nlh, sock_net(cb->skb->sk), ops, - cb->extack, false); + ret = ethnl_default_parse(req_info, info->attrs, sock_net(cb->skb->sk), + ops, cb->extack, false); if (req_info->dev) { /* We ignore device specification in dump requests but as the * same parser as for non-dump (doit) requests is used, it @@ -696,6 +692,8 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_strset_get_policy, + .maxattr = ARRAY_SIZE(ethnl_strset_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_LINKINFO_GET, @@ -703,11 +701,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_linkinfo_get_policy, + .maxattr = ARRAY_SIZE(ethnl_linkinfo_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_LINKINFO_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_linkinfo, + .policy = ethnl_linkinfo_set_policy, + .maxattr = ARRAY_SIZE(ethnl_linkinfo_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_LINKMODES_GET, @@ -715,11 +717,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_linkmodes_get_policy, + .maxattr = ARRAY_SIZE(ethnl_linkmodes_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_LINKMODES_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_linkmodes, + .policy = ethnl_linkmodes_set_policy, + .maxattr = ARRAY_SIZE(ethnl_linkmodes_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_LINKSTATE_GET, @@ -727,6 +733,8 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_linkstate_get_policy, + .maxattr = ARRAY_SIZE(ethnl_linkstate_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_DEBUG_GET, @@ -734,11 +742,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_debug_get_policy, + .maxattr = ARRAY_SIZE(ethnl_debug_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_DEBUG_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_debug, + .policy = ethnl_debug_set_policy, + .maxattr = ARRAY_SIZE(ethnl_debug_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_WOL_GET, @@ -747,11 +759,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_wol_get_policy, + .maxattr = ARRAY_SIZE(ethnl_wol_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_WOL_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_wol, + .policy = ethnl_wol_set_policy, + .maxattr = ARRAY_SIZE(ethnl_wol_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_FEATURES_GET, @@ -759,11 +775,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_features_get_policy, + .maxattr = ARRAY_SIZE(ethnl_features_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_FEATURES_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_features, + .policy = ethnl_features_set_policy, + .maxattr = ARRAY_SIZE(ethnl_features_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_PRIVFLAGS_GET, @@ -771,11 +791,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_privflags_get_policy, + .maxattr = ARRAY_SIZE(ethnl_privflags_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_PRIVFLAGS_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_privflags, + .policy = ethnl_privflags_set_policy, + .maxattr = ARRAY_SIZE(ethnl_privflags_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_RINGS_GET, @@ -783,11 +807,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_rings_get_policy, + .maxattr = ARRAY_SIZE(ethnl_rings_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_RINGS_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_rings, + .policy = ethnl_rings_set_policy, + .maxattr = ARRAY_SIZE(ethnl_rings_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_CHANNELS_GET, @@ -795,11 +823,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_channels_get_policy, + .maxattr = ARRAY_SIZE(ethnl_channels_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_CHANNELS_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_channels, + .policy = ethnl_channels_get_policy, + .maxattr = ARRAY_SIZE(ethnl_channels_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_COALESCE_GET, @@ -807,11 +839,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_coalesce_get_policy, + .maxattr = ARRAY_SIZE(ethnl_coalesce_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_COALESCE_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_coalesce, + .policy = ethnl_coalesce_set_policy, + .maxattr = ARRAY_SIZE(ethnl_coalesce_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_PAUSE_GET, @@ -819,11 +855,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_pause_get_policy, + .maxattr = ARRAY_SIZE(ethnl_pause_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_PAUSE_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_pause, + .policy = ethnl_pause_set_policy, + .maxattr = ARRAY_SIZE(ethnl_pause_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_EEE_GET, @@ -831,11 +871,15 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_eee_get_policy, + .maxattr = ARRAY_SIZE(ethnl_eee_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_EEE_SET, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_set_eee, + .policy = ethnl_eee_set_policy, + .maxattr = ARRAY_SIZE(ethnl_eee_set_policy) - 1, }, { .cmd = ETHTOOL_MSG_TSINFO_GET, @@ -843,22 +887,30 @@ static const struct genl_ops ethtool_genl_ops[] = { .start = ethnl_default_start, .dumpit = ethnl_default_dumpit, .done = ethnl_default_done, + .policy = ethnl_tsinfo_get_policy, + .maxattr = ARRAY_SIZE(ethnl_tsinfo_get_policy) - 1, }, { .cmd = ETHTOOL_MSG_CABLE_TEST_ACT, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_act_cable_test, + .policy = ethnl_cable_test_act_policy, + .maxattr = ARRAY_SIZE(ethnl_cable_test_act_policy) - 1, }, { .cmd = ETHTOOL_MSG_CABLE_TEST_TDR_ACT, .flags = GENL_UNS_ADMIN_PERM, .doit = ethnl_act_cable_test_tdr, + .policy = ethnl_cable_test_tdr_act_policy, + .maxattr = ARRAY_SIZE(ethnl_cable_test_tdr_act_policy) - 1, }, { .cmd = ETHTOOL_MSG_TUNNEL_INFO_GET, .doit = ethnl_tunnel_info_doit, .start = ethnl_tunnel_info_start, .dumpit = ethnl_tunnel_info_dumpit, + .policy = ethnl_tunnel_info_get_policy, + .maxattr = ARRAY_SIZE(ethnl_tunnel_info_get_policy) - 1, }, }; diff --git a/net/ethtool/netlink.h b/net/ethtool/netlink.h index e2085005caac..3f5719786b0f 100644 --- a/net/ethtool/netlink.h +++ b/net/ethtool/netlink.h @@ -266,10 +266,8 @@ static inline void ethnl_ops_complete(struct net_device *dev) * @request_cmd: command id for request (GET) * @reply_cmd: command id for reply (GET_REPLY) * @hdr_attr: attribute type for request header - * @max_attr: maximum (top level) attribute type * @req_info_size: size of request info * @reply_data_size: size of reply data - * @request_policy: netlink policy for message contents * @allow_nodev_do: allow non-dump request with no device identification * @parse_request: * Parse request except common header (struct ethnl_req_info). Common @@ -312,10 +310,8 @@ struct ethnl_request_ops { u8 request_cmd; u8 reply_cmd; u16 hdr_attr; - unsigned int max_attr; unsigned int req_info_size; unsigned int reply_data_size; - const struct nla_policy *request_policy; bool allow_nodev_do; int (*parse_request)(struct ethnl_req_info *req_info, @@ -349,6 +345,37 @@ extern const struct ethnl_request_ops ethnl_pause_request_ops; extern const struct ethnl_request_ops ethnl_eee_request_ops; extern const struct ethnl_request_ops ethnl_tsinfo_request_ops; +extern const struct nla_policy ethnl_header_policy[ETHTOOL_A_HEADER_FLAGS + 1]; +extern const struct nla_policy ethnl_header_policy_stats[ETHTOOL_A_HEADER_FLAGS + 1]; +extern const struct nla_policy ethnl_strset_get_policy[ETHTOOL_A_STRSET_STRINGSETS + 1]; +extern const struct nla_policy ethnl_linkinfo_get_policy[ETHTOOL_A_LINKINFO_HEADER + 1]; +extern const struct nla_policy ethnl_linkinfo_set_policy[ETHTOOL_A_LINKINFO_TP_MDIX_CTRL + 1]; +extern const struct nla_policy ethnl_linkmodes_get_policy[ETHTOOL_A_LINKMODES_HEADER + 1]; +extern const struct nla_policy ethnl_linkmodes_set_policy[ETHTOOL_A_LINKMODES_MASTER_SLAVE_CFG + 1]; +extern const struct nla_policy ethnl_linkstate_get_policy[ETHTOOL_A_LINKSTATE_HEADER + 1]; +extern const struct nla_policy ethnl_debug_get_policy[ETHTOOL_A_DEBUG_HEADER + 1]; +extern const struct nla_policy ethnl_debug_set_policy[ETHTOOL_A_DEBUG_MSGMASK + 1]; +extern const struct nla_policy ethnl_wol_get_policy[ETHTOOL_A_WOL_HEADER + 1]; +extern const struct nla_policy ethnl_wol_set_policy[ETHTOOL_A_WOL_SOPASS + 1]; +extern const struct nla_policy ethnl_features_get_policy[ETHTOOL_A_FEATURES_HEADER + 1]; +extern const struct nla_policy ethnl_features_set_policy[ETHTOOL_A_FEATURES_WANTED + 1]; +extern const struct nla_policy ethnl_privflags_get_policy[ETHTOOL_A_PRIVFLAGS_HEADER + 1]; +extern const struct nla_policy ethnl_privflags_set_policy[ETHTOOL_A_PRIVFLAGS_FLAGS + 1]; +extern const struct nla_policy ethnl_rings_get_policy[ETHTOOL_A_RINGS_HEADER + 1]; +extern const struct nla_policy ethnl_rings_set_policy[ETHTOOL_A_RINGS_TX + 1]; +extern const struct nla_policy ethnl_channels_get_policy[ETHTOOL_A_CHANNELS_HEADER + 1]; +extern const struct nla_policy ethnl_channels_set_policy[ETHTOOL_A_CHANNELS_COMBINED_COUNT + 1]; +extern const struct nla_policy ethnl_coalesce_get_policy[ETHTOOL_A_COALESCE_HEADER + 1]; +extern const struct nla_policy ethnl_coalesce_set_policy[ETHTOOL_A_COALESCE_RATE_SAMPLE_INTERVAL + 1]; +extern const struct nla_policy ethnl_pause_get_policy[ETHTOOL_A_PAUSE_HEADER + 1]; +extern const struct nla_policy ethnl_pause_set_policy[ETHTOOL_A_PAUSE_TX + 1]; +extern const struct nla_policy ethnl_eee_get_policy[ETHTOOL_A_EEE_HEADER + 1]; +extern const struct nla_policy ethnl_eee_set_policy[ETHTOOL_A_EEE_TX_LPI_TIMER + 1]; +extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_HEADER + 1]; +extern const struct nla_policy ethnl_cable_test_act_policy[ETHTOOL_A_CABLE_TEST_HEADER + 1]; +extern const struct nla_policy ethnl_cable_test_tdr_act_policy[ETHTOOL_A_CABLE_TEST_TDR_CFG + 1]; +extern const struct nla_policy ethnl_tunnel_info_get_policy[ETHTOOL_A_TUNNEL_INFO_HEADER + 1]; + int ethnl_set_linkinfo(struct sk_buff *skb, struct genl_info *info); int ethnl_set_linkmodes(struct sk_buff *skb, struct genl_info *info); int ethnl_set_debug(struct sk_buff *skb, struct genl_info *info); diff --git a/net/ethtool/pause.c b/net/ethtool/pause.c index 1980aa7eb2b6..09998dc5c185 100644 --- a/net/ethtool/pause.c +++ b/net/ethtool/pause.c @@ -16,14 +16,9 @@ struct pause_reply_data { #define PAUSE_REPDATA(__reply_base) \ container_of(__reply_base, struct pause_reply_data, base) -static const struct nla_policy -pause_get_policy[ETHTOOL_A_PAUSE_MAX + 1] = { - [ETHTOOL_A_PAUSE_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_PAUSE_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_PAUSE_AUTONEG] = { .type = NLA_REJECT }, - [ETHTOOL_A_PAUSE_RX] = { .type = NLA_REJECT }, - [ETHTOOL_A_PAUSE_TX] = { .type = NLA_REJECT }, - [ETHTOOL_A_PAUSE_STATS] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_pause_get_policy[] = { + [ETHTOOL_A_PAUSE_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy_stats), }; static void ethtool_stats_init(u64 *stats, unsigned int n) @@ -130,10 +125,8 @@ const struct ethnl_request_ops ethnl_pause_request_ops = { .request_cmd = ETHTOOL_MSG_PAUSE_GET, .reply_cmd = ETHTOOL_MSG_PAUSE_GET_REPLY, .hdr_attr = ETHTOOL_A_PAUSE_HEADER, - .max_attr = ETHTOOL_A_PAUSE_MAX, .req_info_size = sizeof(struct pause_req_info), .reply_data_size = sizeof(struct pause_reply_data), - .request_policy = pause_get_policy, .prepare_data = pause_prepare_data, .reply_size = pause_reply_size, @@ -142,30 +135,24 @@ const struct ethnl_request_ops ethnl_pause_request_ops = { /* PAUSE_SET */ -static const struct nla_policy -pause_set_policy[ETHTOOL_A_PAUSE_MAX + 1] = { - [ETHTOOL_A_PAUSE_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_PAUSE_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_pause_set_policy[] = { + [ETHTOOL_A_PAUSE_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_PAUSE_AUTONEG] = { .type = NLA_U8 }, [ETHTOOL_A_PAUSE_RX] = { .type = NLA_U8 }, [ETHTOOL_A_PAUSE_TX] = { .type = NLA_U8 }, - [ETHTOOL_A_PAUSE_STATS] = { .type = NLA_REJECT }, }; int ethnl_set_pause(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_PAUSE_MAX + 1]; struct ethtool_pauseparam params = {}; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; const struct ethtool_ops *ops; struct net_device *dev; bool mod = false; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_PAUSE_MAX, - pause_set_policy, info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_PAUSE_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/privflags.c b/net/ethtool/privflags.c index 77447dceb109..fc9f3be23a19 100644 --- a/net/ethtool/privflags.c +++ b/net/ethtool/privflags.c @@ -18,11 +18,9 @@ struct privflags_reply_data { #define PRIVFLAGS_REPDATA(__reply_base) \ container_of(__reply_base, struct privflags_reply_data, base) -static const struct nla_policy -privflags_get_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = { - [ETHTOOL_A_PRIVFLAGS_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_PRIVFLAGS_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_privflags_get_policy[] = { + [ETHTOOL_A_PRIVFLAGS_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; static int ethnl_get_priv_flags_info(struct net_device *dev, @@ -124,10 +122,8 @@ const struct ethnl_request_ops ethnl_privflags_request_ops = { .request_cmd = ETHTOOL_MSG_PRIVFLAGS_GET, .reply_cmd = ETHTOOL_MSG_PRIVFLAGS_GET_REPLY, .hdr_attr = ETHTOOL_A_PRIVFLAGS_HEADER, - .max_attr = ETHTOOL_A_PRIVFLAGS_MAX, .req_info_size = sizeof(struct privflags_req_info), .reply_data_size = sizeof(struct privflags_reply_data), - .request_policy = privflags_get_policy, .prepare_data = privflags_prepare_data, .reply_size = privflags_reply_size, @@ -137,18 +133,17 @@ const struct ethnl_request_ops ethnl_privflags_request_ops = { /* PRIVFLAGS_SET */ -static const struct nla_policy -privflags_set_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1] = { - [ETHTOOL_A_PRIVFLAGS_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_PRIVFLAGS_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_privflags_set_policy[] = { + [ETHTOOL_A_PRIVFLAGS_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_PRIVFLAGS_FLAGS] = { .type = NLA_NESTED }, }; int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_PRIVFLAGS_MAX + 1]; const char (*names)[ETH_GSTRING_LEN] = NULL; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; const struct ethtool_ops *ops; struct net_device *dev; unsigned int nflags; @@ -157,11 +152,6 @@ int ethnl_set_privflags(struct sk_buff *skb, struct genl_info *info) u32 flags; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_PRIVFLAGS_MAX, privflags_set_policy, - info->extack); - if (ret < 0) - return ret; if (!tb[ETHTOOL_A_PRIVFLAGS_FLAGS]) return -EINVAL; ret = ethnl_bitset_is_compact(tb[ETHTOOL_A_PRIVFLAGS_FLAGS], &compact); diff --git a/net/ethtool/rings.c b/net/ethtool/rings.c index 5422526f4eef..4e097812a967 100644 --- a/net/ethtool/rings.c +++ b/net/ethtool/rings.c @@ -15,18 +15,9 @@ struct rings_reply_data { #define RINGS_REPDATA(__reply_base) \ container_of(__reply_base, struct rings_reply_data, base) -static const struct nla_policy -rings_get_policy[ETHTOOL_A_RINGS_MAX + 1] = { - [ETHTOOL_A_RINGS_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_RINGS_RX_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_RX_MINI_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_RX_JUMBO_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_TX_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_RX] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_RX_MINI] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_RX_JUMBO] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_TX] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_rings_get_policy[] = { + [ETHTOOL_A_RINGS_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_RINGS_GET, .reply_cmd = ETHTOOL_MSG_RINGS_GET_REPLY, .hdr_attr = ETHTOOL_A_RINGS_HEADER, - .max_attr = ETHTOOL_A_RINGS_MAX, .req_info_size = sizeof(struct rings_req_info), .reply_data_size = sizeof(struct rings_reply_data), - .request_policy = rings_get_policy, .prepare_data = rings_prepare_data, .reply_size = rings_reply_size, @@ -109,14 +98,9 @@ const struct ethnl_request_ops ethnl_rings_request_ops = { /* RINGS_SET */ -static const struct nla_policy -rings_set_policy[ETHTOOL_A_RINGS_MAX + 1] = { - [ETHTOOL_A_RINGS_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_RINGS_RX_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_RX_MINI_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_RX_JUMBO_MAX] = { .type = NLA_REJECT }, - [ETHTOOL_A_RINGS_TX_MAX] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_rings_set_policy[] = { + [ETHTOOL_A_RINGS_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_RINGS_RX] = { .type = NLA_U32 }, [ETHTOOL_A_RINGS_RX_MINI] = { .type = NLA_U32 }, [ETHTOOL_A_RINGS_RX_JUMBO] = { .type = NLA_U32 }, @@ -125,20 +109,15 @@ rings_set_policy[ETHTOOL_A_RINGS_MAX + 1] = { int ethnl_set_rings(struct sk_buff *skb, struct genl_info *info) { - struct nlattr *tb[ETHTOOL_A_RINGS_MAX + 1]; struct ethtool_ringparam ringparam = {}; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; const struct nlattr *err_attr; const struct ethtool_ops *ops; struct net_device *dev; bool mod = false; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, - ETHTOOL_A_RINGS_MAX, rings_set_policy, - info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_RINGS_HEADER], genl_info_net(info), info->extack, diff --git a/net/ethtool/strset.c b/net/ethtool/strset.c index 82707b662fe4..0734e83c674c 100644 --- a/net/ethtool/strset.c +++ b/net/ethtool/strset.c @@ -99,18 +99,14 @@ struct strset_reply_data { #define STRSET_REPDATA(__reply_base) \ container_of(__reply_base, struct strset_reply_data, base) -static const struct nla_policy strset_get_policy[ETHTOOL_A_STRSET_MAX + 1] = { - [ETHTOOL_A_STRSET_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_STRSET_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_strset_get_policy[] = { + [ETHTOOL_A_STRSET_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_STRSET_STRINGSETS] = { .type = NLA_NESTED }, }; -static const struct nla_policy -get_stringset_policy[ETHTOOL_A_STRINGSET_MAX + 1] = { - [ETHTOOL_A_STRINGSET_UNSPEC] = { .type = NLA_REJECT }, +static const struct nla_policy get_stringset_policy[] = { [ETHTOOL_A_STRINGSET_ID] = { .type = NLA_U32 }, - [ETHTOOL_A_STRINGSET_COUNT] = { .type = NLA_REJECT }, - [ETHTOOL_A_STRINGSET_STRINGS] = { .type = NLA_REJECT }, }; /** @@ -138,10 +134,10 @@ static bool strset_include(const struct strset_req_info *info, static int strset_get_id(const struct nlattr *nest, u32 *val, struct netlink_ext_ack *extack) { - struct nlattr *tb[ETHTOOL_A_STRINGSET_MAX + 1]; + struct nlattr *tb[ARRAY_SIZE(get_stringset_policy)]; int ret; - ret = nla_parse_nested(tb, ETHTOOL_A_STRINGSET_MAX, nest, + ret = nla_parse_nested(tb, ARRAY_SIZE(get_stringset_policy) - 1, nest, get_stringset_policy, extack); if (ret < 0) return ret; @@ -152,9 +148,7 @@ static int strset_get_id(const struct nlattr *nest, u32 *val, return 0; } -static const struct nla_policy -strset_stringsets_policy[ETHTOOL_A_STRINGSETS_MAX + 1] = { - [ETHTOOL_A_STRINGSETS_UNSPEC] = { .type = NLA_REJECT }, +static const struct nla_policy strset_stringsets_policy[] = { [ETHTOOL_A_STRINGSETS_STRINGSET] = { .type = NLA_NESTED }, }; @@ -169,7 +163,8 @@ static int strset_parse_request(struct ethnl_req_info *req_base, if (!nest) return 0; - ret = nla_validate_nested(nest, ETHTOOL_A_STRINGSETS_MAX, + ret = nla_validate_nested(nest, + ARRAY_SIZE(strset_stringsets_policy) - 1, strset_stringsets_policy, extack); if (ret < 0) return ret; @@ -445,10 +440,8 @@ const struct ethnl_request_ops ethnl_strset_request_ops = { .request_cmd = ETHTOOL_MSG_STRSET_GET, .reply_cmd = ETHTOOL_MSG_STRSET_GET_REPLY, .hdr_attr = ETHTOOL_A_STRSET_HEADER, - .max_attr = ETHTOOL_A_STRSET_MAX, .req_info_size = sizeof(struct strset_req_info), .reply_data_size = sizeof(struct strset_reply_data), - .request_policy = strset_get_policy, .allow_nodev_do = true, .parse_request = strset_parse_request, diff --git a/net/ethtool/tsinfo.c b/net/ethtool/tsinfo.c index 7cb5b512b77c..63b5814bd460 100644 --- a/net/ethtool/tsinfo.c +++ b/net/ethtool/tsinfo.c @@ -18,14 +18,9 @@ struct tsinfo_reply_data { #define TSINFO_REPDATA(__reply_base) \ container_of(__reply_base, struct tsinfo_reply_data, base) -static const struct nla_policy -tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1] = { - [ETHTOOL_A_TSINFO_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_TSINFO_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_TSINFO_TIMESTAMPING] = { .type = NLA_REJECT }, - [ETHTOOL_A_TSINFO_TX_TYPES] = { .type = NLA_REJECT }, - [ETHTOOL_A_TSINFO_RX_FILTERS] = { .type = NLA_REJECT }, - [ETHTOOL_A_TSINFO_PHC_INDEX] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_tsinfo_get_policy[] = { + [ETHTOOL_A_TSINFO_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_TSINFO_GET, .reply_cmd = ETHTOOL_MSG_TSINFO_GET_REPLY, .hdr_attr = ETHTOOL_A_TSINFO_HEADER, - .max_attr = ETHTOOL_A_TSINFO_MAX, .req_info_size = sizeof(struct tsinfo_req_info), .reply_data_size = sizeof(struct tsinfo_reply_data), - .request_policy = tsinfo_get_policy, .prepare_data = tsinfo_prepare_data, .reply_size = tsinfo_reply_size, diff --git a/net/ethtool/tunnels.c b/net/ethtool/tunnels.c index d93bf2da0f34..e7f2ee0d2471 100644 --- a/net/ethtool/tunnels.c +++ b/net/ethtool/tunnels.c @@ -8,10 +8,9 @@ #include "common.h" #include "netlink.h" -static const struct nla_policy -ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = { - [ETHTOOL_A_TUNNEL_INFO_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_TUNNEL_INFO_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_tunnel_info_get_policy[] = { + [ETHTOOL_A_TUNNEL_INFO_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; static_assert(ETHTOOL_UDP_TUNNEL_TYPE_VXLAN == ilog2(UDP_TUNNEL_TYPE_VXLAN)); @@ -161,35 +160,19 @@ err_cancel_ports: return -EMSGSIZE; } -static int -ethnl_tunnel_info_req_parse(struct ethnl_req_info *req_info, - const struct nlmsghdr *nlhdr, struct net *net, - struct netlink_ext_ack *extack, bool require_dev) -{ - struct nlattr *tb[ETHTOOL_A_TUNNEL_INFO_MAX + 1]; - int ret; - - ret = nlmsg_parse(nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_TUNNEL_INFO_MAX, - ethtool_tunnel_info_policy, extack); - if (ret < 0) - return ret; - - return ethnl_parse_header_dev_get(req_info, - tb[ETHTOOL_A_TUNNEL_INFO_HEADER], - net, extack, require_dev); -} - int ethnl_tunnel_info_doit(struct sk_buff *skb, struct genl_info *info) { struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; struct sk_buff *rskb; void *reply_payload; int reply_len; int ret; - ret = ethnl_tunnel_info_req_parse(&req_info, info->nlhdr, - genl_info_net(info), info->extack, - true); + ret = ethnl_parse_header_dev_get(&req_info, + tb[ETHTOOL_A_TUNNEL_INFO_HEADER], + genl_info_net(info), info->extack, + true); if (ret < 0) return ret; @@ -233,16 +216,19 @@ struct ethnl_tunnel_info_dump_ctx { int ethnl_tunnel_info_start(struct netlink_callback *cb) { + const struct genl_dumpit_info *info = genl_dumpit_info(cb); struct ethnl_tunnel_info_dump_ctx *ctx = (void *)cb->ctx; + struct nlattr **tb = info->attrs; int ret; BUILD_BUG_ON(sizeof(*ctx) > sizeof(cb->ctx)); memset(ctx, 0, sizeof(*ctx)); - ret = ethnl_tunnel_info_req_parse(&ctx->req_info, cb->nlh, - sock_net(cb->skb->sk), cb->extack, - false); + ret = ethnl_parse_header_dev_get(&ctx->req_info, + tb[ETHTOOL_A_TUNNEL_INFO_HEADER], + sock_net(cb->skb->sk), cb->extack, + false); if (ctx->req_info.dev) { dev_put(ctx->req_info.dev); ctx->req_info.dev = NULL; diff --git a/net/ethtool/wol.c b/net/ethtool/wol.c index 1798421e9f1c..ada7df2331d2 100644 --- a/net/ethtool/wol.c +++ b/net/ethtool/wol.c @@ -17,12 +17,9 @@ struct wol_reply_data { #define WOL_REPDATA(__reply_base) \ container_of(__reply_base, struct wol_reply_data, base) -static const struct nla_policy -wol_get_policy[ETHTOOL_A_WOL_MAX + 1] = { - [ETHTOOL_A_WOL_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_WOL_HEADER] = { .type = NLA_NESTED }, - [ETHTOOL_A_WOL_MODES] = { .type = NLA_REJECT }, - [ETHTOOL_A_WOL_SOPASS] = { .type = NLA_REJECT }, +const struct nla_policy ethnl_wol_get_policy[] = { + [ETHTOOL_A_WOL_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), }; 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 = { .request_cmd = ETHTOOL_MSG_WOL_GET, .reply_cmd = ETHTOOL_MSG_WOL_GET_REPLY, .hdr_attr = ETHTOOL_A_WOL_HEADER, - .max_attr = ETHTOOL_A_WOL_MAX, .req_info_size = sizeof(struct wol_req_info), .reply_data_size = sizeof(struct wol_reply_data), - .request_policy = wol_get_policy, .prepare_data = wol_prepare_data, .reply_size = wol_reply_size, @@ -101,10 +96,9 @@ const struct ethnl_request_ops ethnl_wol_request_ops = { /* WOL_SET */ -static const struct nla_policy -wol_set_policy[ETHTOOL_A_WOL_MAX + 1] = { - [ETHTOOL_A_WOL_UNSPEC] = { .type = NLA_REJECT }, - [ETHTOOL_A_WOL_HEADER] = { .type = NLA_NESTED }, +const struct nla_policy ethnl_wol_set_policy[] = { + [ETHTOOL_A_WOL_HEADER] = + NLA_POLICY_NESTED(ethnl_header_policy), [ETHTOOL_A_WOL_MODES] = { .type = NLA_NESTED }, [ETHTOOL_A_WOL_SOPASS] = { .type = NLA_BINARY, .len = SOPASS_MAX }, @@ -113,16 +107,12 @@ wol_set_policy[ETHTOOL_A_WOL_MAX + 1] = { int ethnl_set_wol(struct sk_buff *skb, struct genl_info *info) { struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL }; - struct nlattr *tb[ETHTOOL_A_WOL_MAX + 1]; struct ethnl_req_info req_info = {}; + struct nlattr **tb = info->attrs; struct net_device *dev; bool mod = false; int ret; - ret = nlmsg_parse(info->nlhdr, GENL_HDRLEN, tb, ETHTOOL_A_WOL_MAX, - wol_set_policy, info->extack); - if (ret < 0) - return ret; ret = ethnl_parse_header_dev_get(&req_info, tb[ETHTOOL_A_WOL_HEADER], genl_info_net(info), info->extack, true); diff --git a/net/netlink/policy.c b/net/netlink/policy.c index cf23c0151721..ee26d01328ee 100644 --- a/net/netlink/policy.c +++ b/net/netlink/policy.c @@ -263,6 +263,14 @@ send_attribute: else type = NL_ATTR_TYPE_U64; + if (pt->validation_type == NLA_VALIDATE_MASK) { + if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MASK, + pt->mask, + NL_POLICY_TYPE_ATTR_PAD)) + goto nla_put_failure; + break; + } + nla_get_range_unsigned(pt, &range); if (nla_put_u64_64bit(skb, NL_POLICY_TYPE_ATTR_MIN_VALUE_U, |