Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 61fa713c authored by Holger Schurig's avatar Holger Schurig Committed by John W. Linville
Browse files

cfg80211: return channel noise via survey API



This patch implements the NL80211_CMD_GET_SURVEY command and an get_survey()
ops that a driver can implement. The goal of this command is to allow a
drivers to report channel survey data (e.g. channel noise, channel
occupation).

For now, only the mechanism to report back channel noise has been
implemented.

In future, there will either be a survey-trigger command --- or the existing
scan-trigger command will be enhanced. This will allow user-space to
request survey for arbitrary channels.

Note: any driver that cannot report channel noise should not report
any value at all, e.g. made-up -92 dBm.

Signed-off-by: default avatarHolger Schurig <holgerschurig@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent a043897a
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -160,6 +160,11 @@
 * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
 *	partial scan results may be available
 *
 * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
 *      or noise level
 * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
 *	NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
 *
 * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
 * 	has been changed and provides details of the request information
 * 	that caused the change such as who initiated the regulatory request
@@ -341,6 +346,9 @@ enum nl80211_commands {

	NL80211_CMD_SET_WIPHY_NETNS,

	NL80211_CMD_GET_SURVEY,
	NL80211_CMD_NEW_SURVEY_RESULTS,

	/* add new commands above here */

	/* used to define NL80211_CMD_MAX below */
@@ -586,6 +594,10 @@ enum nl80211_commands {
 *
 * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
 *
 * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of
 *      the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
 *      containing info as possible, see &enum survey_info.
 *
 * @NL80211_ATTR_MAX: highest attribute number currently defined
 * @__NL80211_ATTR_AFTER_LAST: internal use
 */
@@ -718,6 +730,8 @@ enum nl80211_attrs {

	NL80211_ATTR_4ADDR,

	NL80211_ATTR_SURVEY_INFO,

	/* add attributes here, update the policy in nl80211.c */

	__NL80211_ATTR_AFTER_LAST,
@@ -1120,6 +1134,26 @@ enum nl80211_reg_rule_flags {
	NL80211_RRF_NO_IBSS		= 1<<8,
};

/**
 * enum nl80211_survey_info - survey information
 *
 * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
 * when getting information about a survey.
 *
 * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
 * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
 * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
 */
enum nl80211_survey_info {
	__NL80211_SURVEY_INFO_INVALID,
	NL80211_SURVEY_INFO_FREQUENCY,
	NL80211_SURVEY_INFO_NOISE,

	/* keep last */
	__NL80211_SURVEY_INFO_AFTER_LAST,
	NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
};

/**
 * enum nl80211_mntr_flags - monitor configuration flags
 *
+34 −0
Original line number Diff line number Diff line
@@ -234,6 +234,35 @@ struct key_params {
	u32 cipher;
};

/**
 * enum survey_info_flags - survey information flags
 *
 * Used by the driver to indicate which info in &struct survey_info
 * it has filled in during the get_survey().
 */
enum survey_info_flags {
	SURVEY_INFO_NOISE_DBM = 1<<0,
};

/**
 * struct survey_info - channel survey response
 *
 * Used by dump_survey() to report back per-channel survey information.
 *
 * @channel: the channel this survey record reports, mandatory
 * @filled: bitflag of flags from &enum survey_info_flags
 * @noise: channel noise in dBm. This and all following fields are
 *     optional
 *
 * This structure can later be expanded with things like
 * channel duty cycle etc.
 */
struct survey_info {
	struct ieee80211_channel *channel;
	u32 filled;
	s8 noise;
};

/**
 * struct beacon_parameters - beacon parameters
 *
@@ -944,6 +973,8 @@ struct cfg80211_bitrate_mask {
 * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting
 *	functions to adjust rfkill hw state
 *
 * @dump_survey: get site survey information.
 *
 * @testmode_cmd: run a test mode command
 */
struct cfg80211_ops {
@@ -1063,6 +1094,9 @@ struct cfg80211_ops {
				    const u8 *peer,
				    const struct cfg80211_bitrate_mask *mask);

	int	(*dump_survey)(struct wiphy *wiphy, struct net_device *netdev,
			int idx, struct survey_info *info);

	/* some temporary stuff to finish wext */
	int	(*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
				  bool enabled, int timeout);
+105 −0
Original line number Diff line number Diff line
@@ -3245,6 +3245,106 @@ static int nl80211_dump_scan(struct sk_buff *skb,
	return err;
}

static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
				int flags, struct net_device *dev,
				struct survey_info *survey)
{
	void *hdr;
	struct nlattr *infoattr;

	/* Survey without a channel doesn't make sense */
	if (!survey->channel)
		return -EINVAL;

	hdr = nl80211hdr_put(msg, pid, seq, flags,
			     NL80211_CMD_NEW_SURVEY_RESULTS);
	if (!hdr)
		return -ENOMEM;

	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex);

	infoattr = nla_nest_start(msg, NL80211_ATTR_SURVEY_INFO);
	if (!infoattr)
		goto nla_put_failure;

	NLA_PUT_U32(msg, NL80211_SURVEY_INFO_FREQUENCY,
		    survey->channel->center_freq);
	if (survey->filled & SURVEY_INFO_NOISE_DBM)
		NLA_PUT_U8(msg, NL80211_SURVEY_INFO_NOISE,
			    survey->noise);

	nla_nest_end(msg, infoattr);

	return genlmsg_end(msg, hdr);

 nla_put_failure:
	genlmsg_cancel(msg, hdr);
	return -EMSGSIZE;
}

static int nl80211_dump_survey(struct sk_buff *skb,
			struct netlink_callback *cb)
{
	struct survey_info survey;
	struct cfg80211_registered_device *dev;
	struct net_device *netdev;
	int ifidx = cb->args[0];
	int survey_idx = cb->args[1];
	int res;

	if (!ifidx)
		ifidx = nl80211_get_ifidx(cb);
	if (ifidx < 0)
		return ifidx;
	cb->args[0] = ifidx;

	rtnl_lock();

	netdev = __dev_get_by_index(sock_net(skb->sk), ifidx);
	if (!netdev) {
		res = -ENODEV;
		goto out_rtnl;
	}

	dev = cfg80211_get_dev_from_ifindex(sock_net(skb->sk), ifidx);
	if (IS_ERR(dev)) {
		res = PTR_ERR(dev);
		goto out_rtnl;
	}

	if (!dev->ops->dump_survey) {
		res = -EOPNOTSUPP;
		goto out_err;
	}

	while (1) {
		res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
					    &survey);
		if (res == -ENOENT)
			break;
		if (res)
			goto out_err;

		if (nl80211_send_survey(skb,
				NETLINK_CB(cb->skb).pid,
				cb->nlh->nlmsg_seq, NLM_F_MULTI,
				netdev,
				&survey) < 0)
			goto out;
		survey_idx++;
	}

 out:
	cb->args[1] = survey_idx;
	res = skb->len;
 out_err:
	cfg80211_unlock_rdev(dev);
 out_rtnl:
	rtnl_unlock();

	return res;
}

static bool nl80211_valid_auth_type(enum nl80211_auth_type auth_type)
{
	return auth_type <= NL80211_AUTHTYPE_MAX;
@@ -4322,6 +4422,11 @@ static struct genl_ops nl80211_ops[] = {
		.policy = nl80211_policy,
		.flags = GENL_ADMIN_PERM,
	},
	{
		.cmd = NL80211_CMD_GET_SURVEY,
		.policy = nl80211_policy,
		.dumpit = nl80211_dump_survey,
	},
};
static struct genl_multicast_group nl80211_mlme_mcgrp = {
	.name = "mlme",