aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/cfg80211.h3
-rw-r--r--include/uapi/linux/nl80211.h16
-rw-r--r--net/wireless/nl80211.c31
3 files changed, 33 insertions, 17 deletions
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 3b489f8fc4cd..5a861440c122 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -542,7 +542,8 @@ enum survey_info_flags {
542/** 542/**
543 * struct survey_info - channel survey response 543 * struct survey_info - channel survey response
544 * 544 *
545 * @channel: the channel this survey record reports, mandatory 545 * @channel: the channel this survey record reports, may be %NULL for a single
546 * record to report global statistics
546 * @filled: bitflag of flags from &enum survey_info_flags 547 * @filled: bitflag of flags from &enum survey_info_flags
547 * @noise: channel noise in dBm. This and all following fields are 548 * @noise: channel noise in dBm. This and all following fields are
548 * optional 549 * optional
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 1a5acc80ab88..5e8b65f239a5 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -1727,6 +1727,14 @@ enum nl80211_commands {
1727 * is located at bit 0 of byte 0. bit index 25 would be located at bit 1 1727 * is located at bit 0 of byte 0. bit index 25 would be located at bit 1
1728 * of byte 3 (u8 array). 1728 * of byte 3 (u8 array).
1729 * 1729 *
1730 * @NL80211_ATTR_SURVEY_RADIO_STATS: Request overall radio statistics to be
1731 * returned along with other survey data. If set, @NL80211_CMD_GET_SURVEY
1732 * may return a survey entry without a channel indicating global radio
1733 * statistics (only some values are valid and make sense.)
1734 * For devices that don't return such an entry even then, the information
1735 * should be contained in the result as the sum of the respective counters
1736 * over all channels.
1737 *
1730 * @NUM_NL80211_ATTR: total number of nl80211_attrs available 1738 * @NUM_NL80211_ATTR: total number of nl80211_attrs available
1731 * @NL80211_ATTR_MAX: highest attribute number currently defined 1739 * @NL80211_ATTR_MAX: highest attribute number currently defined
1732 * @__NL80211_ATTR_AFTER_LAST: internal use 1740 * @__NL80211_ATTR_AFTER_LAST: internal use
@@ -2088,6 +2096,8 @@ enum nl80211_attrs {
2088 2096
2089 NL80211_ATTR_EXT_FEATURES, 2097 NL80211_ATTR_EXT_FEATURES,
2090 2098
2099 NL80211_ATTR_SURVEY_RADIO_STATS,
2100
2091 /* add attributes here, update the policy in nl80211.c */ 2101 /* add attributes here, update the policy in nl80211.c */
2092 2102
2093 __NL80211_ATTR_AFTER_LAST, 2103 __NL80211_ATTR_AFTER_LAST,
@@ -2816,15 +2826,15 @@ enum nl80211_user_reg_hint_type {
2816 * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm) 2826 * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
2817 * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used 2827 * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
2818 * @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio 2828 * @NL80211_SURVEY_INFO_TIME: amount of time (in ms) that the radio
2819 * spent on this channel 2829 * was turned on (on channel or globally)
2820 * @NL80211_SURVEY_INFO_TIME_BUSY: amount of the time the primary 2830 * @NL80211_SURVEY_INFO_TIME_BUSY: amount of the time the primary
2821 * channel was sensed busy (either due to activity or energy detect) 2831 * channel was sensed busy (either due to activity or energy detect)
2822 * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension 2832 * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension
2823 * channel was sensed busy 2833 * channel was sensed busy
2824 * @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent 2834 * @NL80211_SURVEY_INFO_TIME_RX: amount of time the radio spent
2825 * receiving data 2835 * receiving data (on channel or globally)
2826 * @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent 2836 * @NL80211_SURVEY_INFO_TIME_TX: amount of time the radio spent
2827 * transmitting data 2837 * transmitting data (on channel or globally)
2828 * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number 2838 * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
2829 * currently defined 2839 * currently defined
2830 * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use 2840 * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 94ab2014fefe..9555ef9fd99e 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -6613,12 +6613,17 @@ static int nl80211_dump_scan(struct sk_buff *skb, struct netlink_callback *cb)
6613} 6613}
6614 6614
6615static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, 6615static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
6616 int flags, struct net_device *dev, 6616 int flags, struct net_device *dev,
6617 struct survey_info *survey) 6617 bool allow_radio_stats,
6618 struct survey_info *survey)
6618{ 6619{
6619 void *hdr; 6620 void *hdr;
6620 struct nlattr *infoattr; 6621 struct nlattr *infoattr;
6621 6622
6623 /* skip radio stats if userspace didn't request them */
6624 if (!survey->channel && !allow_radio_stats)
6625 return 0;
6626
6622 hdr = nl80211hdr_put(msg, portid, seq, flags, 6627 hdr = nl80211hdr_put(msg, portid, seq, flags,
6623 NL80211_CMD_NEW_SURVEY_RESULTS); 6628 NL80211_CMD_NEW_SURVEY_RESULTS);
6624 if (!hdr) 6629 if (!hdr)
@@ -6631,7 +6636,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
6631 if (!infoattr) 6636 if (!infoattr)
6632 goto nla_put_failure; 6637 goto nla_put_failure;
6633 6638
6634 if (nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY, 6639 if (survey->channel &&
6640 nla_put_u32(msg, NL80211_SURVEY_INFO_FREQUENCY,
6635 survey->channel->center_freq)) 6641 survey->channel->center_freq))
6636 goto nla_put_failure; 6642 goto nla_put_failure;
6637 6643
@@ -6671,19 +6677,22 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
6671 return -EMSGSIZE; 6677 return -EMSGSIZE;
6672} 6678}
6673 6679
6674static int nl80211_dump_survey(struct sk_buff *skb, 6680static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
6675 struct netlink_callback *cb)
6676{ 6681{
6677 struct survey_info survey; 6682 struct survey_info survey;
6678 struct cfg80211_registered_device *rdev; 6683 struct cfg80211_registered_device *rdev;
6679 struct wireless_dev *wdev; 6684 struct wireless_dev *wdev;
6680 int survey_idx = cb->args[2]; 6685 int survey_idx = cb->args[2];
6681 int res; 6686 int res;
6687 bool radio_stats;
6682 6688
6683 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev); 6689 res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
6684 if (res) 6690 if (res)
6685 return res; 6691 return res;
6686 6692
6693 /* prepare_wdev_dump parsed the attributes */
6694 radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
6695
6687 if (!wdev->netdev) { 6696 if (!wdev->netdev) {
6688 res = -EINVAL; 6697 res = -EINVAL;
6689 goto out_err; 6698 goto out_err;
@@ -6701,13 +6710,9 @@ static int nl80211_dump_survey(struct sk_buff *skb,
6701 if (res) 6710 if (res)
6702 goto out_err; 6711 goto out_err;
6703 6712
6704 /* Survey without a channel doesn't make sense */ 6713 /* don't send disabled channels, but do send non-channel data */
6705 if (!survey.channel) { 6714 if (survey.channel &&
6706 res = -EINVAL; 6715 survey.channel->flags & IEEE80211_CHAN_DISABLED) {
6707 goto out;
6708 }
6709
6710 if (survey.channel->flags & IEEE80211_CHAN_DISABLED) {
6711 survey_idx++; 6716 survey_idx++;
6712 continue; 6717 continue;
6713 } 6718 }
@@ -6715,7 +6720,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
6715 if (nl80211_send_survey(skb, 6720 if (nl80211_send_survey(skb,
6716 NETLINK_CB(cb->skb).portid, 6721 NETLINK_CB(cb->skb).portid,
6717 cb->nlh->nlmsg_seq, NLM_F_MULTI, 6722 cb->nlh->nlmsg_seq, NLM_F_MULTI,
6718 wdev->netdev, &survey) < 0) 6723 wdev->netdev, radio_stats, &survey) < 0)
6719 goto out; 6724 goto out;
6720 survey_idx++; 6725 survey_idx++;
6721 } 6726 }