#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] = {
+const struct nla_policy
+ethnl_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 },
        .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,
 
 __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] = {
+const struct nla_policy
+ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy
+ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy
+ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy
+ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy
+ethnl_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 },
        .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,
 
 /**
  * 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
  * 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;
 }
 
 /**
                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);
 /* 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;
                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
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
                .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,
        },
 };
 
 
  * @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
        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,
 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_strset_get_policy[ETHTOOL_A_STRSET_MAX + 1];
+extern const struct nla_policy ethnl_linkinfo_get_policy[ETHTOOL_A_LINKINFO_MAX + 1];
+extern const struct nla_policy ethnl_linkmodes_get_policy[ETHTOOL_A_LINKMODES_MAX + 1];
+extern const struct nla_policy ethnl_linkstate_get_policy[ETHTOOL_A_LINKSTATE_MAX + 1];
+extern const struct nla_policy ethnl_debug_get_policy[ETHTOOL_A_DEBUG_MAX + 1];
+extern const struct nla_policy ethnl_wol_get_policy[ETHTOOL_A_WOL_MAX + 1];
+extern const struct nla_policy ethnl_features_get_policy[ETHTOOL_A_FEATURES_MAX + 1];
+extern const struct nla_policy ethnl_privflags_get_policy[ETHTOOL_A_PRIVFLAGS_MAX + 1];
+extern const struct nla_policy ethnl_rings_get_policy[ETHTOOL_A_RINGS_MAX + 1];
+extern const struct nla_policy ethnl_channels_get_policy[ETHTOOL_A_CHANNELS_MAX + 1];
+extern const struct nla_policy ethnl_coalesce_get_policy[ETHTOOL_A_COALESCE_MAX + 1];
+extern const struct nla_policy ethnl_pause_get_policy[ETHTOOL_A_PAUSE_MAX + 1];
+extern const struct nla_policy ethnl_eee_get_policy[ETHTOOL_A_EEE_MAX + 1];
+extern const struct nla_policy ethnl_tsinfo_get_policy[ETHTOOL_A_TSINFO_MAX + 1];
+extern const struct nla_policy ethnl_tunnel_info_get_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 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);
 
 #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] = {
+const struct nla_policy ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy
+ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy ethnl_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 },
        .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,
 
 #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] = {
+const struct nla_policy ethnl_strset_get_policy[ETHTOOL_A_STRSET_MAX + 1] = {
        [ETHTOOL_A_STRSET_UNSPEC]       = { .type = NLA_REJECT },
        [ETHTOOL_A_STRSET_HEADER]       = { .type = NLA_NESTED },
        [ETHTOOL_A_STRSET_STRINGSETS]   = { .type = NLA_NESTED },
        .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,
 
 #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] = {
+const struct nla_policy ethnl_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 },
        .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,
 
 #include "common.h"
 #include "netlink.h"
 
-static const struct nla_policy
-ethtool_tunnel_info_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = {
+const struct nla_policy
+ethnl_tunnel_info_get_policy[ETHTOOL_A_TUNNEL_INFO_MAX + 1] = {
        [ETHTOOL_A_TUNNEL_INFO_UNSPEC]          = { .type = NLA_REJECT },
        [ETHTOOL_A_TUNNEL_INFO_HEADER]          = { .type = NLA_NESTED },
 };
        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;
 
 
 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;
 
 #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] = {
+const struct nla_policy ethnl_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 },
        .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,