diff options
-rw-r--r-- | include/net/cfg80211.h | 3 | ||||
-rw-r--r-- | include/uapi/linux/nl80211.h | 16 | ||||
-rw-r--r-- | net/wireless/nl80211.c | 31 |
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 | ||
6615 | static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq, | 6615 | static 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 | ||
6674 | static int nl80211_dump_survey(struct sk_buff *skb, | 6680 | static 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 | } |