static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
				       struct netlink_callback *cb,
				       struct cfg80211_registered_device **rdev,
				       struct wireless_dev **wdev)
{
	struct nlattr **attrbuf;
	u32 vid, subcmd;
	unsigned int i;
	int vcmd_idx = -1;
	int err;
	void *data = NULL;
	unsigned int data_len = 0;

	if (cb->args[0]) {
		/* subtract the 1 again here */
		struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
		struct wireless_dev *tmp;

		if (!wiphy)
			return -ENODEV;
		*rdev = wiphy_to_rdev(wiphy);
		*wdev = NULL;

		if (cb->args[1]) {
			list_for_each_entry(tmp, &wiphy->wdev_list, list) {
				if (tmp->identifier == cb->args[1] - 1) {
					*wdev = tmp;
					break;
				}
			}
		}

		/* keep rtnl locked in successful case */
		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)
		goto out;

	if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
	    !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)) {
		err = PTR_ERR(*rdev);
		goto out;
	}

	vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
	subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);

	for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
		const struct wiphy_vendor_command *vcmd;

		vcmd = &(*rdev)->wiphy.vendor_commands[i];

		if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
			continue;

		if (!vcmd->dumpit) {
			err = -EOPNOTSUPP;
			goto out;
		}

		vcmd_idx = i;
		break;
	}

	if (vcmd_idx < 0) {
		err = -EOPNOTSUPP;
		goto out;
	}

	if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
		data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
		data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);

		err = nl80211_vendor_check_policy(
				&(*rdev)->wiphy.vendor_commands[vcmd_idx],
				attrbuf[NL80211_ATTR_VENDOR_DATA],
				cb->extack);
		if (err)
			goto out;
	}

	/* 0 is the first index - add 1 to parse only once */
	cb->args[0] = (*rdev)->wiphy_idx + 1;
	/* add 1 to know if it was NULL */
	cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
	cb->args[2] = vcmd_idx;
	cb->args[3] = (unsigned long)data;
	cb->args[4] = data_len;

	/* keep rtnl locked in successful case */
	err = 0;
out:
	kfree(attrbuf);
	return err;
}
static int nl80211_prepare_vendor_dump(struct sk_buff *skb,
				       struct netlink_callback *cb,
				       struct cfg80211_registered_device **rdev,
				       struct wireless_dev **wdev)
{
	struct nlattr **attrbuf;
	u32 vid, subcmd;
	unsigned int i;
	int vcmd_idx = -1;
	int err;
	void *data = NULL;
	unsigned int data_len = 0;

	if (cb->args[0]) {
		 
		struct wiphy *wiphy = wiphy_idx_to_wiphy(cb->args[0] - 1);
		struct wireless_dev *tmp;

		if (!wiphy)
			return -ENODEV;
		*rdev = wiphy_to_rdev(wiphy);
		*wdev = NULL;

		if (cb->args[1]) {
			list_for_each_entry(tmp, &wiphy->wdev_list, list) {
				if (tmp->identifier == cb->args[1] - 1) {
					*wdev = tmp;
					break;
				}
			}
		}

		 
		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)
		goto out;

	if (!attrbuf[NL80211_ATTR_VENDOR_ID] ||
	    !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)) {
		err = PTR_ERR(*rdev);
		goto out;
	}

	vid = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_ID]);
	subcmd = nla_get_u32(attrbuf[NL80211_ATTR_VENDOR_SUBCMD]);

	for (i = 0; i < (*rdev)->wiphy.n_vendor_commands; i++) {
		const struct wiphy_vendor_command *vcmd;

		vcmd = &(*rdev)->wiphy.vendor_commands[i];

		if (vcmd->info.vendor_id != vid || vcmd->info.subcmd != subcmd)
			continue;

		if (!vcmd->dumpit) {
			err = -EOPNOTSUPP;
			goto out;
		}

		vcmd_idx = i;
		break;
	}

	if (vcmd_idx < 0) {
		err = -EOPNOTSUPP;
		goto out;
	}

	if (attrbuf[NL80211_ATTR_VENDOR_DATA]) {
		data = nla_data(attrbuf[NL80211_ATTR_VENDOR_DATA]);
		data_len = nla_len(attrbuf[NL80211_ATTR_VENDOR_DATA]);

		err = nl80211_vendor_check_policy(
				&(*rdev)->wiphy.vendor_commands[vcmd_idx],
				attrbuf[NL80211_ATTR_VENDOR_DATA],
				cb->extack);
		if (err)
			goto out;
	}

	 
	cb->args[0] = (*rdev)->wiphy_idx + 1;
	 
	cb->args[1] = *wdev ? (*wdev)->identifier + 1 : 0;
	cb->args[2] = vcmd_idx;
	cb->args[3] = (unsigned long)data;
	cb->args[4] = data_len;

	 
	err = 0;
out:
	kfree(attrbuf);
	return err;
}