Commit ce6b6974 authored by Johannes Berg's avatar Johannes Berg
Browse files

nl80211: fix radio statistics in survey dump



Even if userspace specifies the NL80211_ATTR_SURVEY_RADIO_STATS
attribute, we cannot get the statistics because we're not really
parsing the incoming attributes properly any more.

Fix this by passing the attrbuf to nl80211_prepare_wdev_dump()
and filling it there, if given, and using a local version only
if no output is desired.

Since I'm touching it anyway, make nl80211_prepare_wdev_dump()
static.

Fixes: 50508d94 ("cfg80211: use parallel_ops for genl")
Reported-by: default avatarJan Fuchs <jf@simonwunderlich.de>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Tested-by: default avatarSven Eckelmann <sven@narfation.org>
Link: https://lore.kernel.org/r/20211029092539.2851b4799386.If9736d4575ee79420cbec1bd930181e1d53c7317@changeid


Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 563fbefe
Loading
Loading
Loading
Loading
+19 −15
Original line number Diff line number Diff line
@@ -936,33 +936,37 @@ nl80211_packet_pattern_policy[MAX_NL80211_PKTPAT + 1] = {
	[NL80211_PKTPAT_OFFSET] = { .type = NLA_U32 },
};

int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
static int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
				     struct cfg80211_registered_device **rdev,
			      struct wireless_dev **wdev)
				     struct wireless_dev **wdev,
				     struct nlattr **attrbuf)
{
	int err;

	if (!cb->args[0]) {
		struct nlattr **attrbuf;
		struct nlattr **attrbuf_free = NULL;

		if (!attrbuf) {
			attrbuf = kcalloc(NUM_NL80211_ATTR, sizeof(*attrbuf),
					  GFP_KERNEL);
			if (!attrbuf)
				return -ENOMEM;
			attrbuf_free = attrbuf;
		}

		err = nlmsg_parse_deprecated(cb->nlh,
					     GENL_HDRLEN + nl80211_fam.hdrsize,
					     attrbuf, nl80211_fam.maxattr,
					     nl80211_policy, NULL);
		if (err) {
			kfree(attrbuf);
			kfree(attrbuf_free);
			return err;
		}

		rtnl_lock();
		*wdev = __cfg80211_wdev_from_attrs(NULL, sock_net(cb->skb->sk),
						   attrbuf);
		kfree(attrbuf);
		kfree(attrbuf_free);
		if (IS_ERR(*wdev)) {
			rtnl_unlock();
			return PTR_ERR(*wdev);
@@ -6197,7 +6201,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
	int sta_idx = cb->args[2];
	int err;

	err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
	err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
	if (err)
		return err;
	/* nl80211_prepare_wdev_dump acquired it in the successful case */
@@ -7092,7 +7096,7 @@ static int nl80211_dump_mpath(struct sk_buff *skb,
	int path_idx = cb->args[2];
	int err;

	err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
	err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
	if (err)
		return err;
	/* nl80211_prepare_wdev_dump acquired it in the successful case */
@@ -7292,7 +7296,7 @@ static int nl80211_dump_mpp(struct sk_buff *skb,
	int path_idx = cb->args[2];
	int err;

	err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
	err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
	if (err)
		return err;
	/* nl80211_prepare_wdev_dump acquired it in the successful case */
@@ -9718,7 +9722,7 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
	int start = cb->args[2], idx = 0;
	int err;

	err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
	err = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, NULL);
	if (err)
		return err;
	/* nl80211_prepare_wdev_dump acquired it in the successful case */
@@ -9851,7 +9855,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
	if (!attrbuf)
		return -ENOMEM;

	res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev);
	res = nl80211_prepare_wdev_dump(cb, &rdev, &wdev, attrbuf);
	if (res) {
		kfree(attrbuf);
		return res;
+1 −5
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/*
 * Portions of this file
 * Copyright (C) 2018, 2020 Intel Corporation
 * Copyright (C) 2018, 2020-2021 Intel Corporation
 */
#ifndef __NET_WIRELESS_NL80211_H
#define __NET_WIRELESS_NL80211_H
@@ -22,10 +22,6 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
	       ((u64)wiphy_to_rdev(wdev->wiphy)->wiphy_idx << 32);
}

int nl80211_prepare_wdev_dump(struct netlink_callback *cb,
			      struct cfg80211_registered_device **rdev,
			      struct wireless_dev **wdev);

int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
			  struct genl_info *info,
			  struct cfg80211_chan_def *chandef);