Merge tag 'mac80211-next-for-davem-2015-01-19' of git://git.kernel.org/pub/scm/linux...
[cascardo/linux.git] / net / wireless / nl80211.c
index 7029201..4fc812f 100644 (file)
@@ -59,13 +59,13 @@ enum nl80211_multicast_groups {
 };
 
 static const struct genl_multicast_group nl80211_mcgrps[] = {
-       [NL80211_MCGRP_CONFIG] = { .name = "config", },
-       [NL80211_MCGRP_SCAN] = { .name = "scan", },
-       [NL80211_MCGRP_REGULATORY] = { .name = "regulatory", },
-       [NL80211_MCGRP_MLME] = { .name = "mlme", },
-       [NL80211_MCGRP_VENDOR] = { .name = "vendor", },
+       [NL80211_MCGRP_CONFIG] = { .name = NL80211_MULTICAST_GROUP_CONFIG },
+       [NL80211_MCGRP_SCAN] = { .name = NL80211_MULTICAST_GROUP_SCAN },
+       [NL80211_MCGRP_REGULATORY] = { .name = NL80211_MULTICAST_GROUP_REG },
+       [NL80211_MCGRP_MLME] = { .name = NL80211_MULTICAST_GROUP_MLME },
+       [NL80211_MCGRP_VENDOR] = { .name = NL80211_MULTICAST_GROUP_VENDOR },
 #ifdef CONFIG_NL80211_TESTMODE
-       [NL80211_MCGRP_TESTMODE] = { .name = "testmode", }
+       [NL80211_MCGRP_TESTMODE] = { .name = NL80211_MULTICAST_GROUP_TESTMODE }
 #endif
 };
 
@@ -1088,6 +1088,11 @@ static int nl80211_send_wowlan(struct sk_buff *msg,
                        return -ENOBUFS;
        }
 
+       if ((rdev->wiphy.wowlan->flags & WIPHY_WOWLAN_NET_DETECT) &&
+           nla_put_u32(msg, NL80211_WOWLAN_TRIG_NET_DETECT,
+                       rdev->wiphy.wowlan->max_nd_match_sets))
+               return -ENOBUFS;
+
        if (large && nl80211_send_wowlan_tcp_caps(rdev, msg))
                return -ENOBUFS;
 
@@ -1706,12 +1711,18 @@ static int nl80211_send_wiphy(struct cfg80211_registered_device *rdev,
                    nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
                        goto nla_put_failure;
 
+               if (nla_put(msg, NL80211_ATTR_EXT_FEATURES,
+                           sizeof(rdev->wiphy.ext_features),
+                           rdev->wiphy.ext_features))
+                       goto nla_put_failure;
+
                /* done */
                state->split_start = 0;
                break;
        }
  finish:
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -2394,7 +2405,8 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
                        goto nla_put_failure;
        }
 
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -3568,6 +3580,7 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
        struct nlattr *rate;
        u32 bitrate;
        u16 bitrate_compat;
+       enum nl80211_attrs rate_flg;
 
        rate = nla_nest_start(msg, attr);
        if (!rate)
@@ -3584,12 +3597,36 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
            nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
                return false;
 
+       switch (info->bw) {
+       case RATE_INFO_BW_5:
+               rate_flg = NL80211_RATE_INFO_5_MHZ_WIDTH;
+               break;
+       case RATE_INFO_BW_10:
+               rate_flg = NL80211_RATE_INFO_10_MHZ_WIDTH;
+               break;
+       default:
+               WARN_ON(1);
+               /* fall through */
+       case RATE_INFO_BW_20:
+               rate_flg = 0;
+               break;
+       case RATE_INFO_BW_40:
+               rate_flg = NL80211_RATE_INFO_40_MHZ_WIDTH;
+               break;
+       case RATE_INFO_BW_80:
+               rate_flg = NL80211_RATE_INFO_80_MHZ_WIDTH;
+               break;
+       case RATE_INFO_BW_160:
+               rate_flg = NL80211_RATE_INFO_160_MHZ_WIDTH;
+               break;
+       }
+
+       if (rate_flg && nla_put_flag(msg, rate_flg))
+               return false;
+
        if (info->flags & RATE_INFO_FLAGS_MCS) {
                if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
                        return false;
-               if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
-                   nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
-                       return false;
                if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
                    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
                        return false;
@@ -3598,18 +3635,6 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
                        return false;
                if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
                        return false;
-               if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
-                   nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
-                       return false;
-               if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
-                   nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
-                       return false;
-               if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
-                   nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
-                       return false;
-               if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
-                   nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
-                       return false;
                if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
                    nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
                        return false;
@@ -3645,8 +3670,8 @@ static bool nl80211_put_signal(struct sk_buff *msg, u8 mask, s8 *signal,
        return true;
 }
 
-static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
-                               int flags,
+static int nl80211_send_station(struct sk_buff *msg, u32 cmd, u32 portid,
+                               u32 seq, int flags,
                                struct cfg80211_registered_device *rdev,
                                struct net_device *dev,
                                const u8 *mac_addr, struct station_info *sinfo)
@@ -3654,7 +3679,7 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
        void *hdr;
        struct nlattr *sinfoattr, *bss_param;
 
-       hdr = nl80211hdr_put(msg, portid, seq, flags, NL80211_CMD_NEW_STATION);
+       hdr = nl80211hdr_put(msg, portid, seq, flags, cmd);
        if (!hdr)
                return -1;
 
@@ -3666,115 +3691,77 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
        sinfoattr = nla_nest_start(msg, NL80211_ATTR_STA_INFO);
        if (!sinfoattr)
                goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_CONNECTED_TIME) &&
-           nla_put_u32(msg, NL80211_STA_INFO_CONNECTED_TIME,
-                       sinfo->connected_time))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_INACTIVE_TIME) &&
-           nla_put_u32(msg, NL80211_STA_INFO_INACTIVE_TIME,
-                       sinfo->inactive_time))
-               goto nla_put_failure;
-       if ((sinfo->filled & (STATION_INFO_RX_BYTES |
-                             STATION_INFO_RX_BYTES64)) &&
+
+#define PUT_SINFO(attr, memb, type) do {                               \
+       if (sinfo->filled & BIT(NL80211_STA_INFO_ ## attr) &&           \
+           nla_put_ ## type(msg, NL80211_STA_INFO_ ## attr,            \
+                            sinfo->memb))                              \
+               goto nla_put_failure;                                   \
+       } while (0)
+
+       PUT_SINFO(CONNECTED_TIME, connected_time, u32);
+       PUT_SINFO(INACTIVE_TIME, inactive_time, u32);
+
+       if (sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES) |
+                            BIT(NL80211_STA_INFO_RX_BYTES64)) &&
            nla_put_u32(msg, NL80211_STA_INFO_RX_BYTES,
                        (u32)sinfo->rx_bytes))
                goto nla_put_failure;
-       if ((sinfo->filled & (STATION_INFO_TX_BYTES |
-                             STATION_INFO_TX_BYTES64)) &&
+
+       if (sinfo->filled & (BIT(NL80211_STA_INFO_TX_BYTES) |
+                            BIT(NL80211_STA_INFO_TX_BYTES64)) &&
            nla_put_u32(msg, NL80211_STA_INFO_TX_BYTES,
                        (u32)sinfo->tx_bytes))
                goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_RX_BYTES64) &&
-           nla_put_u64(msg, NL80211_STA_INFO_RX_BYTES64,
-                       sinfo->rx_bytes))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_TX_BYTES64) &&
-           nla_put_u64(msg, NL80211_STA_INFO_TX_BYTES64,
-                       sinfo->tx_bytes))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_LLID) &&
-           nla_put_u16(msg, NL80211_STA_INFO_LLID, sinfo->llid))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_PLID) &&
-           nla_put_u16(msg, NL80211_STA_INFO_PLID, sinfo->plid))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_PLINK_STATE) &&
-           nla_put_u8(msg, NL80211_STA_INFO_PLINK_STATE,
-                      sinfo->plink_state))
-               goto nla_put_failure;
+
+       PUT_SINFO(RX_BYTES64, rx_bytes, u64);
+       PUT_SINFO(TX_BYTES64, tx_bytes, u64);
+       PUT_SINFO(LLID, llid, u16);
+       PUT_SINFO(PLID, plid, u16);
+       PUT_SINFO(PLINK_STATE, plink_state, u8);
+
        switch (rdev->wiphy.signal_type) {
        case CFG80211_SIGNAL_TYPE_MBM:
-               if ((sinfo->filled & STATION_INFO_SIGNAL) &&
-                   nla_put_u8(msg, NL80211_STA_INFO_SIGNAL,
-                              sinfo->signal))
-                       goto nla_put_failure;
-               if ((sinfo->filled & STATION_INFO_SIGNAL_AVG) &&
-                   nla_put_u8(msg, NL80211_STA_INFO_SIGNAL_AVG,
-                              sinfo->signal_avg))
-                       goto nla_put_failure;
+               PUT_SINFO(SIGNAL, signal, u8);
+               PUT_SINFO(SIGNAL_AVG, signal_avg, u8);
                break;
        default:
                break;
        }
-       if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL) {
+       if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL)) {
                if (!nl80211_put_signal(msg, sinfo->chains,
                                        sinfo->chain_signal,
                                        NL80211_STA_INFO_CHAIN_SIGNAL))
                        goto nla_put_failure;
        }
-       if (sinfo->filled & STATION_INFO_CHAIN_SIGNAL_AVG) {
+       if (sinfo->filled & BIT(NL80211_STA_INFO_CHAIN_SIGNAL_AVG)) {
                if (!nl80211_put_signal(msg, sinfo->chains,
                                        sinfo->chain_signal_avg,
                                        NL80211_STA_INFO_CHAIN_SIGNAL_AVG))
                        goto nla_put_failure;
        }
-       if (sinfo->filled & STATION_INFO_TX_BITRATE) {
+       if (sinfo->filled & BIT(NL80211_STA_INFO_TX_BITRATE)) {
                if (!nl80211_put_sta_rate(msg, &sinfo->txrate,
                                          NL80211_STA_INFO_TX_BITRATE))
                        goto nla_put_failure;
        }
-       if (sinfo->filled & STATION_INFO_RX_BITRATE) {
+       if (sinfo->filled & BIT(NL80211_STA_INFO_RX_BITRATE)) {
                if (!nl80211_put_sta_rate(msg, &sinfo->rxrate,
                                          NL80211_STA_INFO_RX_BITRATE))
                        goto nla_put_failure;
        }
-       if ((sinfo->filled & STATION_INFO_RX_PACKETS) &&
-           nla_put_u32(msg, NL80211_STA_INFO_RX_PACKETS,
-                       sinfo->rx_packets))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_TX_PACKETS) &&
-           nla_put_u32(msg, NL80211_STA_INFO_TX_PACKETS,
-                       sinfo->tx_packets))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_TX_RETRIES) &&
-           nla_put_u32(msg, NL80211_STA_INFO_TX_RETRIES,
-                       sinfo->tx_retries))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_TX_FAILED) &&
-           nla_put_u32(msg, NL80211_STA_INFO_TX_FAILED,
-                       sinfo->tx_failed))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_EXPECTED_THROUGHPUT) &&
-           nla_put_u32(msg, NL80211_STA_INFO_EXPECTED_THROUGHPUT,
-                       sinfo->expected_throughput))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_BEACON_LOSS_COUNT) &&
-           nla_put_u32(msg, NL80211_STA_INFO_BEACON_LOSS,
-                       sinfo->beacon_loss_count))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_LOCAL_PM) &&
-           nla_put_u32(msg, NL80211_STA_INFO_LOCAL_PM,
-                       sinfo->local_pm))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_PEER_PM) &&
-           nla_put_u32(msg, NL80211_STA_INFO_PEER_PM,
-                       sinfo->peer_pm))
-               goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_NONPEER_PM) &&
-           nla_put_u32(msg, NL80211_STA_INFO_NONPEER_PM,
-                       sinfo->nonpeer_pm))
-               goto nla_put_failure;
-       if (sinfo->filled & STATION_INFO_BSS_PARAM) {
+
+       PUT_SINFO(RX_PACKETS, rx_packets, u32);
+       PUT_SINFO(TX_PACKETS, tx_packets, u32);
+       PUT_SINFO(TX_RETRIES, tx_retries, u32);
+       PUT_SINFO(TX_FAILED, tx_failed, u32);
+       PUT_SINFO(EXPECTED_THROUGHPUT, expected_throughput, u32);
+       PUT_SINFO(BEACON_LOSS, beacon_loss_count, u32);
+       PUT_SINFO(LOCAL_PM, local_pm, u32);
+       PUT_SINFO(PEER_PM, peer_pm, u32);
+       PUT_SINFO(NONPEER_PM, nonpeer_pm, u32);
+
+       if (sinfo->filled & BIT(NL80211_STA_INFO_BSS_PARAM)) {
                bss_param = nla_nest_start(msg, NL80211_STA_INFO_BSS_PARAM);
                if (!bss_param)
                        goto nla_put_failure;
@@ -3793,23 +3780,68 @@ static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
 
                nla_nest_end(msg, bss_param);
        }
-       if ((sinfo->filled & STATION_INFO_STA_FLAGS) &&
+       if ((sinfo->filled & BIT(NL80211_STA_INFO_STA_FLAGS)) &&
            nla_put(msg, NL80211_STA_INFO_STA_FLAGS,
                    sizeof(struct nl80211_sta_flag_update),
                    &sinfo->sta_flags))
                goto nla_put_failure;
-       if ((sinfo->filled & STATION_INFO_T_OFFSET) &&
-               nla_put_u64(msg, NL80211_STA_INFO_T_OFFSET,
-                           sinfo->t_offset))
-               goto nla_put_failure;
+
+       PUT_SINFO(T_OFFSET, t_offset, u64);
+       PUT_SINFO(RX_DROP_MISC, rx_dropped_misc, u64);
+       PUT_SINFO(BEACON_RX, rx_beacon, u64);
+       PUT_SINFO(BEACON_SIGNAL_AVG, rx_beacon_signal_avg, u8);
+
+#undef PUT_SINFO
+
+       if (sinfo->filled & BIT(NL80211_STA_INFO_TID_STATS)) {
+               struct nlattr *tidsattr;
+               int tid;
+
+               tidsattr = nla_nest_start(msg, NL80211_STA_INFO_TID_STATS);
+               if (!tidsattr)
+                       goto nla_put_failure;
+
+               for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
+                       struct cfg80211_tid_stats *tidstats;
+                       struct nlattr *tidattr;
+
+                       tidstats = &sinfo->pertid[tid];
+
+                       if (!tidstats->filled)
+                               continue;
+
+                       tidattr = nla_nest_start(msg, tid + 1);
+                       if (!tidattr)
+                               goto nla_put_failure;
+
+#define PUT_TIDVAL(attr, memb, type) do {                              \
+       if (tidstats->filled & BIT(NL80211_TID_STATS_ ## attr) &&       \
+           nla_put_ ## type(msg, NL80211_TID_STATS_ ## attr,           \
+                            tidstats->memb))                           \
+               goto nla_put_failure;                                   \
+       } while (0)
+
+                       PUT_TIDVAL(RX_MSDU, rx_msdu, u64);
+                       PUT_TIDVAL(TX_MSDU, tx_msdu, u64);
+                       PUT_TIDVAL(TX_MSDU_RETRIES, tx_msdu_retries, u64);
+                       PUT_TIDVAL(TX_MSDU_FAILED, tx_msdu_failed, u64);
+
+#undef PUT_TIDVAL
+                       nla_nest_end(msg, tidattr);
+               }
+
+               nla_nest_end(msg, tidsattr);
+       }
+
        nla_nest_end(msg, sinfoattr);
 
-       if ((sinfo->filled & STATION_INFO_ASSOC_REQ_IES) &&
+       if (sinfo->assoc_req_ies_len &&
            nla_put(msg, NL80211_ATTR_IE, sinfo->assoc_req_ies_len,
                    sinfo->assoc_req_ies))
                goto nla_put_failure;
 
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -3849,7 +3881,7 @@ static int nl80211_dump_station(struct sk_buff *skb,
                if (err)
                        goto out_err;
 
-               if (nl80211_send_station(skb,
+               if (nl80211_send_station(skb, NL80211_CMD_NEW_STATION,
                                NETLINK_CB(cb->skb).portid,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
                                rdev, wdev->netdev, mac_addr,
@@ -3896,7 +3928,8 @@ static int nl80211_get_station(struct sk_buff *skb, struct genl_info *info)
        if (!msg)
                return -ENOMEM;
 
-       if (nl80211_send_station(msg, info->snd_portid, info->snd_seq, 0,
+       if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION,
+                                info->snd_portid, info->snd_seq, 0,
                                 rdev, dev, mac_addr, &sinfo) < 0) {
                nlmsg_free(msg);
                return -ENOBUFS;
@@ -4538,7 +4571,8 @@ static int nl80211_send_mpath(struct sk_buff *msg, u32 portid, u32 seq,
 
        nla_nest_end(msg, pinfoattr);
 
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -5490,7 +5524,8 @@ static int nl80211_send_regdom(struct sk_buff *msg, struct netlink_callback *cb,
            nla_put_flag(msg, NL80211_ATTR_WIPHY_SELF_MANAGED_REG))
                goto nla_put_failure;
 
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
 nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -6123,7 +6158,7 @@ nl80211_parse_sched_scan(struct wiphy *wiphy, struct wireless_dev *wdev,
                }
 
                /* there was no other matchset, so the RSSI one is alone */
-               if (i == 0)
+               if (i == 0 && n_match_sets)
                        request->match_sets[0].rssi_thold = default_match_rssi;
 
                request->min_rssi_thold = INT_MAX;
@@ -6560,7 +6595,8 @@ static int nl80211_send_bss(struct sk_buff *msg, struct netlink_callback *cb,
 
        nla_nest_end(msg, bss);
 
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
  fail_unlock_rcu:
        rcu_read_unlock();
@@ -6608,12 +6644,17 @@ 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,
-                               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)
@@ -6626,7 +6667,8 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
        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;
 
@@ -6636,49 +6678,57 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 portid, u32 seq,
        if ((survey->filled & SURVEY_INFO_IN_USE) &&
            nla_put_flag(msg, NL80211_SURVEY_INFO_IN_USE))
                goto nla_put_failure;
-       if ((survey->filled & SURVEY_INFO_CHANNEL_TIME) &&
-           nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME,
-                       survey->channel_time))
+       if ((survey->filled & SURVEY_INFO_TIME) &&
+           nla_put_u64(msg, NL80211_SURVEY_INFO_TIME,
+                       survey->time))
                goto nla_put_failure;
-       if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_BUSY) &&
-           nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_BUSY,
-                       survey->channel_time_busy))
+       if ((survey->filled & SURVEY_INFO_TIME_BUSY) &&
+           nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_BUSY,
+                       survey->time_busy))
                goto nla_put_failure;
-       if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_EXT_BUSY) &&
-           nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_EXT_BUSY,
-                       survey->channel_time_ext_busy))
+       if ((survey->filled & SURVEY_INFO_TIME_EXT_BUSY) &&
+           nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_EXT_BUSY,
+                       survey->time_ext_busy))
                goto nla_put_failure;
-       if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_RX) &&
-           nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_RX,
-                       survey->channel_time_rx))
+       if ((survey->filled & SURVEY_INFO_TIME_RX) &&
+           nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_RX,
+                       survey->time_rx))
                goto nla_put_failure;
-       if ((survey->filled & SURVEY_INFO_CHANNEL_TIME_TX) &&
-           nla_put_u64(msg, NL80211_SURVEY_INFO_CHANNEL_TIME_TX,
-                       survey->channel_time_tx))
+       if ((survey->filled & SURVEY_INFO_TIME_TX) &&
+           nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_TX,
+                       survey->time_tx))
+               goto nla_put_failure;
+       if ((survey->filled & SURVEY_INFO_TIME_SCAN) &&
+           nla_put_u64(msg, NL80211_SURVEY_INFO_TIME_SCAN,
+                       survey->time_scan))
                goto nla_put_failure;
 
        nla_nest_end(msg, infoattr);
 
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
        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;
@@ -6696,13 +6746,9 @@ static int nl80211_dump_survey(struct sk_buff *skb,
                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;
                }
@@ -6710,7 +6756,7 @@ static int nl80211_dump_survey(struct sk_buff *skb,
                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++;
        }
@@ -8726,6 +8772,48 @@ static int nl80211_send_wowlan_tcp(struct sk_buff *msg,
        return 0;
 }
 
+static int nl80211_send_wowlan_nd(struct sk_buff *msg,
+                                 struct cfg80211_sched_scan_request *req)
+{
+       struct nlattr *nd, *freqs, *matches, *match;
+       int i;
+
+       if (!req)
+               return 0;
+
+       nd = nla_nest_start(msg, NL80211_WOWLAN_TRIG_NET_DETECT);
+       if (!nd)
+               return -ENOBUFS;
+
+       if (nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, req->interval))
+               return -ENOBUFS;
+
+       freqs = nla_nest_start(msg, NL80211_ATTR_SCAN_FREQUENCIES);
+       if (!freqs)
+               return -ENOBUFS;
+
+       for (i = 0; i < req->n_channels; i++)
+               nla_put_u32(msg, i, req->channels[i]->center_freq);
+
+       nla_nest_end(msg, freqs);
+
+       if (req->n_match_sets) {
+               matches = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+               for (i = 0; i < req->n_match_sets; i++) {
+                       match = nla_nest_start(msg, i);
+                       nla_put(msg, NL80211_SCHED_SCAN_MATCH_ATTR_SSID,
+                               req->match_sets[i].ssid.ssid_len,
+                               req->match_sets[i].ssid.ssid);
+                       nla_nest_end(msg, match);
+               }
+               nla_nest_end(msg, matches);
+       }
+
+       nla_nest_end(msg, nd);
+
+       return 0;
+}
+
 static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -8783,6 +8871,11 @@ static int nl80211_get_wowlan(struct sk_buff *skb, struct genl_info *info)
                                            rdev->wiphy.wowlan_config->tcp))
                        goto nla_put_failure;
 
+               if (nl80211_send_wowlan_nd(
+                           msg,
+                           rdev->wiphy.wowlan_config->nd_config))
+                       goto nla_put_failure;
+
                nla_nest_end(msg, nl_wowlan);
        }
 
@@ -10952,7 +11045,8 @@ static int nl80211_send_scan_msg(struct sk_buff *msg,
        /* ignore errors and send incomplete event anyway */
        nl80211_add_scan_req(msg, rdev);
 
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -10975,7 +11069,8 @@ nl80211_send_sched_scan_msg(struct sk_buff *msg,
            nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
                goto nla_put_failure;
 
-       return genlmsg_end(msg, hdr);
+       genlmsg_end(msg, hdr);
+       return 0;
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
@@ -11673,7 +11768,7 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
        if (!msg)
                return;
 
-       if (nl80211_send_station(msg, 0, 0, 0,
+       if (nl80211_send_station(msg, NL80211_CMD_NEW_STATION, 0, 0, 0,
                                 rdev, dev, mac_addr, sinfo) < 0) {
                nlmsg_free(msg);
                return;
@@ -11684,12 +11779,16 @@ void cfg80211_new_sta(struct net_device *dev, const u8 *mac_addr,
 }
 EXPORT_SYMBOL(cfg80211_new_sta);
 
-void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
+void cfg80211_del_sta_sinfo(struct net_device *dev, const u8 *mac_addr,
+                           struct station_info *sinfo, gfp_t gfp)
 {
        struct wiphy *wiphy = dev->ieee80211_ptr->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
        struct sk_buff *msg;
-       void *hdr;
+       struct station_info empty_sinfo = {};
+
+       if (!sinfo)
+               sinfo = &empty_sinfo;
 
        trace_cfg80211_del_sta(dev, mac_addr);
 
@@ -11697,27 +11796,16 @@ void cfg80211_del_sta(struct net_device *dev, const u8 *mac_addr, gfp_t gfp)
        if (!msg)
                return;
 
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_DEL_STATION);
-       if (!hdr) {
+       if (nl80211_send_station(msg, NL80211_CMD_DEL_STATION, 0, 0, 0,
+                                rdev, dev, mac_addr, sinfo) < 0) {
                nlmsg_free(msg);
                return;
        }
 
-       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
-           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, mac_addr))
-               goto nla_put_failure;
-
-       genlmsg_end(msg, hdr);
-
        genlmsg_multicast_netns(&nl80211_fam, wiphy_net(&rdev->wiphy), msg, 0,
                                NL80211_MCGRP_MLME, gfp);
-       return;
-
- nla_put_failure:
-       genlmsg_cancel(msg, hdr);
-       nlmsg_free(msg);
 }
-EXPORT_SYMBOL(cfg80211_del_sta);
+EXPORT_SYMBOL(cfg80211_del_sta_sinfo);
 
 void cfg80211_conn_failed(struct net_device *dev, const u8 *mac_addr,
                          enum nl80211_connect_failed_reason reason,