*     is located at bit 0 of byte 0. bit index 25 would be located at bit 1
  *     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
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
 
        NL80211_ATTR_EXT_FEATURES,
 
+       NL80211_ATTR_SURVEY_RADIO_STATS,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
  * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
  * @NL80211_SURVEY_INFO_IN_USE: channel is currently being used
  * @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
  *     channel was sensed busy (either due to activity or energy detect)
  * @NL80211_SURVEY_INFO_TIME_EXT_BUSY: amount of time the extension
  *     channel was sensed busy
  * @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
- *     transmitting data
+ *     transmitting data (on channel or globally)
  * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number
  *     currently defined
  * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use
 
 }
 
 static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
-                               int flags, struct net_device *dev,
-                               struct survey_info *survey)
+                              int flags, struct net_device *dev,
+                              bool allow_radio_stats,
+                              struct survey_info *survey)
 {
        void *hdr;
        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,
                             NL80211_CMD_NEW_SURVEY_RESULTS);
        if (!hdr)
        if (!infoattr)
                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))
                goto nla_put_failure;
 
        return -EMSGSIZE;
 }
 
-static int nl80211_dump_survey(struct sk_buff *skb,
-                       struct netlink_callback *cb)
+static int nl80211_dump_survey(struct sk_buff *skb, struct netlink_callback *cb)
 {
        struct survey_info survey;
        struct cfg80211_registered_device *rdev;
        struct wireless_dev *wdev;
        int survey_idx = cb->args[2];
        int res;
+       bool radio_stats;
 
        res = nl80211_prepare_wdev_dump(skb, cb, &rdev, &wdev);
        if (res)
                return res;
 
+       /* prepare_wdev_dump parsed the attributes */
+       radio_stats = nl80211_fam.attrbuf[NL80211_ATTR_SURVEY_RADIO_STATS];
+
        if (!wdev->netdev) {
                res = -EINVAL;
                goto out_err;
                if (res)
                        goto out_err;
 
-               /* Survey without a channel doesn't make sense */
-               if (!survey.channel) {
-                       res = -EINVAL;
-                       goto out;
-               }
-
-               if (survey.channel->flags & IEEE80211_CHAN_DISABLED) {
+               /* don't send disabled channels, but do send non-channel data */
+               if (survey.channel &&
+                   survey.channel->flags & IEEE80211_CHAN_DISABLED) {
                        survey_idx++;
                        continue;
                }
                if (nl80211_send_survey(skb,
                                NETLINK_CB(cb->skb).portid,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
-                               wdev->netdev, &survey) < 0)
+                               wdev->netdev, radio_stats, &survey) < 0)
                        goto out;
                survey_idx++;
        }