Commit 11f78ac3 authored by Johannes Berg's avatar Johannes Berg

cfg80211: allow survey data to return global data

Not all devices are able to report survey data (particularly
time spent for various operations) per channel. As all these
statistics already exist in survey data, allow such devices
to report them (if userspace requested it)
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 4ed20beb
...@@ -542,7 +542,8 @@ enum survey_info_flags { ...@@ -542,7 +542,8 @@ enum survey_info_flags {
/** /**
* struct survey_info - channel survey response * struct survey_info - channel survey response
* *
* @channel: the channel this survey record reports, mandatory * @channel: the channel this survey record reports, may be %NULL for a single
* record to report global statistics
* @filled: bitflag of flags from &enum survey_info_flags * @filled: bitflag of flags from &enum survey_info_flags
* @noise: channel noise in dBm. This and all following fields are * @noise: channel noise in dBm. This and all following fields are
* optional * optional
......
...@@ -1727,6 +1727,14 @@ enum nl80211_commands { ...@@ -1727,6 +1727,14 @@ enum nl80211_commands {
* is located at bit 0 of byte 0. bit index 25 would be located at bit 1 * is located at bit 0 of byte 0. bit index 25 would be located at bit 1
* of byte 3 (u8 array). * of byte 3 (u8 array).
* *
* @NL80211_ATTR_SURVEY_RADIO_STATS: Request overall radio statistics to be
* returned along with other survey data. If set, @NL80211_CMD_GET_SURVEY
* may return a survey entry without a channel indicating global radio
* statistics (only some values are valid and make sense.)
* For devices that don't return such an entry even then, the information
* should be contained in the result as the sum of the respective counters
* over all channels.
*
* @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined * @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use * @__NL80211_ATTR_AFTER_LAST: internal use
...@@ -2088,6 +2096,8 @@ enum nl80211_attrs { ...@@ -2088,6 +2096,8 @@ enum nl80211_attrs {
NL80211_ATTR_EXT_FEATURES, NL80211_ATTR_EXT_FEATURES,
NL80211_ATTR_SURVEY_RADIO_STATS,
/* add attributes here, update the policy in nl80211.c */ /* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST, __NL80211_ATTR_AFTER_LAST,
...@@ -2816,15 +2826,15 @@ enum nl80211_user_reg_hint_type { ...@@ -2816,15 +2826,15 @@ enum nl80211_user_reg_hint_type {
* @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
* @NL80211_SURVEY_INFO_IN_USE: channel is currently being used * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
* @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio * @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio
* spent on this channel * was turned on (on channel or globally)
* @NL80211_SURVEY_INFO_TIME_BUSY: amount of the time the primary * @NL80211_SURVEY_INFO_TIME_BUSY: amount of the time the primary
* channel was sensed busy (either due to activity or energy detect) * channel was sensed busy (either due to activity or energy detect)
* @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension
* channel was sensed busy * channel was sensed busy
* @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent * @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent
* receiving data * receiving data (on channel or globally)
* @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent * @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent
* transmitting data * transmitting data (on channel or globally)
* @NL80211_SURVEY_INFO_MAX: highest survey info attribute number * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
* currently defined * currently defined
* @__NL80211_SURVEY_INFO_AFTER_LAST: internal use * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
......
...@@ -6614,11 +6614,16 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -6614,11 +6614,16 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
int flags, struct net_device *dev, int flags, struct net_device *dev,
bool allow_radio_stats,
struct survey_info *survey) struct survey_info *survey)
{ {
void *hdr; void *hdr;
struct nlattr *infoattr; struct nlattr *infoattr;
/* skip radio stats if userspace didn't request them */
if (!survey->channel && !allow_radio_stats)
return 0;
hdr = nl80211hdr_put(msg, portid, seq, flags, hdr = nl80211hdr_put(msg, portid, seq, flags,
NL80211_CMD_NEW_SURVEY_RESULTS); NL80211_CMD_NEW_SURVEY_RESULTS);
if (!hdr) if (!hdr)
...@@ -6631,7 +6636,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, ...@@ -6631,7 +6636,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
if (!infoattr) if (!infoattr)
goto nla_put_failure; goto nla_put_failure;
if (nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY, if (survey->channel &&
nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
survey->channel->center_freq)) survey->channel->center_freq))
goto nla_put_failure; goto nla_put_failure;
...@@ -6671,19 +6677,22 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, ...@@ -6671,19 +6677,22 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
return -EMSGSIZE; return -EMSGSIZE;
} }
static int nl80211_dump_survey(struct sk_buff *skb, static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
struct netlink_callback *cb)
{ {
struct survey_info survey; struct survey_info survey;
struct cfg80211_registered_device *rdev; struct cfg80211_registered_device *rdev;
struct wireless_dev *wdev; struct wireless_dev *wdev;
int survey_idx = cb->args[2]; int survey_idx = cb->args[2];
int res; int res;
bool radio_stats;
res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
if (res) if (res)
return res; return res;
/* prepare_wdev_dump parsed the attributes */
radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
if (!wdev->netdev) { if (!wdev->netdev) {
res = -EINVAL; res = -EINVAL;
goto out_err; goto out_err;
...@@ -6701,13 +6710,9 @@ static int nl80211_dump_survey(struct sk_buff *skb, ...@@ -6701,13 +6710,9 @@ static int nl80211_dump_survey(struct sk_buff *skb,
if (res) if (res)
goto out_err; goto out_err;
/* Survey without a channel doesn't make sense */ /* don't send disabled channels, but do send non-channel data */
if (!survey.channel) { if (survey.channel &&
res = -EINVAL; survey.channel->flags & IEEE80211_CHAN_DISABLED) {
goto out;
}
if (survey.channel->flags & IEEE80211_CHAN_DISABLED) {
survey_idx++; survey_idx++;
continue; continue;
} }
...@@ -6715,7 +6720,7 @@ static int nl80211_dump_survey(struct sk_buff *skb, ...@@ -6715,7 +6720,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
if (nl80211_send_survey(skb, if (nl80211_send_survey(skb,
NETLINK_CB(cb->skb).portid, NETLINK_CB(cb->skb).portid,
cb->nlh->nlmsg_seq, NLM_F_MULTI, cb->nlh->nlmsg_seq, NLM_F_MULTI,
wdev->netdev, &survey) < 0) wdev->netdev, radio_stats, &survey) < 0)
goto out; goto out;
survey_idx++; survey_idx++;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment