int err;
 
        if (!cb->args[0]) {
+               struct nlattr **attrbuf;
+
+               attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
+                                 GFP_KERNEL);
+               if (!attrbuf)
+                       return -ENOMEM;
+
                err = nlmsg_parse_deprecated(cb->nlh,
                                             GENL_HDRLEN + nl80211_fam.hdrsize,
-                                            genl_family_attrbuf(&nl80211_fam),
-                                            nl80211_fam.maxattr,
+                                            attrbuf, nl80211_fam.maxattr,
                                             nl80211_policy, NULL);
-               if (err)
+               if (err) {
+                       kfree(attrbuf);
                        return err;
+               }
 
-               *wdev = __cfg80211_wdev_from_attrs(
-                                       sock_net(cb->skb->sk),
-                                       genl_family_attrbuf(&nl80211_fam));
+               *wdev = __cfg80211_wdev_from_attrs(sock_net(cb->skb->sk),
+                                                  attrbuf);
+               kfree(attrbuf);
                if (IS_ERR(*wdev))
                        return PTR_ERR(*wdev);
                *rdev = wiphy_to_rdev((*wdev)->wiphy);
                                    struct netlink_callback *cb,
                                    struct nl80211_dump_wiphy_state *state)
 {
-       struct nlattr **tb = genl_family_attrbuf(&nl80211_fam);
-       int ret = nlmsg_parse_deprecated(cb->nlh,
-                                        GENL_HDRLEN + nl80211_fam.hdrsize,
-                                        tb, nl80211_fam.maxattr,
-                                        nl80211_policy, NULL);
+       struct nlattr **tb = kcalloc(NUM_NL80211_ATTR, sizeof(*tb), GFP_KERNEL);
+       int ret;
+
+       if (!tb)
+               return -ENOMEM;
+
+       ret = nlmsg_parse_deprecated(cb->nlh,
+                                    GENL_HDRLEN + nl80211_fam.hdrsize,
+                                    tb, nl80211_fam.maxattr,
+                                    nl80211_policy, NULL);
        /* ignore parse errors for backward compatibility */
-       if (ret)
-               return 0;
+       if (ret) {
+               ret = 0;
+               goto out;
+       }
 
        state->split = tb[NL80211_ATTR_SPLIT_WIPHY_DUMP];
        if (tb[NL80211_ATTR_WIPHY])
                int ifidx = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
 
                netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
-               if (!netdev)
-                       return -ENODEV;
+               if (!netdev) {
+                       ret = -ENODEV;
+                       goto out;
+               }
                if (netdev->ieee80211_ptr) {
                        rdev = wiphy_to_rdev(
                                netdev->ieee80211_ptr->wiphy);
                }
        }
 
-       return 0;
+       ret = 0;
+out:
+       kfree(tb);
+       return ret;
 }
 
 static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
 
 static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
 {
-       struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
+       struct nlattr **attrbuf;
        struct survey_info survey;
        struct cfg80211_registered_device *rdev;
        struct wireless_dev *wdev;
        int res;
        bool radio_stats;
 
+       attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
+       if (!attrbuf)
+               return -ENOMEM;
+
        rtnl_lock();
        res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
        if (res)
        cb->args[2] = survey_idx;
        res = skb->len;
  out_err:
+       kfree(attrbuf);
        rtnl_unlock();
        return res;
 }
                                 struct netlink_callback *cb)
 {
        struct cfg80211_registered_device *rdev;
+       struct nlattr **attrbuf = NULL;
        int err;
        long phy_idx;
        void *data = NULL;
                        goto out_err;
                }
        } else {
-               struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
+               attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
+                                 GFP_KERNEL);
+               if (!attrbuf) {
+                       err = -ENOMEM;
+                       goto out_err;
+               }
 
                err = nlmsg_parse_deprecated(cb->nlh,
                                             GENL_HDRLEN + nl80211_fam.hdrsize,
        /* see above */
        cb->args[0] = phy_idx + 1;
  out_err:
+       kfree(attrbuf);
        rtnl_unlock();
        return err;
 }
                                       struct cfg80211_registered_device **rdev,
                                       struct wireless_dev **wdev)
 {
-       struct nlattr **attrbuf = genl_family_attrbuf(&nl80211_fam);
+       struct nlattr **attrbuf;
        u32 vid, subcmd;
        unsigned int i;
        int vcmd_idx = -1;
                return 0;
        }
 
+       attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf), GFP_KERNEL);
+       if (!attrbuf)
+               return -ENOMEM;
+
        err = nlmsg_parse_deprecated(cb->nlh,
                                     GENL_HDRLEN + nl80211_fam.hdrsize,
                                     attrbuf, nl80211_fam.maxattr,
                                     nl80211_policy, NULL);
        if (err)
-               return err;
+               goto out;
 
        if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
-           !attrbuf[NL80211_ATTR_VENDOR_SUBCMD])
-               return -EINVAL;
+           !attrbuf[NL80211_ATTR_VENDOR_SUBCMD]) {
+               err = -EINVAL;
+               goto out;
+       }
 
        *wdev = __cfg80211_wdev_from_attrs(sock_net(skb->sk), attrbuf);
        if (IS_ERR(*wdev))
                *wdev = NULL;
 
        *rdev = __cfg80211_rdev_from_attrs(sock_net(skb->sk), attrbuf);
-       if (IS_ERR(*rdev))
-               return PTR_ERR(*rdev);
+       if (IS_ERR(*rdev)) {
+               err = PTR_ERR(*rdev);
+               goto out;
+       }
 
        vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
        subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);
                if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
                        continue;
 
-               if (!vcmd->dumpit)
-                       return -EOPNOTSUPP;
+               if (!vcmd->dumpit) {
+                       err = -EOPNOTSUPP;
+                       goto out;
+               }
 
                vcmd_idx = i;
                break;
        }
 
-       if (vcmd_idx < 0)
-               return -EOPNOTSUPP;
+       if (vcmd_idx < 0) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
 
        if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
                data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
                                attrbuf[NL80211_ATTR_VENDOR_DATA],
                                cb->extack);
                if (err)
-                       return err;
+                       goto out;
        }
 
        /* 0 is the first index - add 1 to parse only once */
        cb->args[4] = data_len;
 
        /* keep rtnl locked in successful case */
-       return 0;
+       err = 0;
+out:
+       kfree(attrbuf);
+       return err;
 }
 
 static int nl80211_vendor_cmd_dump(struct sk_buff *skb,
        .n_ops = ARRAY_SIZE(nl80211_ops),
        .mcgrps = nl80211_mcgrps,
        .n_mcgrps = ARRAY_SIZE(nl80211_mcgrps),
+       .parallel_ops = true,
 };
 
 /* notification functions */